简体   繁体   English

Gson 反序列化使用自定义方法扩展特定类的嵌套对象

[英]Gson deserialize nested object that extend specific class using custom method

I have a abstract class as given below我有一个抽象类,如下所示

public abstract class IndexedPojo {
    List<String> keySet;

    public List<String> getKeySet() {
        return keySet;
    }

    public void setKeySet(List<String> keySet) {
        this.keySet = keySet;
    }
    public void setKeySet(JsonObject parameters) {
        this.keySet = new ArrayList<>(parameters.keySet());
    }
    public void setKeySet(Map<String,String> parameters) {
        this.keySet = new ArrayList<>(parameters.keySet());
    }
}

The purpose of this abstract class is to provide functionality of keeping track of variables that has been initialized in the classes that extend this.这个抽象类的目的是提供跟踪已在扩展它的类中初始化的变量的功能。 Why I need this?为什么我需要这个? I am modelling pojo class for forms to be used in Test automation project.我正在为要在测试自动化项目中使用的表单建模 pojo 类。 Where some parameters are optional and if they have not been initialized corresponding form elements are not filled.其中一些参数是可选的,如果它们尚未初始化,则不会填充相应的表单元素。 Currently I am using this method to create instance of the classes that extend IndexedPojo class:目前我正在使用这种方法来创建扩展IndexedPojo类的类的实例:

public static <T extends IndexedPojo> T deserializeJsonTo(JsonObject parameters, Class<T> tClass) {
    Gson gson = new Gson();
    T instance = gson.fromJson(parameters, tClass);
    instance.setKeySet(parameters);
    return instance;
}

But now the problem is some of the nested children are also classes that extend IndexedPojo and I want to initialize them in the same way.但是现在问题是一些嵌套的子级也是extend IndexedPojo类,我想以相同的方式初始化它们。 For example例如

public class RuleSetConfigForm extends IndexedPojo {
    @SerializedName("Key")
    SomeNestedConfig nestedConfig;    
}
public class SomeNestedConfig extends IndexedPojo {
    @SerializedName("Some Key")
    private String someOptionalParamater1 = "";

    @SerializedName("Some Key2")
    private String someOptionalParamater2 = "";

    @SerializedName("Some Key3")
    private String someOptionalParamater3 = "";
}

How can I initialize the nested SomeNestedConfig nestedConfig as I initialized the RuleSetConfigForm ?我如何在初始化SomeNestedConfig nestedConfig初始化嵌套的SomeNestedConfig nestedConfig RuleSetConfigForm Is there any automated way of doing this?有没有自动执行此操作的方法?

This can be solved using a custom TypeAdapterFactory which delegates to the default adapter and afterwards calls your IndexedPojo.setKeySet(...) method:这可以通过使用委托给默认适配器的自定义TypeAdapterFactory来解决,然后调用您的IndexedPojo.setKeySet(...)方法:

class IndexedPojoTypeAdapterFactory implements TypeAdapterFactory {
  public static final IndexedPojoTypeAdapterFactory INSTANCE = new IndexedPojoTypeAdapterFactory();

  private IndexedPojoTypeAdapterFactory() { }

  public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
    // Only handle IndexedPojo and subclasses
    if (!IndexedPojo.class.isAssignableFrom(type.getRawType())) {
      return null;
    }

    // Get the default adapter as delegate
    // Cast is safe due to `type` check at method start
    @SuppressWarnings("unchecked")
    TypeAdapter<IndexedPojo> delegate = (TypeAdapter<IndexedPojo>) gson.getDelegateAdapter(this, type);
    // Cast is safe because `T` is IndexedPojo or subclass (due to `type` check at method start)
    @SuppressWarnings("unchecked")
    TypeAdapter<T> adapter = (TypeAdapter<T>) new TypeAdapter<IndexedPojo>() {
      @Override
      public void write(JsonWriter out, IndexedPojo value) throws IOException {
        delegate.write(out, value);
      }

      @Override
      public IndexedPojo read(JsonReader in) throws IOException {
        // Read JsonObject from JsonReader to be able to pass it to `IndexedPojo.setKeySet(...)`
        // afterwards
        // Note: JsonParser automatically parses in lenient mode, which cannot be disabled
        // Note: Might have to add handling for JSON null values
        JsonObject jsonObject = JsonParser.parseReader(in).getAsJsonObject();
        
        IndexedPojo value = delegate.fromJsonTree(jsonObject);
        value.setKeySet(jsonObject);
        return value;
      }
    };

    return adapter;
  }
}

And then use this factory in your deserializeJsonTo(...) method:然后在您的deserializeJsonTo(...)方法中使用这个工厂:

public static <T extends IndexedPojo> T deserializeJsonTo(JsonObject parameters, Class<T> tClass) {
  // Note: Could also store Gson instance in `static final` field
  Gson gson = new GsonBuilder()
    .registerTypeAdapterFactory(IndexedPojoTypeAdapterFactory.INSTANCE)
    .create();
  return gson.fromJson(parameters, tClass);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM