Generics pains

J

Joshua Cranmer

I am trying to create an options class that manages options for a
project. In this class, the options are internally stored as Strings that
can be cast to (depending on circumstances) integers, booleans, or even
enums. However, I am having trouble getting the code to compile:

public final class Options {
private Options() {}
private static HashMap<String, String> opts = new HashMap<String,
String>();
private static HashMap<String, Class<?>> types = new HashMap<String,
Class<?>>();
public static String getOption(String name) {
return opts.get(name);
}

public static <T extends Enum<T>> T getAsEnum(String name) {
Class<?> c = types.get(name);
if (!c.isEnum())
throw new RuntimeException("Option "+name+" is not an enum!");
Class<T> ec = c.asSubclass(Enum.class);
return Enum.valueOf(ec, getOption(name));
}
}

The exact error:
C:\Documents and Settings\Josh\Desktop\Programming\Java\Decompiler_new
\util\Options.java:43: incompatible types
found : java.lang.Class<capture of ? extends java.lang.Enum>
required: java.lang.Class<T>
Class<T> ec = c.asSubclass(Enum.class);
^
If it helps, this is one of the intended usages:

// Options.opts has pair "log","ERROR"
// and Options.types has pair "log",LogLevel.class
// via my options scheme
@Option("log",LogLevel.class,"ERROR")
public class Logger {

// various methods

private static void log(String message, LogLevel severity) {
if (severity.ordinal() < Options.getAsEnum("log").ordinal())
return;
// log the message somehow
}

private enum LogLevel {
ERROR, WARNING, VERBOSE, DEBUG;
}
}

P.S. I know my error-handling is as of right now unacceptable; I am going
to start fixing that once I implement my logger, for which I need my
getAsEnum function to work.
 
T

Tom Hawtin

Joshua said:
public static <T extends Enum<T>> T getAsEnum(String name) {
Class<?> c = types.get(name);
if (!c.isEnum())
throw new RuntimeException("Option "+name+" is not an enum!");
Class<T> ec = c.asSubclass(Enum.class);

ec could be of type Class said:
return Enum.valueOf(ec, getOption(name));

You could simply cast it with (T).

The general way of dealing with heterogeneous collections is to pass a
class of the type you want:

public static <T> T get(Class<T> type, String name) {
return type.cast(types.get(name));
}
public static Enum<?> getEnum(String name) {
return get(Enum.class, name);
}

Tom Hawtin
 
I

Ingo R. Homann

Hi,

Joshua said:
I am trying to create an options class that manages options for a
project. In this class, the options are internally stored as Strings that
can be cast to (depending on circumstances) integers, booleans, or even
enums. However, I am having trouble getting the code to compile:

My suggestiuon (although I am not really sure about it ;-) is this:


class Options
{

private Options()
{
}

private static HashMap<String, String> opts = new HashMap<String,
String>();

private static HashMap<String, Class<?>> types = new HashMap<String,
Class<?>>();

public static String getOption(String name)
{
return opts.get(name);
}

public static <T extends Enum<T>> T getAsEnum(String name)
{
Class<?> c = types.get(name);
if (!c.isEnum())
throw new RuntimeException("Option " + name + " is not an enum!");
@SuppressWarnings("unchecked")
Class<T> ec = (Class<T>) c.asSubclass(Enum.class);
return Enum.valueOf(ec, getOption(name));
}
}


Hth,
Ingo
 
T

Twisted

The exact error:
C:\Documents and Settings\Josh\Desktop\Programming\Java\Decompiler_new
\util\Options.java:43: incompatible types
found : java.lang.Class<capture of ? extends java.lang.Enum>
required: java.lang.Class<T>
Class<T> ec = c.asSubclass(Enum.class);

Try Class<T> ec = (Class<T>)c.asSubclass(Enum.class);

and throw an @SuppressWarnings("unchecked") right before the method
declaration.

If your logic is right, the return value should always be a Class<T>;
if your logic is wrong, well, then things won't work, but they
wouldn't have been able to anyway.
 
J

Joshua Cranmer

Try Class<T> ec = (Class<T>)c.asSubclass(Enum.class);

and throw an @SuppressWarnings("unchecked") right before the method
declaration.

If your logic is right, the return value should always be a Class<T>; if
your logic is wrong, well, then things won't work, but they wouldn't
have been able to anyway.

My original intent of the question was how to get Enum.class to return a
type of Class<Enum<?>> and not Class<Enum>, which (after external
verification) cannot be done.

However, looking at Sun's bug database, it appears that the return of the
raw type for class literals was a mistake, and they seem to be in the
process of rectifying it: http://bugs.sun.com/bugdatabase/view_bug.do?
bug_id=6209029.

I was afraid that I would be forced to use the @SuppressWarnings, but it
seems I have no choice...

Thanks for your help anyways!
 
O

Owen Jacobson

I am trying to create an options class that manages options for a
project. In this class, the options are internally stored as Strings that
can be cast to (depending on circumstances) integers, booleans, or even
enums. However, I am having trouble getting the code to compile:

public final class Options {
private Options() {}
private static HashMap<String, String> opts = new HashMap<String,
String>();
private static HashMap<String, Class<?>> types = new HashMap<String,
Class<?>>();
public static String getOption(String name) {
return opts.get(name);
}

public static <T extends Enum<T>> T getAsEnum(String name) {
Class<?> c = types.get(name);
if (!c.isEnum())
throw new RuntimeException("Option "+name+" is not an enum!");
Class<T> ec = c.asSubclass(Enum.class);
return Enum.valueOf(ec, getOption(name));
}

}

The exact error:
C:\Documents and Settings\Josh\Desktop\Programming\Java\Decompiler_new
\util\Options.java:43: incompatible types
found : java.lang.Class<capture of ? extends java.lang.Enum>
required: java.lang.Class<T>
Class<T> ec = c.asSubclass(Enum.class);
....

P.S. I know my error-handling is as of right now unacceptable; I am going
to start fixing that once I implement my logger, for which I need my
getAsEnum function to work.

I realize you're writing a completely general Options class, but the
only actual use you've shown so far is logging... Is there a reason
not to use log4j, which has enough logging levels and configurability
to cover what it looks like you're trying to do?

Owen
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,233
Members
46,820
Latest member
GilbertoA5

Latest Threads

Top