Gson 使用自定义方法反序列化扩展特定 class 的嵌套对象
Gson deserialize nested object that extend specific class using custom method
我有一个摘要 class 如下所示
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());
}
}
此摘要 class 的目的是提供跟踪在扩展此摘要的 classes 中初始化的变量的功能。为什么我需要这个?我正在为要在测试自动化项目中使用的表单建模 pojo class。其中一些参数是可选的,如果它们尚未初始化,则不会填充相应的表单元素。目前我正在使用此方法创建扩展 IndexedPojo
class:
的 classes 的实例
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;
}
但现在的问题是一些嵌套子项也是 class 是 extend IndexedPojo
,我想以相同的方式初始化它们。例如
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 = "";
}
如何在初始化 RuleSetConfigForm
时初始化嵌套 SomeNestedConfig nestedConfig
?有没有自动执行此操作的方法?
这可以使用自定义 TypeAdapterFactory
来解决,该自定义 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;
}
}
然后在您的 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);
}
我有一个摘要 class 如下所示
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());
}
}
此摘要 class 的目的是提供跟踪在扩展此摘要的 classes 中初始化的变量的功能。为什么我需要这个?我正在为要在测试自动化项目中使用的表单建模 pojo class。其中一些参数是可选的,如果它们尚未初始化,则不会填充相应的表单元素。目前我正在使用此方法创建扩展 IndexedPojo
class:
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;
}
但现在的问题是一些嵌套子项也是 class 是 extend IndexedPojo
,我想以相同的方式初始化它们。例如
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 = "";
}
如何在初始化 RuleSetConfigForm
时初始化嵌套 SomeNestedConfig nestedConfig
?有没有自动执行此操作的方法?
这可以使用自定义 TypeAdapterFactory
来解决,该自定义 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;
}
}
然后在您的 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);
}