GP Coder

Trang chia sẻ kiến thức lập trình Java

  • Java Core
    • Basic Java
    • OOP
    • Exception Handling
    • Multi-Thread
    • Java I/O
    • Networking
    • Reflection
    • Collection
    • Java 8
  • Design pattern
    • Creational Pattern
    • Structuaral Pattern
    • Behavior Pattern
  • Web Service
    • SOAP
    • REST
  • JPA
  • Java library
    • Report
    • Json
    • Unit Test
  • Message Queue
    • ActiveMQ
    • RabbitMQ
  • All
Trang chủ Java library Json Hướng dẫn sử dụng Gson TypeAdapter

Hướng dẫn sử dụng Gson TypeAdapter

Đăng vào 18/01/2018 . Được đăng bởi GP Coder . 4292 Lượt xem . Toàn màn hình

Nội dung

  • 1 Giới thiệu
  • 2 Ví dụ sử dụng TypeAdapter
  • 3 So sánh hiệu suất của TypeAdapter với JsonSerializer

Giới thiệu

Trong bài viết Gson Custom Serialization và Deserialization, tôi đã hướng dẫn cách custom dữ liệu được chuyển đổi sang/ từ chuỗi JSON sử dụng thư viện GSON. Tuy nhiên, các lớp JsonSerializer và JsonDeserializer sử dụng một lớp trung gian của các đối tượng. Các đối tượng Java hoặc JSON lần đầu tiên được chuyển thành JsonElement (lớp trung gian) và sau đó chuyển sang chuỗi Java hoặc JSON như được hiển thị trong hình ảnh sau:

Lớp trung gian này có thể tránh được bằng cách sử dụng TypeAdapter thay vì JsonSerializer hoặc JsonDeserializer. TypeAdapter hiệu quả hơn JsonSerializer và JsonDeserializer khi nó bỏ qua lớp trung gian.

Với JsonSerializer và JsonDeserializer cung cấp đệm an toàn rất tiện lợi vì nó làm giảm nguy cơ tạo chuỗi JSON không hợp lệ. Hình ảnh được hiển thị ở trên cho thấy cách các đối tượng được tuần tự hóa bằng cách sử dụng JsonSerializer. Đầu tiên các đối tượng Java được chuyển sang JsonElements, và sau đó chuyển sang chuỗi JSON. Quá trình này tạo ra một tập hợp các đối tượng tạm thời, sau đó được chuyển đổi thành chuỗi JSON. Các đối tượng này được chuyển thành chuỗi JSON sử dụng một thực hiện nội bộ của TypeAdapter. TypeAdapter có thể lấy bất kỳ đối tượng Java (bao gồm các đối tượng thuộc kiểu JsonElement) và chuyển nó sang chuỗi JSON như thể hiện trong hình dưới đây:

TypeAdapter là một lớp trừu tượng, có hai phương thức trừu tượng:

  • Phương thức write() lấy một thể hiện của JsonWriter và đối tượng được nối tiếp. Đối tượng được ghi vào JsonWriter một cách tương tự như một đối tượng được in tới PrintStream.
  • Phương thức read() lấy một thể hiện của JsonReader và trả về một thể hiện của đối tượng deserialised.

Tương tự như JsonSerializer và JsonDeserializer, TypeAdapter cần được đăng ký thông qua GsonBuilder trước khi nó có thể được sử dụng như sau:


    final GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.registerTypeAdapter(Book.class, new BookTypeAdapter());
    final Gson gson = gsonBuilder.create();

Trong phần dưới đây chúng ta sẽ thấy cách sử dụng TypeAdapter để chuyển các đối tượng Java sang chuỗi JSON (serialise) và ngược lại (deserialise).

Ví dụ sử dụng TypeAdapter

Book.java


public class Book {
	private String title;
	private String[] authors;
	private String isbn10;
	private String isbn13;
	private Double price;
	private Date publishedDate;

        // Getters and setters ...
}

BookTypeAdapter.java


package com.gpcoder.gson.adapter;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import com.gpcoder.gson.object.Book;

public class BookTypeAdapter extends TypeAdapter<Book> {

	public static final SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");

	@Override
	public Book read(final JsonReader in) throws IOException {
		final Book book = new Book();

		in.beginObject();
		while (in.hasNext()) {
			switch (in.nextName()) {
			case "title":
				book.setTitle(in.nextString());
				break;
			case "isbn-10":
				book.setIsbn10(in.nextString());
				break;
			case "isbn-13":
				book.setIsbn13(in.nextString());
				break;
			case "price":
				book.setPrice(in.nextDouble());
				break;
			case "publishedDate":
				Date publishedDate = null;
				try {
					publishedDate = sdf.parse(in.nextString());
				} catch (ParseException e) {
					e.printStackTrace();
				}
				book.setPublishedDate(publishedDate);
				break;
			case "authors":
				in.beginArray();
				final List<String> authors = new ArrayList<>();
				while (in.hasNext()) {
					authors.add(in.nextString());
				}
				in.endArray();
				book.setAuthors(authors.toArray(new String[authors.size()]));
				break;
			}
		}
		in.endObject();

		return book;
	}

	@Override
	public void write(final JsonWriter out, final Book book) throws IOException {
		out.beginObject();
		out.name("title").value(book.getTitle());
		out.name("isbn-10").value(book.getIsbn10());
		out.name("isbn-13").value(book.getIsbn13());
		out.name("price").value(book.getPrice());
		out.name("publishedDate").value(sdf.format(book.getPublishedDate()));
		out.name("authors");
		out.beginArray();
		for (final String author : book.getAuthors()) {
			out.value(author);
		}
		out.endArray();
		out.endObject();
	}
}

GsonCustomTypeAdapterExample.java


package com.gpcoder.gson.adapter;

import java.io.IOException;
import java.util.Calendar;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.gpcoder.gson.object.Book;

public class GsonCustomTypeAdapterExample {

	public static void main(final String[] args) throws IOException {

		final GsonBuilder gsonBuilder = new GsonBuilder();
		gsonBuilder.registerTypeAdapter(Book.class, new BookTypeAdapter());
		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: ");
		final String json = gson.toJson(book);
		System.out.println(json);

		System.out.println("Convert JSON String to Book object: ");
		final Book parsedBook = gson.fromJson(json, Book.class);
		System.out.println(parsedBook);
	}
}


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]

So sánh hiệu suất của TypeAdapter với JsonSerializer

Như đã nói ở trên, hiệu suất khi sử dụng TypeAdapter tốt hơn so với JsonSerializer bởi vì nó bỏ qua lớp trung gian. Trong phần tiếp theo, tôi sẽ chứng minh cho các bạn thấy điều này.

LargeData


package com.gpcoder.gson.object;

public class LargeData {

	private long[] numbers;

	public void create(final int length) {
		numbers = new long[length];
		for (int i = 0; i < length; i++) {
			numbers[i] = i;
		}
	}

	public long[] getNumbers() {
		return numbers;
	}

}

JsonSerializer

LargeDataserializer.java


package com.gpcoder.gson.performance;

import java.lang.reflect.Type;

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.LargeData;

public class LargeDataserializer implements JsonSerializer<LargeData> {

	@Override
	public JsonElement serialize(final LargeData data, final Type typeOfSrc, final JsonSerializationContext context) {
		final JsonArray jsonNumbers = new JsonArray();
		for (final long number : data.getNumbers()) {
			jsonNumbers.add(new JsonPrimitive(number));
		}

		final JsonObject jsonObject = new JsonObject();
		jsonObject.add("numbers", jsonNumbers);
		return jsonObject;
	}
}

LargeDataserializerTest.java


package com.gpcoder.gson.performance;

import java.io.File;
import java.io.IOException;
import java.io.PrintStream;

import org.apache.commons.lang3.time.StopWatch;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.gpcoder.gson.object.LargeData;

public class LargeDataserializerTest {

	public static void main(final String[] args) throws IOException {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();

		// Configure GSON
		final GsonBuilder gsonBuilder = new GsonBuilder();
		gsonBuilder.registerTypeAdapter(LargeData.class, new LargeDataserializer());
		gsonBuilder.setPrettyPrinting();

		final Gson gson = gsonBuilder.create();

		final LargeData data = new LargeData();
		data.create(10485760);

		final String json = gson.toJson(data);

		final File dir = new File("data");
		dir.mkdirs();

		try (PrintStream out = new PrintStream(new File(dir, "outputserializer.json"), "UTF-8")) {
			out.println(json);
		}

		stopWatch.stop();
		System.out.println("Done in " + stopWatch.getTime());
	}
}

Thực thi chương trình trên, bạn sẽ thấy thời gian thực thi của JsonSerializer khoảng 15950 ms. Một file outputserializer.json được tạo ra trong thư mục data có kích thước là 129 MB. Bộ nhớ sử dụng khoảng 1.1 GB.

TypeAdapter

LargeDataTypeAdapter.java


package com.gpcoder.gson.performance;

import java.io.IOException;

import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import com.gpcoder.gson.object.LargeData;

public class LargeDataTypeAdapter extends TypeAdapter<LargeData> {

	@Override
	public LargeData read(final JsonReader in) throws IOException {
		throw new UnsupportedOperationException("Coming soon");
	}

	@Override
	public void write(final JsonWriter out, final LargeData data) throws IOException {
		out.beginObject();
		out.name("numbers");
		out.beginArray();
		for (final long number : data.getNumbers()) {
			out.value(number);
		}
		out.endArray();
		out.endObject();
	}
}

LargeDataTypeAdapterTest.java


package com.gpcoder.gson.performance;

import java.io.File;
import java.io.IOException;
import java.io.PrintStream;

import org.apache.commons.lang3.time.StopWatch;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.gpcoder.gson.object.LargeData;

public class LargeDataTypeAdapterTest {

	public static void main(final String[] args) throws IOException {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();

		// Configure GSON
		final GsonBuilder gsonBuilder = new GsonBuilder();
		gsonBuilder.registerTypeAdapter(LargeData.class, new LargeDataTypeAdapter());
		gsonBuilder.setPrettyPrinting();

		final Gson gson = gsonBuilder.create();

		final LargeData data = new LargeData();
		data.create(10485760);

		final String json = gson.toJson(data);

		final File dir = new File("data");
		dir.mkdirs();

		try (PrintStream out = new PrintStream(new File(dir, "outputTypeAdapter.json"), "UTF-8")) {
			out.println(json);
		}

		stopWatch.stop();
		System.out.println("Done in " + stopWatch.getTime());
	}
}

Thực thi chương trình trên, bạn sẽ thấy thời gian thực thi của TypeAdapter chỉ khoảng 3293 ms, nhanh hơn rất nhiều so với 15950 ms của JsonSerializer. Một file outputTypeAdapter.json được tạo ra trong thư mục data có kích thước là 129 MB, bằng với kích thước được tạo ra khi sử dụng JsonSerializer. Bộ nhớ sử dụng khoảng 640 MB.

Kết hợp JsonSerializer và Streams


package com.gpcoder.gson.performance.serializer;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;

import org.apache.commons.lang3.time.StopWatch;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.gpcoder.gson.object.LargeData;

public class LargeDataserializerStreamingTest {

	public static void main(final String[] args) throws IOException {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();

		// Configure GSON
		final GsonBuilder gsonBuilder = new GsonBuilder();
		gsonBuilder.registerTypeAdapter(LargeData.class, new LargeDataserializer());
		gsonBuilder.setPrettyPrinting();

		final Gson gson = gsonBuilder.create();

		final LargeData data = new LargeData();
		data.create(10485760);

		final File dir = new File("data");
		dir.mkdirs();

		try (OutputStream os = new FileOutputStream(new File(dir, "outputserializerStreaming.json"));
				BufferedWriter out = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"))) {
			gson.toJson(data, out);
		}

		stopWatch.stop();
		System.out.println("Done in " + stopWatch.getTime());
	}
}

Thực thi chương trình trên, bạn sẽ thấy thời gian thực thi là 12511 ms, nhanh hơn so với 15950 ms của JsonSerializer không sử dụng Stream. Một file outputTypeAdapterStreaming.json được tạo ra trong thư mục data có cùng kích thước là 129 MB. Bộ nhớ sử dụng khoảng 727 MB.

Kết hợp TypeAdapter và Streams


package com.gpcoder.gson.performance.typeadapter;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;

import org.apache.commons.lang3.time.StopWatch;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.gpcoder.gson.object.LargeData;

public class LargeDataTypeAdapterStreamingTest {

	public static void main(final String[] args) throws IOException {

		StopWatch stopWatch = new StopWatch();
		stopWatch.start();

		// Configure GSON
		final GsonBuilder gsonBuilder = new GsonBuilder();
		gsonBuilder.registerTypeAdapter(LargeData.class, new LargeDataTypeAdapter());
		gsonBuilder.setPrettyPrinting();

		final Gson gson = gsonBuilder.create();

		final LargeData data = new LargeData();
		data.create(10485760);

		final File dir = new File("data");
		dir.mkdirs();

		try (OutputStream os = new FileOutputStream(new File(dir, "outputTypeAdapterStreaming.json"));
				BufferedWriter out = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"))) {
			gson.toJson(data, out);
		}

		stopWatch.stop();
		System.out.println("Done in " + stopWatch.getTime());
	}
}

Thực thi chương trình trên, bạn sẽ thấy thời gian thực thi là 2247 ms, nhanh hơn so với 3293 ms của TypeAdapter không sử dụng Stream. Một file outputTypeAdapterStreaming.json được tạo ra trong thư mục data có cùng kích thước là 129 MB. Bộ nhớ sử dụng khoảng 160 MB.

Tóm lại, TypeAdapter tốt hơn về mặt hiệu suất so với JsonSerializer do bỏ qua lớp đệm. Tuy nhiên, với JsonSerializer và JsonDeserializer cung cấp đệm an toàn rất tiện lợi vì nó làm giảm nguy cơ tạo chuỗi JSON không hợp lệ. Luôn cố gắng kết hợp TypeAdapter với Stream hoặc JsonSerializer với Stream để có được hiệu suất tốt nhất.

Tài liệu tham khảo:

  • http://www.javacreed.com/gson-typeadapter-example/
  • http://www.javacreed.com/gson-typeadapter-example-serialise-large-objects/
5.0
03
Nếu bạn thấy hay thì hãy chia sẻ bài viết cho mọi người nhé! Và Donate tác giả

Shares

Chuyên mục: Json Được gắn thẻ: Gson, json

Gson Custom Serialization và Deserialization
Hướng dẫn sử dụng thư viện Jackson

Có thể bạn muốn xem:

  • Hướng dẫn sử dụng Gson ExclusionStrategy (13/01/2018)
  • Hướng dẫn sử dụng Jackson Json Annotations (28/01/2018)
  • Giới thiệu Json (05/01/2018)
  • Hướng dẫn Jackson Streaming API để đọc và ghi JSON (31/01/2018)
  • Hướng dẫn sử dụng Gson Annotations (12/01/2018)

Bình luận

bình luận

Tìm kiếm

Bài viết mới

  • Clean code 13/01/2024
  • Giới thiệu CloudAMQP – Một RabbitMQ server trên Cloud 02/10/2020
  • Kết nối RabbitMQ sử dụng Web STOMP Plugin 19/06/2020
  • Sử dụng publisher confirm trong RabbitMQ 16/06/2020
  • Sử dụng Dead Letter Exchange trong RabbitMQ 13/06/2020

Xem nhiều

  • Hướng dẫn Java Design Pattern – Factory Method (98059 lượt xem)
  • Hướng dẫn Java Design Pattern – Singleton (97700 lượt xem)
  • Giới thiệu Design Patterns (87764 lượt xem)
  • Lập trình đa luồng trong Java (Java Multi-threading) (86434 lượt xem)
  • Giới thiệu về Stream API trong Java 8 (83839 lượt xem)

Nội dung bài viết

  • 1 Giới thiệu
  • 2 Ví dụ sử dụng TypeAdapter
  • 3 So sánh hiệu suất của TypeAdapter với JsonSerializer

Lưu trữ

Thẻ đánh dấu

Annotation Authentication Basic Java Behavior Pattern Collection Creational Design Pattern Cấu trúc điều khiển Database Dependency Injection Design pattern Eclipse Exception Executor Service Google Guice Gson Hibernate How to Interceptor IO Jackson Java 8 Java Core JDBC JDK Jersey JMS JPA json JUnit JWT Message Queue Mockito Multithreading OOP PowerMockito RabbitMQ Reflection Report REST SOAP Structuaral Pattern Swagger Thread Pool Unit Test Webservice

Liên kết

  • Clean Code
  • JavaTpoint
  • Refactoring Guru
  • Source Making
  • TutorialsPoint
  • W3Schools Online Web Tutorials

Giới thiệu

GP Coder là trang web cá nhân, được thành lập với mục đích lưu trữ, chia sẽ kiến thức đã học và làm việc của tôi. Các bài viết trên trang này chủ yếu về ngôn ngữ Java và các công nghệ có liên quan đến Java như: Spring, JSF, Web Services, Unit Test, Hibernate, SQL, ...
Hi vọng góp được chút ít công sức cho sự phát triển cộng đồng Coder Việt.

Donate tác giả

Tìm kiếm các bài viết của GP Coder với Google Search

Liên hệ

Các bạn có thể liên hệ với tôi thông qua:
  • Trang liên hệ
  • Linkedin: gpcoder
  • Email: contact@gpcoder.com
  • Skype: ptgiang56it

Follow me

Copyright 2025 © GP Coder · All Rights Reserved · Giới thiệu · Chính sách · Điều khoản · Liên hệ ·

Share

Blogger
Delicious
Digg
Email
Facebook
Facebook messenger
Flipboard
Google
Hacker News
Line
LinkedIn
Mastodon
Mix
Odnoklassniki
PDF
Pinterest
Pocket
Print
Reddit
Renren
Short link
SMS
Skype
Telegram
Tumblr
Twitter
VKontakte
wechat
Weibo
WhatsApp
X
Xing
Yahoo! Mail

Copy short link

Copy link