Bagaimana saya bisa memberitahu jackson untuk mengabaikan properti yang kode sumbernya tidak saya kendalikan?

112

Singkat cerita, salah satu entitas saya memiliki GeometryCollection yang memberikan pengecualian saat Anda memanggil "getBoundary" (mengapa ini adalah buku lain, untuk sekarang katakanlah begini cara kerjanya).

Adakah cara agar saya bisa memberi tahu Jackson untuk tidak memasukkan pengambil yang spesifik itu? Saya tahu saya bisa menggunakan @JacksonIgnore ketika saya memiliki / mengontrol kode. Tapi ini tidak terjadi, jackson akhirnya mencapai titik ini melalui serialisasi terus menerus dari objek induk. Saya melihat opsi pemfilteran dalam dokumentasi jackson. Apakah itu solusi yang masuk akal?

Terima kasih!

maverick
sumber

Jawaban:

168

Anda dapat menggunakan Jackson Mixins . Sebagai contoh:

class YourClass {
  public int ignoreThis() { return 0; }    
}

Dengan Mixin ini

abstract class MixIn {
  @JsonIgnore abstract int ignoreThis(); // we don't need it!  
}

Dengan ini:

objectMapper.getSerializationConfig().addMixInAnnotations(YourClass.class, MixIn.class);

Edit:

Berkat komentarnya, dengan Jackson 2.5+, API telah berubah dan harus dipanggil dengan objectMapper.addMixIn(Class<?> target, Class<?> mixinSource)

Amir Raminfar
sumber
1
Dan jika properti tersebut dibuat oleh mesin dan memiliki karakter yang tidak didukung dalam namanya? Suka '@'? JVM mengizinkannya, tetapi kompiler Java tidak. Apakah Jackson punya solusi untuk ini?
tandai
3
Dan di jackson 2.2 ituobjectMapper.addMixInAnnotations(Class<?> target, Class<?> mixinSource);
CorayThan
Bagaimana cara mengabaikan dengan menentukan nama properti alih-alih getter?
Erran Morad
68

Satu kemungkinan lainnya adalah, jika Anda ingin mengabaikan semua properti yang tidak diketahui, Anda dapat mengkonfigurasi mapper sebagai berikut:

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
laloumen.dll
sumber
5
Akan sangat bagus jika kita dapat mengkonfigurasi objectMapper untuk mengabaikan properti tertentu saja. yaitu laporkan pengecualian untuk semua kolom baru / tidak diketahui kecuali katakanlah 'myfield'. Sesuatu sepertimapper.configure(DeserializationFeature.failOnUnknownPropertiesExcep(new String[] {"myField"}));
ms_27
Perhatikan bahwa ini juga dapat dikonfigurasi pada alat pembaca dengan menggunakan without()seperti pada:mapper.reader().without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
Drew Stephens
Saya sangat menyarankan agar tidak menggunakan mekanisme ini. Pola pikir "ketat" di Jackson, menyebabkan kesalahan muncul pada bidang yang tidak diketahui / tidak tertangani adalah salah satu kekuatannya dan cocok dengan sifat Java yang diketik secara statis / dianalisis waktu kompilasi dengan baik. Jauh lebih baik memilih untuk tidak menangani sekumpulan bidang yang diabaikan sebagai gantinya.
Per Lundberg
26

Menggunakan Kelas Java

new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

Menggunakan Annotation

@JsonIgnoreProperties(ignoreUnknown=true)
Sireesh Yarlagadda
sumber
11

Pendekatan berbasis anotasi lebih baik. Tetapi terkadang operasi manual diperlukan. Untuk tujuan ini, Anda dapat menggunakan tanpa metode ObjectWriter .

ObjectMapper mapper   = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
ObjectWriter writer   = mapper.writer().withoutAttribute("property1").withoutAttribute("property2");
String       jsonText = writer.writeValueAsString(sourceObject);
Fırat KÜÇÜK
sumber
9
Pendekatan ini tidak berhasil untuk saya, tetapi mixin berhasil. Saya masih mendapatkan properti yang diabaikan setelah serialisasi. Mengapa kita memiliki mixin ketika kita memiliki withoutAttribute ()?
Erran Morad
9

Anotasi campuran bekerja dengan cukup baik di sini seperti yang telah disebutkan. Kemungkinan lain di luar per-properti @JsonIgnore adalah menggunakan @JsonIgnoreType jika Anda memiliki tipe yang tidak boleh disertakan (mis. Jika semua instance properti GeometryCollection harus diabaikan). Anda kemudian dapat menambahkannya secara langsung (jika Anda mengontrol jenisnya), atau menggunakan campuran, seperti:

@JsonIgnoreType abstract class MixIn { }
// and then register mix-in, either via SerializationConfig, or by using SimpleModule

Ini bisa lebih mudah jika Anda memiliki banyak kelas yang semuanya memiliki satu atau lebih aksesor 'IgnoredType getContext ()' (yang merupakan kasus untuk banyak kerangka kerja)

StaxMan
sumber
5

Saya memiliki masalah serupa, tetapi itu terkait dengan hubungan dua arah Hibernate. Saya ingin menunjukkan satu sisi hubungan dan secara terprogram mengabaikan yang lain, tergantung pada pandangan apa yang saya hadapi. Jika Anda tidak bisa melakukan itu, Anda akan berakhir dengan nasty StackOverflowExceptions. Misalnya, jika saya memiliki benda-benda ini

public class A{
  Long id;
  String name;
  List<B> children;
}

public class B{
  Long id;
  A parent;
}

Saya ingin mengabaikan secara terprogram parentbidang di B jika saya melihat A, dan mengabaikan childrenbidang di A jika saya melihat B.

Saya mulai menggunakan mixin untuk melakukan ini, tapi itu dengan sangat cepat menjadi mengerikan; Anda memiliki begitu banyak kelas tidak berguna yang hanya ada untuk memformat data. Saya akhirnya menulis serializer saya sendiri untuk menangani ini dengan cara yang lebih bersih: https://github.com/monitorjbl/json-view .

Ini memungkinkan Anda menentukan secara terprogram kolom apa yang akan diabaikan:

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(JsonView.class, new JsonViewSerializer());
mapper.registerModule(module);

List<A> list = getListOfA();
String json = mapper.writeValueAsString(JsonView.with(list)
    .onClass(B.class, match()
        .exclude("parent")));

Ini juga memungkinkan Anda dengan mudah menentukan tampilan yang sangat disederhanakan melalui pencocokan karakter pengganti:

String json = mapper.writeValueAsString(JsonView.with(list)
    .onClass(A.class, match()
        .exclude("*")
         .include("id", "name")));

Dalam kasus awal saya, kebutuhan akan tampilan sederhana seperti ini adalah untuk menunjukkan minimal tentang orang tua / anak, tetapi juga menjadi berguna untuk keamanan berbasis peran kita. Tampilan objek yang kurang memiliki hak istimewa diperlukan untuk mengembalikan lebih sedikit informasi tentang objek.

Semua ini berasal dari serializer, tetapi saya menggunakan Spring MVC di aplikasi saya. Agar dapat menangani kasus ini dengan benar, saya menulis integrasi yang dapat Anda masukkan ke kelas pengontrol Spring yang ada:

@Controller
public class JsonController {
  private JsonResult json = JsonResult.instance();
  @Autowired
  private TestObjectService service;

  @RequestMapping(method = RequestMethod.GET, value = "/bean")
  @ResponseBody
  public List<TestObject> getTestObject() {
    List<TestObject> list = service.list();

    return json.use(JsonView.with(list)
        .onClass(TestObject.class, Match.match()
            .exclude("int1")
            .include("ignoredDirect")))
        .returnValue();
  }
}

Keduanya tersedia di Maven Central. Saya harap ini membantu orang lain di luar sana, ini adalah masalah yang sangat buruk dengan Jackson yang tidak memiliki solusi yang baik untuk kasus saya.

monitorjbl
sumber
Untuk apa impor itu Match.match()?
Pasupathi Rajamanickam
2

Jika Anda ingin SELALU mengecualikan properti tertentu untuk kelas apa pun, Anda dapat menggunakan setMixInResolvermetode:

    @JsonIgnoreProperties({"id", "index", "version"})
    abstract class MixIn {
    }

    mapper.setMixInResolver(new ClassIntrospector.MixInResolver(){
        @Override
        public Class<?> findMixInClassFor(Class<?> cls) {
            return MixIn.class;  
        }

        @Override
        public ClassIntrospector.MixInResolver copy() {
            return this;
        }
    });
fifman
sumber