Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: specific enums and generic Enum<?> parameters

I want to pass any enum value to method in utility class and get another enum value of same enum type. Something like this:

public class XMLUtils {

    public static Enum<?> getEnumAttribute(Element element, String name, 
            Enum<?> defaultValue) {

        if (element.hasAttribute(name)) {
            String valueName = element.getAttribute(name);
            // search for value 
            for (Enum<?> value: defaultValue.getClass().getEnumConstants())
                if (value.toString().equalsIgnoreCase(valueName))
                    return value;
        }
        // not found, return default value
        return defaultValue;
    } 
}

Use of method getEnumAttribute():

// simple enum
public enum EUploadMethod {
    INSERT, UPDATE, DELETE
}

// read enum value from XML config file
EUploadMethod method = XMLUtils.getEnumAttribute(element, "method",
        EUploadMethod.INSERT);

This code is fully functional, Eclipse compiles and runs it without warnings or errors and it works like a charm.

But when I clean and compile project from command line by Maven2, it fails with error on line where is getEnumAttribute called:

$ mvn clean compile
....
[ERROR] /home/.... DataUploader.java:[173,53] inconvertible types
found   : java.lang.Enum<capture#414 of ?>
required: .....DataUploader.EUploadMethod

I am using Sun JDK 1.6 in either Eclipse and Maven:

$ mvn -version
Apache Maven 2.2.1 (r801777; 2009-08-06 21:16:01+0200)
Java version: 1.6.0_14
Java home: /usr/lib/jvm/java-6-sun-1.6.0.14/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "linux" version: "2.6.27-17-generic" arch: "i386" Family: "unix"

Questions:

  1. Why this code is compilable and functional in Eclipse, and compile fails in Maven which using as far as I know same javac compiler?

  2. What's wrong with passing specific enums to generic Enum<?> parameters?

Thanks,

Martin Schayna

like image 509
mschayna Avatar asked Feb 08 '10 10:02

mschayna


2 Answers

  1. Eclipse compiler and javac have some differences, especially when it comes to generics. It is believed that eclipse is correct, but that doesn't matter :)

  2. Try

    public static <T extends Enum<T>> Enum<T> getEnumAttribute(Element element, String name, 
        Enum<T> defaultValue) {
       ...
    }
    
like image 165
Bozho Avatar answered Oct 11 '22 03:10

Bozho


I don't know what version of Eclipse you are using but I think it is wrong here. My version reports the same error that you are seeing with Maven, which appears to be a genuine error.

The problem is that you have two wildcards ("?") in the signature of getEnumAttribute() but there is no constraint (nor is it possible to create one) that forces them to be the same. So a client could pass in an enum of one type as the default value and get an enum of a different type in return.

You can eliminate the error in the calling code by replacing both wildcards with a named type parameter:

class XMLUtils {

    @SuppressWarnings("unchecked")
    public static <E extends Enum<E>> E getEnumAttribute(Element element, String name, 
            E defaultValue) {

        if (element.hasAttribute(name)) {
            String valueName = element.getAttribute(name);
            // search for value 
            for (Enum<?> value: defaultValue.getClass().getEnumConstants())
                if (value.toString().equalsIgnoreCase(valueName))
                    return (E) value;
        }
        // not found, return default value
        return defaultValue;
    } 
}

But I don't think it's possible to eliminate the unchecked cast, because Enum<E>.getClass() returns Class<Enum<?>> so the compiler cannot tell what type of enum is contained in the enumConstants array.

like image 21
finnw Avatar answered Oct 11 '22 05:10

finnw