Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Discrepancy between Eclipse compiler and javac - Enums, interfaces, and generics

The following code compiles (and runs tests as expected) in Eclipse:

import java.util.EnumSet;
public class EnumTest {

    static enum Cloneables implements Cloneable {
        One, Two, Three;
    }

    public <T extends Cloneable> T getOne(Class enumType) {
        EnumSet<? extends T> set = EnumSet.allOf(enumType);
        return set.iterator().next();
    }
}

However, compiling with either javac (JDK 7) directly or via Maven fails with the following error:

type argument ? extends T is not within bounds of type-variable E

To be honest, the complexity of enums + interfaces + type-parameters (generics) all at play at once threw me off as I was writing the code, but I thought I had finally gotten it right.

The goal is to write calling code like this:

Cloneable something = enumTest.getOne(Cloneables.class);

For example, in Eclipse the following test compiles and passes:

@Test
public void testGetFirst() {
    assertSame(Cloneables.One, getOne(Cloneables.class));
}

Any clues about which is "correct," Eclipse or javac, are appreciated.

Also appreciated is any advice about alternate ways to implement the idea: take a class as a method param that can be used in EnumSet.allOf() and that also determines the type of Enum objects in the EnumSet

By the way, don't bother critiquing the purpose of this method; I've reduced it down from more useful/meaningful code. I'm not interested in discussing the merits of "finding the first element from an enum type" - that's not the point of this question.

like image 613
E-Riz Avatar asked Dec 31 '14 22:12

E-Riz


1 Answers

You need to make sure that T is an enum type, or it won't meet the constraints for EnumSet:

public <T extends Enum<T> & Cloneable> T getOne(Class enumType) 

Also, you don't need the wildcard in your EnumSet, and you shouldn't use the raw Class type:

public <T extends Enum<T> & Cloneable> T getOne(Class<T> enumType) {
    EnumSet<T> set = EnumSet.allOf(enumType);
    return set.iterator().next();
}
like image 72
SLaks Avatar answered Oct 10 '22 12:10

SLaks