Tag Archive | jb5n

Compiler aware access to properties files in Java

The standard way in the Java world to provide internationalization to your application is the usage of properties files. You create a simple text file where you store your key/value pairs. Access to these files is normally done through the JDK class ResourceBundle:

ResourceBundle myResources = ResourceBundle.getBundle("MyResources", currentLocale);

So far, so good. But what if your project grows? How do you keep track of the link between the Java code, i.e. means all the lines that access a particular key, and the properties files? You have to find a way to cope with this, because otherwise it becomes difficult to answer questions like: “Can I remove this key/value pair from my properties file or is it still referenced by some Java code?”. Or what if you want to rename a key? You’ll have to find all occurrences of this string in the Java code. Hopefully you will find all, otherwise ResourceBundle will throw a MissingResourceException.
A simple concept to overcome this problem is to route all access to your properties files to Java interfaces. Let a proxy implementation of this interface fetch the required key from the properties file. This way your IDE can help you to find all lines in your Java code where a certain property is accessed:

MyMessageResource myMessageResource = JB5n.createInstance(MyMessageResource.class);
String ok = myMessageResource.ok();

The Google Web Toolkit (GWT) has introduced this mechanism as Messages. As I needed this kind of functionality quite often, I have implemented a library that implements this idea. In contrast to other implementations I wanted to be backward compatible, so that you can upgrade an existing application step by step. For this I have added an annotation to the interface methods that lets you define the key to use to access the properties file. Normally the name of the method is used as key.

@Message(key = "no.default.key")
String noDefaultKey();

Beyond that the library should also stay extensible. If your requirements change and your customer wants to be able to change the translations without the need of recompilation, you could easily implement your own InvocationHandler that loads the messages e.g. from a database or some other kind of storage:

private interface MyInvocationHandler {
	String ok();

Like Google’s GWT my implementation can of course also handle arguments to the message, using Java’s MessageFormat:

public interface MyMessageResource {
	String youHaveNREtries(int numberOfRetries); // "You have {0} retries."

And last but not least the jb5n library also allows you to use inheritance to group the messages/translations and distribute the methods over different interfaces and therewith the messages over different files:

public interface MyMessageResource {
	String ok();
public interface MySpecificMessageResource extends MyMessageResource {
	String specificMessage();

But the library is not yet finished. A maven plugin as well as an ant task are on my todo list. This way you can check that interface and properties file are in sync during the build process.
The source code can be found on github: https://github.com/siom79/jb5n.