Saya ingin membuat serial dan deserialisasi objek yang tidak dapat diubah menggunakan com.fasterxml.jackson.databind.ObjectMapper.
Kelas tetap terlihat seperti ini (hanya 3 atribut internal, pengambil dan konstruktor):
public final class ImportResultItemImpl implements ImportResultItem {
private final ImportResultItemType resultType;
private final String message;
private final String name;
public ImportResultItemImpl(String name, ImportResultItemType resultType, String message) {
super();
this.resultType = resultType;
this.message = message;
this.name = name;
}
public ImportResultItemImpl(String name, ImportResultItemType resultType) {
super();
this.resultType = resultType;
this.name = name;
this.message = null;
}
@Override
public ImportResultItemType getResultType() {
return this.resultType;
}
@Override
public String getMessage() {
return this.message;
}
@Override
public String getName() {
return this.name;
}
}
Namun ketika saya menjalankan tes unit ini:
@Test
public void testObjectMapper() throws Exception {
ImportResultItemImpl originalItem = new ImportResultItemImpl("Name1", ImportResultItemType.SUCCESS);
String serialized = new ObjectMapper().writeValueAsString((ImportResultItemImpl) originalItem);
System.out.println("serialized: " + serialized);
//this line will throw exception
ImportResultItemImpl deserialized = new ObjectMapper().readValue(serialized, ImportResultItemImpl.class);
}
Saya mendapatkan pengecualian ini:
com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class eu.ibacz.pdkd.core.service.importcommon.ImportResultItemImpl]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)
at [Source: {"resultType":"SUCCESS","message":null,"name":"Name1"}; line: 1, column: 2]
at
... nothing interesting here
Pengecualian ini meminta saya untuk membuat konstruktor default, tetapi ini adalah objek yang tidak dapat diubah, jadi saya tidak ingin memilikinya. Bagaimana cara mengatur atribut internal? Ini benar-benar akan membingungkan pengguna API.
Jadi pertanyaan saya adalah: Dapatkah saya menghilangkan / membuat serial objek yang tidak dapat diubah tanpa konstruktor default?
Jawaban:
Untuk memberi tahu Jackson cara membuat objek untuk deserialisasi, gunakan anotasi
@JsonCreator
dan@JsonProperty
untuk konstruktor Anda, seperti ini:sumber
@JsonCreator
dan@JsonProperty
karena Anda tidak memiliki akses ke POJO untuk mengubahnya? Apakah masih ada cara untuk menghilangkan objek tersebut?Anda dapat menggunakan konstruktor default pribadi, Jackson kemudian akan mengisi bidang melalui refleksi bahkan jika final pribadi.
EDIT: Dan gunakan konstruktor default yang dilindungi / dilindungi paket untuk kelas induk jika Anda memiliki warisan.
sumber
Jawaban pertama Sergei Petunin benar. Namun, kita dapat menyederhanakan kode dengan menghapus anotasi @JsonProperty yang berlebihan pada setiap parameter konstruktor.
Itu bisa dilakukan dengan menambahkan com.fasterxml.jackson.module.paramnames.ParameterNamesModule ke ObjectMapper:
(Btw: modul ini terdaftar secara default di SpringBoot. Jika Anda menggunakan kacang ObjectMapper dari JacksonObjectMapperConfiguration atau jika Anda membuat ObjectMapper Anda sendiri dengan kacang Jackson2ObjectMapperBuilder maka Anda dapat melewati pendaftaran modul secara manual)
Sebagai contoh:
dan ObjectMapper melakukan deserialisasi json ini tanpa kesalahan:
sumber