Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the compiler state no unique maximal instance exists?

I have the following classes:

public class Obj<T> extends BaseModel {      public static final String OBJECT = "object";      public Obj(T object) {         setObject(object);     }      public T getObject() {         return get(OBJECT);     }      public void setObject(T object) {         set(OBJECT, object);     } } 

And...

/** This is a 3rd party library class **/ public class BaseModel implements ModelData, Serializable {   //...members and stuff...    @SuppressWarnings({"unchecked", "rawtypes"})   public <X> X get(String property) {     X obj = null;     if (start > -1 && end > -1) {       Object o = map.get(property.substring(0, start));       String p = property.substring(start + 1, end);       if (o instanceof Object[]) {         obj = (X) ((Object[]) o)[Integer.valueOf(p)];       } else if (o instanceof List) {         obj = (X) ((List) o).get(Integer.valueOf(p));       } else if (o instanceof Map) {         obj = (X) ((Map) o).get(p);       }     } else {       obj = (X) map.get(property);     }     return obj;   } } 

When I compile, I get the following error.

type parameters of <X>X cannot be determined; no unique maximal instance exists for type variable X with upper bounds T,java.lang.Object -> getObject()

It doesn't happen in Eclipse, which, as far as I can tell, is using the same JDK as my Ant build. I've seen the SO thread about the Sun compiler issue, but that seemed to be for static methods declaring types on the fly.

Why am I getting this error, and more importantly, how do I get around it?

So far the only why I've found is to cast in my method like this:

@SuppressWarnings({"unchecked"}) public T getObject() {     return (T) get(OBJECT); //yuck } 

Telling my I'm on crack and this is the proper way is acceptable.

like image 651
Snekse Avatar asked Apr 14 '11 15:04

Snekse


2 Answers

This is dummy bug that has been fixed in Java SE 7.

like image 77
Mike Avatar answered Oct 21 '22 00:10

Mike


It does not compile because your code expects too much from generics -> i.e., the < X > X part in:

public <X> X get(String property) { ... } 

In the following code:

public T getObject() {   return get(OBJECT); } 

you have to keep in mind that generics are always "unfolded" before the compiler actually starts to compile the Java code. It is a pre-processing step.

In your case, the compiler does not know what to use to replace X at compile time. The compiler needs to be sure about the type of X, because it needs to check it against T to validate the code. Hence the error...

A solution to your issue is to replace < X > X with Object:

public Object get(String property) { ... } 

and add a cast in:

public T getObject() {   return (T) get(OBJECT); } 

Your will get an unchecked-cast warning at compile time, but your code will compile (so yes your workaround is valid).

like image 37
Jérôme Verstrynge Avatar answered Oct 21 '22 01:10

Jérôme Verstrynge