首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >使用TypeAdapter对对象中的一个(多个)变量进行自定义序列化

使用TypeAdapter对对象中的一个(多个)变量进行自定义序列化
EN

Stack Overflow用户
提问于 2012-06-30 12:22:12
回答 1查看 28.8K关注 0票数 96

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

我想定制对象中单个字段的序列化,让默认的Gson机制来处理剩下的事情。

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

代码语言:javascript
复制
public class MyClass extends SomeClass {

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

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-06-30 15:50:51

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

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

代码语言:javascript
复制
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表示),然后调用钩子方法beforeWrite()以允许子类定制该树。使用afterRead()进行反序列化时也是如此。

接下来,我们为特定的MyClass示例继承这个子类。为了说明这一点,我将在序列化地图时添加一个名为'size‘的合成属性。为了对称,我将在反序列化时将其删除。实际上,这可以是任何定制。

代码语言:javascript
复制
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实例来将其整合在一起:

代码语言:javascript
复制
Gson gson = new GsonBuilder()
    .registerTypeAdapterFactory(new MyClassTypeAdapterFactory())
    .create();

Gson的新TypeAdapterTypeAdapterFactory类型非常强大,但它们也是抽象的,需要实践才能有效地使用。希望你能发现这个例子很有用!

票数 133
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11271375

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档