Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/imod/resource-bundle-gen

A small Java Annotation Processor (JSR-269) to generate a class to ease the access to resource bundles.
https://github.com/imod/resource-bundle-gen

Last synced: 26 days ago
JSON representation

A small Java Annotation Processor (JSR-269) to generate a class to ease the access to resource bundles.

Awesome Lists containing this project

README

        

# ResourceBundle Processor

ResourceBundle Processor is a small Java Annotation Processor (JSR-269) generating a class to ease the access to java resource bundles.

## What does it do?

The processor will generate a class with a method for each key in the given resource bundle. If the message contains placeholders, the method will have arguments to pass the values for each argument. The final message will be formated with a `java.text.MessageFormat`.

e.g.

`say.hi=Hello {0} {1}` will generate the following method signature:

```java
public String sayHi(Locale locale, String arg0, String arg1)
```

_Note:_ Per default, the 'default bundle' file will be used to determine all the available keys and messages.
If the 'default bundle' does not hold all the messages which should be made available within the final class,
you can define all the files which should be used to find keys and messages in `filesToAnalyse` of `@ResourceBundle` (see <>).

## Advantages

- No message/bundle keys distributed all over the source code.
- Have the compiler check the number of arguments passed to `MessageFormat.format(..)`.
- Source of the generated class is available and you can step through with any debugger.

## Named arguments

The type field of the `@ResourceBundle`-annotation can be used to instruct the generator to support named arguments.

e.g.

Annotation: `@ResourceBundle(bundle = "mybundle", type = COMMONS_TEXT)`

Bundle content: `say.by=By {firstName} {lastName}`

will generate the following method signature:

```java
public String sayBy(Locale locale, String firstName, String lastName)
```

In this case, the generated class will depend on `org.apache.commons.text.StringSubstitutor` of `commons-text`, therefore you need to add the following dependency to you project:

```xml

org.apache.commons
commons-text
1.9

```

## Example

Take the following resource bundle file (`ch/fortysix/test/messages.properties`):

```txt
somekey=Some text
say.hi=Hello {0}
say_by=By {0} {1}
```

Annotating a class with `@ResourceBundle` e.g.:

```java
@ResourceBundle(bundle = "ch.fortysix.test.messages", suffix = "Messages")
public class Application {
}
```

Will generate this:

```java
public class ApplicationMessages {

private static final class Holder {
private static final String BUNDLE_NAME = "ch.fortysix.test.messages";
private Map bundles = new ConcurrentHashMap<>();

public ResourceBundle getBundle(Locale locale) {
return bundles.computeIfAbsent(locale, l -> ResourceBundle.getBundle(BUNDLE_NAME, l));
}
}

private Holder holder = new Holder();

public String somekey(Locale locale) {
try {
return holder.getBundle(locale).getString("somekey");
} catch (MissingResourceException e) {
return "[somekey]";
}
}

public String sayHi(Locale locale, String arg1) {
try {
String messagePattern = holder.getBundle(locale).getString("say.hi");
return MessageFormat.format(messagePattern, arg1);
} catch (MissingResourceException e) {
return "[say.hi]";
}
}

public String sayBy(Locale locale, String arg1, String arg2) {
try {
String messagePattern = holder.getBundle(locale).getString("say_by");
return MessageFormat.format(messagePattern, arg1, arg2);
} catch (MissingResourceException e) {
return "[say_by]";
}
}
}
```

## Configuration

### Annotation

`@ResourceBundle` takes the following properties

|=======================
| property | default | description
| bundle | | The name of the resource bundle. If the (properties) files are located within a package, you need to define the qualified name, but without the extension. e.g. `ch.fortysix.test.mybundle`
| type | JDK | - `JDK`: Generates the implementation based on the Java JDK only, no other dependencies are needed at runtime. Note: this implementation can not ensure the order of the arguments passed to MessageFormat is correct.

- `COMMONS_TEXT`: Generates the implementation based on apache commons-text, supporting named arguments within the message. If you choose this type, you also need to add org.apache.commons:commons-text as a dependency to your project.
| suffix | Bundle | The suffix to be added to the generated class. Base name is the name of the class this annotation is set on.
| filesToAnalyse | | Per default, the default bundle file will be used to determine all the available keys and messages. If the default bundle does not hold all the messages which should be made available within the final class, you can add all the files which should be used to find keys and messages here.
|=======================

### Dependency

To get `@ResourceBundle` available during compilation, you need add the dependency to `ch.fortysix:resource-bundle-annotation`. This is dependency is not required a runtime.

```xml

resource-bundle-annotation
ch.fortysix
${latest.version}
true

```

### Processor

To make the annotation processor/code generation work, you need to extend the compiler configuration:

```xml

org.apache.maven.plugins
maven-compiler-plugin
${maven-compiler-plugin.version}

${jdk.version}
${jdk.version}


ch.fortysix
resource-bundle-processor
${latest.version}


```

## Limitations

- A annotation processor is only triggered in case a java file changes, but the resource bundles actually are `properties`-files (XML is currenlty not supported),
therefore a compilation of the java class annotated with `@ResourceBundle` might need to be triggered in case the bunlde file changes.
e.g. `mvn clean compile`
- The current version only supports resource bundles in the form of properties files (no XML).

## Alternatives

- http://cal10n.qos.ch Compiler Assisted Localization, abbreviated as CAL10N (pronounced as "calion") is a java library for writing localized (internationalized) messages using resource bundles you are already familiar with, but with much greater comfort.