如何使用一个 gson 反序列化器反序列化具有泛型的不同子类型
How to deserialize different subtypes with generics with one gson deserializer
我必须为不同的测试用例保存配置对象。我决定为此使用 GSON,因为我已经使用过它。问题是配置文件的 structure/inheritance 在其定义中包含泛型。如果这是重复的,我已经阅读了该线程,但无法将其应用于我的问题。代码分解到最少。
配置class
除了其他易于序列化的组件外,它还有一个 ArrayList<T>
。
//There are classes that inherit from that too
public class Configuration<T extends ParamSet> implements Iterable<T>{
// this list is what i want to set from my ApplicationClass
private ArrayList<T> _paramSets = new ArrayList<T>();
//getter, setter and constructor
}
ParameterSet 定义
这些 class 没有什么特别之处。只是整数和布尔值。
public class ParamSet {}
public class ChildParamSet extends ParamSet{}
摘要申请class
这是保存过程开始的地方。我定义了一个抽象方法,后来在 classes 中实现,其中 T
在 运行 时已知。
public abstract class ApplicationClass<T extends ParamSet>{
private Configuration<T> config;
// in this method i want to set either a new config or new params in the config
public setupConfig(){
//some checks and if the user wants to load a config from file
loadConfig(file);
}
//abstract method to be called in more concrete classes
abstract protected Configuration<T> loadConfig(File file);
}
具体应用class
我知道 T
的类型,我想调用 getConfiguration
方法。
public abstract class MoreConcreteApplicationClass extends ApplicationClass<ChildParamSet>{
//constructor and other stuff
@Override
protected Configuration<ChildParamSet> loadConfig(File file){
return ConfigurationPersistenceHelper.getConfiguration(file);
}
}
Configuration Persistence Helper -- 问题
public class ConfigurationPersistenceHelper(){
//i get the configuration with a linked treeMap --> wrong type
public static <T extends ParamSet> Configuration<T> getConfiguration(final File location){
GsonBuilder builder = new GsonBuilder();
GsonBuilder builder.enableComplexMapKeySerialization.create();
final Type type = new TypeToken<Configuration<T>>(){}.getType();
final String jsonRepresentation = new String(Files.readAllBytes(location.toPath()));
return gson.fromJson(jsonRepresentation, type);
}
}
所以问题是 ConfigurationPersistenceHelper 中的 getConfiguration
方法。当我 运行 这个方法时,我在配置中得到 Linked TreeMap
而不是 ArrayList<ChildParamSet>
。
我猜这是因为在 运行 期间对泛型进行了类型擦除以及我使用 T extends ParamSet
.
定义了方法
但是我该如何解决这个问题呢?是否有另一种方法来调用该方法,这样类型就不会丢失?
我知道的解决方法
我知道我可以在每个具体应用程序 class 的 loadConfig
方法中实现反序列化器逻辑。但这会导致很多重复代码。这是我目前的解决方案。
我还知道我可以将类型从 loadConfig
(该类型在 运行 时间仍然可用)传递给序列化器到 getConfiguration
方法。那是不好的做法吗?
我也知道我可以编写自己的反序列化器,但我还需要 运行 时的类型,这是我目前的问题。
是的,类型擦除就是问题所在。只需像这样传递类型信息:
abstract protected Configuration<T> loadConfig(File file, Class<T> clazz);
在该方法中为您的 ArrayList 使用自定义 ParameterizedType,请参阅:
- Java Type Generic as Argument for GSON
- Deserialise a generic list in Gson
我必须为不同的测试用例保存配置对象。我决定为此使用 GSON,因为我已经使用过它。问题是配置文件的 structure/inheritance 在其定义中包含泛型。如果这是重复的,我已经阅读了该线程,但无法将其应用于我的问题。代码分解到最少。
配置class
除了其他易于序列化的组件外,它还有一个 ArrayList<T>
。
//There are classes that inherit from that too
public class Configuration<T extends ParamSet> implements Iterable<T>{
// this list is what i want to set from my ApplicationClass
private ArrayList<T> _paramSets = new ArrayList<T>();
//getter, setter and constructor
}
ParameterSet 定义
这些 class 没有什么特别之处。只是整数和布尔值。
public class ParamSet {}
public class ChildParamSet extends ParamSet{}
摘要申请class
这是保存过程开始的地方。我定义了一个抽象方法,后来在 classes 中实现,其中 T
在 运行 时已知。
public abstract class ApplicationClass<T extends ParamSet>{
private Configuration<T> config;
// in this method i want to set either a new config or new params in the config
public setupConfig(){
//some checks and if the user wants to load a config from file
loadConfig(file);
}
//abstract method to be called in more concrete classes
abstract protected Configuration<T> loadConfig(File file);
}
具体应用class
我知道 T
的类型,我想调用 getConfiguration
方法。
public abstract class MoreConcreteApplicationClass extends ApplicationClass<ChildParamSet>{
//constructor and other stuff
@Override
protected Configuration<ChildParamSet> loadConfig(File file){
return ConfigurationPersistenceHelper.getConfiguration(file);
}
}
Configuration Persistence Helper -- 问题
public class ConfigurationPersistenceHelper(){
//i get the configuration with a linked treeMap --> wrong type
public static <T extends ParamSet> Configuration<T> getConfiguration(final File location){
GsonBuilder builder = new GsonBuilder();
GsonBuilder builder.enableComplexMapKeySerialization.create();
final Type type = new TypeToken<Configuration<T>>(){}.getType();
final String jsonRepresentation = new String(Files.readAllBytes(location.toPath()));
return gson.fromJson(jsonRepresentation, type);
}
}
所以问题是 ConfigurationPersistenceHelper 中的 getConfiguration
方法。当我 运行 这个方法时,我在配置中得到 Linked TreeMap
而不是 ArrayList<ChildParamSet>
。
我猜这是因为在 运行 期间对泛型进行了类型擦除以及我使用 T extends ParamSet
.
但是我该如何解决这个问题呢?是否有另一种方法来调用该方法,这样类型就不会丢失?
我知道的解决方法
我知道我可以在每个具体应用程序 class 的 loadConfig
方法中实现反序列化器逻辑。但这会导致很多重复代码。这是我目前的解决方案。
我还知道我可以将类型从 loadConfig
(该类型在 运行 时间仍然可用)传递给序列化器到 getConfiguration
方法。那是不好的做法吗?
我也知道我可以编写自己的反序列化器,但我还需要 运行 时的类型,这是我目前的问题。
是的,类型擦除就是问题所在。只需像这样传递类型信息:
abstract protected Configuration<T> loadConfig(File file, Class<T> clazz);
在该方法中为您的 ArrayList 使用自定义 ParameterizedType,请参阅:
- Java Type Generic as Argument for GSON
- Deserialise a generic list in Gson