Đây là một câu hỏi tuyệt vời bởi vì nó cô lập một cái gì đó đáng ra dễ dàng nhưng thực tế lại đòi hỏi rất nhiều mã.
Để bắt đầu, hãy viết một bản tóm tắt TypeAdapterFactory
cung cấp cho bạn các móc để sửa đổi dữ liệu gửi đi. Ví dụ này sử dụng một API mới trong Gson 2.2 được gọi là getDelegateAdapter()
cho phép bạn tra cứu bộ điều hợp mà Gson sẽ sử dụng theo mặc định. Bộ điều hợp đại biểu cực kỳ tiện dụng nếu bạn chỉ muốn điều chỉnh hành vi tiêu chuẩn. Và không giống như các bộ điều hợp loại tùy chỉnh đầy đủ, chúng sẽ tự động cập nhật khi bạn thêm và xóa các trường.
public abstract class CustomizedTypeAdapterFactory<C>
implements TypeAdapterFactory {
private final Class<C> customizedClass;
public CustomizedTypeAdapterFactory(Class<C> customizedClass) {
this.customizedClass = customizedClass;
}
@SuppressWarnings("unchecked") // we use a runtime check to guarantee that 'C' and 'T' are equal
public final <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
return type.getRawType() == customizedClass
? (TypeAdapter<T>) customizeMyClassAdapter(gson, (TypeToken<C>) type)
: null;
}
private TypeAdapter<C> customizeMyClassAdapter(Gson gson, TypeToken<C> type) {
final TypeAdapter<C> delegate = gson.getDelegateAdapter(this, type);
final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);
return new TypeAdapter<C>() {
@Override public void write(JsonWriter out, C value) throws IOException {
JsonElement tree = delegate.toJsonTree(value);
beforeWrite(value, tree);
elementAdapter.write(out, tree);
}
@Override public C read(JsonReader in) throws IOException {
JsonElement tree = elementAdapter.read(in);
afterRead(tree);
return delegate.fromJsonTree(tree);
}
};
}
/**
* Override this to muck with {@code toSerialize} before it is written to
* the outgoing JSON stream.
*/
protected void beforeWrite(C source, JsonElement toSerialize) {
}
/**
* Override this to muck with {@code deserialized} before it parsed into
* the application type.
*/
protected void afterRead(JsonElement deserialized) {
}
}
Lớp trên sử dụng tuần tự hóa mặc định để lấy một cây JSON (được đại diện bởi JsonElement
), và sau đó gọi phương thức hook beforeWrite()
để cho phép lớp con tùy chỉnh cây đó. Tương tự đối với deserialization với afterRead()
.
Tiếp theo, chúng tôi phân lớp này cho MyClass
ví dụ cụ thể . Để minh họa, tôi sẽ thêm một thuộc tính tổng hợp được gọi là 'kích thước' vào bản đồ khi nó được tuần tự hóa. Và để đối xứng, tôi sẽ loại bỏ nó khi nó được khử trên không. Trong thực tế, đây có thể là bất kỳ tùy chỉnh nào.
private class MyClassTypeAdapterFactory extends CustomizedTypeAdapterFactory<MyClass> {
private MyClassTypeAdapterFactory() {
super(MyClass.class);
}
@Override protected void beforeWrite(MyClass source, JsonElement toSerialize) {
JsonObject custom = toSerialize.getAsJsonObject().get("custom").getAsJsonObject();
custom.add("size", new JsonPrimitive(custom.entrySet().size()));
}
@Override protected void afterRead(JsonElement deserialized) {
JsonObject custom = deserialized.getAsJsonObject().get("custom").getAsJsonObject();
custom.remove("size");
}
}
Cuối cùng, kết hợp tất cả lại với nhau bằng cách tạo một phiên bản tùy chỉnh Gson
sử dụng bộ điều hợp loại mới:
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new MyClassTypeAdapterFactory())
.create();
Mới Gson của TypeAdapter và TypeAdapterFactory loại là cực kỳ mạnh mẽ, nhưng chúng cũng trừu tượng và chịu thực hành để sử dụng một cách hiệu quả. Hy vọng rằng bạn thấy ví dụ này hữu ích!