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实现了JsonSerializer
和JsonDeserializer
,那么您可以使用很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。