Jackson dengan JSON: Bidang yang tidak dikenal, tidak ditandai sebagai dapat diabaikan


677

Saya perlu mengonversi string JSON tertentu ke objek Java. Saya menggunakan Jackson untuk penanganan JSON. Saya tidak memiliki kendali atas input JSON (saya baca dari layanan web). Ini adalah input JSON saya:

{"wrapper":[{"id":"13","name":"Fred"}]}

Berikut ini adalah kasus penggunaan yang disederhanakan:

private void tryReading() {
    String jsonStr = "{\"wrapper\"\:[{\"id\":\"13\",\"name\":\"Fred\"}]}";
    ObjectMapper mapper = new ObjectMapper();  
    Wrapper wrapper = null;
    try {
        wrapper = mapper.readValue(jsonStr , Wrapper.class);
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println("wrapper = " + wrapper);
}

Kelas entitas saya adalah:

public Class Student { 
    private String name;
    private String id;
    //getters & setters for name & id here
}

Kelas Wrapper saya pada dasarnya adalah objek wadah untuk mendapatkan daftar siswa saya:

public Class Wrapper {
    private List<Student> students;
    //getters & setters here
}

Saya terus mendapatkan kesalahan ini dan "bungkus" kembali null. Saya tidak yakin apa yang hilang. Bisakah seseorang membantu?

org.codehaus.jackson.map.exc.UnrecognizedPropertyException: 
    Unrecognized field "wrapper" (Class Wrapper), not marked as ignorable
 at [Source: java.io.StringReader@1198891; line: 1, column: 13] 
    (through reference chain: Wrapper["wrapper"])
 at org.codehaus.jackson.map.exc.UnrecognizedPropertyException
    .from(UnrecognizedPropertyException.java:53)

2
Saya menemukan ini berguna untuk menghindari membuat kelas pembungkus: Map dummy<String,Student> = myClientResponse.getEntity(new GenericType<Map<String, Student>>(){});dan kemudianStudent myStudent = dummy.get("wrapper");
pulkitsinghal

6
JSON akan terlihat seperti: String jsonStr = "{\" students \ "\: [{\" id \ ": \" 13 \ ", \" name \ ": \" Fred \ "}]}"; jika Anda mengharapkan objek Wrapper dalam permintaan REST POST Anda
Dmitri Algazin


5
Dan kebetulan, sebagian besar jawaban untuk pertanyaan ini sebenarnya menjawab pertanyaan yang berbeda, yaitu yang serupa dengan yang saya tautkan di atas.
sleske

4
sebagian besar jawaban membantu menyikat masalah di bawah permadani daripada benar-benar menyelesaikannya :(
NoobEditor

Jawaban:


992

Anda dapat menggunakan anotasi tingkat kelas Jackson:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties

@JsonIgnoreProperties
class { ... }

Ini akan mengabaikan setiap properti yang belum Anda tetapkan dalam POJO Anda. Sangat berguna ketika Anda hanya mencari beberapa properti di JSON dan tidak ingin menulis seluruh pemetaan. Info lebih lanjut di situs web Jackson . Jika Anda ingin mengabaikan properti yang tidak dinyatakan, Anda harus menulis:

@JsonIgnoreProperties(ignoreUnknown = true)

9
Ariel, apakah ada cara untuk menyatakan ini di luar kelas?
Jon Lorusso

4
Saya membuat serialisasi kelas yang bukan milik saya (tidak dapat dimodifikasi). Dalam satu tampilan, saya ingin membuat cerita bersambung dengan seperangkat bidang tertentu. Dalam tampilan lain, saya ingin sekumpulan bidang berbeda serial (atau mungkin mengubah nama properti di JSON).
Jon Lorusso

11
saya harus menambahkan bahwa Anda memang perlu (ignoreUnknown = true)ketika membubuhi keterangan kelas Anda jika tidak maka tidak akan berhasil
necromancer

85
Julián, ini bukan jawaban yang benar untuk pertanyaan OP. Namun, saya menduga bahwa orang-orang datang ke sini karena mereka google cara mengabaikan properti yang tidak didefinisikan dalam POJO dan ini adalah hasil pertama, jadi mereka akhirnya memilih ini dan tanggapan Suresh (itulah yang terjadi pada saya). Meskipun pertanyaan aslinya tidak ada hubungannya dengan keinginan untuk mengabaikan properti yang tidak terdefinisi.
Ric Jafe

5
ini adalah pengaturan default yang sangat bodoh, jika Anda menambahkan properti ke api Anda, seluruh serialisasi gagal
headvk

481

Kamu bisa menggunakan

ObjectMapper objectMapper = getObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

Ini akan mengabaikan semua properti yang tidak dideklarasikan.


5
Ini tidak berhasil untuk saya, masih gagal pada properti yang tidak dikenal
Denis Kniazhev

1
Bisakah Anda menempelkan setidaknya satu kode apa yang sebenarnya Anda lakukan, Anda mungkin telah melewatkan sesuatu di sana .. Baik dengan melakukan ini atau dengan menggunakan "@JsonIgnoreProperties (ignUnknown = true)" Masalah Anda harus diselesaikan. Semoga beruntung.
Suresh

27
FWIW - Saya harus mengimpor enum yang sedikit berbeda ini: org.codehaus.jackson.map.DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES
raf

9
^ Di atas adalah untuk versi Jackson sebelum 2
755

10
Anda juga dapat membuat panggilan ini seperti: getObjectMapper (). Disable (DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
icfantv

126

Jawaban pertama hampir benar, tetapi yang diperlukan adalah mengubah metode pengambil, BUKAN bidang - bidang bersifat pribadi (dan tidak terdeteksi secara otomatis); lebih lanjut, getter memiliki prioritas di atas bidang jika keduanya terlihat. (Ada cara untuk membuat bidang pribadi terlihat juga, tetapi jika Anda ingin memiliki pengambil tidak ada gunanya)

Jadi rajin pengambil harus diberi nama getWrapper(), atau dijelaskan dengan:

@JsonProperty("wrapper")

Jika Anda lebih suka nama metode pengambil seperti apa adanya.


Tolong jelaskan - pengambil mana yang perlu diubah atau dianotasi?
Frans

maksudmu dijelaskan dengan @JsonGetter ("wrapper"), kan?
pedram bashiri

@pedrambashiri Tidak, maksud saya @JsonProperty. Meskipun @JsonGetteralias legal, ini jarang digunakan sebagai @JsonPropertykarya untuk getter, setter, dan bidang; setter dan getter dapat dibedakan dengan tanda tangan (satu tidak mengambil argumen, mengembalikan tidak kosong; lainnya mengambil satu argumen).
StaxMan

Ini jawaban yang saya cari! Kedengarannya seperti Jackson mengalami kesulitan memetakan JSON sumber ke POJO Anda, tetapi Anda dapat menjamin kecocokan dengan menandai getter. Terima kasih!
Andrew Kirna

90

menggunakan Jackson 2.6.0, ini bekerja untuk saya:

private static final ObjectMapper objectMapper = 
    new ObjectMapper()
        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

dan dengan pengaturan:

@JsonIgnoreProperties(ignoreUnknown = true)

12
Dengan konfigurasi anotasi itu tidak perlu
neworld

Apakah Anda perlu mengonfigurasi ObjectMapper dan Annotation on class? Saya kira objectMapper akan memperbaiki untuk semua, tanpa perlu membubuhi keterangan setiap kelas. Saya menggunakan anotasi.
prayagupd

Anda tidak perlu kedua pengaturan di kelas yang sama. Anda juga dapat menggunakan DI untuk mendapatkan instance singleton global ObjectMapper, untuk mengatur FAIL_ON_UNKNOWN_PROPERTIESproperti secara global.
user991710

Anda tidak perlu keduanya, Anda dapat memilih satu atau yang lain.
heez

58

dapat dicapai 2 cara:

  1. Tandai POJO untuk mengabaikan properti yang tidak dikenal

    @JsonIgnoreProperties(ignoreUnknown = true)
  2. Mengkonfigurasi ObjectMapper yang membuat cerita bersambung / De-cerita bersambung POJO / json seperti di bawah ini:

    ObjectMapper mapper =new ObjectMapper();            
    // for Jackson version 1.X        
    mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    // for Jackson version 2.X
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) 
    

2
Mengapa ini harus menjadi jawaban yang diterima? Ini hanya memberitahu untuk mengabaikan properti yang tidak diketahui, sedangkan pertanyaannya adalah untuk menemukan cara untuk mendapatkan json yang dibungkus menjadi objek yang solusi ini jelas mengatakan untuk diabaikan.
Sayantan

42

Ini hanya bekerja untuk saya

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(
    DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);

@JsonIgnoreProperties(ignoreUnknown = true) penjelasan tidak.


2
Turun karena tidak menjawab pertanyaan OP. Mengabaikan properti yang tidak diketahui tidak menyelesaikan masalahnya, tetapi meninggalkannya dengan Wrappercontoh di mana daftar siswa nullatau kosong.
Frans

37

Ini berfungsi lebih baik daripada Semua, harap merujuk ke properti ini.

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    projectVO = objectMapper.readValue(yourjsonstring, Test.class);

Bekerja seperti yang diharapkan!
MADHAIYAN M

Ya, ini yang memecahkan masalah saya - yang cocok dengan judul posting ini.
Scott Langeberg

Jawaban berfungsi dengan baik untuk saya dan itu sangat mudah. ​​Terima kasih
Touya Akira

29

Jika Anda menggunakan Jackson 2.0

ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

mengapa konfigurasi ini tidak berpengaruh bagi saya?
zhaozhi

@ zhaozhi Tergantung pada versi Jackson
Aalkhodiry

20

Menurut dokumen Anda dapat mengabaikan bidang yang dipilih atau semua bidang yang terkenal:

 // to prevent specified fields from being serialized or deserialized
 // (i.e. not include in JSON output; or being set even if they were included)
 @JsonIgnoreProperties({ "internalId", "secretKey" })

 // To ignore any unknown properties in JSON input without exception:
 @JsonIgnoreProperties(ignoreUnknown=true)

15

Ini bekerja untuk saya dengan kode berikut:

ObjectMapper mapper =new ObjectMapper();    
mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);

15

Menambahkan setter dan getter memecahkan masalah , yang saya rasakan adalah masalah sebenarnya adalah bagaimana menyelesaikannya tetapi tidak bagaimana menekan / mengabaikan kesalahan. Saya mendapat kesalahan " Bidang tidak dikenal .. tidak ditandai sebagai dapat diabaikan .. "

Meskipun saya menggunakan penjelasan di bawah ini di atas kelas itu tidak dapat mengurai objek json dan memberi saya masukan

@JsonIgnoreProperties (ignUnknown = true)

Kemudian saya menyadari bahwa saya tidak menambahkan setter dan getter, setelah menambahkan setter dan getter ke "Wrapper" dan ke "Student" itu bekerja seperti pesona.


Tampaknya ini adalah satu-satunya jawaban yang benar-benar menjawab pertanyaan. Semua jawaban lain hanya menandai properti tidak dikenal sebagai diabaikan, tetapi 'pembungkus' bukan properti yang tidak dikenal, itu adalah apa yang kami coba uraikan.
lbenedetto

14

Jackson mengeluh karena tidak dapat menemukan bidang di pembungkus kelas Anda yang disebut "pembungkus". Ini melakukan ini karena objek JSON Anda memiliki properti yang disebut "wrapper".

Saya pikir perbaikannya adalah mengubah nama bidang kelas Wrapper Anda menjadi "wrapper", bukan "siswa".


Terima kasih, Jim. Saya mencobanya dan itu tidak memperbaiki masalah. Saya bertanya-tanya apakah saya kehilangan beberapa anotasi ..
jshree

1
Hmm, apa yang terjadi ketika Anda membuat data yang setara di Jawa dan kemudian menggunakan Jackson untuk menuliskannya di JSON. Setiap perbedaan antara JSON dan JSON di atas harus menjadi petunjuk untuk apa yang salah.
Jim Ferrans

Jawaban ini berhasil bagi saya, dengan contoh dari pertanyaan.
sleske

14

Saya telah mencoba metode di bawah ini dan berfungsi untuk pembacaan format JSON dengan Jackson. Gunakan solusi yang sudah disarankan dari: pengambil anotasi dengan@JsonProperty("wrapper")

Kelas pembungkus Anda

public Class Wrapper{ 
  private List<Student> students;
  //getters & setters here 
} 

Saran saya untuk kelas pembungkus

public Class Wrapper{ 

  private StudentHelper students; 

  //getters & setters here 
  // Annotate getter
  @JsonProperty("wrapper")
  StudentHelper getStudents() {
    return students;
  }  
} 


public class StudentHelper {

  @JsonProperty("Student")
  public List<Student> students; 

  //CTOR, getters and setters
  //NOTE: If students is private annotate getter with the annotation @JsonProperty("Student")
}

Namun ini akan memberi Anda output format:

{"wrapper":{"student":[{"id":13,"name":Fred}]}}

Juga untuk informasi lebih lanjut, lihat https://github.com/FasterXML/jackson-annotations

Semoga ini membantu


Selamat datang di stackoverflow. Kiat, Anda dapat menggunakan {}simbol di bilah alat untuk memformat cuplikan kode Anda.
Leigh

11

Solusi ini bersifat umum ketika membaca aliran json dan hanya perlu mendapatkan beberapa bidang sementara bidang yang tidak dipetakan dengan benar di Kelas Domain Anda dapat diabaikan:

import org.codehaus.jackson.annotate.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)

Solusi terperinci adalah menggunakan alat seperti jsonschema2pojo untuk autogenerasi Kelas Domain yang diperlukan seperti Siswa dari Skema Respons json. Anda dapat melakukan yang terakhir dengan pengonversi skema json ke online.


10

Beri catatan pada siswa bidang seperti di bawah ini karena ada ketidakcocokan dalam nama properti json dan properti java

public Class Wrapper {
    @JsonProperty("wrapper")
    private List<Student> students;
    //getters & setters here
}

9

Seperti tidak ada orang lain yang disebutkan, saya pikir ...

Masalahnya adalah properti Anda di JSON Anda disebut "pembungkus" dan properti Anda di Wrapper.class disebut "siswa".

Jadi ...

  1. Perbaiki nama properti di kelas atau JSON.
  2. Beri anotasi variabel properti Anda sesuai komentar StaxMan.
  3. Anotasi setter (jika Anda memilikinya)

6

setel publik bidang kelas Anda bukan pribadi .

public Class Student { 
    public String name;
    public String id;
    //getters & setters for name & id here
}

2
praktik yang buruk - ini merusak enkapsulasi.
Downhillski

1
Saya pernah mendengarnya.
Downhillski

Kelas Anda berisiko ketika pengguna menggunakannya karena keadaan internal dapat dimutasi melalui bidang ini.
Downhillski

5

Apa yang berhasil bagi saya, adalah menjadikan properti itu milik umum. Itu memecahkan masalah bagi saya.


1
Bekerja untuk saya: D
TienLuong

5

Entah Ubah

public Class Wrapper {
    private List<Student> students;
    //getters & setters here
}

untuk

public Class Wrapper {
    private List<Student> wrapper;
    //getters & setters here
}

---- atau ----

Ubah string JSON Anda menjadi

{"students":[{"id":"13","name":"Fred"}]}

5

Masukan Anda

{"wrapper":[{"id":"13","name":"Fred"}]}

menunjukkan bahwa itu adalah Obyek, dengan bidang bernama "pembungkus", yang merupakan Koleksi Siswa. Jadi rekomendasi saya adalah,

Wrapper = mapper.readValue(jsonStr , Wrapper.class);

dimana Wrapperdidefinisikan sebagai

class Wrapper {
    List<Student> wrapper;
}

5

Firebase Android baru memperkenalkan beberapa perubahan besar; di bawah salinan dokumen:

[ https://firebase.google.com/support/guides/firebase-android] :

Perbarui objek model Java Anda

Seperti dengan 2.x SDK, Firebase Database akan secara otomatis mengonversi objek Java yang Anda akses DatabaseReference.setValue()ke JSON dan dapat membaca JSON menjadi objek Java menggunakan DataSnapshot.getValue().

Di SDK baru, ketika membaca JSON menjadi objek Java dengan DataSnapshot.getValue(), properti yang tidak dikenal di JSON sekarang diabaikan secara default sehingga Anda tidak lagi membutuhkannya @JsonIgnoreExtraProperties(ignoreUnknown=true).

Untuk mengecualikan bidang / getter saat menulis objek Java ke JSON, anotasi sekarang disebut @Excludebukan @JsonIgnore.

BEFORE

@JsonIgnoreExtraProperties(ignoreUnknown=true)
public class ChatMessage {
   public String name;
   public String message;
   @JsonIgnore
   public String ignoreThisField;
}

dataSnapshot.getValue(ChatMessage.class)

AFTER

public class ChatMessage {
   public String name;
   public String message;
   @Exclude
   public String ignoreThisField;
}

dataSnapshot.getValue(ChatMessage.class)

Jika ada properti tambahan di JSON Anda yang tidak ada di kelas Java Anda, Anda akan melihat peringatan ini di file log:

W/ClassMapper: No setter/field for ignoreThisProperty found on class com.firebase.migrationguide.ChatMessage

Anda dapat menyingkirkan peringatan ini dengan meletakkan @IgnoreExtraPropertiesanotasi di kelas Anda. Jika Anda ingin Firebase Database berperilaku seperti yang terjadi pada 2.x SDK dan melemparkan pengecualian jika ada properti yang tidak dikenal, Anda bisa meletakkan @ThrowOnExtraPropertiesanotasi di kelas Anda.


4

Bagi saya, satu-satunya jalur

@JsonIgnoreProperties(ignoreUnknown = true)

tidak bekerja juga.

Cukup tambahkan

@JsonInclude(Include.NON_EMPTY)

Jackson 2.4.0


4

Ini bekerja dengan baik untuk saya

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

4

Saya memperbaiki masalah ini dengan hanya mengubah tanda tangan setter dan metode pengambil kelas POJO saya. Yang harus saya lakukan adalah mengubah metode getObject agar sesuai dengan apa yang dicari oleh mapper. Dalam kasus saya, saya memiliki getImageUrl awalnya, tetapi data JSON memiliki image_url yang melemparkan mapper off. Saya mengubah setter dan getter saya menjadi getImage_url dan setImage_url .

Semoga ini membantu.


Anda benar rupanya: jika nama yang Anda inginkan adalah xxx_yyy Cara untuk memanggilnya adalah getXxx_yyy dan setXxx_yyy. Ini sangat aneh tetapi berhasil.
sivi

3

POJO harus didefinisikan sebagai

Kelas respons

public class Response {
    private List<Wrapper> wrappers;
    // getter and setter
}

Kelas pembungkus

public class Wrapper {
    private String id;
    private String name;
    // getters and setters
}

dan mapper untuk membaca nilai

Response response = mapper.readValue(jsonStr , Response.class);

Hampir. Bukan wrappers, tapi wrapper.
Frans

@ Trans Haha, terima kasih telah menangkap kesalahannya. Saya biasanya menggunakan jamak untuk koleksi. Tetapi per pertanyaan OP, itu harus tunggal.
Dino Tw

3

Ini mungkin respons yang sangat terlambat, tetapi hanya mengubah POJO untuk ini akan menyelesaikan string json yang disediakan dalam masalah (karena, string input tidak dalam kendali Anda seperti yang Anda katakan):

public class Wrapper {
    private List<Student> wrapper;
    //getters & setters here
}

3

Satu kemungkinan lain adalah properti ini di properti application.prop spring.jackson.deserialization.fail-on-unknown-properties=false, yang tidak memerlukan perubahan kode lain dalam aplikasi Anda. Dan ketika Anda yakin kontraknya stabil, Anda dapat menghapus properti ini atau menandainya benar.


3

Ini mungkin bukan masalah yang sama dengan yang dimiliki OP tetapi jika seseorang datang ke sini dengan kesalahan yang sama yang saya miliki maka ini akan membantu mereka memecahkan masalah mereka. Saya mendapatkan kesalahan yang sama dengan OP ketika saya menggunakan ObjectMapper dari ketergantungan yang berbeda dengan anotasi JsonProperty.

Ini bekerja:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.annotation.JsonProperty;

Tidak bekerja:

import org.codehaus.jackson.map.ObjectMapper; //org.codehaus.jackson:jackson-mapper-asl:1.8.8
import com.fasterxml.jackson.annotation.JsonProperty; //com.fasterxml.jackson.core:jackson-databind:2.2.3

Terima kasih! import com.fasterxml.jackson.annotation.JsonProperty bekerja untuk saya sebagai gantinya yang lain :-)
phil

2

Google membawa saya ke sini dan saya terkejut melihat jawabannya ... semua menyarankan melewati kesalahan ( yang selalu menggigit 4 kali lipat kemudian dalam pengembangan ) daripada menyelesaikannya sampai pria ini dipulihkan oleh iman dalam SO!

objectMapper.readValue(responseBody, TargetClass.class)

digunakan untuk mengonversi String json ke objek kelas, yang hilang adalah bahwa TargetClassharus memiliki getter publik set. Sama juga tidak ada dalam cuplikan pertanyaan OP! :)

via lombok kelas Anda seperti di bawah ini seharusnya berfungsi !!

@Data
@Builder
public class TargetClass {
    private String a;
}

2

impor com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties


Mungkin beberapa penjelasan atau dokumen lebih lanjut akan menyenangkan
Benj

@JsonIgnoreProperties (ignUnknown = true) berfungsi dengan baik, terima kasih
Guilherme
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.