Home > Enterprise >  How to get an enum of static class members in Java?
How to get an enum of static class members in Java?

Time:12-13

I have a Java class (which I do not control and cannot modify) which has a large number of static String members. How can I have these as an enum (for convenience in coding)?

E.g. I have:

public class ClassWithStaticMembers {
  public static String ONE = "one";
  public static String TWO = "dos";
}

...and I want to derive the following from it:

public enum NUMBERS {
  ONE,
  TWO
}

Is this possible, with reflection or otherwise?

(Assume I don't know Java well, and that I have 100 values, so repeating each is painful and not desirable (in case more values get added later). Also I don't need the actual values from the class ("one" and "dos" above)).

CodePudding user response:

To make it simple: Enum are statically described so there isn't any possibility to create it by reflection.

You can still create an enumeration that wraps your constants, and optionally had a unit test (that uses reflection) to ensure that your enum is complete.

public enum NumbersEnumeration {
  ONE(ClassWithStaticMembers.ONE),
  TWO(ClassWithStaticMembers.TWO);
  private static final String name;
  public String getName(){return name};
  public NumbersEnumeration(String name){this.name=name;}
}


public class NumbersEnumerationTest{

  @Test
  public void checkEnumComplete() throws Exception{
    var fields = List.of(ClassWithStaticMembers.class.getDeclaredFields());
    for( var field:fields){
      Assertions.assertNotNull(NumbersEnumeration.valueof(field.getName());
    }
  }
}

(there may be compilation problems on reflection but you got the idea)

CodePudding user response:

You can obtain java.lang.reflect.Field instances representing fields defined by your class using Class.getDeclaredFields() and filter out those that marked as static and access their values.

But the problem is that getDeclaredFields() does not guarantee that an array it returns would be ordered in any particular way. Here's a quote from the documentation:

The elements in the returned array are not sorted and are not in any particular order.

So if you were thinking about associating static fields and enum members automatically based on their order of declaration, then it wouldn't work, Reflection API can't help here.

I would advise introducing a separate utility-class which would wrap a Map associating string values and enum constants.

public class NumbersUtils {
    public static final Map<String, Numbers> NUMBERS = Map.ofEntries(
        Map.entry("one", Numbers.ONE),
        Map.entry("dos", Numbers.TWO),
        ...
    );
    
    private NumbersUtils() {} // utility classes are not meant to be instantiated

    public static Numbers toNumber(String str) {
        if (!NUMBERS.containsKey(str)) throw new IllegalStateException(); // or remove this line if you don's want to throw in such case, method would return null instead
        
        return NUMBERS.get(str);
    }
}

Even if you have a possibility of modifying the enum, probably it would be better to keep this logic outside the enum and within the enum you can introduce a method delegating to NumbersUtils.toNumber()

Sidenotes:

  • If these static strings and enums in your code represent the same thing in different languages, and they are mean to facilitate internationalization of the application, then keeping hard-coded strings you might want to get familiar with the proper I18N technics (through properties files and ResourceBundles). This tutorial will give a general idea on that topic.

  • Try to adhere to the [Java language naming conventions][conventions] while writing code. Names enums (as well as classes and interfaces) should newer be written in uppercase.

  • Related