Generic Arguments of type Enum -- Can't Call valueOf()

In the code, the two lines where the method "valueOf()" is called on my generic parameters of type Enum are giving an error:

"The method valueOf(String) is undefined for the type class <capture#3 of ? extends Enum>"

But my generic argument is of type enum, so I don't understand this error.  

Ulitmately, my goal is to convert a string representation of a hashmap (whose keys are enums and whose values are arraylists of enums) into a proper hashmap of the correct enum types.  Since there are different possible enums that can be used as the keys and values, I need a generic solution to avoid recreating the same method over and over for all the types.  

I am also confused by the definition of the Enum type:

public abstract class Enum<E extends Enum<E>>

It appears that parameterizing it by itself would create an infinite regression.  

Thanks,
Jonah
protected static <K extends Enum<?>, V extends Enum<?>> HashMap<K,ArrayList<V>> getHmap(String s, K keyType, V valType) {
        HashMap<K, ArrayList<V>> ret = new HashMap<K, ArrayList<V>>();
        HashMap<String, String[]> strHashmap = getStringHashmap(s);
        Iterator<String> iter = strHashmap.keySet().iterator();
        while (iter.hasNext()) {
            String oldKey = iter.next();
            String[] oldVals = strHashmap.get(oldKey);
            K newKey = keyType.getClass().valueOf(oldKey);
            ArrayList<V> newVals = new ArrayList<V>(oldVals.length);
	        for(int i=0; i<oldVals.length; i++) {
	            newVals.add(valType.getClass().valueOf( oldVals[i]));
	        }
	        ret.put(newKey, newVals);
        }
        return ret;

Open in new window

LVL 7
Jonah11Asked:
Who is Participating?
 
CEHJConnect With a Mentor Commented:
That needs the following method prototype (adjusted to return the more generic and flexible Map as opposed to HashMap)
protected static <K extends Enum<K>, V extends Enum<V>> Map<K, List<V>> getMap(
        String s, K keyType, V valType)

Open in new window

0
 
Jonah11Author Commented:
What about usage like this:

http://www.java2s.com/Code/JavaAPI/java.lang/EnumvalueOfStringv.htm

Also, even if I change the code to:
K newKey = Enum.valueOf(keyType.getClass(),oldKey);

it still does not work.
0
Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

 
CEHJCommented:
Try
            K newKey = K.valueOf(keyType.getDeclaringClass(), oldKey);
            ArrayList<V> newVals = new ArrayList<V>(oldVals.length);

            for (int i = 0; i < oldVals.length; i++) {
                newVals.add(valType.valueOf(valType.getDeclaringClass(), oldVals[i]));
            }

Open in new window

0
 
CEHJCommented:
The whole method:
    protected static <K extends Enum<K>, V extends Enum<V>> Map<K, List<V>> getMap(
        String s, K keyType, V valType) {
        Map<K, List<V>> ret = null;

        HashMap<String, String[]> strHashmap = getStringHashmap(s);
        Iterator<String> iter = strHashmap.keySet().iterator();

        while (iter.hasNext()) {
            String oldKey = iter.next();
            String[] oldVals = strHashmap.get(oldKey);
            K newKey = K.valueOf(keyType.getDeclaringClass(), oldKey);
            List<V> newVals = new ArrayList<V>(oldVals.length);

            for (int i = 0; i < oldVals.length; i++) {
                newVals.add(valType.valueOf(valType.getDeclaringClass(), oldVals[i]));
            }

            ret.put(newKey, newVals);
        }

        return ret;
    }

Open in new window

0
 
Jonah11Author Commented:
CEHJ,

Thanks very much, that works.  I still don't completely understand why, however.  Can you answer a few more questions:

1.  Why does getDeclaringClass work but getClass does not?  
2.  Why does the syntax used in this example NOT work:
http://www.java2s.com/Code/JavaAPI/java.lang/EnumvalueOfStringv.htm
3.  Why did we need to use the syntax "<K extends Enum<K>", which is also used by the definition of the Enum class itself?  As I said, it seems to be self referential and thus confuses me.

Thanks again,
Jonah
0
 
objectsCommented:
Don't you love it when someone posts some code but cannot actually explain it :)
0
 
objectsCommented:
Will see if I can help you

> 1.  Why does getDeclaringClass work but getClass does not?  

The two aren't actually related, you need Enum.getDeclaringClass() to the the Enum class to call valueOf() as I mentioned in my earlier comment

http://download.oracle.com/javase/6/docs/api/java/lang/Enum.html#getDeclaringClass()

> 2.  Why does the syntax used in this example NOT work:

thats a special case I think, will check that for you
0
 
CEHJCommented:
1. Because the compiler needs to allow for the fact that the type might use a constant-specific class body (see API doc)
2. How would you use that?
3. That's the way Enum is defined
0
 
objectsCommented:
rotfl :D
0
 
Jonah11Author Commented:
objects, thanks for that explanation of 1.

CEHJ, regarding point 2, I was thinking, in analogy with the example in that link, that something like:

 K newKey = keyType.getClass().valueOf(oldKey);

might work, but it does not.

Regarding 3, I understand that is the definition, but the definition seems paradoxical to me.  That is, looking at the definition of Enum itself we have:

Class Enum<E extends Enum<E>>

which is a generic definition, but the objects allowed in the generics must extend Enum<E>, but what is the definition of Enum<E>?  Won't this give us an infinite regress?

0
 
objectsCommented:
>  K newKey = keyType.getClass().valueOf(oldKey);

thats calling valueOf() on the Class instance, not the enum.
0
 
Jonah11Author Commented:
objects, okay, bear with me.  The line from the example I linked is:

ap = Apple.valueOf("C");

where Apple is the enum class in question.  So I am still not seeing the difference.  Thanks.
0
 
objectsCommented:
>  K newKey = keyType.getClass().valueOf(oldKey);

getClass() returns a Class object (not an Enum object)
Class does not have a valueOf() method
0
 
Jonah11Author Commented:
ah ok, thanks.

finally, did you have an explanation of point 3, my question about the seeming infinite regress?
0
 
Jonah11Author Commented:
Also, I cannot seem to find any documentation on the valueOf(String) method used in that example -- all I see is this:

http://download.oracle.com/javase/1.5.0/docs/api/java/lang/Enum.html#valueOf%28java.lang.Class,%20java.lang.String%29

which is a different method.
0
 
objectsConnect With a Mentor Commented:
Its saying extenders of Enum can only pass themselves as E

some more reading on enums

http://madbean.com/2004/mb2004-3/
0
 
objectsCommented:
> Also, I cannot seem to find any documentation on the valueOf(String) method used in that example -- all I see is this:

thats a special case as I mentioned earlier
the compiler creates it, the link above discusses it I think
0
 
Jonah11Author Commented:
objects,

that is a great link, it answered all my questions.  thank you.  
0
 
objectsCommented:
Amazed how often people post code on this site that they are unable to actually explain
0
 
CEHJCommented:
:-)
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.