incompatible types: inference variable E#1 has incompatible upper bounds Enum<E#2>

Viewed 544

Why does this throw an error while I build the project (but not while running unittests)...

protected <E extends Enum<E>> E getEnum(JSONObject jsonObject, String propertyName, Type type)
{
    String jsonString = jsonObject.optString(propertyName, null);
    return new GsonBuilder().create().fromJson(jsonString, type);
}

...while this perfectly works (note the difference - last parameter - which is unused!):

protected <E extends Enum<E>> E getEnum(JSONObject jsonObject, String propertyName, Type type, Class<E> clazz)
{
    String jsonString = jsonObject.optString(propertyName, null);
    return new GsonBuilder().create().fromJson(jsonString, type);
}

The error:

   warning: [options] bootstrap class path not set in conjunction with -source 1.7 C:\Projects\bla\bla\bla.java:32: error: incompatible types: inference variable E#1 has incompatible upper bounds Enum<E#2>,Termination
    Termination termination = getEnum(jsonObject, "termination", Termination.TYPE);                                                         
    where E#1,E#2 are type-variables:
      E#1 extends Enum<E#1> declared in method <E#1>getEnum(JSONObject,String,Type)
      E#2 extends Termination

What should I do to improve this?

Edit:

As additional info: this is how I call the method (using the 2nd example, 1st example is already shown in the error message):

Termination termination = getEnum(jsonObject, "termination", Termination.TYPE, Termination.class).

And this is the simplified version of that enum:

public enum Termination
{
    @SerializedName("endDate")END_DATE, 
    @SerializedName("recurrenceCount")COUNT,
    @SerializedName("forever")FOREVER;

    public static final java.lang.reflect.Type TYPE = new TypeToken<Termination>(){}.getType();
}

Now I understand that - due to type inference - I apparently need to define the class type as shown in the 2nd example. However, that's not my question. I'm wondering 1: why is the Gson library able to do exactly the same as I do (as far as I can see from code-examples below), and 2: why doesn't this compile in most cases, while running unittests is no problem.

Gson example code (the method called in both examples):

@SuppressWarnings("unchecked")
public <T> T fromJson(String json, Type typeOfT) throws JsonSyntaxException {
  if (json == null) {
    return null;
  }
  StringReader reader = new StringReader(json);
  T target = (T) fromJson(reader, typeOfT);
  return target;
}

Edit 2:

Apparently when I leave out the 'extends Enum' part the compiler doesn't complain anymore, so I don't need to pass the type as parameter. (this looks more like the Gson example, which was the reason why it compiled for that code but didn't compile for me in 1st example). So my first example now becomes:

protected <E> E getEnum(JSONObject jsonObject, String propertyName, Type type)
{
    String jsonString = jsonObject.optString(propertyName, null);
    return new GsonBuilder().create().fromJson(jsonString, type);
}

Of course I'd still like to extends E to be sure the method can only be used to return enums.

Questions remaining:

  1. how can I improve the code to solve this?
  2. Why does this work without passing the concrete type as parameter, and why doesn't it work while extending Enum?
  3. Why doesn't the compiler complain for the original 1st example when running unittests?
1 Answers
Related