** Note: This document is currently targeted at JBoss Logging 3.0.0 CR1 and JBoss Logging Tooling 1.0.0 Beta8-SNAPSHOT (the reason for the snapshot is a bug retrieving loggers from translated loggers).
Why?
If you want to internationalize (i18n) your logging, exception messages and messages in general, then along with JBoss Logging 3.x, JBoss Logging Tools is for you. It provides an easy way to offer internationalized messages, exceptions and logger messages to your project.
With JBoss Logging Tools you write interfaces and annotate the methods with a default message. Then you or a translator will create a properties file with the translated text.
How does it work?
JBoss Logging Tools uses an annotation processor to implement concrete classes of your annotated interfaces. If you have also provided translation properties files, then a new concrete class will be created extending the implementation and overriding the messages returned.
The translation properties files must exist in the same directory structure as the interface. The name of the properties file InterfaceName.i18n_language_country_variant.properties. For example if you have a class named org.jboss.as.As7RocksMessages and you want to translate this into French you create a properties file called As7RocksMessages.i18n_fr.properties in a directory org/jboss/as.
Dependencies
- JBoss Logging 3
- tools.jar or CodeModel (which can be found here http://codemodel.java.net/)
Constraints
The following annotations are defined:
- @org.jboss.logging.annotations.MessageBundle - This annotation is attached to an interface which is intended to be a message bundle (a generic source of translated strings; i.e. there are no logging methods on the interface). Interfaces annotated with this annotation can be instantiated via the Messages.getBundle(InterfaceName.class) method.
- @org.jboss.logging.annotations.MessageLogger - This annotation is attached to an interface which is intended to act as a translating message logger. Such interfaces may include plain bundle messages as well as logger messages. Interfaces annotated with this annotation can be instantiated via the Logger.getMessageLogger(InterfaceName.class, "category.name") method.
- @org.jboss.logging.annotations.Message - this annotation is attached to any interface method which corresponds to a message which may be translated. This includes both simple messages and log messages.
- @org.jboss.logging.annotations.LogMessage - this annotation is attached to log messages (in addition to Message above), and includes additional information such as the log level for the message.
- @org.jboss.logging.annotations.Cause - this annotation is attached to a method parameter which should be considered to be the causing java.lang.Throwable (or subclass thereof).
Message bundle interfaces must conform to these rules:
- The message bundle annotation may specify a project code.
- All methods defined on the message bundle interface must have a @org.jboss.logging.annotations.Message annotation present, unless the method has the same name as another method on the interface and same number of parameters (minus the cause parameter) which has the annotation present.
- All methods defined on the message bundle interface must return either java.lang.String or one of its supertypes, or java.lang.Throwable or one of its subtypes.
- All methods defined on the message bundle interface must accept a number of parameters consistent with the format string on the value attribute of the @org.jboss.logging.annotations.Message annotation. This assertion is complex to ascertain at compile-time, thus the no errors are shown at compile time.
- The @org.jboss.logging.annotations.Cause annotation may appear at most once on any given method's parameter list.
- If the method returns a java.lang.Throwable, the parameter marked as @Cause is passed in to that Throwable's constructor if it has such a parameter; if not, then it is passed in to the Throwable's initCause() method after the Throwable is constructed.
- If the method returns a java.lang.Throwable the message of the Throwable will initialized with the message from the annotation if available.
- All of the @org.jboss.logging.annotations.Message annotations found on methods on all message bundle interfaces with the same project code which specify an id must specify a unique number, INHERIT, or NONE.
- A message bundle interface may extend other message bundle interfaces.
- A message bundle interface may extend java.io.Serializable; however, doing so is superfluous as the implementation class will implement this interface regardless.
- A message bundle interface may not extend any other interfaces which do not fit the criteria specified above.
Message logger interfaces must conform to the above rules, except:
- A message logger interface may not specify a @org.jboss.logging.annotations.MessageBundle annotation; instead, it must specify a @org.jboss.logging.annotations.MessageLogger annotation (which also has a property for project code).
- Any method on a message logger interface may additionally specify a @org.jboss.logging.annotations.LogMessage annotation. This annotation signifies that the method is a logger method.
- All logger methods must be declared to return void.
- A logger method may have a specified log level in the level property of the @LogMessage annotation.
- If multiple methods of the same name exist, any number of them may have @LogMessage annotations. Only methods so annotated are log message methods. The rules regarding equally-named methods on message bundles continue to apply.
- Log methods with a parameter marked as @Cause will pass that parameter in to the appropriate log method as the causing exception.
- Message logger interfaces may extend other message logger interfaces in addition to the rules for message bundle interfaces.
- Message logger interfaces may extend the org.jboss.logging.BasicLogger interface. All methods of the BasicLogger will be delegated to the logger being used for the log methods.
Parameter count rules:
You should be aware parameters are counted a little differently than a normal overloaded method. The parameter count used for validation is comprised of a count of all the parameters minus the @Cause parameter.
Example Code
More examples to come, but for now is is a source repository of examples on how to create the interfaces for loggers and message bundles.
https://github.com/jamezp/jboss-logging-example
How to set it up in your project?
Using the logging tool requires minimal set-up.
Maven
For a maven project you are having two options
maven-compiler-plugin
In this case the JBoss Logging Tool library needs to be specified as project dependency.
{code:xml}
...
<dependencies>
...
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging-annotations</artifactId>
<version>${version.org.jboss.logging.tools}</version>
<!-- Only required during compile of the current module -->
<scope>provided</scope>
<optional>true</optional>
</dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging-processor</artifactId>
<version>${version.org.jboss.logging.tools}</version>
<!-- Only required during compile of the current module -->
<scope>provided</scope>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<!-- Must be at least version 2.2 with a target of 1.6 to generate the source files in
target/generated-sources -->
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<showWarnings>true</showWarnings>
<!-- Optional if you wan to generate skeleton translation properties files -->
<compilerArgument>
-AgeneratedTranslationFilesPath=${project.basedir}/target/generated-translation-files
</compilerArgument>
</configuration>
</plugin>
</plugins>
</build>
...
{code}
maven-processor-plugin
In this approach the maven-processor-plugin is used for running the annotation processor. The jboss-logging-processor dependency is now local to the plugin and the Maven bugs MCOMPILER-62 and MCOMPILER-66 are avoided.
... <plugin> <groupId>org.bsc.maven</groupId> <artifactId>maven-processor-plugin</artifactId> <version>2.0.2</version> <executions> <!-- Run annotation processors on src/main/java sources --> <execution> <id>process</id> <goals> <goal>process</goal> </goals> <phase>generate-sources</phase> <configuration> <processors> <processor>org.jboss.logging.generator.apt.LoggingToolsProcessor</processor> </processors> </configuration> </execution> <!-- Run annotation processors on src/test/java sources --> <execution> <id>process-test</id> <goals> <goal>process-test</goal> </goals> <phase>generate-test-sources</phase> <configuration> <processors> <processor>org.jboss.logging.generator.apt.LoggingToolsProcessor</processor> </processors> </configuration> </execution> </executions> <dependencies> <dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging-processor</artifactId> <version>${jbossLoggingProcessorVersion}</version> <scope>compile</scope> </dependency> </dependencies> </plugin> ...
This approach is also described on this blog entry on in.relation.to
IDE
Eclipse
When using an Eclipse project follow the instructions here http://help.eclipse.org/helios/index.jsp?topic=/org.eclipse.jdt.doc.isv/guide/jdt_apt_getting_started.htm to enable annotation processing.
NetBeans
When using NetBeans as long as the library is in the class path, the annotations will automatically be processed.
Intellij
Intellij IDEA offers the following documentation to enable annotation processing. http://www.jetbrains.com/idea/webhelp/compiler-annotation-processors.html
Issue tracking
JBoss issue tracker:
Comments