Convertir JsonNode en POJO

143

Esto puede parecer un poco inusual, pero estoy buscando una manera eficiente de transformar / mapear a JsonNodeen a POJO.

Guardo parte de la información de mi modelo en archivos json y tengo que admitir un par de versiones de mi modelo.

Lo que hago es cargar el archivo json en la memoria en un JsonNode, aplicar un par de estrategias de versiones para que coincida con la última versión de mi Modelo.

    ObjectMapper mapper = new ObjectMapper();
    BufferedReader fileReader = new BufferedReader(new FileReader(projPath));

    JsonNode rootNode = mapper.readTree(fileReader);

    //Upgrade our file in memory
    applyVersioningStrategy(rootNode);

    ProjectModel project = mapJsonNodeToProject(rootNode);

A menos que haya una forma más rápida de hacerlo, probablemente termine simplemente aplicando manualmente JsonNodesa mi Modelo

Alexandre
fuente

Respuestas:

264

En Jackson 2.4, puedes convertir lo siguiente:

MyClass newJsonNode = jsonObjectMapper.treeToValue(someJsonNode, MyClass.class);

¿Dónde jsonObjectMapperestá un Jackson ObjectMapper?


En versiones anteriores de Jackson, sería

MyClass newJsonNode = jsonObjectMapper.readValue(someJsonNode, MyClass.class);
icedtrees
fuente
18
Desafortunadamente no hay una variante treeToValue (TreeNode n, TypeReference <T> type) como la hay para readValue (). Malas noticias para cualquiera que trate con tipos más complejos con genéricos :(
Espinosa
13
@Espinosa Per jackson-databind # 1294 , querrás algo como (desafortunadamente más detallado)jsonObjectMapper.readValue(jsonObjectMapper.treeAsTokens(someJsonNode), someTypeReference)
M. Justin
Para uso en versiones anteriores:objectMapper.treeToValue(jsonNode, MyClass.class)
amod
2
También puede utilizar este método en StdDeserializer: p.codec.treeToValue.
galcyurio
@icedtrees jsonObjectMapper es una instancia de JsonObjectMapper o simplemente el ObjectMapper
KNDheeraj
8

Esto debería funcionar:

mapper.readValue(fileReader, MyClass.class);

Digo debería porque lo estoy usando con un String, no con un BufferedReaderpero todavía debería funcionar.

Aquí está mi código:

String inputString = // I grab my string here
MySessionClass sessionObject;
try {
    ObjectMapper objectMapper = new ObjectMapper();
    sessionObject = objectMapper.readValue(inputString, MySessionClass.class);

Aquí está la documentación oficial para esa llamada: http://jackson.codehaus.org/1.7.9/javadoc/org/codehaus/jackson/map/ObjectMapper.html#readValue(java.lang.String, java.lang.Class)

También puede definir un deserializador personalizado cuando crea una instancia de ObjectMapper: http://wiki.fasterxml.com/JacksonHowToCustomDeserializers

Editar: acabo de recordar algo más. Si su objeto entrante tiene más propiedades que las que POJOtiene y solo quiere ignorar los extras, querrá configurar esto:

    objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);

O recibirá un error que no puede encontrar la propiedad para establecer.

Eric Barr
fuente
Usaré un CustomDeserializers, ¡me ahorrará muchos dolores de cabeza! También podré aplicar mis estrategias de versiones allí con muy pocas modificaciones. ¡Gracias!
Alexandre
55
La sintaxis ahora es: com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper (); mapper.disable (com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
llambda
Buen punto @llambda! No he tocado el ObjectMapper desde la versión 1.7.9, parece que mi respuesta está desactualizada en algunas versiones. Definitivamente verifica qué versión de Jackson estás usando.
Eric Barr
@EricBarr, estoy usando Jackson v1.9.11 y la sintaxis en su respuesta es la correcta para esa versión. Tal vez trataron de cambiar las cosas y las revirtieron nuevamente en las versiones más recientes
Ivaylo Slavov el
5

Si está usando org.codehaus.jackson, esto ha sido posible desde 1.6. Puede convertir un JsonNode en un POJO con ObjectMapper#readValue: http://jackson.codehaus.org/1.9.4/javadoc/org/codehaus/jackson/map/ObjectMapper.html#readValue(org.codehaus.jackson.JsonNode , java. lang.Class)


    ObjectMapper mapper = new ObjectMapper();
    JsonParser jsonParser = mapper.getJsonFactory().createJsonParser("{\"foo\":\"bar\"}");
    JsonNode tree = jsonParser.readValueAsTree();
    // Do stuff to the tree
    mapper.readValue(tree, Foo.class);
mumrah
fuente
55
Parece que faltan estos métodos en 2.4.4
Kevin Wittek
1
Vea la respuesta de icedtrees a continuación, para una solución de la versión 2
Tim Büthe
La documentación está ahora en más rápidoxml.github.io
David Tonhofer
3
String jsonInput = "{ \"hi\": \"Assume this is the JSON\"} ";
com.fasterxml.jackson.databind.ObjectMapper mapper =
    new com.fasterxml.jackson.databind.ObjectMapper();
MyClass myObject = objectMapper.readValue(jsonInput, MyClass.class);

Si su entrada JSON tiene más propiedades que su POJO y solo quiere ignorar los extras en Jackson 2.4, puede configurar su ObjectMapper de la siguiente manera. Esta sintaxis es diferente de las versiones anteriores de Jackson. (Si usa la sintaxis incorrecta, no hará nada en silencio).

mapper.disable(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNK‌​NOWN_PROPERTIES);
llambda
fuente