Issue
I'm using a Marker Interface to implement pseudo enum inheritance.
Let's say I define Marker class as follows:
public interface FieldInterface
Now I have have 5 enum classes that implement this interface.
enum Field1 implements FieldInterface
enum Field2 implements FieldInterface
enum Field3 implements FieldInterface
enum Field4 implements FieldInterface
enum Field5 implements FieldInterface
Each of the 5 enum "Field" class above defines a list of enums related to that field type. For example, enum Field1
might define enums: Field1A, Field1B, Field1C
. Enum Field2
might define enums: Field2A, Field2B, Field2C
Now I need to convert plain text representation of each enum to the corresponding enum (similar to calling enum.valueOf(String)
) without knowing which of the 5 enum classes the String belongs to.
One way to achieve this might be through reflection
by first retrieving a list of all classes that implement said interface and iterating through all of the 5 enum classes until a match is found. However, I prefer to avoid reflection if possible (mainly due to performance reasons).
What other options are there to solve this problem?
Thanks
Solution
A traditional implementation of a Map<String, Enum<?>> with a small complication of handling several enum classes. The static final map instance is defined in an interface and shared across all enums.
class Main {
// Nice shorthand for an anonymous instance of X
private static final X X = new X(){};
public static void main(final String[] args) {
// Enum classes must be loaded
loadEnums();
// You can call get() on any enum constant but that would look unintiitve. We need an instance of X
System.out.println(X.get("FIELD1B"));
}
private static void loadEnums() {
IntStream.range(1, 10).mapToObj(n -> Main.class.getPackageName() + ".Main$Field" + n).forEach(Main::loadEnum);
}
private static void loadEnum(String name) {
try {
Class.forName(name);
} catch (ClassNotFoundException e) {}
}
/**
* All enums implement this marker interface and therefore share access to a static map from the name of the enum to its value.
*/
interface X {
Map<String, X> map = new HashMap<>();
/**
* This shared method uses enum's name method to get enum's string representation.
*/
default void add() {
map.put(name(), this);
}
default X get(String key) {
return map.get(key);
}
/**
* This method is always overwritten by each enum because all enums have a name() method. It is declared here so that we can provide add() method without requiring name passed as an argument. having a default implementation allows us to new X(){}.
*/
default String name() {
return null;
}
}
enum Field1 implements X {
FIELD1A, FIELD1B, FIELD1C;
// We have to call add() to place each enum value in the shared map
Field1() { add(); }
}
enum Field2 implements X {
FIELD2A, FIELD2B, FIELD2C;
Field2() { add(); }
}
Answered By - Delta George
Answer Checked By - Dawn Plyler (JavaFixing Volunteer)