Trong những bài viết trước tôi đã hướng dẫn các bạn sử dụng thư viện Gson để chuyển đổi Java object sang / từ JSON sử dụng serialization / deserialization mặc định của Gson. Tuy nhiên, đôi khi mặc định serialization / deserialization được sử dụng bởi GSON là không đủ và chúng ta cần tùy chỉnh một vài thứ được áp dụng trong khi serializing / deserializing đối tượng sang / từ JSON. Điều này có thể dễ dàng thực hiện bằng cách sử dụng JsonSerializer và JsonDeserializer và liên kết chúng với GsonBuilder.
Trong phần tiếp theo của bài viết, tôi sẽ hướng dẫn cách custom dữ liệu được chuyển đổi sang/ từ chuỗi JSON.
Nội dung
Dữ liệu sử dụng trong ví dụ
Hãy xem đoạn code dưới đây:
public class Book { private String title; private String[] authors; private String isbn10; private String isbn13; private Double price; private Date publishedDate; }
Với class Book như trên, chúng ta mong muốn khi chuyển sang chuỗi Json sẽ được kết quả như sau:
{ "title": "Head First Design Patterns", "isbn-10": "0596007124", "isbn-13": "978-0596007126", "price": 52.41, "publishedDate": "01/10/2004", "authors": [ "Eric Freeman", "Bert Bates", "Kathy Sierra", "Elisabeth Robson" ] }
Gson có thể serializer các lớp mà không có bất kỳ cấu hình đặc biệt, chỉ cần sử dụng cấu hình mặc định. Gson sử dụng các tên trường Java như tên của JSON và sẽ sắp xếp các giá trị của chúng tương ứng.
{ "title": "Head First Design Patterns", "authors": [ "Eric Freeman", "Bert Bates", "Kathy Sierra", "Elisabeth Robson" ], "isbn10": "0596007124", "isbn13": "978-0596007126", "price": 52.41, "publishedDate": "Oct 1, 2004 4:46:20 PM" }
Nếu chúng ta xem xét kỹ hơn kết quả mong đợi của chuỗi JSON ở trên, chúng ta sẽ thấy rằng các trường ISBN chứa dấu gạch ngang: isbn-10 và isbn-13. Thật không may, chúng ta không thể lấy các tên trường này bằng cách sử dụng cấu hình mặc định Gson mặc định. Một cách để giải quyết vấn đề này là sử dụng các chú thích (Annotation) như mô tả trong bài viết: Hướng dẫn sử dụng Gson Annotations. Sử dụng chú thích chúng ta có thể xác định tên trường JSON và Gson sẽ xem xét phần còn lại.
Một vấn đề khác là trường publishedDate, chúng ta mong muốn kiểu ngày được format với định dạng dd/MM/yyyy. Điều này không thể thực hiện nếu sử dụng cấu hình mặc định của Gson.
Để giải quyết các vấn đề trên, chúng ta có thể sử dụng 2 lớp Jsonserializer và JsonDeserializer được cung cấp bởi thư viện Gson.
- Jsonserializer : cung cấp phương thức serialize cho việc tùy chỉnh quá trình chuyển đổi từ Java object sang chuỗi JSON.
- JsonDeserializer : cung cấp phương thức deserialize cho việc tùy chỉnh quá trình chuyển đổi từ chuỗi JSON sang Java object.
Custom Jsonserializer
Xem ví dụ bên dưới:
package com.gpcoder.gson.custom; import java.lang.reflect.Type; import java.text.SimpleDateFormat; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import com.gpcoder.gson.object.Book; public class Bookserializer implements JsonSerializer<Book> { public static final SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); public JsonElement serialize(Book book, Type typeOfSrc, JsonSerializationContext context) { final JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("title", book.getTitle()); jsonObject.addProperty("isbn-10", book.getIsbn10()); jsonObject.addProperty("isbn-13", book.getIsbn13()); jsonObject.addProperty("price", book.getPrice()); // Write custom Date Serializer final JsonPrimitive jsonDate = new JsonPrimitive(sdf.format(book.getPublishedDate())); jsonObject.add("publishedDate", jsonDate); // Write custom Array Serializer final JsonArray jsonAuthorsArray = new JsonArray(); for (final String author : book.getAuthors()) { final JsonPrimitive jsonAuthor = new JsonPrimitive(author); jsonAuthorsArray.add(jsonAuthor); } jsonObject.add("authors", jsonAuthorsArray); return jsonObject; } }
Như bạn thấy, interface JsonSerializer yêu cầu cung cấp một kiểu dữ liệu mà nó sẽ được serializer. Interface này cũng yêu cầu cài đặt một phương thức serialize() để thực hiện việc tùy chỉnh Java object sang chuỗi Json. Kiểu trả về của phương thức serialize() phải là một thể hiện của kiểu JsonElement.
JsonElement là một abstract class, có 4 lớp cài đặt như sau:
- JsonPrimitive : bao gồm một chuỗi hoặc số nguyên, số thực, ngày, …
- JsonObject : một bộ tập hợp của JsonElements. Nó cài đặt một LinkedTreeMap để lưu trữ các khóa (key) của chuỗi json, tương tự như một Map<String, JsonElement>.
- JsonNull : một giá trị null.
- JsonArray : một mảng của JsonElements. Các phần tử mảng có thể là bất kỳ loại nào trong số bốn loại và loại hỗn hợp được hỗ trợ.
Custom JsonDeserializer
Xem ví dụ bên dưới:
package com.gpcoder.gson.custom; import java.lang.reflect.Type; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import com.google.gson.JsonArray; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.gpcoder.gson.object.Book; public class BookDeserializer implements JsonDeserializer<Book> { public static final SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); public Book deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { final JsonObject jsonObject = json.getAsJsonObject(); final String title = jsonObject.get("title").getAsString(); final String isbn10 = jsonObject.get("isbn-10").getAsString(); final String isbn13 = jsonObject.get("isbn-13").getAsString(); final Double price = jsonObject.get("price").getAsDouble(); // Write custom Date Deserializer Date publishedDate = null; try { publishedDate = sdf.parse(jsonObject.get("publishedDate").getAsString()); } catch (ParseException e) { e.printStackTrace(); } // Write custom Array Deserializer final JsonArray jsonAuthorsArray = jsonObject.get("authors").getAsJsonArray(); final String[] authors = new String[jsonAuthorsArray.size()]; for (int i = 0; i <span data-mce-type="bookmark" style="display: inline-block; width: 0px; overflow: hidden; line-height: 0;" class="mce_SELRES_start"></span>< authors.length; i++) { final JsonElement jsonAuthor = jsonAuthorsArray.get(i); authors[i] = jsonAuthor.getAsString(); } final Book book = new Book(); book.setTitle(title); book.setIsbn10(isbn10); book.setIsbn13(isbn13); book.setPrice(price); book.setPublishedDate(publishedDate); book.setAuthors(authors); return book; } }
Đăng ký Custom Serializer / Deserializer với GsonBuilder và chạy chương trình
Xem code bên dưới:
package com.gpcoder.gson.custom; import java.util.Calendar; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.gpcoder.gson.object.Book; public class GsonCustomSerializationExample { public static void main(String args[]) { final GsonBuilder gsonBuilder = new GsonBuilder().setPrettyPrinting(); // Register custom serializers / deserializers with GsonBuilder gsonBuilder.registerTypeAdapter(Book.class, new Bookserializer()); gsonBuilder.registerTypeAdapter(Book.class, new BookDeserializer()); // format the JSON String gsonBuilder.setPrettyPrinting(); final Gson gson = gsonBuilder.create(); final Book book = new Book(); book.setTitle("Head First Design Patterns"); book.setIsbn10("0596007124"); book.setIsbn13("978-0596007126"); book.setPrice(52.41); Calendar c = Calendar.getInstance(); c.set(2004, Calendar.OCTOBER, 1); book.setPublishedDate(c.getTime()); String[] authors = new String[] { "Eric Freeman", "Bert Bates", "Kathy Sierra", "Elisabeth Robson" }; book.setAuthors(authors); System.out.println("Convert Book object to JSON string: "); String jsonString = gson.toJson(book); System.out.println(jsonString); System.out.println("Convert JSON String to Book object: "); Book book2 = gson.fromJson(jsonString, Book.class); System.out.println(book2); } }
Kết quả thực thi chương trình trên:
Convert Book object to JSON string: { "title": "Head First Design Patterns", "isbn-10": "0596007124", "isbn-13": "978-0596007126", "price": 52.41, "publishedDate": "01/10/2004", "authors": [ "Eric Freeman", "Bert Bates", "Kathy Sierra", "Elisabeth Robson" ] } Convert JSON String to Book object: Book [title=Head First Design Patterns, authors=[Eric Freeman, Bert Bates, Kathy Sierra, Elisabeth Robson], isbn10=0596007124, isbn13=978-0596007126, price=52.41, publishedDate=Fri Oct 01 00:00:00 ICT 2004]
Tài liệu tham khảo:
- https://github.com/google/gson
- http://www.javacreed.com/gson-deserializer-example/
- http://www.javacreed.com/gson-serializer-example/