¿Cómo analizar una cadena JSON en JsonNode en Jackson?

231

Debería ser tan simple, pero no puedo encontrarlo después de haberlo intentado durante una hora.

Necesito obtener una cadena JSON, por ejemplo {"k1":v1,"k2":v2}, analizada como a JsonNode.

JsonFactory factory = new JsonFactory();
JsonParser jp = factory.createJsonParser("{\"k1\":\"v1\"}");
JsonNode actualObj = jp.readValueAsTree();

da

java.lang.IllegalStateException: No ObjectCodec defined for the parser, can not deserialize JSON into JsonNode tree

fadmaa
fuente
54
#embarrasing- no Si las cosas simples no son simples, entonces el diseñador de la API ha fallado, no tú.
jameshfisher
Respuesta de @ StaxMan en el código: JsonFactory factory = new MappingJsonFactory ();
Juan Rojas

Respuestas:

371

Una ligera variación en la respuesta de Richards, pero readTreepuede tomar una cadena para que pueda simplificarla a:

ObjectMapper mapper = new ObjectMapper();
JsonNode actualObj = mapper.readTree("{\"k1\":\"v1\"}");
slashnick
fuente
44
Para cualquiera que necesite un uso en ObjectNodelugar de un JsonNodeusomapper.valueToTree("{\"k1\":\"v1\"}")
Matthew Herbst
55
@MatthewHerbst En 2.5.1, esto crea un nuevo nodo de texto con la cadena "{\" k1 \ ": \" v1 \ "}" en lugar de analizarlo como JSON.
minexew
69

Necesitas usar un ObjectMapper:

ObjectMapper mapper = new ObjectMapper();
JsonFactory factory = mapper.getJsonFactory(); // since 2.1 use mapper.getFactory() instead
JsonParser jp = factory.createJsonParser("{\"k1\":\"v1\"}");
JsonNode actualObj = mapper.readTree(jp);

Puede encontrar más documentación sobre la creación de analizadores aquí .

Richard Fearn
fuente
¿Es posible tomar el JsonNode, modificarlo un poco y luego llamar a mapper.readValue (nodo, clase); y salir de una clase?
portforwardpodcast
1
Si. Incluso hay un alias para que, mapper.treeToValue(). Pero readValue()también funciona.
StaxMan
El enlace parece estar roto
manuna
28

Una tercera variante:

ObjectMapper mapper = new ObjectMapper();
JsonNode actualObj = mapper.readValue("{\"k1\":\"v1\"}", JsonNode.class);
qerub
fuente
¿Qué te hizo pasar aquí en JsonNode.class?
David
3
@David: Nada, así que la variante de Slashnick es obviamente mejor si solo quieres una JsonNode. Sin embargo, por lo general no quieres un JsonNode, así que quería mostrarte cómo decirle a Jackson qué tipo de valor quieres.
qerub
Para mí, JsonNodeaparentemente era necesario pasar para evitar que Jackson lo deserializara como algo más, lo que habría fallado.
Cory Klein
5

La respuesta de Richard es correcta. Alternativamente, también puede crear un MappingJsonFactory(in org.codehaus.jackson.map) que sepa dónde encontrar ObjectMapper. El error que obtuvo fue porque el regular JsonFactory(del corepaquete) no tiene dependencia ObjectMapper(que está en el mapperpaquete).

Pero generalmente solo usa ObjectMappery no se preocupa por JsonParserotros componentes de bajo nivel; solo serán necesarios si desea unir partes de datos de la transmisión o hacer un manejo de bajo nivel.

StaxMan
fuente
3
import com.github.fge.jackson.JsonLoader;
JsonLoader.fromString("{\"k1\":\"v1\"}")
== JsonNode = {"k1":"v1"}
pdxleif
fuente
0

Nuevo enfoque a la vieja pregunta. Una solución que funciona desde java 9+

ObjectNode agencyNode = new ObjectMapper().valueToTree(Map.of("key", "value"));

es más legible y mantenible para objetos complejos. Ej

Map<String, Object> agencyMap = Map.of(
        "name", "Agencia Prueba",
        "phone1", "1198788373",
        "address", "Larrea 45 e/ calligaris y paris",
        "number", 267,
        "enable", true,
        "location", Map.of("id", 54),
        "responsible", Set.of(Map.of("id", 405)),
        "sellers", List.of(Map.of("id", 605))
);
ObjectNode agencyNode = new ObjectMapper().valueToTree(agencyMap);
Manuel Ortiz
fuente