views:

808

answers:

4

I have a situation where I'm receiving an enum from an external system, and for which I need to return an enum of our own. The two enums have the exact same literal values in them:

// externalEnum is guaranteed not to be null 
public static MyEnum enumToEnum(final Enum<? extends Enum<?>> externalEnum)
{
    if( externalEnum instanceof MyEnum )
    {
     return (MyEnum)enumType;
    }
    else
    {
     return MyEnum.valueOf(externalEnum.name());
    }
}

However, the compiler squeals the following:

    [javac] found   : java.lang.Enum<capture#117 of ? extends java.lang.Enum<?>>
    [javac] required: myEnum
    [javac]             if( externalEnum instanceof MyEnum )

I got a version of that function that works by simply returning MyEnum.valueOf(externalEnum.name()) - it works and that's all that matters. However, I'm baffled about the compiler error.

I'm trying to understand the reification process of generics in this case. An instance of Enum<? extends Enum<?>> or simply Enum<?> can be a MyEnum (given that the later can never be anything other than a subtype of the former.)

So the instanceof test should work, but there seems to be something in the generic definition of Enum (and perhaps the fact that Enums cannot be extended) that causes the compiler to puke with that particular statement.

The workaround for me is easy, but I like to understand the problems well, and any insight on this will be appreciated.

  • Luis.
+2  A: 

My (possibly flawed) analysis of your problem is that the two wildcards in your type definition are separate from each other:

Enum<? extends Enum<?>>

means "An Enum of a type that extends Enum that extends some unknown type".

What you want is probably more like this:

Enum<T extends Enum<T>>

which means "An Enum of a type that extends Enum of itself". That is a curious recursive definition (which somehow loops back to Comparable<T>), but it's just how Enums are defined.

Of course your static method would need to take a type parameter <T> for this to work. Try this:

public static <T extends Enum<T>> MyEnum enumToEnum(final T externalEnum) {
 if (externalEnum instanceof MyEnum) {
  return (MyEnum) externalEnum;
 } else {
  return MyEnum.valueOf(externalEnum.name());
 }
}

Edit: fixing the compiler error caused by a wrong identifier makes the code in the question compile for me. So my analysis is definitely flawed ;-)

Joachim Sauer
A: 

I think you mean externalEnum rather than enumType in your first return statement.

That fixed, it compiles in Eclipse and with ant.

David Moles
A: 

I have a situation where I'm receiving an enum from an external system, and for which I need to return an enum of our own.

The instanceof will return false if both classes are loaded by different classloader and/or do have a different minor/major version. Take this into account as well.

BalusC
+2  A: 

Why even bother if both are the same?

public static MyEnum enumToEnum(final Enum<? extends Enum<?>> externalEnum)
{
    try
    {
     return MyEnum.valueOf(externalEnum.name());
    }
    catch (Exception ex)
    {
     return MyEnum.UNKNOWN;
    }
}
Droo
Duh! Good point. It's amazing I didn't realize this until after 7 months :)
luis.espinal