Saya memiliki dua kelas Java yang ingin saya serialkan ke JSON menggunakan Jackson:
public class User {
public final int id;
public final String name;
public User(int id, String name) {
this.id = id;
this.name = name;
}
}
public class Item {
public final int id;
public final String itemNr;
public final User createdBy;
public Item(int id, String itemNr, User createdBy) {
this.id = id;
this.itemNr = itemNr;
this.createdBy = createdBy;
}
}
Saya ingin membuat serial Item ke JSON ini:
{"id":7, "itemNr":"TEST", "createdBy":3}
dengan Pengguna berseri untuk hanya menyertakan id
. Saya juga akan dapat mengubah semua objek pengguna ke JSON seperti:
{"id":3, "name": "Jonas", "email": "[email protected]"}
Jadi saya rasa saya perlu menulis serializer khusus Item
dan mencoba dengan ini:
public class ItemSerializer extends JsonSerializer<Item> {
@Override
public void serialize(Item value, JsonGenerator jgen,
SerializerProvider provider) throws IOException,
JsonProcessingException {
jgen.writeStartObject();
jgen.writeNumberField("id", value.id);
jgen.writeNumberField("itemNr", value.itemNr);
jgen.writeNumberField("createdBy", value.user.id);
jgen.writeEndObject();
}
}
Saya membuat serial JSON dengan kode ini dari Jackson How-to: Custom Serializers :
ObjectMapper mapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule("SimpleModule",
new Version(1,0,0,null));
simpleModule.addSerializer(new ItemSerializer());
mapper.registerModule(simpleModule);
StringWriter writer = new StringWriter();
try {
mapper.writeValue(writer, myItem);
} catch (JsonGenerationException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Tapi saya mendapatkan kesalahan ini:
Exception in thread "main" java.lang.IllegalArgumentException: JsonSerializer of type com.example.ItemSerializer does not define valid handledType() (use alternative registration method?)
at org.codehaus.jackson.map.module.SimpleSerializers.addSerializer(SimpleSerializers.java:62)
at org.codehaus.jackson.map.module.SimpleModule.addSerializer(SimpleModule.java:54)
at com.example.JsonTest.main(JsonTest.java:54)
Bagaimana saya bisa menggunakan Serializer khusus dengan Jackson?
Beginilah cara saya melakukannya dengan Gson:
public class UserAdapter implements JsonSerializer<User> {
@Override
public JsonElement serialize(User src, java.lang.reflect.Type typeOfSrc,
JsonSerializationContext context) {
return new JsonPrimitive(src.id);
}
}
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(User.class, new UserAdapter());
Gson gson = builder.create();
String json = gson.toJson(myItem);
System.out.println("JSON: "+json);
Tapi saya perlu melakukannya dengan Jackson sekarang, karena Gson tidak memiliki dukungan untuk antarmuka.
java
json
serialization
jackson
Jonas
sumber
sumber
Item
? Saya mengalami masalah di mana metode pengontrol saya mengembalikan objek serial standarTypeA
, tetapi untuk metode pengontrol khusus lainnya, saya ingin membuat serial secara berbeda. Seperti apa kelihatannya?Jawaban:
Seperti yang disebutkan, @JsonValue adalah cara yang bagus. Tetapi jika Anda tidak keberatan dengan serializer khusus, tidak perlu menulis satu untuk Item melainkan satu untuk Pengguna - jika demikian, itu akan sesederhana:
Namun kemungkinan lain adalah untuk menerapkan
JsonSerializable
, dalam hal ini tidak diperlukan pendaftaran.Untuk kesalahan; itu aneh - Anda mungkin ingin meningkatkan ke versi yang lebih baru. Tetapi juga lebih aman untuk diperpanjang
org.codehaus.jackson.map.ser.SerializerBase
karena akan memiliki implementasi standar dari metode non-esensial (yaitu semuanya kecuali panggilan serialisasi aktual).sumber
Exception in thread "main" java.lang.IllegalArgumentException: JsonSerializer of type com.example.JsonTest$UserSerilizer does not define valid handledType() (use alternative registration method?) at org.codehaus.jackson.map.module.SimpleSerializers.addSerializer(SimpleSerializers.java:62) at org.codehaus.jackson.map.module.SimpleModule.addSerializer(SimpleModule.java:54) at com.example.JsonTest.<init>(JsonTest.java:27) at com.exampple.JsonTest.main(JsonTest.java:102)
Anda dapat meletakkan
@JsonSerialize(using = CustomDateSerializer.class)
setiap bidang tanggal objek yang akan dibuat serial.sumber
@JsonSerialize(contentUsing= ...)
saat membuat anotasi Koleksi (misalnya@JsonSerialize(contentUsing= CustomDateSerializer.class) List<Date> dates
)Saya mencoba melakukan ini juga, dan ada kesalahan dalam kode contoh di halaman web Jackson yang gagal menyertakan type (
.class
) dalam metode panggilan keaddSerializer()
, yang seharusnya terbaca seperti ini:Dengan kata lain, ini adalah baris yang memberi contoh
simpleModule
dan menambahkan serializer (dengan baris yang salah sebelumnya dikomentari):FYI: Berikut adalah referensi untuk kode contoh yang benar: http://wiki.fasterxml.com/JacksonFeatureModules
sumber
Gunakan @JsonValue:
@JsonValue hanya berfungsi pada metode jadi Anda harus menambahkan metode getId. Anda harus dapat melewati serializer kustom Anda sama sekali.
sumber
Saya menulis contoh untuk
Timestamp.class
serialisasi / deserialisasi kustom , tetapi Anda dapat menggunakannya untuk apa pun yang Anda inginkan.Saat membuat pemeta objek, lakukan sesuatu seperti ini:
misalnya di
java ee
Anda bisa menginisialisasi dengan ini:di mana serializer harus seperti ini:
dan deserializer sesuatu seperti ini:
sumber
Ini adalah pola perilaku yang saya perhatikan saat mencoba memahami serialisasi Jackson.
1) Asumsikan ada objek Classroom dan satu class Student. Saya telah membuat semuanya menjadi publik dan final untuk kemudahan.
2) Asumsikan bahwa ini adalah serializers yang kami gunakan untuk membuat serialisasi objek ke dalam JSON. WriteObjectField menggunakan serializer objek itu sendiri jika itu terdaftar dengan pemeta objek; jika tidak, maka serialisasi itu sebagai POJO. WriteNumberField secara eksklusif hanya menerima primitif sebagai argumen.
3) Daftarkan hanya DoubleSerializer dengan pola keluaran DecimalFormat
###,##0.000
, di SimpleModule dan keluarannya adalah:Anda dapat melihat bahwa serialisasi POJO membedakan antara ganda dan Ganda, menggunakan DoubleSerialzer untuk Ganda dan menggunakan format String biasa untuk ganda.
4) Daftarkan DoubleSerializer dan ClassroomSerializer, tanpa StudentSerializer. Kita berharap bahwa hasilnya adalah jika kita menulis sebuah double sebagai sebuah objek, ia berperilaku seperti Double, dan jika kita menulis sebuah Double sebagai sebuah angka, ia berperilaku seperti sebuah double. Variabel instance Student harus ditulis sebagai POJO dan mengikuti pola di atas karena tidak terdaftar.
5) Daftarkan semua pembuat serial. Outputnya adalah:
persis seperti yang diharapkan.
Catatan penting lainnya: Jika Anda memiliki beberapa serializer untuk kelas yang sama yang terdaftar dengan Modul yang sama, maka Modul akan memilih serializer untuk kelas tersebut yang paling baru ditambahkan ke daftar. Ini tidak boleh digunakan - ini membingungkan dan saya tidak yakin seberapa konsistennya ini
Moral: jika Anda ingin menyesuaikan serialisasi primitif di objek Anda, Anda harus menulis serializer Anda sendiri untuk objek tersebut. Anda tidak dapat mengandalkan serialisasi POJO Jackson.
sumber
Tampilan JSON Jackson mungkin merupakan cara yang lebih sederhana untuk memenuhi kebutuhan Anda, terutama jika Anda memiliki fleksibilitas dalam format JSON Anda.
Jika
{"id":7, "itemNr":"TEST", "createdBy":{id:3}}
merupakan representasi yang dapat diterima maka ini akan sangat mudah dicapai dengan sedikit kode.Anda hanya perlu menganotasi bidang nama Pengguna sebagai bagian dari tampilan, dan menentukan tampilan yang berbeda dalam permintaan serialisasi Anda (bidang yang tidak diberi anotasi akan disertakan secara default)
Misalnya: Tentukan tampilan:
Anotasi Pengguna:
Dan serialisasi meminta tampilan yang tidak berisi bidang yang ingin Anda sembunyikan (bidang non-anotasi diserialkan secara default):
sumber
createdBy
nilai selain sebagai objek?setSerializationView()
tampaknya sudah usang jadi saya gunakanmapper.viewWriter(JacksonViews.ItemView.class).writeValue(writer, myItem);
sebagai gantinya.Dalam kasus saya (Spring 3.2.4 dan Jackson 2.3.1), konfigurasi XML untuk serializer khusus:
dengan cara yang tidak dapat dijelaskan ditimpa kembali ke default oleh sesuatu.
Ini berhasil untuk saya:
CustomObject.java
CustomObjectSerializer.java
Tidak ada konfigurasi XML (
<mvc:message-converters>(...)</mvc:message-converters>
) yang diperlukan dalam solusi saya.sumber
Jika satu-satunya persyaratan Anda dalam serializer kustom Anda adalah melewati
name
bidang serialisasiUser
, tandai sebagai sementara . Jackson tidak akan membuat serial atau deserialisasi sementara bidang .[lihat juga: Mengapa Java memiliki kolom transien? ]
sumber
User
kelas-? Tapi saya akan membuat serialisasi semua objek pengguna juga. Misalnya pertama hanya membuat serial semuaitems
(dengan hanyauserId
sebagai referensi ke objek pengguna) dan kemudian membuat serial semuausers
. Dalam hal ini saya tidak bisa menandai fiels diUser
-class.handledType()
metode dalam dokumentasi yang saya tautkan dan kapan Eclipse menghasilkan metode untuk menerapkan tidakhandledType()
dibuat, jadi saya bingung.Anda harus mengganti metode handlingType dan semuanya akan bekerja
sumber
Masalah dalam kasus Anda adalah ItemSerializer kehilangan metode handlingType () yang perlu diganti dari JsonSerializer
Oleh karena itu Anda mendapatkan kesalahan eksplisit yang ditanganiType () tidak ditentukan
Semoga bisa membantu seseorang. Terima kasih telah membaca jawaban saya.
sumber