gpt4 book ai didi

java - 使用 TypeAdapter 的对象中一个(多个)变量的 Gson 自定义序列化程序

转载 作者:IT老高 更新时间:2023-10-28 11:34:06 44 4
gpt4 key购买 nike

我见过很多使用自定义 TypeAdapter 的简单示例。最有帮助的是 Class TypeAdapter<T> .但这还没有回答我的问题。

我想自定义对象中单个字段的序列化,并让默认的 Gson 机制处理其余部分。

出于讨论的目的,我们可以使用这个类定义作为我希望序列化的对象的类。我想让 Gson 序列化前两个类成员以及基类的所有公开成员,并且我想对下面显示的第三个和最后一个类成员进行自定义序列化。

public class MyClass extends SomeClass {

@Expose private HashMap<String, MyObject1> lists;
@Expose private HashMap<String, MyObject2> sources;
private LinkedHashMap<String, SomeClass> customSerializeThis;
[snip]
}

最佳答案

这是一个很好的问题,因为它隔离了一些应该很容易但实际上需要大量代码的东西。

首先,编写一个抽象的TypeAdapterFactory,它为您提供了修改输出数据的钩子(Hook)。此示例使用 Gson 2.2 中名为 getDelegateAdapter() 的新 API,它允许您查找 Gson 默认使用的适配器。如果您只想调整标准行为,委托(delegate)适配器非常方便。与完整的自定义类型适配器不同,它们会在您添加和删除字段时自动保持最新状态。

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) {
}
}

上面的类使用默认的序列化得到一个JSON树(用JsonElement表示),然后调用钩子(Hook)方法beforeWrite()让子类自定义那棵树。与 afterRead() 进行反序列化类似。

接下来,我们为特定的 MyClass 示例对其进行子类化。为了说明,我将在序列化时向 map 添加一个名为“大小”的合成属性。为了对称,我会在反序列化时将其删除。实际上,这可以是任何自定义。

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");
}
}

最后通过创建一个使用新类型适配器的自定义 Gson 实例将它们组合在一起:

Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new MyClassTypeAdapterFactory())
.create();

Gson 的新 TypeAdapterTypeAdapterFactory类型非常强大,但它们也是抽象的,需要练习才能有效地使用。希望这个示例对您有用!

关于java - 使用 TypeAdapter 的对象中一个(多个)变量的 Gson 自定义序列化程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11271375/

44 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com