Gson自定义Seralizer的一个variables(很多)在一个对象使用TypeAdapter

我见过很多使用自定义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 ,它给你钩子来修改输出数据。 这个例子在Gson 2.2中使用了一个名为getDelegateAdapter()的新API,允许你查找Gson默认使用的适配器。 代理适配器是非常方便的,如果你只是想调整标准的行为。 与完整的自定义types适配器不同,它们将在您添加和删除字段时自动保持最新状态。

 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()反序列化。

接下来,我们inheritance这个特定的MyClass示例。 为了说明,我将在序列化时向地图添加一个名为“size”的合成属性。 而对于对称性,我将在反序列化时将其删除。 实际上这可以是任何定制。

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

最后,通过创build一个使用新types适配器的定制Gson实例,将它们放在一起:

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

Gson的新型TypeAdapter和TypeAdapterFactorytypesfunction非常强大,但它们也是抽象的,可以有效地使用。 希望你find这个例子有用!

还有另一种方法。 正如杰西·威尔逊(Jesse Wilson)所说,这应该是容易的。 猜猜看,这容易!

如果您为您的types实现了JsonSerializerJsonDeserializer ,那么您可以使用很less的代码来处理您想要的部分,并将其委托给Gson 。 为了方便起见,我在@ Perception的另一个问题上回答了这个问题 ,请参阅以下答案以获取更多详细信息:

在这种情况下,最好使用JsonSerializer而不是TypeAdapter ,原因很简单,序列化程序可以访问序列化上下文。

 public class PairSerializer implements JsonSerializer<Pair> { @Override public JsonElement serialize(final Pair value, final Type type, final JsonSerializationContext context) { final JsonObject jsonObj = new JsonObject(); jsonObj.add("first", context.serialize(value.getFirst())); jsonObj.add("second", context.serialize(value.getSecond())); return jsonObj; } } 

这样做的主要优点(除了避免复杂的变通方法之外)是,您仍然可以使用其他types的适配器和可能已经在主要上下文中注册的自定义序列化器。 请注意,序列化器和适配器的注册使用完全相同的代码。

不过,我会承认,如果您经常要修改Java对象中的字段,那么Jesse的方法看起来会更好。 这是一个易于使用和灵活性的权衡,请select。