17

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.

10 Answers 10

17

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.

Sign up to request clarification or add additional context in comments.

5 Comments

Doesn't use the getDisplayValue method.
modified, please review exception handling
If it's a heavily used method and/or you have a lot of Enums, then you may want to consider having that array calculated once as a static during class initialization rather than recreating it every time.
You changed his ArrayList to a LinkedList. AFAIU, the difference is that the first has higher performance in random lookup, while the second has higher performance in random insert or delete. Since his list is originally an enumeration, he will (likely) need to lookup the list at random indexes... so wouldn't ArrayList perform faster?
I would add the methodName string parameter to this method so this could be used for any of the methods of the Enum.
10

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

5 Comments

Doesn't use the getDisplayValue method.
Yeah, realized that after I posted. It does now.
Where does Displayable come from?
Whoops, can't add an interface; I'll edit this to do it via reflection.
Unfortunately that's not an option as explained to Sbodd and in the original question.
3

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).

3 Comments

Thanks, but I already explained that the first option is not available to me.
+1 for the second option as it makes the accepted answer type safe by making sure it implements getDisplayValue(). and removes the reflection.
+1 for the second option as well, no reflection, @Sbodd you rock ;-) Elegantly solved a problem that I have been trying to workaround in Java due to Scala enum, errr implementation.
3

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.

Comments

2

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());

Comments

1

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.

Comments

0

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.

1 Comment

Unfortunately I can't do that either, because the output of toString has to match values in the database that I can't change!
0

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;
}

Comments

-1

(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.

1 Comment

your Java code doesn't even compile; FYI use aClass.getEnumValues() in Java in place of Enum.GetNames(typeof(T))
-4

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;       
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.