Ubah JsonNode menjadi POJO

143

Ini mungkin tampak sedikit tidak biasa, tetapi saya mencari cara yang efisien untuk mengubah / memetakan JsonNodemenjadi POJO.

Saya menyimpan beberapa informasi Model saya dalam file json dan saya harus mendukung beberapa versi model saya.

Apa yang saya lakukan adalah memuat file json di memori dalam JsonNode, menerapkan beberapa strategi versi agar cocok dengan versi terbaru dari Model saya.

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

Kecuali jika ada cara yang lebih cepat untuk melakukannya, saya mungkin akan berakhir hanya dengan menerapkannya secara manual JsonNodeske Model saya

Alexandre
sumber

Jawaban:

264

Di Jackson 2.4, Anda dapat mengonversi sebagai berikut:

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

dimana jsonObjectMapperseorang Jackson ObjectMapper.


Dalam versi yang lebih lama dari Jackson, itu akan menjadi

MyClass newJsonNode = jsonObjectMapper.readValue(someJsonNode, MyClass.class);
es
sumber
18
Sayangnya tidak ada varian treeToValue (TreeNode n, TypeReference <T>) seperti ada untuk readValue (). Berita buruk bagi siapa pun yang berurusan dengan jenis yang lebih kompleks dengan obat generik :(
Espinosa
13
@Espinosa Per jackson-databind # 1294 , Anda akan menginginkan sesuatu seperti (sayangnya lebih bertele-tele)jsonObjectMapper.readValue(jsonObjectMapper.treeAsTokens(someJsonNode), someTypeReference)
M. Justin
Untuk penggunaan versi yang lebih lama:objectMapper.treeToValue(jsonNode, MyClass.class)
amod
2
Anda juga dapat menggunakan metode ini dalam StdDeserializer: p.codec.treeToValue.
galcyurio
@icedtrees jsonObjectMapper adalah turunan dari JsonObjectMapper atau hanya ObjectMapper
KNDheeraj
8

Ini harus melakukan trik:

mapper.readValue(fileReader, MyClass.class);

Saya katakan harus karena saya menggunakan itu dengan String, bukan BufferedReadertetapi itu masih harus bekerja.

Ini kode saya:

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

Berikut dokumentasi resmi untuk panggilan itu: http://jackson.codehaus.org/1.7.9/javadoc/org/codehaus/jackson/map/ObjectMapper.html#readValue(java.lang.String, java.lang.Class)

Anda juga dapat menentukan deserializer khusus ketika Anda instantiate ObjectMapper: http://wiki.fasterxml.com/JacksonHowToCustomDeserializers

Sunting: Saya baru ingat sesuatu yang lain. Jika objek Anda yang masuk memiliki lebih banyak properti daripada yang POJOdimiliki dan Anda hanya ingin mengabaikan ekstra Anda akan ingin mengatur ini:

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

Atau Anda akan mendapatkan kesalahan karena tidak dapat menemukan properti untuk diatur.

Eric Barr
sumber
Saya akan menggunakan CustomDeserializers, ini akan menyelamatkan saya dari banyak sakit kepala! Saya juga dapat menerapkan strategi versi saya di sana dengan sedikit modifikasi. Terima kasih!
Alexandre
5
Sintaksnya sekarang: com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper (); mapper.disable (com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
llambda
Poin bagus @llambda! Saya belum menyentuh ObjectMapper sejak versi 1.7.9, sepertinya jawaban saya sudah ketinggalan zaman oleh beberapa versi. Periksa versi Jackson yang Anda gunakan.
Eric Barr
@EricBarr, saya menggunakan Jackson v1.9.11 dan sintaks dalam jawaban Anda adalah yang benar untuk versi itu. Mungkin mereka mencoba mengubah sesuatu dan mengembalikannya lagi di versi yang lebih baru
Ivaylo Slavov
5

Jika Anda menggunakan org.codehaus.jackson, ini sudah dimungkinkan sejak 1.6. Anda bisa mengonversi JsonNode menjadi POJO dengan ObjectMapper#readValue: http://jackson.codehaus.org/1.9.4/javadoc/org/codehaus/jackson/map/ObjectMapper.html#readValue(org.codehaus.jackson.JsonNode , java. lang.Kelas)


    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
sumber
5
Metode ini sepertinya tidak ada di 2.4.4
Kevin Wittek
1
Lihat jawaban icedtrees di bawah ini, untuk solusi versi 2
Tim Büthe
Dokumentasinya sekarang di fastxml.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);

Jika input JSON Anda memiliki lebih banyak properti daripada POJO Anda dan Anda hanya ingin mengabaikan ekstra di Jackson 2.4, Anda dapat mengonfigurasi ObjectMapper Anda sebagai berikut. Sintaks ini berbeda dari versi Jackson yang lebih lama. (Jika Anda menggunakan sintaks yang salah, itu tidak akan melakukan apa-apa.)

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