Conversão JsonNode em POJO

143

Isso pode parecer um pouco incomum, mas estou procurando uma maneira eficiente de transformar / mapear a JsonNodeem a POJO.

Eu armazeno algumas das informações do meu modelo em arquivos json e tenho que suportar algumas versões do meu modelo.

O que faço é carregar o arquivo json na memória em um JsonNode, aplicar algumas estratégias de versão para torná-lo compatível com a versão mais recente do meu Model.

    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 exista uma maneira mais rápida de fazer isso, provavelmente acabarei aplicando manualmente o JsonNodesao meu Model

Alexandre
fonte

Respostas:

264

No Jackson 2.4, você pode converter da seguinte maneira:

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

Onde jsonObjectMapperestá um Jackson ObjectMapper?


Nas versões mais antigas de Jackson, seria

MyClass newJsonNode = jsonObjectMapper.readValue(someJsonNode, MyClass.class);
icedtrees
fonte
18
Infelizmente, não há variante treeToValue (TreeNode n, TypeReference <T>) como existe para readValue (). Más notícias para quem lida com tipos mais complexos com genéricos :(
Espinosa
13
@Espinosa Per jackson-databind # 1294 , você vai querer algo como (infelizmente mais detalhado)jsonObjectMapper.readValue(jsonObjectMapper.treeAsTokens(someJsonNode), someTypeReference)
M. Justin
Para versão mais antiga, use:objectMapper.treeToValue(jsonNode, MyClass.class)
amod
2
Você também pode usar esse método em StdDeserializer: p.codec.treeToValue.
Galcyurio 28/05
@icedtrees jsonObjectMapper é uma instância de JsonObjectMapper ou apenas o ObjectMapper
KNDheeraj
8

Isso deve fazer o truque:

mapper.readValue(fileReader, MyClass.class);

Eu digo que deveria, porque estou usando isso com um String, não um, BufferedReadermas ainda deve funcionar.

Aqui está o meu código:

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

Aqui está a documentação oficial para essa chamada: http://jackson.codehaus.org/1.7.9/javadoc/org/codehaus/jackson/map/ObjectMapper.html#readValue(java.lang.String, java.lang.Class)

Você também pode definir um desserializador personalizado ao instanciar o ObjectMapper: http://wiki.fasterxml.com/JacksonHowToCustomDeserializers

Edit: Acabei de me lembrar de outra coisa. Se o seu objeto que chega tem mais propriedades do que o POJOseu e você deseja apenas ignorar os extras, defina isso:

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

Ou você receberá um erro que não consegue encontrar a propriedade para definir.

Eric Barr
fonte
Vou usar um CustomDeserializers, isso vai me salvar muitas dores de cabeça! Também poderei aplicar minhas estratégias de versão com poucas modificações. Obrigado!
31413 Alexandre
5
A sintaxe agora é: mapeador com.fasterxml.jackson.databind.ObjectMapper = novo mapeador com.fasterxml.jackson.databind.ObjectMapper (); mapper.disable (com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
llambda
Bom ponto @llambda! Não toquei no ObjectMapper desde a versão 1.7.9, parece que minha resposta está desatualizada em algumas versões. Definitivamente, verifique qual versão do Jackson você está usando.
Eric Barr
@ EricBarr, estou usando o Jackson v1.9.11 e a sintaxe na sua resposta é a correta para essa versão. Talvez eles tentaram mudar as coisas e reverteu-los novamente nas versões mais recentes
Ivaylo Slavov
5

Se você estiver usando org.codehaus.jackson, isso é possível desde a versão 1.6. Você pode converter um JsonNode em um POJO com 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
fonte
5
Estes métodos parece estar faltando no 2.4.4
Kevin Wittek
1
Veja a resposta dos icedtrees abaixo, para uma solução da versão 2
Tim Büthe 4/15/15
A documentação agora está em mais rápidaxml.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);

Se sua entrada JSON tiver mais propriedades do que seu POJO e você quiser apenas ignorar os extras no Jackson 2.4, poderá configurar seu ObjectMapper da seguinte maneira. Essa sintaxe é diferente das versões mais antigas de Jackson. (Se você usar a sintaxe errada, ela silenciosamente não fará nada.)

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