Pemrosesan JSON di Java EE 7

1. Ikhtisar

Artikel ini akan menunjukkan kepada Anda cara memproses JSON hanya menggunakan inti Java EE, tanpa menggunakan dependensi pihak ketiga seperti Jersey atau Jackson. Hampir semua yang akan kita gunakan disediakan oleh paket javax.json.

2. Menulis Objek ke String JSON

Mengonversi objek Java menjadi String JSON sangat mudah. Mari kita asumsikan kita memiliki kelas Person sederhana :

public class Person { private String firstName; private String lastName; private Date birthdate; // getters and setters }

Untuk mengonversi instance kelas itu ke String JSON , pertama-tama kita perlu membuat instance JsonObjectBuilder dan menambahkan pasangan properti / nilai menggunakan metode add () :

JsonObjectBuilder objectBuilder = Json.createObjectBuilder() .add("firstName", person.getFirstName()) .add("lastName", person.getLastName()) .add("birthdate", new SimpleDateFormat("DD/MM/YYYY") .format(person.getBirthdate()));

Perhatikan bahwa metode add () memiliki beberapa versi yang kelebihan beban. Ini dapat menerima sebagian besar tipe primitif (serta objek dalam kotak) sebagai parameter keduanya.

Setelah kita selesai mengatur properti, kita hanya perlu menulis objek ke dalam String :

JsonObject jsonObject = objectBuilder.build(); String jsonString; try(Writer writer = new StringWriter()) { Json.createWriter(writer).write(jsonObject); jsonString = writer.toString(); }

Dan itu dia! String yang dihasilkan akan terlihat seperti ini:

{"firstName":"Michael","lastName":"Scott","birthdate":"06/15/1978"}

2.1. Menggunakan JsonArrayBuilder untuk Membangun Array

Sekarang, untuk menambahkan sedikit lebih banyak kerumitan pada contoh kita, anggaplah kelas Person telah dimodifikasi untuk menambahkan properti baru yang disebut email yang akan berisi daftar alamat email:

public class Person { private String firstName; private String lastName; private Date birthdate; private List emails; // getters and setters }

Untuk menambahkan semua nilai dari daftar itu ke JsonObjectBuilder, kita membutuhkan bantuan JsonArrayBuilder :

JsonArrayBuilder arrayBuilder = Json.createArrayBuilder(); for(String email : person.getEmails()) { arrayBuilder.add(email); } objectBuilder.add("emails", arrayBuilder);

Perhatikan bahwa kami menggunakan versi lain yang kelebihan beban dari metode add () yang mengambil objek JsonArrayBuilder sebagai parameter keduanya.

Jadi, mari kita lihat String yang dihasilkan untuk objek Person dengan dua alamat email:

{"firstName":"Michael","lastName":"Scott","birthdate":"06/15/1978", "emails":["[email protected]","[email protected]"]}

2.2. Memformat Output Dengan PRETTY_PRINTING

Jadi kami telah berhasil mengubah objek Java menjadi String JSON yang valid . Sekarang, sebelum pindah ke bagian berikutnya, mari tambahkan beberapa pemformatan sederhana untuk membuat keluaran lebih "seperti JSON" dan lebih mudah dibaca.

Pada contoh sebelumnya, kami membuat JsonWriter menggunakan Json langsung . createWriter () metode statis. Untuk mendapatkan lebih banyak kendali atas String yang dihasilkan , kita akan memanfaatkan kemampuan JsonWriterFactory Java 7 untuk membuat penulis dengan konfigurasi tertentu.

Map config = new HashMap(); config.put(JsonGenerator.PRETTY_PRINTING, true); JsonWriterFactory writerFactory = Json.createWriterFactory(config); String jsonString; try(Writer writer = new StringWriter()) { writerFactory.createWriter(writer).write(jsonObject); jsonString = writer.toString(); }

Kode tersebut mungkin terlihat sedikit bertele-tele, tetapi sebenarnya tidak banyak gunanya.

Pertama, ini membuat sebuah instance JsonWriterFactory yang meneruskan peta konfigurasi ke konstruktornya. Peta hanya berisi satu entri yang disetel true ke properti PRETTY_PRINTING. Kemudian, kami menggunakan contoh pabrik itu untuk membuat penulis, daripada menggunakan Json.createWriter () .

Keluaran baru akan berisi jeda baris dan tabulasi khusus yang menjadi ciri String JSON :

{ "firstName":"Michael", "lastName":"Scott", "birthdate":"06/15/1978", "emails":[ "[email protected]", "[email protected]" ] }

3. Membangun Objek Java Dari String

Sekarang mari kita lakukan operasi sebaliknya: ubah String JSON menjadi objek Java.

Bagian utama dari proses konversi berkisar pada JsonObject . Untuk membuat instance kelas ini, gunakan metode statis Json.createReader () diikuti oleh readObject () :

JsonReader reader = Json.createReader(new StringReader(jsonString)); JsonObject jsonObject = reader.readObject();

Metode createReader () menggunakan InputStream sebagai parameter. Dalam contoh ini, kami menggunakan StringReader, karena JSON kami terdapat dalam objek String , tetapi metode yang sama ini dapat digunakan untuk membaca konten dari file, misalnya, menggunakan FileInputStream .

Dengan instance JsonObject , kita dapat membaca properti menggunakan metode getString () dan menetapkan nilai yang diperoleh ke instance yang baru dibuat dari kelas Person :

Person person = new Person(); person.setFirstName(jsonObject.getString("firstName")); person.setLastName(jsonObject.getString("lastName")); person.setBirthdate(dateFormat.parse(jsonObject.getString("birthdate")));

3.1. Menggunakan JsonArray untuk Mendapatkan Nilai Daftar

Kita perlu menggunakan kelas khusus, yang disebut JsonArray untuk mengekstrak nilai daftar dari JsonObject :

JsonArray emailsJson = jsonObject.getJsonArray("emails"); List emails = new ArrayList(); for (JsonString j : emailsJson.getValuesAs(JsonString.class)) { emails.add(j.getString()); } person.setEmails(emails);

Itu dia! Kami telah membuat instance lengkap Person dari Json String .

4. Menanyakan Nilai

Sekarang, mari kita asumsikan kita tertarik pada bagian data yang sangat spesifik yang ada di dalam JSON String .

Pertimbangkan JSON di bawah ini yang mewakili klien dari toko hewan peliharaan. Katakanlah, karena alasan tertentu, Anda perlu mendapatkan nama hewan peliharaan ketiga dari daftar hewan peliharaan:

{ "ownerName": "Robert", "pets": [{ "name": "Kitty", "type": "cat" }, { "name": "Rex", "type": "dog" }, { "name": "Jake", "type": "dog" }] }

Mengubah keseluruhan teks menjadi objek Java hanya untuk mendapatkan satu nilai tidak akan sangat efisien. Jadi, mari kita periksa beberapa strategi untuk membuat kueri JSON Strings tanpa harus melalui keseluruhan cobaan konversi.

4.1. Membuat Kueri Menggunakan API Model Objek

Menanyakan nilai properti dengan lokasi yang diketahui dalam struktur JSON sangatlah mudah. Kita bisa menggunakan instance JsonObject, kelas yang sama yang digunakan dalam contoh sebelumnya:

JsonReader reader = Json.createReader(new StringReader(jsonString)); JsonObject jsonObject = reader.readObject(); String searchResult = jsonObject .getJsonArray("pets") .getJsonObject(2) .getString("name"); 

Tangkapan di sini adalah untuk menavigasi melalui properti jsonObject menggunakan urutan metode get * () yang benar.

In this example, we first get a reference to the “pets” list using getJsonArray(), which returns a list with 3 records. Then, we use getJsonObject() method, which takes an index as a parameter, returning another JsonObject representing the third item in the list. Finally, we use getString() to get the string value we are looking for.

4.2. Querying Using Streaming API

Another way to perform precise queries on a JSON String is using the Streaming API, which has JsonParser as its main class.

JsonParser provides extremely fast, read-only, forward access to JS, with the drawback of being somewhat more complicated than the Object Model:

JsonParser jsonParser = Json.createParser(new StringReader(jsonString)); int count = 0; String result = null; while(jsonParser.hasNext()) { Event e = jsonParser.next(); if (e == Event.KEY_NAME) { if(jsonParser.getString().equals("name")) { jsonParser.next(); if(++count == 3) { result = jsonParser.getString(); break; } } } }

This example delivers the same result as the previous one. It returns the name from the third pet in the pets list.

Once a JsonParser is created using Json.createParser(), we need to use an iterator (hence the “forward access” nature of the JsonParser) to navigate through the JSON tokens until we get to the property (or properties) we are looking for.

Every time we step through the iterator we move to the next token of the JSON data. So we have to be careful to check if the current token has the expected type. This is done by checking the Event returned by the next() call.

There are many different types of tokens. In this example, we are interested in the KEY_NAME types, which represent the name of a property (e.g. “ownerName”, “pets”, “name”, “type”). Once we stepped through a KEY_NAME token with a value of “name” for the third time, we know that the next token will contain a string value representing the name of the third pet from the list.

This is definitely harder than using the Object Model API, especially for more complicated JSON structures. The choice between one or the other, as always, depends on the specific scenario you will be dealing with.

5. Conclusion

We have covered a lot of ground on the Java EE JSON Processing API with a couple of simple examples. To learn other cool stuff about JSON processing, check our series of Jackson articles.

Periksa kode sumber kelas yang digunakan dalam artikel ini, serta beberapa pengujian unit, di repositori GitHub kami.