GSON adalah perpustakaan Java yang digunakan untuk mengimplementasikan konversi timbal balik antara objek JSON dan Java. GSON adalah proyek open source yang diselenggarakan di https://github.com/google/gson.
Kelas utama di GSON adalah GSON. Anda juga dapat menggunakan kelas GsonBuilder untuk mengatur beberapa opsi saat membuat objek GSON.
Objek GSON tidak menyimpan keadaan apa pun saat memproses JSON, sehingga pengguna dapat dengan mudah melakukan beberapa serialisasi, deserialisasi, dan operasi lain pada objek GSON yang sama.
Contoh: Penggunaan Dasar
// serialisasigson gson = GSON baru (); gson.toJson (1); // ==> mencetak 1gson.toJson ("ABCD"); // ==> mencetak "abcd" gson.toJson (baru long (10)); // ==> mencetak 10int [] values = {1}; gson.toJson (nilai); // ==> Cetak [1] // DeserializationIning satu = gson.fromjson ("1", int.class); integer satu = gson.fromjson ("1", integer.class); long one = gson.fromjson ("1", integer.class); long one = gsonfromjson ("1", integer.class); long one one = gsonfromjson ("1", integer.class); long one one = gsonfromjson gson.fromjson ("false", boolean.class); string str = gson.fromjson ("/" abc/"", string.class); string anotherstr = gson.fromjson ("[/" ABC/"], string.class); // goNsoneBagofPrimitif Obj = Bagofprim = goNPon = goNson = goNson = goNson = goNson = goNson = goNson = goNson = goNson (goNson (goNson (goNson (goNTON (goSPRIVE (GERSON (GERSON (GERSON (GERSON (GERSON (/ABC (/ABC (/ABC (GERSON (GERSON (/" gson.tojson (OBJ); // ==> json adalah {"value1": 1, "value2": "abc"}Contoh: Konversi antara objek dan JSON
Tentukan kelas Bagofprimitives:
kelas bagofprimitives {private int value1 = 1; private string value2 = "ABC"; value int trasien pribadi3 = 3; BagofPrimitives () {// No-Args Constructor}}Serial ke JSON:
// SerializationBagofprimitives Obj = BagofPrimitives baru (); gson GSON = GSON baru (); string json = gson.toJson (OBJ); // ==> json adalah {"value1": 1, "value2": "abc"}Jangan membuat serialisasi objek yang mengandung referensi melingkar, jika tidak, rekursi tak terbatas akan terjadi.
Deserialisasi:
// DeserializationBagofprimitives obj2 = gson.fromjson (json, Bagofprimitives.class); // ==> obj2 sama seperti OBJ
Beberapa detail saat memproses objek:
Penanganan kelas bersarang (termasuk kelas dalam)
GSON dapat dengan mudah membuat serial kelas bersarang dan menghapus kelas bersarang statis. GSON tidak dapat secara otomatis deserialisasi kelas dalam murni karena konstruktor tanpa parameter dari kelas dalam perlu merujuk pada objek yang mengandungnya (mis., Contoh kelas luar). Untuk menghapus kelas statis, Anda dapat secara statis kelas dalam atau memberikan pencipta instance khusus. Inilah contohnya:
kelas publik A {public string a; kelas B {public string b; publik b () {// tidak ada konstruktor args untuk b}}}Kelas B di atas tidak dapat diserialisasi oleh GSON. Karena kelas B adalah kelas dalam (non-statis), GSON juga tidak dapat menghapus {"b": "ABC"} menjadi contoh kelas B. Jika B dinyatakan sebagai kelas B statis, maka GSON dapat menghapus string.
Solusi lain adalah menulis instance pencipta untuk b:
kelas publik InstanceCreatorForb mengimplementasikan InstanceCreator <BS> {private final a a; public InstanceCreatorForb (a) {this.a = a; } public ab createInstance (type type) {return a.new b (); }}Metode ini layak, tetapi tidak dianjurkan. (Penerjemah mengatakan dia tidak mengerti pencipta contoh ini dan tidak tahu bagaimana menggunakannya)
Contoh: Array
Gson gson = gson (); int [] ints = {1, 2, 3, 4, 5}; string [] string = {"abc", "def", "ghi"}; // serializationGson.tojson (ints); ==> Cetakan [1,2,3,4,5] gson.toJson (string); ==> mencetak ["abc", "def", "ghi"] // deserializationint [] ints2 = gson.fromjson ("[1,2,3,4,5]", int []. class); ==> ints2 akan sama dengan intsGSON juga mendukung array multidimensi dengan tipe data yang kompleks.
Contoh: Koleksi
GSON GSON = GSON baru (); koleksi <Integer> ints = lists.immutablelist (1,2,3,4,5); // serializationstring json = gson.toJson (ints); // ==> json adalah [1,2,3,4,5] // deserializationType collectionType = new typetoken <molection <Integer>> () {}. getType (); collection <Integer> ints2 = gson.fromjson (json, collectionType); // ints2 sama dengan ints2Keterbatasan saat memproses koleksi:
Serialize/Deserialize Generik
Saat menggunakan TOJSON (OBJ), GSON memanggil OBJ.GetClass () untuk mendapatkan informasi lapangan untuk digunakan dalam serialisasi. Demikian pula, objek myclass.class dapat dilewati sebagai parameter ke metode fromjson (json, myclass.class), yang dapat digunakan ketika objek tidak generik. Namun, ketika objek adalah objek tipe generik, informasi tipe generik akan hilang karena mekanisme penghapusan jenis di Java. Contoh berikut menggambarkan ini:
kelas foo <t> {t value;} gson gson = new gson (); foo <Bar> foo = new foo <Bar> (); gson.toJson (foo); // tidak dapat membuat serialisasi foo.value benar -benargson.fromjson (json, foo.getClass ()); // gagal deserialize foo.value sebagai barKode di atas menginterpretasikan nilai sebagai jenis batang, karena GSON memanggil foo.getClass () untuk mendapatkan informasi kelas, tetapi metode ini mengembalikan kelas primitif, yaitu foo.class. Ini berarti bahwa GSON tidak dapat mengetahui bahwa ini adalah objek tipe foo <Bar>.
Untuk mengatasi masalah ini, Anda dapat menentukan jenis parameter yang benar untuk obat generik Anda. Anda dapat menggunakan kelas yang diketik untuk dilakukan:
Type footype = typetoken baru <foo <bar>> () {} .getType (); gson.tojson (foo, footype); gson.fromjson (json, footype);Footype sebenarnya mendefinisikan kelas dalam anonim, yang berisi metode getType () yang dapat mengembalikan semua jenis parameter.
Serialize/Deserialize Koleksi objek dari jenis apa pun
Terkadang JSON yang diproses berisi jenis campuran, seperti:
['halo', 5, {name: 'salam', sumber: 'tamu'}]Set yang sesuai harus:
Koleksi koleksi = arraylist baru (); collection.add ("hello"); collection.add (5); collection.add (acara baru ("salam", "tamu"));Kelas acara didefinisikan sebagai berikut:
Acara kelas {name string privat; sumber string pribadi; Private Event (String Name, String Source) {this.name = name; this.source = sumber; }}Dengan GSON, Anda tidak perlu melakukan sesuatu yang istimewa untuk membuat serial koleksi: TOJSON (Koleksi) akan menghasilkan hasil yang memuaskan.
Namun, deserialisasi melalui dariJSON (JSON, Collection.class) tidak dimungkinkan, karena GSON tidak dapat sesuai dengan konten dalam JSON dengan jenisnya. GSON mengharuskan Anda untuk memberikan versi umum dari jenis koleksi di Fromjson. Anda memiliki tiga pilihan:
Solusi 1: Gunakan API GSON Parser (Parser Stream Level Level atau Dom Parser JsonParser) untuk parse elemen array, dan kemudian gunakan gson.fromjson () untuk memproses setiap elemen array. Ini adalah solusi yang disukai.
Skema 2: Daftarkan adaptor jenis untuk koleksi.class ke elemen peta dalam array ke objek yang sesuai. Kerugian dari metode ini adalah bahwa hal itu akan menyebabkan ketidaknyamanan saat berhadapan dengan jenis koleksi lainnya.
Skema 3: Daftarkan adaptor tipe untuk MyCollectionMemberType, dan gunakan Collection <myCollectionMemberType> di Fromjson. Metode ini hanya mungkin jika array terlihat seperti elemen tingkat tinggi atau jika Anda dapat mengubah jenis bidang menjadi koleksi <myCollectionMemberType>.
Serializer/Deserializer bawaan
GSON menyediakan serializer/deserializer untuk kelas yang umum digunakan yang mungkin tidak sesuai untuk representasi default.
Berikut adalah daftar kelas -kelas ini:
Serialisasi/Deserialisasi Kustom
Kadang -kadang, implementasi default GSON bukanlah yang Anda inginkan, yang lebih umum ketika berhadapan dengan beberapa perpustakaan kelas (seperti datetime).
GSON memungkinkan Anda untuk mendaftarkan serial/deserializer khusus. Untuk melakukan ini, Anda perlu menerapkan bagian -bagian berikut:
JSON Serializer: perlu menyesuaikan serialisasi untuk suatu objek
JSON Deserializer: Anda perlu menyesuaikan pencipta kelas deserialisasi untuk suatu jenis: Jika ada konstruktor tanpa parameter atau deserializer telah terdaftar, itu tidak perlu.
Gsonbuilder gson = gsonbuilder baru (); gson.registertypeadapter (mytype2.class, mytypeadapter baru ()); gson.registertypeadapter (mytype.class, new myserializer ()); gson.registertypeadapter (mytype.classs, new -classs ()); Mydeserializer ()); gson.registertypeadapter (mytype.class, myinstancecreator baru ());
RegisterTypeAdapter memeriksa apakah adaptor tipe mengimplementasikan beberapa antarmuka dan mendaftar adaptor tipe untuk antarmuka ini.
Tulis serializer
Berikut adalah contoh penyesuaian serializer untuk datetime:
Kelas Pribadi Datetimeserializer mengimplementasikan jSonserializer <datetime> {public jsoneLement serialize (datetime src, type typeOfSrc, JSonserializationContext Context) {return new jsonprimitive (src.tostring ())); }}GSON memanggil TOJSON () saat membuat serial instance datetime.
Tulis deserializer
Contoh berikut menunjukkan cara menulis deserializer dari kelas datetime:
Private Class DateTimedeserializer mengimplementasikan jsondeSerializer <DateTime> {public dateTime deserialize (JSONElement JSON, Type Typeoft, JSondeSerializationContext Context) melempar JsonParseException {return new DateTime (json.getAsjsonPrimitive (). Getasstring {return dateTime (json.getAsjsonPrimitive (). Getasstring ())). }}Ketika GSON perlu deserialize string JSON ke objek datetime, fromjson () akan dipanggil.
Untuk serializer/deserializer, perhatian harus diberikan kepada:
Tulis pencipta instance
Saat menghapus suatu objek, GSON perlu membuat instance dari suatu kelas. Kelas yang berkinerja baik selama serialisasi/deserialisasi berarti bahwa kelas ini memiliki konstruktor tanpa parameter. Biasanya, ketika berhadapan dengan kelas tanpa konstruktor tanpa parameter di perpustakaan kelas, diperlukan pencipta instan.
Contoh Pencipta Contoh:
MoneyInstanceCreator kelas privat mengimplementasikan InstanceCreator <u Money> {Uang Publik CreateTance (Tipe Jenis) {mengembalikan uang baru ("1000000", CurrencyCode.usd); }}Parameterisasi Jenis Pembuat Instal
Terkadang jenis yang akan dipakai akan menjadi tipe parameter. Secara keseluruhan, karena instance sebenarnya adalah tipe primitif, ini bukan masalah. Inilah contohnya:
kelas mylist <t> memperluas arraylist <t> {} kelas mylistInstancecreator mengimplementasikan instanceCreator <mylist <? >> {@suppresswarnings ("uncecked") mylist public <?> createinstance (type) {// tidak perlu menggunakan daftar public yang aktueter sejak parameter sejak parameter. mengembalikan myList baru (); }}Namun, kadang -kadang Anda perlu membuat instance berdasarkan jenis parameter nyata. Dalam hal ini, Anda dapat meneruskan parameter tipe ke metode CreateInstance. Inilah contohnya:
ID Kelas Publik <T> {Private Final Class <T> ClassOfID; nilai panjang akhir pribadi; ID publik (kelas <T> classOfId, nilai panjang) {this.classofid = classOfId; this.value = nilai; }} class IDInstanceCreator mengimplementasikan InstanceCreator <id <? >> {ID publik <?> CreateInstance (type type) {type [] typeParameters = ((parameterizedType) type) .getActualTypeArguments (); Ketik idtype = typeparameters [0]; // id hanya memiliki satu tipe parameter T return id.get ((class) idType, 0l); }}Dalam contoh di atas, instance dari kelas ID tidak dapat dibuat tanpa meneruskan tipe yang benar ke tipe parameterisasi. Kita dapat menyelesaikan masalah ini dengan meneruskan jenis parameter ke metode ini. Di sini, objek tipe dapat dianggap sebagai representasi dari tipe ID Java yang parameterisasi <foo>, dan instance yang sesuai harus terikat pada ID <foo>. Karena ID kelas hanya memiliki satu parameter t parameter, kami menggunakan getActualTypeargument () untuk mengembalikan elemen ke -0 dari tipe array, dalam contoh ini, foo.class.
Output kompak vs output yang indah
Output default JSON di GSON berada dalam format JSON yang ringkas. Dengan kata lain, tidak ada karakter spasi putih tambahan di JSON. Oleh karena itu, tidak ada ruang kosong antara nama lapangan dan nilai bidang, antara bidang, dan antara elemen array dalam output JSON. Juga, bidang nol tidak akan output (Catatan: NULL akan dipertahankan dalam objek pengumpulan dan array).
Jika Anda ingin menghasilkan lebih indah, Anda perlu menggunakan GsonBuilder untuk mengonfigurasi instance GSON. JsonFormatter tidak ada di API publik, sehingga klien tidak dapat mengkonfigurasi pengaturan output default. Sekarang kami hanya menyediakan jsonPrintFormatter, yang secara default adalah 80 karakter per baris, indentasi menggunakan 2 karakter dan margin kanan adalah 4 karakter.
Contoh berikut menunjukkan cara mendapatkan instance GSON untuk menggunakan jsonPrintFormatter alih -alih menggunakan JSONCompactFacTatter default.
Gson gson = gsonbuilder baru (). SetPrettyPrinting (). Create (); string jsonoutput = gson.toJson (someObject);
Objek kosong
Dalam implementasi default GSON, objek nol diabaikan. Ini dapat membuat format output (yang dapat dianggap sebagai hasil serialisasi) lebih ketat; Namun, klien harus menentukan nilai default untuk itu sehingga JSON dapat deserialisasi secara normal.
Jika Anda ingin membuat instance GSON NULL SERIALIZABLE, Anda dapat:
Gson gson = gsonbuilder baru (). Serializenulls (). Create ();
Perhatikan bahwa ketika membuat serial null, elemen JSonnull akan ditambahkan ke struktur JSONElement. Oleh karena itu, kami dapat menggunakan objek ini (GSON) di serializer/deserializer khusus kami.
Inilah contohnya:
kelas publik foo {private final string s; private final int i; foo publik () {this (null, 5); } public foo (string s, int i) {this.s = s; this.i = i; }} Gson gson = gsonbuilder baru (). Serializenulls (). Create (); foo foo = new foo (); string json = gson.toJson (foo); System.out.println (json); json = gson.tojson (null); System.out.println (json); json = gson);Keluaran:
{"s": null, "i": 5} nullDukungan Versi
Anda dapat menggunakan anotasi @Since untuk mempertahankan beberapa versi objek yang sama. Anotasi ini dapat digunakan di kelas dan bidang, dan juga akan didukung pada metode di masa depan. Untuk menggunakan fitur ini, Anda perlu mengkonfigurasi instance GSON untuk mengabaikan bidang dan objek yang lebih besar dari nomor versi tertentu. Jika versi tidak ditetapkan dalam objek GSON, semua bidang dan kelas digunakan saat serialisasi/deserializing.
Public Class VersionedClass {@since (1.1) Private Final String NewerField; @Since (1.0) Private Final String Newfield; bidang string final pribadi; public versionedclass () {this.newerfield = "newer"; this.newfield = "baru"; this.field = "old"; }} VersionEdclass VersionedObject = new versionedclass (); gson gson = gsonBuilder baru (). SetVersion (1.0) .create (); string jsonoutput = gson.toJson (someObject); System.out.println (jsonoutput); System.out.println (); gson =) (jsonoutput); System.out.println (); gson =) (jsonoutput); System.out.println (); gson.toJson (beberapa hale); System.out.println (jsonoutput);Keluaran:
{"newfield": "new", "field": "old"} {"newerfield": "newer", "newfield": "new", "field": "old"}Mengecualikan bidang dari serialisasi/deserialisasi
GSON mendukung penggunaan banyak metode untuk menghapus kelas, bidang, dan jenis lapangan. Jika metode berikut tidak memenuhi kebutuhan Anda, Anda dapat menggunakan metode serialisasi/deserializer khusus.
1. Pengecualian pengubah java
Secara default, jika suatu bidang dinyatakan sebagai sementara, lapangan dikecualikan. Selain itu, jika suatu bidang dinyatakan statis, bidang ini juga akan dikecualikan secara default. Jika Anda ingin memasukkan beberapa bidang yang dinyatakan sebagai sementara, Anda dapat melakukan ini:
impor java.lang.reflect.modifier; gson gson = gsonbuilder baru () .excludefieldswithmodifiers (Modifier.static) .create ();
Perhatikan bahwa dalam metode ExcudefieldsWithModifiers, Anda dapat menggunakan konstanta pengubah sebanyak mungkin. Misalnya:
Gson gson = gsonbuilder baru () .excludefieldswithmodifiers (Modifier.Static, Modifier.transient, Modifier.volatile) .create ();
2. Gunakan bidang @Expose untuk mengecualikan
Fitur ini memungkinkan Anda untuk menandai bidang spesifik di kelas sehingga tidak dikecualikan/dikecualikan dalam serialisasi/deserialisasi. Untuk menggunakan anotasi ini, Anda harus membuat GSON menggunakan GsonBuilder baru (). ExcudefieldswithoutExposeanNotation (). Create (). Contoh GSON akan mengecualikan semua bidang di kelas yang tidak ditandai oleh @Expose.
3. Kebijakan Pengecualian yang Ditentukan Pengguna
Jika metode pengecualian di atas tidak dapat memenuhi kebutuhan, Anda juga dapat menyesuaikan strategi pengecualian Anda. Untuk informasi lebih lanjut, silakan merujuk ke Exclusionstrategy Javadoc.
Contoh berikut menunjukkan cara mengecualikan bidang yang ditandai dengan @foo, dan mengecualikan jenis kelas atas dari kelas string atau jenis bidang yang dinyatakan:
@Retention (retentionPolicy.runtime) @Target ({elementType.field}) public @interface foo {// Tag lapangan hanya anotasi} kelas publik sampleObjectFortest {@foo private final int annotatedfield; Private Final String Stringfield; final longfield final pribadi; kelas akhir pribadi <?> Clazzfield; Public SampleObjectFortest () {AnnotatedField = 5; Stringfield = "SomedefaultValue"; Longfield = 1234; }} kelas publik MyExClusionstrategy mengimplementasikan Excupionstrategy {Private Final Class <?> TypeToSkip; private myExclusionstrategy (class <?> typetoskip) {this.typetoskip = typetoskip; } public boolean seharusnyaskipclass (class <?> clazz) {return (clazz == typetoskip); } public boolean wuldskipfield (fieldattributes f) {return f.getannotation (foo.class)! = null; }} public static void main (string [] args) {gson gson = new gsonbuilder () .setExclusionstrategy (new myexclusionstrategy (string.class)) .serializenulls () .create (); SampleObjectFortest src = sampleObjectFortest baru (); String json = gson.toJson (src); System.out.println (JSON); }Keluaran:
{"Longfield": 1234}Dukungan untuk Penamaan Lapangan JSON
Beberapa strategi penamaan lapangan yang telah ditentukan dari GSON dapat mengubah nama lapangan Java standar (yaitu, nomenklatur unta, seperti sampleFieldNameInjava) menjadi nama lapangan JSON (yaitu sample_field_name_in_java atau samplefieldNameinjava). Untuk informasi lebih lanjut, silakan merujuk ke fieldnamingpolicy.
GSON juga memiliki kebijakan berbasis anotasi untuk memungkinkan klien menyesuaikan nama-nama bidang. Di bawah strategi ini, jika nama lapangan ilegal disediakan sebagai nilai beranotasi, GSON akan melempar pengecualian runtime.
Contoh berikut menunjukkan cara menggunakan dua strategi penamaan GSON ini:
kelas privat beberapa halobject {@serializedName ("custom_naming") Private final string Somefield; string final private someotherfield; public someObject (string a, string b) {this.somefield = a; this.someotherfield = b; }} SomeObject someObject = new someObject ("first", "second"); gson gson = new gsonbuilder (). SetFieldnamingPolicy (fieldnamingpolicy.upper_camel_case) .create (); string jsonrepresentation = gsono.tojson (someObject); sistem.outprect.outprintl (gsone.ttojson (someObject); System.Keluaran:
{"custom_naming": "first", "someotherfield": "kedua"}Jika Anda ingin menyesuaikan nama, Anda dapat menggunakan anotasi @serializedName.
Keadaan berbagi antara serializer dan deserializer
Terkadang Anda perlu berbagi keadaan antara serializer dan deserializer, dan Anda dapat menggunakan tiga metode berikut untuk mencapai tujuan Anda:
Dua metode pertama tidak aman utas, yang ketiga.
Solusi untuk GSON Parsing Null Error
Salah satu kelemahan GSON adalah bahwa ia tidak dapat mengatur penggantian nol.
Kami hanya dapat mengganti nol secara manual yang dikembalikan oleh server dalam batch. Ketika antarmuka normal didefinisikan, server pasti tidak akan diizinkan untuk mengembalikan nol, tetapi hasil latar belakang akan selalu muncul nol!
Jika Anda mencari, ada jawaban umum,
Gson gson = gsonbuilder baru (). Serializenulls (). Create ();
Tapi ini tidak dapat menyelesaikan masalah Desequence, bagaimana menyelesaikannya?
Solusinya adalah sebagai berikut:
Gson gson = gsonbuilder baru (). Registertypeadapterfactory (baru nullstringToEmptyAdapterfactory ()). Create (); // Kemudian gunakan GSON yang ditulis di baris di atas untuk serialize dan deserialize classicors classicty (json (json, type); gsona. NullStringToEmptyAdapterFactory <T> mengimplementasikan TypeAdapterFactory {@suppressWarnings ("Uncecked") Public <t> TypeAdapter <T> Buat (GSON GSON, typetoken <T> type) {class <t> rawtype = (class <t>) type.getrawType (); if (rawType! = string.class) {return null; } return (TypeAdapter <T>) New StringNullAdapter (); }} // StringNullAdapter Kode Public Class Public StringNullAdapter Memperluas TypeAdapter <String> {@Override Public String Read (JSONREADER READER) melempar IoException {// TODO METODE AUTO-ENTEERATED if (reader.peek () == jsontoken.null) {Nextnextnextnext (); kembali ""; } return reader.nextString (); } @Override public void write (penulis JSONWRITER, nilai string) melempar IoException {// TODO Metode yang dihasilkan otomatis Stub if (value == null) {writer.nullValue (); kembali; } writer.value (value); }}