I have a method which returns a List<Property<?>>
.
Property is a type having one generic parameter:
public class Property<T extends Comparable<T>> { ... }
Having a list of mixed-typed properties, I cannot know what type parameter a specific element has.
I would like to do something like that:
List<Property<?>> list = getList();
for(Property<?> crt : list)
{
PropertyWrapper<?> crtWrapper = new PropertyWrapper(crt.getGenericType());
// I know this doesn't exist ----^
}
In one sentence: I need the PropertyWrapper
to have the same generic template argument as the current Property
does. Is there any way to do this?
I could apply a suggestion as stated in https://stackoverflow.com/a/3437930/146003 but even if I do this, how to instanciate the appropriate PropertyWrapper<XXX>
then, only having an instance of Class<T>
?
I can modify Property<?>
if required. I also don't mind if reflection needs to be used (I assume it needs to be)
EDIT: I forgot something. In fact I cannot instanciate the wrapper by the line
PropertyWrapper<?> crtWrapper = new PropertyWrapper(crt.getGenericType());
because I have specialized subclasses (PropertyWrapper_String
).
Now I see two possibilities:
1: Instanciate the class by string:
String strGenericType = "";
Class<?> wrapperClass = Class.forName("PropertyWrapper_" + strGenericType);
2: Is there any way to specialize a generic class without creating a subclass?
Many thanks in advance for your tips
You can see that in the main method, or in any instance method, I am capable to get the name of the generics type, in this case the main will print: java. lang. Integer. ...and you get the name of the subclass (if any).
The short answer is, that there is no way to find out the runtime type of generic type parameters in Java. A solution to this is to pass the Class of the type parameter into the constructor of the generic type, e.g.
A parameterized type is an instantiation of a generic type with actual type arguments. A generic type is a reference type that has one or more type parameters. These type parameters are later replaced by type arguments when the generic type is instantiated (or declared ).
< T > is a conventional letter that stands for "Type", and it refers to the concept of Generics in Java.
Try creating the following method:
<T> PropertyWrapper<T> createWrapper(Property<T> property){
return new PropertyWrapper<T>(property);
}
Then call it as such.
List<Property<?>> list = getList();
for(Property<?> crt : list)
{
PropertyWrapper<?> crtWrapper = createWrapper(crt);
}
The reason the above works is that the generic type T
is inferred from the argument and is locked down for the entire method. Unlike using <?>
in the loop where each instance of <?>
is inferred to be a different type.
Edit:
To deal with the issue of having a different class type depending on the class in the wrapper, consider a Map where the key is the class being wrapped and the value is the wrapper.
Map<Class<?>, Class<?>> myMap;
Then you could so something like this:
Class<?> wrappedType = property.getGenericType();
Class<?> wrapperClass = myMap.get(wrappedType);
PropertyWrapper<?> wrapper = (PropertyWrapper<?>) wrapperClass.newInstance();
Although you might need to do something like this if you need to pass an argument.
Constructor<?> constructor = wrapperClass.getDeclaredConstructor(property.getClass());
PropertyWrapper<?> wrapper = (PropertyWrapper<?>) constructor.newInstance(property);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With