Message Bundle Interfaces

Message bundle interfaces provide a way to internationalize exceptions or strings. A message bundle interface is annotated with @MessageBundle. Each method in must be annotated with @Message which will be used to determine the String used for either the return type or the message for the exception being returned.

The value for a @Message may contain an expression.

Expressions are in the form of ${key:defaultValue}. If the key is prefixed with sys. a system property is used. If the key is prefixed with env. an environment variable is used. In all other cases the properties are resolved from the org.jboss.logging.tools.expressionProperties path. If the key is not found in the properties the default value will be used.
Expressions are processed at compile time. The values will be hard-coded in the generated source files.

The following constraints are placed on methods in a message bundle:

  • The return type must be one of the follow

    • A java.lang.String

    • A java.lang.Throwable or a subtype of java.lang.Throwable

    • A java.lang.function.Supplier who’s return type fits one of the other two constraints above.

  • The method must be annotated with @Message or a message must be inheritable.

  • A method can have only one @Cause parameter.

  • A method can only have one @Producer parameter.

A message is inheritable if the two methods have the same name and same number of format parameters.
A format parameter is a parameter that has no annotations or is annotated with one of the following annotations; @FormatWith, @Pos or @Transform.

Example Message Bundle

@MessageBundle(projectCode = "CW") (1)
public interface ErrorMessages {
    ErrorMessages MESSAGES = Messages.getBundle(ErrorMessages.class);

    @Message("Version %d.%d.%d.%s") (2)
    String version(int major, int minor, int macro, String rel);

    @Message(id = 1, value = "Value '%s' is invalid")
    IllegalArgumentException invalidValue(Object value);

    @Message(id = 2, value = "Failure closing %s") (3)
    CloseException closeFailure(@Cause Throwable cause, @Param @Pos(1) Closeable c);

    CloseException closeFailure(@Cause Throwable cause, @Param @Pos(1) Closeable c, @Suppressed Throwable... errors);

    @Message(id = 3, value = "Parameter %s cannot be null")
    Supplier<String> nullParam(String name);

    @Message(id = 4, value = "Operation %s failed.")
    <T extends RuntimeException> T operationFailed(@Producer Function<String, T> fn, String name); (4)

    <T extends RuntimeException> T operationFailed(@Producer BiFunction<String, IOException, T> fn, @Cause IOException cause, String name);
}
1 The projectCode will be prepended to messages which have an id specified. For example with id = 1 the message will be prepended with CW000001. You can control the number padding with the length property on the annotation.
2 No id is specified for this message which means no id will be prepended on this message.
3 The @Param annotation tells the generator that the parameter should be used to construct the CloseException. The @Pos(1) annotation indicates the parameter should also be used when formatting the message.
4 The @Producer annotation indicates that the Function should be used to create the exception being returned.
Message bundle interfaces can also contain valid message logger methods.