Java generics puzzler with shared static factory

I recently started writing a generic object template for a project and came across something that I don't quite understand. Given the following:

public class G<X> { public G(Class<X> c) { } public void m(X x) { } public static <T> G<T> create(Class<T> c) { return new G<T>(c); } public static void main(String[] args) { Object o = ""; // irrelevant! G<?> t = create(o.getClass()); tm(o); } } 

I get the following compilation error:

 m(capture#402 of ?) in G<capture#402 of ?> cannot be applied to (java.lang.Object) 

I cannot figure out how to properly drop t to do this compilation. What am I missing? Using JDK 1.6.

EDIT :

This is not an academic question. I am trying to write a mapper from sleep mode objects to the corresponding DTO, which will be passed at the REST level. It is assumed that for each Foo ORM object, there may be a FooDTO class that has a constructor that takes an instance of Foo as a parameter. The generic class that maps Foo to FooDTO encapsulates this assumption and throws appropriate exceptions if FooDTO does not exist or does not have a corresponding constructor:

 class Mapper<Foo,FooDTO> { private final Constructor<FooDTO> dtoConstructor; Mapper(Class<Foo> fooClass, Class<FooDTO> fooDTOClass){ // find the constructor of FooDTO or throw ... } public FooDTO map(Foo f){ return dtoConstructor.newInstance(f); } // this factory is for convenience when we don't know the type of FooDTO: public static Mapper<X,Object> create(Class<X> fromClass){ Class<Object> dtoClass = // ... find it return new Mapper<X,Object>(fromClass,dtoClass); } } 

It seems to break if I pass a generic class of objects to create .

Please note that in my actual implementation, all FooDTO classes FooDTO distributed from a common superclass, i.e. The Mapper signature is actually something like Mapper<Foo,DTO<Foo>> . I do not think this is relevant here.

EDIT 2 :

Actually the proposal to change the line G<?> t = create(o.getClass()); on G<Object> t = (G<Object>) create(o.getClass()); worked in this context.

Unfortunately, I did not understand that the fact that my class is more complex actually has an effect. Here is a more complete example (I apologize for the phased question):

 public class Y<T> { } public class G<X, Z extends Y<X>> { public G(Class<X> c, Class<Z> s) { } public void m(X x) { } public static <T, S extends Y<T>> G<T, S> create(Class<T> c) { Class<S> s = null; // find this via some reflection magic return new G<T, S>(c, s); } public static void main(String[] args) { Object o = ""; // irrelevant! G<? extends Object, Y<? extends Object>> t = create(o.getClass()); tm(o); } } 

In this case, the Class<S> object is created using reflection and some common location for objects of this type. This part works great and should not be relevant to this discussion. The error I'm getting now is this:

 inconvertible types found : G<capture#155 of ? extends java.lang.Object,Y<capture#155 of ? extends java.lang.Object>> required: G<java.lang.Object,Y<java.lang.Object>> 

And if I change the incriminated line to:

 G<Object, Y<Object>> t = (G<Object, Y<Object>>) create(o.getClass()); 

I get a similar error:

 java: inconvertible types required: G<java.lang.Object,Y<java.lang.Object>> found: G<capture#1 of ? extends java.lang.Object,Y<capture#1 of ? extends java.lang.Object>> 

Once again, I apologize for the piecemeal information. I understand this while I'm writing.

+6
source share
4 answers

You have a consumer here. However, it seems the following compilation (in Eclipse).

 public static class G<X, Z extends Y<X>> { public G(Class<? extends X> c, Class<Z> s) {} public void m(X x) {} public static <T, S extends Y<T>> G<T, S> create(Class<? extends T> c) { Class<S> s = null; // find this via some reflection magic return new G<T, S>(c, s); } public static void main(String[] args) { Object o = ""; // irrelevant! create(o.getClass()).m(o); } } 
+1
source

You passed the Class object from the getClass() method , which returns Class<?> , Which means you had to declare t be G<?> .

You cannot call a method with a generic type parameter when the parameter of the universal variable type is a wildcard. The compiler does not know which concrete class really has a wildcard, so it cannot guarantee type safety when calling such a method. For the same reason that add cannot be called on List<?> .

To get this for compilation, you must use a class literal so as not to have a Class<?> , And declare t not to have a wildcard.

 G<Object> t = create(Object.class); 

Then

 t.mo(o); 

will compile.

+2
source

You create a G<Object> and then assign it to a variable of type G<?> . The called method accepts a variable of type generic, which will not accept anything for <?> . If you change the variable to G<Object> , it will work.

0
source

Since you specify G<?> , Javac expects to find out what generics are (what classes they represent). Changing the statement to G t = create(o.getClass()); corrects errors.

capture errors usually mean that the compiler cannot define classes ...

It’s not entirely clear what you are trying to do ... Perhaps this information would be useful, helping you more ...

-1
source

All Articles