如何让单个 GSON 自定义序列化程序应用于所有子类?



我正在使用 GSON 将通用序列化程序应用于抽象Base类的所有子类。但是,当给定Base类的实际子类时,GSON 不会调用我的序列化程序,除非明确告知使用Base.class作为强制转换。这是我所说的一个简单的例子。

public interface Base<T>{
String getName();
public List<Object> getChildren();
}
public class Derived1 implements Base<Integer>{
private Integer x = 5; 
String getName(){ 
return "Name: " + x;
}
List<Object> getChildren(){
return Lists.newArrayList(new Derived2(), "Some string");
}
}
public class Derived2 implements Base<Double>{
private Double x = 6.3;
String getName(){
return "Name: " + x;
}
List<Object> getChildren(){
return new List<>();
}
}

我正在创建一个序列化程序,如下所示:

JsonSerializer customAdapter = new JsonSerializer<Base>(){
@Override
JsonElement serialize(Base base, Type sourceType, JsonSerializationContext context){
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("name", base.getName());
JsonArray jsonArray = new JsonArray();
for (Object child : base.getChildren()){
jsonArray.add(context.serialize(child));
}
if (jsonArray.size() != 0){
jsonObject.add("children", jsonArray);
}
}
};
Gson customSerializer = new GsonBuilder()
.registerTypeAdapter(Base.class, customAdapter)
.create();

但是,将自定义序列化程序应用于子类List不会产生预期的效果。

customSerializer.toJson(Lists.newArrayList(new Derived1(), new Derived2()));

这会将默认的 GSON 序列化应用于我的子类。有没有简单的方法可以让我的自定义序列化程序在父类的所有子类上使用我的自定义适配器?我怀疑一种解决方案是使用反射来迭代Base的所有子类并注册自定义适配器,但如果可能的话,我想避免类似的事情。

注意:我现在不关心反序列化。

也许你不应该使用JsonSerializer.也就是说,如果您使用TypeAdapter通过注册告诉Gson如何序列化任何类的TypeAdapterFactory来执行相同的魔术,这是可能的。

请参阅下面的TypeAdapterFactoryTypeAdapter

public class CustomAdapterFactory implements TypeAdapterFactory {
@SuppressWarnings("unchecked")
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
// If the class that type token represents is a subclass of Base
// then return your special adapter 
if(Base.class.isAssignableFrom(typeToken.getRawType())) {
return (TypeAdapter<T>) customTypeAdapter;          
}
return null;
}
private TypeAdapter<Base<?>> customTypeAdapter = new TypeAdapter<Base<?>>() {
@Override
public void write(JsonWriter out, Base<?> value) throws IOException {
out.beginObject();
out.value(value.getName());
out.endObject();            
}
@Override
public Base<?> read(JsonReader in) throws IOException {
// Deserializing to subclasses not interesting yet.
// Actually it is impossible if the JSON does not contain 
// information about the subclass to which to deserialize
return null;
}
};
}

如果你做这样的事情:

@Slf4j
public class SubClassTest {
@Test
public void testIt() {
Gson gson = new GsonBuilder()
.setPrettyPrinting()
.registerTypeAdapterFactory(new CustomAdapterFactory())
.create();
log.info("n{}", gson.toJson(new Derived1()));
log.info("n{}", gson.toJson(new Derived2()));
}
}

输出将如下所示:

2018-10-12 23:13:17.037 信息 org.example.gson.subclass.SubClassTest:19 - { "name": "name: 5" } 2018-10-12 23:13:17.043 信息 org.example.gson.subclass.SubClassTest:20 - { "name": "Name: 6.3" }

如果它不完全是您想要的,只需修复write(..)方法即可customTypeAdapter.

最新更新