GsonBuilder - 从接口获取对象

发布于 2025-01-15 14:27:11 字数 1629 浏览 6 评论 0原文

我有一个像这样声明的 GsonFactory :

public class GsonFactory {
    public Gson create() {
        return new GsonBuilder()
                .setPrettyPrinting()
                .registerTypeAdapter(MyInterface.class, new MyInstanceCreator())
                .create();
    }

    private static final GsonFactory instance = new GsonFactory();

    private GsonFactory() {
    }

    public static Gson getInstance(){
        return instance.create();
    }
}

我还有 InstanceCreator 类:

public class MyInstanceCreator implements InstanceCreator<MyInterface> {
    @Override
    public StrategySymbol createInstance(Type type) {
        return new MyInterfaceImpl();
    }
}

class MyClass {
  private List<MyInterface> myList;

  public List<MyInterface> getMyList() { return myList; }

  public void setMyList(List<MyInterface> myList) { this.myList = myList; }
}

interface MyInterface {
  Long getValue1();
  void setValue1(Long value1);
}

class MyInterfaceImpl implements MyInterface {
  private Long value1;

  @Override
  public Long getValue1() {
     return value1;
  }

  @Override
  public void setValue1(Long value1) {
     this.value1 = value1
  }
}

这段代码似乎实现得很好,但是如果我尝试解析 JSON with value1

MyClass obj = GsonFactory.getInstance().fromJson("{'myList': [{'value1':8}]}", MyClass.class);

返回的对象带有 MyInterfaceImpl 的实例,但字段 value1 始终为 null。正如我所看到的,似乎 Gsoninterface 中查找字段(无),而不是在实现 class 中查找字段接口。

有谁知道如何解决这个问题?

I have a GsonFactory declared like this:

public class GsonFactory {
    public Gson create() {
        return new GsonBuilder()
                .setPrettyPrinting()
                .registerTypeAdapter(MyInterface.class, new MyInstanceCreator())
                .create();
    }

    private static final GsonFactory instance = new GsonFactory();

    private GsonFactory() {
    }

    public static Gson getInstance(){
        return instance.create();
    }
}

I also have the InstanceCreator class:

public class MyInstanceCreator implements InstanceCreator<MyInterface> {
    @Override
    public StrategySymbol createInstance(Type type) {
        return new MyInterfaceImpl();
    }
}

class MyClass {
  private List<MyInterface> myList;

  public List<MyInterface> getMyList() { return myList; }

  public void setMyList(List<MyInterface> myList) { this.myList = myList; }
}

interface MyInterface {
  Long getValue1();
  void setValue1(Long value1);
}

class MyInterfaceImpl implements MyInterface {
  private Long value1;

  @Override
  public Long getValue1() {
     return value1;
  }

  @Override
  public void setValue1(Long value1) {
     this.value1 = value1
  }
}

This code seems well implemented, but if I try to parse a JSON with value1:

MyClass obj = GsonFactory.getInstance().fromJson("{'myList': [{'value1':8}]}", MyClass.class);

The Object is returned with an instance of MyInterfaceImpl, but the field value1 is always null. As I could see, it seems like Gson looks for the fields in the interface (none) and not in the class implementing the interface.

Does anyone know how to solve this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

粉红×色少女 2025-01-22 14:27:11

InstanceCreator 可以仅创建未定义无参数构造函数的类的实例。它不处理反序列化。 Gson 仍然无法弄清楚对象的具体数据类型。

解决方案。接口的自定义解串器

您需要为您的接口定义一个自定义反序列化器,并在工厂中注册这个新型适配器。

public class MyInterfaceDeserializer implements JsonDeserializer<MyInterface> {
    @Override
    public MyInterface deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
        return jsonDeserializationContext.deserialize(jsonElement, MyInterfaceImpl.class);
    }
}

public class GsonFactory {
    public Gson create() {
        return new GsonBuilder()
                .setPrettyPrinting()
                .registerTypeAdapter(MyInterface.class, new MyInterfaceDeserializer())
                .create();
    }
}

或通用解串器

public class InterfaceDeserializer<T, E> implements JsonDeserializer<T> {
    private final Class<E> implementationClass;

    public InterfaceDeserializer(Class<E> implementationClass) {
        this.implementationClass = implementationClass;
    }

    @Override
    public T deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
        return jsonDeserializationContext.deserialize(jsonElement, implementationClass);
    }
}

public class GsonFactory {
    public Gson create() {     
        return new GsonBuilder()
                .setPrettyPrinting()                
               .registerTypeAdapter(MyInterface.class, new InterfaceDeserializer<MyInterface, MyInterfaceImpl>(MyInterfaceImpl.class))
                .create();
}

public class MyInterfaceDeserializer implements JsonDeserializer<MyInterface> {
    @Override
    public MyInterface deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
        MyInterface myInterface = new MyInterfaceImpl();
        JsonObject jObject = jsonElement.getAsJsonObject();
        myInterface.setValue1(jObject.get("value1").getAsLong());
        return myInterface;
    }
}

public class GsonFactory {
    public Gson create() {
        return new GsonBuilder()
                .setPrettyPrinting()
                .registerTypeAdapter(MyInterface.class, new MyInterfaceDeserializer())
                .create();
    }
}

另一个选项
使用 RuntimeTypeAdapterFactory 但此解决方案需要 json 中的额外 type 属性来定义确切的子类型,请参阅文档。

示例:

    public Gson create() {
        RuntimeTypeAdapterFactory<MyInterface> runtimeTypeAdapterFactory = RuntimeTypeAdapterFactory.of(MyInterface.class).registerSubtype(MyInterfaceImpl.class, "MyInterfaceImpl");
        return new GsonBuilder()
                .setPrettyPrinting()
                .registerTypeAdapterFactory(runtimeTypeAdapterFactory)
                .create();
    }

JSON 必须包含类型字段:

{
  myList: [
    {
      value1: 8,
      type: MyInterfaceImpl
    }
  ]
}

请注意 gson-extras 库。此工件位于 CronApp 存储库。

InstanceCreator can only create instances of a class that does not define a no-args constructor. It does not handle deserialization. Gson still won't be able to figure out the concrete data type of the object.

Solution. Custom deserializer for interface

You need to define a custom deserializer for your interface and register this new type adapter in factory.

public class MyInterfaceDeserializer implements JsonDeserializer<MyInterface> {
    @Override
    public MyInterface deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
        return jsonDeserializationContext.deserialize(jsonElement, MyInterfaceImpl.class);
    }
}

public class GsonFactory {
    public Gson create() {
        return new GsonBuilder()
                .setPrettyPrinting()
                .registerTypeAdapter(MyInterface.class, new MyInterfaceDeserializer())
                .create();
    }
}

OR Generic deserializer

public class InterfaceDeserializer<T, E> implements JsonDeserializer<T> {
    private final Class<E> implementationClass;

    public InterfaceDeserializer(Class<E> implementationClass) {
        this.implementationClass = implementationClass;
    }

    @Override
    public T deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
        return jsonDeserializationContext.deserialize(jsonElement, implementationClass);
    }
}

public class GsonFactory {
    public Gson create() {     
        return new GsonBuilder()
                .setPrettyPrinting()                
               .registerTypeAdapter(MyInterface.class, new InterfaceDeserializer<MyInterface, MyInterfaceImpl>(MyInterfaceImpl.class))
                .create();
}

OR

public class MyInterfaceDeserializer implements JsonDeserializer<MyInterface> {
    @Override
    public MyInterface deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
        MyInterface myInterface = new MyInterfaceImpl();
        JsonObject jObject = jsonElement.getAsJsonObject();
        myInterface.setValue1(jObject.get("value1").getAsLong());
        return myInterface;
    }
}

public class GsonFactory {
    public Gson create() {
        return new GsonBuilder()
                .setPrettyPrinting()
                .registerTypeAdapter(MyInterface.class, new MyInterfaceDeserializer())
                .create();
    }
}

Another option
Use RuntimeTypeAdapterFactory but this solution requires an extra type property in json to define the exact subtype, see the documentation.

Example:

    public Gson create() {
        RuntimeTypeAdapterFactory<MyInterface> runtimeTypeAdapterFactory = RuntimeTypeAdapterFactory.of(MyInterface.class).registerSubtype(MyInterfaceImpl.class, "MyInterfaceImpl");
        return new GsonBuilder()
                .setPrettyPrinting()
                .registerTypeAdapterFactory(runtimeTypeAdapterFactory)
                .create();
    }

JSON must contain type field:

{
  myList: [
    {
      value1: 8,
      type: MyInterfaceImpl
    }
  ]
}

Please note gson-extras library required for that option. This artifact is located at CronApp repository.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文