I have a large number of Enums that implement this interface:
/**
* Interface for an enumeration, each element of which can be uniquely identified by it's code
*/
public interface CodableEnum {
/**
* Get the element with a particular code
* @param code
* @return
*/
public CodableEnum getByCode(String code);
/**
* Get the code that identifies an element of the enum
* @return
*/
public String getCode();
}
A typical example is:
public enum IMType implements CodableEnum {
MSN_MESSENGER("msn_messenger"),
GOOGLE_TALK("google_talk"),
SKYPE("skype"),
YAHOO_MESSENGER("yahoo_messenger");
private final String code;
IMType (String code) {
this.code = code;
}
public String getCode() {
return code;
}
public IMType getByCode(String code) {
for (IMType e : IMType.values()) {
if (e.getCode().equalsIgnoreCase(code)) {
return e;
}
}
}
}
As you can imagine these methods are virtually identical in all implementations of CodableEnum. I would like to eliminate this duplication, but frankly don't know how. I tried using a class such as the following:
public abstract class DefaultCodableEnum implements CodableEnum {
private final String code;
DefaultCodableEnum(String code) {
this.code = code;
}
public String getCode() {
return this.code;
}
public abstract CodableEnum getByCode(String code);
}
But this turns out to be fairly useless because:
- An enum cannot extend a class
- Elements of an enum (SKYPE, GOOGLE_TALK, etc.) cannot extend a class
- I cannot provide a default implementation of getByCode(), because DefaultCodableEnum is not itself an Enum. I tried changing DefaultCodableEnum to extend java.lang.Enum, but this doesn't appear to be allowed.
Any suggestions that do not rely on reflection? Thanks, Don
How about a static generic method? You could reuse it from within your enum's getByCode() methods or simply use it directly. I always user integer ids for my enums, so my getById() method only has do do this: return values()[id]. It's a lot faster and simpler.
Here I have another solution:
The trick is that the inner class can be used to hold "global methods".
Worked pretty fine for me. OK, you have to implement 3 Methods, but those methods, are just delegators.
You could factor the duplicated code into a
CodeableEnumHelper
class:Each
CodeableEnum
class would still have to implement agetByCode
method, but the actual implementation of the method has at least been centralized to a single place.In my opinion, this would be the easiest way, without reflection and without adding any extra wrapper to your enum.
You create an interface that your enum implements:
Then in a helper class you just create a method like this one:
This method could be then used like this:
About as close as I got to what you want was to create a template in IntelliJ that would 'implement' the generic code (using enum's valueOf(String name)). Not perfect but works quite well.
Abstract enums are potentially very useful (and currently not allowed). But a proposal and prototype exists if you'd like to lobby someone in Sun to add it:
http://freddy33.blogspot.com/2007/11/abstract-enum-ricky-carlson-way.html
Sun RFE:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6570766