Convertir JsonNode en POJO

143

Cela peut sembler un peu inhabituel, mais je recherche un moyen efficace de transformer / mapper un JsonNodeen un fichier POJO.

Je stocke certaines des informations de mon modèle dans des fichiers json et je dois prendre en charge quelques versions de mon modèle.

Ce que je fais, c'est charger le fichier json en mémoire dans un JsonNode, appliquer quelques stratégies de contrôle de version pour le faire correspondre à la dernière version de mon modèle.

    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);

À moins qu'il n'y ait un moyen plus rapide de le faire, je finirai probablement par appliquer simplement manuellement le JsonNodesà mon modèle

Alexandre
la source

Réponses:

264

Dans Jackson 2.4, vous pouvez convertir comme suit:

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

jsonObjectMapperest un Jackson ObjectMapper.


Dans les anciennes versions de Jackson, ce serait

MyClass newJsonNode = jsonObjectMapper.readValue(someJsonNode, MyClass.class);
arbres de glace
la source
19
Malheureusement, il n'y a pas de variante treeToValue (TreeNode n, TypeReference <T> type) comme c'est le cas pour readValue (). Mauvaise nouvelle pour quiconque traite avec des types plus complexes de génériques :(
Espinosa
13
@Espinosa Per jackson-databind # 1294 , vous voudrez quelque chose comme (malheureusement plus verbeux)jsonObjectMapper.readValue(jsonObjectMapper.treeAsTokens(someJsonNode), someTypeReference)
M. Justin
Pour les anciennes versions, utilisez:objectMapper.treeToValue(jsonNode, MyClass.class)
amod
2
Vous pouvez également utiliser cette méthode dans StdDeserializer: p.codec.treeToValue.
galcyurio
@icedtrees jsonObjectMapper est une instance de JsonObjectMapper ou juste l'ObjectMapper
KNDheeraj
8

Cela devrait faire l'affaire:

mapper.readValue(fileReader, MyClass.class);

Je dis que je devrais parce que je l'utilise avec un String, pas un, BufferedReadermais cela devrait toujours fonctionner.

Voici mon code:

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

Voici la documentation officielle pour cet appel: http://jackson.codehaus.org/1.7.9/javadoc/org/codehaus/jackson/map/ObjectMapper.html#readValue(java.lang.String, java.lang.Class)

Vous pouvez également définir un désérialiseur personnalisé lorsque vous instanciez le ObjectMapper: http://wiki.fasterxml.com/JacksonHowToCustomDeserializers

Edit: Je viens de me rappeler autre chose. Si votre objet entrant a plus de propriétés que le POJOa et que vous voulez simplement ignorer les extras, vous voudrez définir ceci:

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

Ou vous obtiendrez une erreur dans laquelle il ne peut pas trouver la propriété à définir.

Eric Barr
la source
Je vais utiliser un CustomDeserializers, ça va me sauver beaucoup de maux de tête! Je pourrai également y appliquer mes stratégies de versioning avec très peu de modifications. Merci!
Alexandre
5
La syntaxe est maintenant: com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper (); mapper.disable (com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
llambda
Bon point @llambda! Je n'ai pas touché à l'ObjectMapper depuis la version 1.7.9, il semble que ma réponse soit dépassée par quelques versions. Vérifiez certainement la version de Jackson que vous utilisez.
Eric Barr
@EricBarr, j'utilise Jackson v1.9.11 et la syntaxe de votre réponse est la bonne pour cette version. Peut-être ont-ils essayé de changer les choses et de les inverser à nouveau dans les versions plus récentes
Ivaylo Slavov
5

Si vous utilisez org.codehaus.jackson, cela est possible depuis la version 1.6. Vous pouvez convertir un JsonNode en POJO avec 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
la source
5
Cette méthode semble manquer dans 2.4.4
Kevin Wittek
1
Voir la réponse d' icedtrees ci-dessous, pour une solution version 2
Tim Büthe
La documentation est maintenant à plus rapidexml.github.io/jackson-databind/javadoc/2.5/com/fasterxml/…
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 votre entrée JSON dans a plus de propriétés que votre POJO et que vous voulez simplement ignorer les extras de Jackson 2.4, vous pouvez configurer votre ObjectMapper comme suit. Cette syntaxe est différente des anciennes versions de Jackson. (Si vous utilisez la mauvaise syntaxe, cela ne fera rien en silence.)

mapper.disable(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNK‌​NOWN_PROPERTIES);
Llambda
la source