views:

592

answers:

2

Hi all,

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

+6  A: 
  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) {
       ...
    }
    
Bozho
Thank you, you are absolutely right, man! With your alternative method signature is my source compilable either in Eclipse and Maven. I am little confused by differences between both compilers... Anyway, thank you again!
mschayna
The constraint `<T extends Enum<T>>` is correct but you could make `T` (the actual enum type) the return type rather than `Enum<T>` which is an abstract superclass of `T`.
finnw
+1  A: 

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.

finnw
Thank you for theoretical analysis, especialy "unwanted" tolerance to two different enum types (one for `defaultValue` and one for the result) is important, but in my case it probably wouldn't cause many mistakes.For completeness: I am using Eclipse 3.5.1.
mschayna