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
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 have a Class<T> you can just take that class, create an instance by calling newInstance() on the class object and cast it to T.
The problem you have is getting the generic parameter of crt. If you have concrete subclasses of Property, e.g. StringProperty extends Property<String>, you can get the type using reflection. However, if you only create instances of Property<T> without concrete subclasses and you don't know where the elements of the list are created, AFAIK it is impossible to get the generic type (even if you know where the elements are created it might be impossible though).
Thus, the only way you might get the property wrapper to know the type of the property might be to store the type parameter (the class) in the property itself. Then the wrapper could query the property for its type/class member variable.
Edit: some explanation on why this is impossible or at least very hard.
The problem with generics is that due to type erasure the generic type is lost when you create a property using new Property<SomeType>(). There's just no runtime information that you could use to retrieve SomeType here.
If you have concrete subclasses (defining concrete generic types) you have reflection information available at runtime of what where the generic parameters of each class. Then you could get the actual class of each property and retrieve the reflection data for that class.
This would also be possible if you have methods or fields that define those types and return/hold references to a propery. However, I doubt you have that information since you seem to get some list and don't know exactly on where and how the elements of that list were created.
I further assume the properties' class is Property only, not a subclass. Thus the only way is to provide the runtime information yourself, i.e. by passing a reference to the type class as a constructor parameter.
Okay I'm going to answer myself.
I'm now passing an instance of Class<?> to the Property-class.
Then I extract the basic name of the property and simply cut away "java.lang." which is possibly as in most cases, I'm doing this to primitive data types - resp. their autoboxing classes.
Further, I just instanciate a new instance of the wrapper by name and pass the to be wrapped property as a parameter to the constructor which applys for that.
Here some code for the interested ones among you:
String template = "..."; // some package definition
for (Property<?> crt : bag)
{
String className = template + crt.getClassName();
Class<? extends PropertyWrapper<?>> wrapperClass = null;
wrapperClass = (Class<? extends PropertyWrapper<?>>) Class.forName(className);
Constructor<? extends PropertyWrapper<?>> constructor = wrapperClass.getConstructor(new Class<?>[] {Property.class});
PropertyWrapper<?> wrapper = constructor.newInstance(crt);
// Further operations using the wrapper
}
for simplicity, I left out the error handling part.
Rather than instantiating the wrapper from the call site, why not have the Property know how to create its own wrapper? Something like:
public class Property<T extends Comparable<T>> {
PropertyWrapper<T> newWrapper();
}
That only half-helps, though. Your real problem is that in a loop like yours:
List<Property<?>> list = getList();
for(Property<?> crt : list)
{
PropertyWrapper<?> crtWrapper = crt.newWrapper();
}
The fact that the PropertyWrapper and the Property have the "same" type isn't very helpful, since that type is just the unbound wildcard.
I really hate to give one of those "what are you really trying to do" answers, but -- what are you really trying to do? Generally speaking, once you get to an unbound wildcard, all hope is lost (unless you're willing to do unsafe, uncheckable casts or bend over backwards with reflection checks). One way around this is to put as much of the action within the Property<T> as possible,before you put that property in the List<Property<?>>. My newWrapper() is an example of this: it puts the action of creating a PropertyWrapper<T> into the Property<T> itself. If you wanted to register a callback for when the property changed, that's also something you may be able to do at each place you instantiate a non-wildcard Property<Whatever>. For instance:
Property<UserLogin> property = new Property<UserLogin>();
SomeListener<UserLogin> listener = whatever();
property.addListener(listener);
wildcardedPropertiesList.add(property);
This particular example probably won't help, but hopefully it'll give you applicable ideas.
Related
Let's suppose you're writing a library, and it is to act upon a client class that is passed to it (i.e. client code cannot be changed).
class ClientClass {
public GenericClientClass<AnotherClientClass> someField;
}
What I'm trying to do is instantiate someField through reflection. Something like:
class LibraryClass{
public instantiateAllFields(Object obj){
//iterate through all fields of obj.class, and instantiate them
}
}
The only requirement of the client's fields is that a constructor without arguments exists. (e.g. GenericClientClass() {} )
The purpose of this is to create a highly automated testing library, currently for my own purposes.
I've been able to implement the above for almost all cases (arrays, objects, primitives, generic arrays etc.); however, this particular case has stumped me.
field.getType().newInstance() does not work, since the generic type parameters are removed.
field.getGenericType() doesn't work, because it returns a type, not a class.
If It's a known generic class, I can create a special case to deal with it. For example:
Class<?> genClass = ((Class<?>)((ParameterizedType)field.getGenericType()).getActualTypeArguments()[0]);
JArray jArray = new JArray(true,n,genClass);
field.set(object, jArray);
...I'm guessing I could do this for things like ArrayList, HashMap etc.
However, I would like to cover the general case, and be able to instantiate any generic class (with a single parameter, and a zero-argument constructor) that may be passed into the library.
Any ideas?
Note that the type of the generic parameter is known. I can get at it through field.getGenericType().
There's no such thing as "an instance of a parameterized type"; or, rather, there's no difference between instances of parameterized types with different type parameters. The type parameter is just something the compiler uses to enforce type correctness.
If you're instantiating it at runtime, the compiler is not in the loop. So you just have to create a "raw"/"wildcard"-typed instance, and cast it; and you have to own the problem of ensuring that the cast actually is safe.
Assuming GenericClientClass is not abstract, and has a constructor without parameters:
someField = (GenericClientClass<AnotherClientClass>) GenericClientClass.class.getConstructor().newInstance();
and deal with the resulting unchecked cast warning appropriately.
currenty I'm facing a problem with generic classes in Java.
I have something like this:
public class GenericClass<T> {
T doSomething() {...}
Collection<String> getCollection() {...}
}
Now I instantiate an object of that class without the type parameter, since I'm not intereseted in that or I don't know it.
GenericClass obj = new GenericClass();
for (String str : obj.getCollection() { // won't work
...
}
The problem is, that the compiler does not simply throw away the information about the type-parameter, but also about the type of the Collection (String), although that's independent from the parameter.
Am I doing something wrong, or is that a restriction of Java? If so, why is that a restriction?
You're doing something wrong.
When you don't know the T type, you should just use a wildcard: GenericClass<?>. You can't do this when you're instantiating a new GenericClass, though, so just use Object:
GenericClass<?> obj = new GenericClass<Object>();
For backwards-compatibility reasons, it is deliberate that a class without any generic information at all (GenericClass without any <>) loses all generic type safety so it can be used safely with pre-generic code.
The following code works perfectly fine. Instead of directly extracting values from obj.getCollectionn(), it would be preferable to store it to some Collection variable and then access it.
GenericClass obj = new GenericClass();
Collection<String> c = obj.getCollection();
for (String string : c)
{
//Some complex Code
}
Creating an instance of a generic type without specifying the type parameter is a practice that should only ever be done by legacy code. Any new code that you are writing should not do this. This is called using a "raw type" and compromises all the compile-time type safety that you had written a generic class for in the first place.
Also, just a note that I hope you'll find helpful as well: if you plan to use your own value-based class instances in the Collection framework, you'll need to give some thought to providing a well-behaved implementation of equals() and hashcode(). Not doing this (and relying upon the default behavior of the Object class for equals() and hashcode()) may mean that your objects don't function well in your collections.
Is it possible to declare the type of a generic using a class object?
For instance, I would like to do something like this:
Class returnType = theMethod.getReturnType();
AttributeComponent<returnType> attComponent;
attComponent = new AttributeComponent<returnType>(returnType, attName);
attributeComponents.put(methodName.substring(3), attComponent);
Now I know obviously this is incorrect, but is there a way to achieve this?
EDIT: explaining a little bit
I'm using reflection to go through all getters and then generate a UI element for each property (the AttributeComponent class, which has a JComponent element and a JLabel). I would like to use generics in order to create a getValue() method that would return an object of the property type.
I do not know if there is a way to compile something like that, but it has little value.
Think that thanks to type erasure, the compiled classes do not use the Generics information. That is, doing a Set<String> a = new Set<String>(); is useful for checking the use of a at compile time, but not at runtime.
So, you want to instantiate a Generic whose type will be only known at runtime, but at runtime it will not be used.
I would say this can be achieved by defining the method return type as generic; but you need to pass the actual type as a class argument to use it like you've shown:
<T> T yourMethod(Class<T> returnType) {
// use <T> as generic and returnType to refer to the actual T class
/* ... */ new AttributeComponent<T>(returnType, attName);
}
It would be also useful to see the larger context for what you're trying to do. If you want AttributeComponent.getValue() to return some generic type T (which is the method return type), that's completely useless unless you know each method return type at compile time, otherwise T will be nothing more than an Object. In my example above, you call yourMethod with a class that you already know and the same type will be returned (or some AttributeComponent of that type or whatever).
I have two classes, one abstract, one concrete:
abstract class Generator<T>;
class ConGenerator<T extends Complex<Z,Y>, Z extends Something1, Y extends Something2> extends Generator<T>;
Due to change in the number of parameters (I think), I cannot get the parameter classes at runtime using the usual approach with ParametrizedType, i.e.
ParameterizedType genericSuperclass = (ParameterizedType)getClass().getGenericSuperclass();
Type[] type = genericSuperclass.getActualTypeArguments();
All I am getting is the name I used for the param, T. I would appreciate any help in tackling this problem, I have already searched the web and used some libraries other people wrote for such problems; no luck so far.
The Problem
It is not always possible to infer type parameters given the runtime class, and yours is such a case. The root problem is that all instances of a generic class (irrespective of their type parameters) share the same runtime class, i.e.:
new ArrayList<Integer>().getClass() == new ArrayList<String>().getClass()
Therefore, it is impossible to discover the type parameters given just the runtime class, if that class is generic and different instances of that class can use different values for the type parameter. (Yes, we can find the type parameter for class X<T extends String>, because String is final, are therefore the only possible argument. Likewise, we can find the type parameters of List if we know the runtime class is class MappedList<T> implements List<String> { ... }).
In contrast, it is always possible to infer the type parameters of a super class if the runtime class is not generic - that's what all those libraries and code examples floating around the net do with various degrees of sophistication. For instance, if you have:
class StringArrayList extends ArrayList<String> { ... }
you can discover that the type argument to ArrayList is String. This also works with anonymous classes (as long as they are not generic), because:
new ArrayList<String>() {}.getClass() != new ArrayList<Integer>() {}.getClass()
but fails with generic classes such as
ArrayList<T> makeList(T t) {
return new ArrayList<T>(t) {};
}
because
makeList("2").getClass() == makeList(2).getClass()
The Solution
If you need the type at runtime, you will need to provide it by other means, typically by passing the Class object to the constructor. You can also use a super type token (an instance of a non-generic, usually anonymous, subclass of the desired type, which allows you to discover type parameters by reflection). This has the advantage that type parameters that are themselves generic can be expressed, too.
If you only need the class for a particular thing, there may be simpler alternatives. For instance, if you simply need to create new instances of the type parameter, a factory (method) pattern is quite a bit simpler :-)
I have next code:
class iCache<K,V> implements Map<Object, Object>
{
...//Code
}
How can I get the class name of K and V?
You can't, the compiler performs type erasure at compile time. In other words, the K and V type parameters are purely a compile time notion, they aren't accessible at runtime.
What you can do is to grab the class of the key/values in your custom Map type at runtime.
You can't. Java generics don't work that way. At runtime, there is no class-specific information available (this is known as erasure). If you really need this information, you will have to pass in e.g. Class objects.
If you extend iCache and want to obtain the typer parameters you used to declare the subclass (like below):
class someCache extends iCache<Integer,Long> {
//...
}
You can find out those parameters at runtime using the following (source):
Class clazz = ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
If you provide the parameters at instantiating like this
iCache<Integer,Long> cache = new iCache<Integer,Long>();
then you are out of luck (more info).
The types will get erased. Pass in Class and Class as args into the constructor to pass through your raw types. Store as fields. Note: your patameterisation is bad anyway: you need to pass K and V to Map as well, or you'll give yourself more pain.
Actually you can, call the getClass() method on the key and value