Home > Software engineering >  java - Set final fields with reflection in Constructor
java - Set final fields with reflection in Constructor

Time:05-25

I'm trying to make a multi-language app with messages inside multiple *.properties files. I've started working on something like this:


    public Language(@NotNull Map<String, String> info) {
        Validate.notNull(info, "Language information cannot be null");

        this.PLUGIN_PREFIX = info.get("PLUGIN_PREFIX");
        this.ARGUMENT_CODE = info.get("ARGUMENT_CODE");
        // etc...
    }

Now, there's a lot of messages, and I don't feel like typing the same thing each time (plus there could me typos which could be an issue...).

The first solution I thought of was to loop through all of the fields that are like that (in caps, final, not static, etc.) and then use reflection to use the field name as a key to set it as the value. Obviously the compiler won't let me because it thinks that the final field hasn't been initialized.

Something like this:

    public Language(@NotNull Map<String, String> info) {
        Validate.notNull(info, "Language information cannot be null");

        Field[] fields = /* TODO get fields */ new Field[0];
        
        for (Field f : fields) f.set(f.getName(), info.get(f.getName()));
    }

Is there a way this can work? Or is there a better solution?

Edit: Quick naming conventions question, should these final "constants" be in upper case?

CodePudding user response:

Usually, you don't store text messages directly in constants, but rather just message keys. Then you use these keys to fetch the actual text messages in the map.

You can use a map directly, but in Java, there is ResourceBundle. A ResourceBundle can be loaded directly from a .properties file.

my-bundle_en.properties:

my.message=Hello, world!

my-bundle_fr.properties:

    my.message=Bonjour tout le monde!
    
    my-bundle_de.properties:
    
    my.message=Hallo Welt!
    
    

Something.java:

public static final MY_MESSAGE = "my.message";
    
ResourceBundle bundle = ResourceBundle.getBundle("my-bundle");
String text = bundle.getMessage(MY_MESSAGE);
    System.out.println(text);
    
  • Related