Freitag, 28. November 2014

Xtend - Active Annotations : Localization

Last time we took our first steps at implementing Xtend Annotation Processors. We did some simple modifications to the Java AST. This time we want to automate a much more involving pattern: Localization and ResourceBundles.

In Java you usually use .properties files to supply localized Strings for the UI. The ResourceBundle API allows you to access them in an untyped way using String constants. If you want more convenience, you need a static facade like this:

Writing this by hand gets tedious quickly, so many IDEs come with a wizard that generates this code for you. But you still need to manually trigger the generator and check that code into version control. Wouldn't it be cool if this statically typed facade was automatically generated and updated based on the property file?

That's exactly what the @Messages annotation does. The full source code is available on Github. There are many parts that you will easily understand with your knowledge from the previous post. For instance, the annotation adds a field to hold the ResourceBundle, a constructor that takes a Locale etc. The interesting part is where we actually read in the property file at compile time:

We use the Path API to find the physical location of the current class and get the property file of the same name. We give the user a good error message when we cannot find the file and just stop processing in that case.

Then we iterate over all messages in that property file and create a method for each. The name is converted from underscore to camelcase naming convention. For each pattern variable we create a method argument. By looking at the type of the pattern variables, we can also make some deductions about the type of the method arguments. For instance, if a pattern uses a NumberFormat, then only Numbers can possibly be passed to it. Again, we use Xtend's awesome template expressions to generate the body of the method.

With this in place, we now just add the @Messages annotation to an otherwise empty class that has the same name as our property file. All the static facade is automatically generated and available in content assist, outline, validation etc. You can even use existing Java tools like UCDetector to find messages that are no longer used. And every time you edit the property file later on, the Java code will be regenerated automatically!

There are many other untyped files that can benefit from a static facade to Java. Sven Efftinge wrote the @Jsonized annotation that takes some example JSON input and generates a Java class hierarchy from that. Toby Kurien maintains the Xtendroid project that parses the Android UI descriptor and automatically generates accessors for each UI element. Anton Kosyakov automated the creation of GWT ClientBundles and CSSResources.

What pattern would you automate? Try it out and tell your story in the forum =)