Reputation: 115322
I have a handful of helper methods that convert enum values into a list of strings suitable for display by an HTML <select>
element. I was wondering if it's possible to refactor these into a single polymorphic method.
This is an example of one of my existing methods:
/**
* Gets the list of available colours.
*
* @return the list of available colours
*/
public static List<String> getColours() {
List<String> colours = new ArrayList<String>();
for (Colour colour : Colour.values()) {
colours.add(colour.getDisplayValue());
}
return colours;
}
I'm still pretty new to Java generics, so I'm not sure how to pass a generic enum to the method and have that used within the for loop as well.
Note that I know that the enums in question will all have that getDisplayValue
method, but unfortunately they don't share a common type that defines it (and I can't introduce one), so I guess that will have to be accessed reflectively...?
Thanks in advance for any help.
Upvotes: 17
Views: 32453
Reputation: 25
Come on guys.. its not that hard. Im using string comparison.. but you can just compare the object type if you want.
public static <T extends Enum<T>> Map<T, String> Initialize_Map(Class<T> enumClass) {
Map<T, String> map = new HashMap<T, String>();
for (T val : enumClass.getEnumConstants()) {
map.put(val, val.toString() + (val.toString().equals("ENUM_ELMT") ? " (appended)" : ""));
}
return map;
}
Upvotes: -4
Reputation: 11
I edited in this way method on first response and it work without problem and without implement any interface
public static <T extends Enum<T>> List<String> getDisplayValues(
Class<T> enumClass) {
try {
T[] items = enumClass.getEnumConstants();
Method accessor = enumClass.getMethod("toString");
ArrayList<String> names = new ArrayList<String>(items.length);
for (T item : items)
names.add(accessor.invoke(item).toString());
return names;
} catch (NoSuchMethodException ex) {
// Didn't actually implement getDisplayValue().
Log.e(TAG, "getDisplayValues [" + ex+"]");
} catch (InvocationTargetException ex) {
// getDisplayValue() threw an exception.
Log.e(TAG, "getDisplayValues [" + ex+"]");
} catch (IllegalAccessException ex) {
// getDisplayValue() threw an exception.
Log.e(TAG, "getDisplayValues [" + ex+"]");
}
return null;
}
Upvotes: 0
Reputation: 36497
You can stick this method in some utility class:
public static <T extends Enum<T>> List<String> getDisplayValues(Class<T> enumClass) {
try {
T[] items = enumClass.getEnumConstants();
Method accessor = enumClass.getMethod("getDisplayValue");
ArrayList<String> names = new ArrayList<String>(items.length);
for (T item : items)
names.add(accessor.invoke(item).toString()));
return names;
} catch (NoSuchMethodException ex) {
// Didn't actually implement getDisplayValue().
} catch (InvocationTargetException ex) {
// getDisplayValue() threw an exception.
}
}
Source: Examining Enums
Upvotes: 10
Reputation: 108859
This approach avoids reflection:
public static interface Displayer<T> {
String displayName(T t);
}
public static <T> List<String> getDisplayNames(Iterable<? extends T> stuff,
Displayer<T> displayer) {
List<String> list = new ArrayList<String>();
for (T t : stuff) {
list.add(displayer.displayName(t));
}
return list;
}
...but does require a separate type for everything you want to display:
enum Foo {
BAR("BAR"), BAZ("BAZ");
private final String displayName;
private Foo(String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return displayName;
}
}
public static void main(String[] args) {
Displayer<Foo> fooDisplayer = new Displayer<Foo>() {
public String displayName(Foo foo) {
return foo.getDisplayName();
}
};
System.out.println(getDisplayNames(Arrays.asList(Foo.BAR, Foo.BAZ),
fooDisplayer));
}
In this case, an anonymous type is used, but it could be a stateless singleton or somesuch.
Upvotes: 3
Reputation: 91871
Here is how I would suggest going about it:
First a helper method and static inner class in a utility class somewhere:
@SuppressWarnings("unchecked")
public static <T> T generateProxy(Object realObject, Class<?>... interfaces) {
return (T) Proxy.newProxyInstance(realObject.getClass().getClassLoader(), interfaces, new SimpleInvocationHandler(realObject));
}
private static class SimpleInvocationHandler implements InvocationHandler {
private Object invokee;
public SimpleInvocationHandler(Object invokee) {
this.invokee = invokee;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
method = invokee.getClass().getMethod(method.getName(), method.getParameterTypes());
if (!method.isAccessible()) {
method.setAccessible(true);
}
try {
return method.invoke(invokee, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
}
And then put that together with your enum:
interface DisplayableEnum {
String getDisplayValue();
}
private static List<String> getFromEnum(Class<? extends Enum<?>> displayableEnum) {
List<String> ret = new ArrayList<String>();
for (Enum e : displayableEnum.getEnumConstants()) {
DisplayableEnum de = generateProxy(e, DisplayableEnum.class);
ret.add(de.getDisplayValue());
}
return ret;
}
If performance is an issue aroung generating so many proxy objects, then I would go along the path of making a mutable class that implements DisplayableEnum that can change with each enum constant (kind of a flyweight pattern) and have an invocation handler there that is more flexible about its real object and invokes the right one on every pass through the loop.
Upvotes: 1
Reputation: 116314
using Class#getEnumConstants() is simple:
static <T extends Enum<T>> List<String> toStringList(Class<T> clz) {
try {
List<String> res = new LinkedList<String>();
Method getDisplayValue = clz.getMethod("getDisplayValue");
for (Object e : clz.getEnumConstants()) {
res.add((String) getDisplayValue.invoke(e));
}
return res;
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
this is not completely typesafe since you can have an Enum without a getDisplayValue
method.
Upvotes: 17
Reputation: 41378
(sorry, this is C#. I didn't see that the question was for Java.)
public string[] GetValues<T>()
{
return Enum.GetNames(typeof(T));
}
For Java, of course, all enum types still inherit from java.util.Enum, so you can write:
public string[] getValues<T extends Enum<T>>()
{
// use reflection on T.class
}
Since java.util.Enum doesn't actually implement values(), I think that reflection is the only way to go.
Upvotes: -1
Reputation: 34301
I'd use a java.util.ResourceBundle
with a bundle file that maps to the toString
(and maybe class name) values of your enums so your code then becomes something like:
bundle.getString(enum.getClass().getName() + enum.toString());
Upvotes: 2
Reputation: 346260
Note that I know that the enums in question will all have that getDisplayValue method, but unfortunately they don't share a common type that defines it (and I can't introduce one), so I guess that will have to be accessed reflectively...?
You are guessing correctly. An alternative would be to have the enums all implement toString()
by returning the display value - but if you can't have them implement an interface then I suppose that's not possible either.
Upvotes: 0
Reputation: 11454
There are two things you can do here. The first (simpler, and therefore better) way would just be to have your getStrings() method take a list of some interface, and make your enums implement that interface:
public interface DisplayableSelection {
public String getDisplayValue();
}
private static List<String> getStrings (Collection<DisplayableSelection> things) {
List<String> retval = new ArrayList<String>();
for (DisplayableSelection thing : things) {
retval.add(thing.getDisplayValue());
}
}
private static List<String> getColours () {
return getStrings(Colour.values());
}
If you really care internally that the type is an Enum, you can also use the fact that all enumerated types automatically subclass the built-in type Enum. So, for your example (disclaimer: I think this compiles, but haven't actually tried it):
public interface DisplayableEnum {
public String getDisplayValue();
}
private static <T extends Enum<T> & DisplayableEnum > List<String> getDisplayValues(Class<T> pClass) {
List<String> retval = new ArrayList<String>();
for (DisplayableSelection thing : pClass.getEnumConstants()) {
retval.add(thing.getDisplayValue());
}
}
private static List<String> getColours () {
return getStrings(Colour.class);
}
This second form can be useful if you want to do something that specifically requires an enumeration (e.g. use an EnumMap or EnumSet for some reason); otherwise, I'd go with the first (since with that method, you can also use non-enumerated types, or just a subset of the enumeration).
Upvotes: 3