imgx64
imgx64

Reputation: 4152

Generate string constants from properties file keys

I'm using .properties files for message internationalization. For example:

HELLO_WORLD = Hello World
HELLO_UNIVERSE = Hello Universe

And then in Java code:

String foo = resourceBundle.getString("HELLO_WORLD");

String literals like "HELLO_WORLD" are problematic because they're error-prone and can't be autocompleted. I'd like to generate code from the keys in the properties file like this:

public interface Messages { // Or abstract class with private constructor
    public static final String HELLO_WORLD = "HELLO_WORLD";
    public static final String HELLO_UNIVERSE = "HELLO_UNIVERSE";
}

And then use it like this:

String foo = resourceBundle.getString(Messages.HELLO_WORLD);

Is there a standard way to do this? I prefer a Maven plugin, but any stand-alone tool that I can run manually would be good enough for my needs.

Upvotes: 7

Views: 2609

Answers (4)

rec
rec

Reputation: 10895

Yes, apparently people have already written such code.

Have a look at this project: https://github.com/kklisura/props-to-constants-generator

From its intro section:

props-to-constants-generator generates a constants class of keys in your properties file. This enables you to have compile time dependency of keys on a properties file.

Technically, props-to-constants-generator is an Java annotation processor that processes PropertySourceConstants annotations which contain information from which properties file you wish to generate constants and output constants class name. For every PropertySourceConstants annotation, it reads a specified properties file and outputs the class containing constants of property keys.

Maven supports Java annotation processor, so it should work with Maven - although I have not tried it myself (yet).

Update The props-to-constants-generator works well when used in a command-line Maven build. Unfortunately, when used in Eclipse, the problem seems to be that the annotation processor is invoked before the *.properties files are copied to target/classes causing the processor to fail when doing a fresh build (cf. https://stackoverflow.com/a/55992061/2511197).

Upvotes: 1

glee8e
glee8e

Reputation: 6419

No, nobody has ever written such sort of plugin that have all capabilities you have expexted, because:

  • Internationalization may have A LOT OF entries, and you will eventually got a gigantic class, interface, enum or whatever on the end, which is bad.
  • A maven/gradle plugin do generate classes for you, but only at compile time. I see you mentioned auto-completion, which means you will need an IDE plugin, too, meaning a plugin for a building tool(gradle/ant/...) is not enough. The interaction betweeen these plugins could be error-prone.
  • Later in project, if you, or your colleagues, want a new translation entry, and you will have to regenerate the classes. That's a bit tiring.

When dealing with internationalization, something like i18n is recommended. If you don't want a new library or your project is small, you can opt to use eclipse's externalize strings function, for that, see

Andriod: Externalize strings for Android project

Other: help.eclipse.org - Java development user guide > Reference > Wizards and Dialogs > Externalize Strings Wizard

Upvotes: 1

Shekhar Khairnar
Shekhar Khairnar

Reputation: 2691

Following code will generate interface MyProperties in your root directory of the project then after you can use that interface anywhere.

public class PropertiesToInterfaceGenerator {

    public static void main(String[] args) throws IOException {

        Properties properties = new Properties();
        InputStream inputStream =PropertiesToInterfaceGenerator.class.getClassLoader().getResourceAsStream("xyz.properties");
        if(null != inputStream ){
            properties.load(inputStream);
        }
        generate(properties);
    }


    public static void generate(Properties properties) {
        Enumeration e = properties.propertyNames();
        try {
            FileWriter aWriter = new FileWriter("MyProperties.java", true);
            aWriter.write("public interface MyProperties{\n");
            while (e.hasMoreElements()) {
                String key = (String) e.nextElement();
                String val =  properties.getProperty(key);
                aWriter.write("\tpublic static String "+key+" = \""+val+"\";\n");
            }
            aWriter.write(" }\n");
            aWriter.flush();      
            aWriter.close();
        }catch(Exception ex){
            ex.printStackTrace();
        }
    }
}

Upvotes: 2

Joop Eggen
Joop Eggen

Reputation: 109557

Best the other way around:

public enum Message {
    HELLO_WORLD,
    HELLO_UNIVERSE;

    public String xlat(Locale locale) {
        resourceBundle.getString(toString(), locale);
    }
}

Generate from that enum a properties template. This can be repeated for new messages if your base language resides in a separate ..._en.properties.

The generation can be done using values() - without parsing. Though maybe you want to introduce some annotation for properties comments or such.

Upvotes: 3

Related Questions