I have to save configuration objects for different testcases. I decided to use GSON for that, since i have worked with that already. The problem is the structure/inheritance of the configuration file contains generics in its definition. If this is a duplicate, i have read the thread, but couldn't apply it to my problem. The code is broken down to the minimum.
The configuration class
Besides other easy to serialize components it has an 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
}
The ParameterSet definitions
There is nothing special in these classes. Just Integer and Boolean values.
public class ParamSet {}
public class ChildParamSet extends ParamSet{}
Abstract Application class
This is where the saving process starts. I have defined a abstract method later implemented in classes where T
is known at runtime.
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);
}
Concrete Application class
Well here i know the type of T
and i want to call a getConfiguration
method.
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 -- the problem
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);
}
}
So the problem is the getConfiguration
method in the ConfigurationPersistenceHelper. When i run this method, instead of an ArrayList<ChildParamSet>
i get a Linked TreeMap
in the configuration.
I guess this is because of type erasure for generics during runtime and my definition of the method with T extends ParamSet
.
But how can i fix this? Is there another way to call the method so the type isn´t lost?
Workarounds i know of
I know i can implement the deserializer logic in the loadConfig
method of every concrete application class. But this would have a lot of duplicate code as a result. This is my current solution.
Also i know i can pass the type to the serializer from the loadConfig
(where the type is still available at runtime) to the getConfiguration
method. Is that bad practice?
I also know i can write my own deserializer but there i would also need the type at runtime, which is currently my problem.