Reputation: 329
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.
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
}
There is nothing special in these classes. Just Integer and Boolean values.
public class ParamSet {}
public class ChildParamSet extends ParamSet{}
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);
}
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);
}
}
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?
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.
Upvotes: 2
Views: 386
Reputation: 56
Yep, Type Erasure is the problem. Just pass in the type info like so:
abstract protected Configuration<T> loadConfig(File file, Class<T> clazz);
inside that method use a custom ParameterizedType for your ArrayList, see:
Upvotes: 1