Konwertuj JsonNode na POJO

143

Może się to wydawać trochę niezwykłe, ale szukam skutecznego sposobu na przekształcenie / zmapowanie pliku JsonNodea POJO.

Przechowuję niektóre informacje o moim modelu w plikach json i muszę obsługiwać kilka wersji mojego modelu.

To, co robię, to załadowanie pliku json do pamięci w JsonNode, zastosowanie kilku strategii przechowywania wersji, aby dopasować go do najnowszej wersji mojego modelu.

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

O ile nie ma szybszego sposobu na zrobienie tego, prawdopodobnie w końcu po prostu ręcznie zastosuję JsonNodesdo mojego Modelu

Alexandre
źródło

Odpowiedzi:

264

W Jackson 2.4 możesz konwertować w następujący sposób:

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

gdzie jsonObjectMapperjest Jackson ObjectMapper.


W starszych wersjach Jacksona tak będzie

MyClass newJsonNode = jsonObjectMapper.readValue(someJsonNode, MyClass.class);
icedtrees
źródło
19
Niestety nie ma wariantu treeToValue (TreeNode n, TypeReference <T> type), takiego jak w przypadku readValue (). Zła wiadomość dla każdego, kto ma do czynienia z bardziej złożonymi typami z typami ogólnymi :(
Espinosa,
13
@Espinosa Per jackson-databind # 1294 , będziesz chciał coś takiego (niestety bardziej rozwlekłe)jsonObjectMapper.readValue(jsonObjectMapper.treeAsTokens(someJsonNode), someTypeReference)
M. Justin
Dla starszej wersji użyj:objectMapper.treeToValue(jsonNode, MyClass.class)
amod
2
Można również użyć tej metody w StdDeserializer: p.codec.treeToValue.
galcyurio
@icedtrees jsonObjectMapper to instancja JsonObjectMapper lub po prostu ObjectMapper
KNDheeraj
8

To powinno załatwić sprawę:

mapper.readValue(fileReader, MyClass.class);

Powinienem, ponieważ używam tego z a String, a nie a, BufferedReaderale powinno nadal działać.

Oto mój kod:

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

Oto oficjalna dokumentacja tego połączenia: http://jackson.codehaus.org/1.7.9/javadoc/org/codehaus/jackson/map/ObjectMapper.html#readValue(java.lang.String, java.lang.Class)

Możesz również zdefiniować niestandardowy deserializator podczas tworzenia wystąpienia ObjectMapper: http://wiki.fasterxml.com/JacksonHowToCustomDeserializers

Edycja: właśnie przypomniałem sobie coś innego. Jeśli twój obiekt ma więcej właściwości niż POJOma i chcesz po prostu zignorować dodatki, które chcesz ustawić w ten sposób:

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

Lub otrzymasz błąd, że nie może znaleźć właściwości do ustawienia.

Eric Barr
źródło
Użyję CustomDeserializerów, zaoszczędzi mi to wielu bólów głowy! Będę też mógł zastosować tam moje strategie wersjonowania z bardzo niewielkimi modyfikacjami. Dzięki!
Alexandre
5
Składnia jest teraz: com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper (); mapper.disable (com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
llambda
Słuszna uwaga @llambda! Nie dotykałem ObjectMapper od wersji 1.7.9, wygląda na to, że moja odpowiedź jest nieaktualna o kilka wersji. Zdecydowanie sprawdź, jakiej wersji Jacksona używasz.
Eric Barr
@EricBarr, używam Jackson v1.9.11 i składnia Twojej odpowiedzi jest poprawna dla tej wersji. Być może próbowali coś zmienić i cofnęli je ponownie w nowszych wersjach
Ivaylo Slavov
5

Jeśli używasz org.codehaus.jackson, jest to możliwe od 1.6. Możesz przekonwertować JsonNode na POJO za pomocą 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
źródło
5
Wydaje się, że tej metody brakuje w 2.4.4
Kevin Wittek
1
Zobacz odpowiedź icedtrees poniżej, dla rozwiązania w wersji 2
Tim Büthe
Dokumentacja jest teraz dostępna pod adresem quickxml.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);

Jeśli twoje dane wejściowe JSON mają więcej właściwości niż twoje POJO i chcesz po prostu zignorować dodatki w Jackson 2.4, możesz skonfigurować ObjectMapper w następujący sposób. Ta składnia różni się od starszych wersji Jacksona. (Jeśli użyjesz złej składni, po cichu nic nie zrobi).

mapper.disable(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNK‌​NOWN_PROPERTIES);
llambda
źródło