En Java, necesito consumir JSON (ejemplo a continuación), con una serie de claves arbitrarias, y producir Map<String, String>. Me gustaría utilizar una biblioteca JSON estándar, compatible a largo plazo para el análisis. Sin embargo, mi investigación muestra que estas bibliotecas están configuradas para la deserialización de las clases Java, donde conoce los campos de antemano. Solo necesito construir Maps.

En realidad, es un paso más complicado que eso, porque las claves arbitrarias no son el nivel superior de JSON; solo ocurren como un sub-objeto para prefs. El resto es conocido y puede caber en una clase predefinida.

{
    "al" : { "type": "admin", "prefs" : { "arbitrary_key_a":"arbitary_value_a", "arbitrary_key_b":"arbitary_value_b"}},
    "bert" : {"type": "user", "prefs" : { "arbitrary_key_x":"arbitary_value_x", "arbitrary_key_y":"arbitary_value_y"}},
    ...
}

En Java, quiero poder tomar esa cadena y hacer algo como:

people.get("al").get("prefs"); // Returns Map<String, String>

¿Cómo puedo hacer esto? Me gustaría usar un analizador estándar bien soportado, evitar excepciones y mantener las cosas simples.


Actualizar

@kumensa ha señalado que esto es más difícil de lo que parece. Ser capaz de hacer:

people.get("al").getPrefs(); // Returns Map<String, String>
people.get("al").getType();  // Returns String

Es igual de buena

Eso debería analizar el JSON a algo como:

public class Person {
    public String type;
    public HashMap<String, String> prefs;
}
// JSON parsed to:
HashMap<String, Person>
2
SRobertJames 10 may. 2019 a las 10:13

3 respuestas

La mejor respuesta

Con su clase Person y usando Gson, simplemente puede hacer:

final Map<String, Person> result = new Gson().fromJson(json, new TypeToken<Map<String, Person>>() {}.getType());

Luego, la recuperación de prefs se logra con people.get("al").getPrefs();.

Pero tenga cuidado: su cadena json no es válida. No debería comenzar con "people:".

1
Abrikot 10 may. 2019 a las 08:19
public static <T> Map<String, T> readMap(String json) {
    if (StringUtils.isEmpty(json))
        return Collections.emptyMap();

    ObjectReader reader = new ObjectMapper().readerFor(Map.class);
    MappingIterator<Map<String, T>> it = reader.readValues(json);

    if (it.hasNextValue()) {
        Map<String, T> res = it.next();
        return res.isEmpty() ? Collections.emptyMap() : res;
    }

    return Collections.emptyMap();
}

Todo lo que necesita hacer a continuación es comprobar el tipo de Object. Si es Map, entonces tienes un objeto. De lo contrario, este es un valor simple.

0
oleg.cherednik 10 may. 2019 a las 07:34

Puede usar Jackson lib para lograr esto. Ponga lo siguiente en pom.xml.

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.8</version>
</dependency>

Consulte el siguiente fragmento que demuestra lo mismo.

ObjectMapper mapper = new ObjectMapper();
HashMap<String, Object> people = mapper.readValue(jsonString, new TypeReference<HashMap>(){});

Ahora, se deserializa como un Mapa;

Ejemplo completo:

import java.io.IOException;
import java.util.HashMap;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class testMain {

    public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {

        String json = "{\"address\":\"3, 43, Cashier Layout, Tavarekere Main Road, 1st Stage, BTM Layout, Ambika Medical, 560029\",\"addressparts\":{\"apartment\":\"Cashier Layout\",\"area\":\"BTM Layout\",\"floor\":\"3\",\"house\":\"43\",\"landmark\":\"Ambika Medical\",\"pincode\":\"560029\",\"street\":\"Tavarekere Main Road\",\"subarea\":\"1st Stage\"}}";

        ObjectMapper mapper = new ObjectMapper();
        HashMap<String, Object> people = mapper.readValue(json, new TypeReference<HashMap>(){});

        System.out.println(((HashMap<String, String>)people.get("addressparts")).get("apartment"));
    }

}

Salida: diseño del cajero

0
azhar 10 may. 2019 a las 08:08