如何将单个GSON定制序列化器应用于所有子类?

时间:2018-10-12 07:21:56

标签: java json serialization 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的所有子类进行迭代并注册自定义适配器,但是如果可能的话,我想避免类似的事情。

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

1 个答案:

答案 0 :(得分:2)

也许您不应该使用JsonSerializer。也就是说,如果您使用TypeAdapter通过注册TypeAdapterFactory来告诉Gson如何序列化任何类来做同样的事情,这是可能的。

请参见下面的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方法。