How to write I18N exceptions

This section describes the steps to implement exceptions with support for internationalization (I18N).

Audience

Note that most of the time the messages provided to exceptions are intended for the system operator or software developer as long as the presentation tier is not concerned. Displaying messages in the presentation tier often requires more structured text than simple text (e.g. messages shown in a web browser). Presentation tier messages should abstract from the messages provided to the exceptions caught from lower levels.

As a rule of thumb: Never display the exception text in the presentation tier to the user of the system. Just keep it inside the system's logging framework. Exception to this rule are exceptions that are part of the presentation tier. There will be a mapping between the exceptions on the presentation tier and those of lower tiers.

Security Issues

Displaying messages intended for the operator or software developer to the user will also introduce a security risk. Please refer to Information Leakage and Improper Error Handling on the OWASP Website for details.

Subclassing

Two base implementations of exceptions are provided by this library extension to smart-exceptions-core .

  1. de.smartics.exceptions.i18n.AbstractLocalizedException
  2. de.smartics.exceptions.i18n.AbstractLocalizedRuntimeException

Make your exceptions subclass one of them.

For details on implementing exception codes please refer to the documentation in the smart-exceptions-core project.

Provide a message bundle

For the localized information required by the exceptions provide a standard exception bundle. You may specify this information for the String property bundleBaseName explicitly as in "de.smartics.exceptions.i18n.message.ParseCodeBundle" or you may use the default location: Name of the code enumeration class (inclusive package name) and suffix Bundle .

A message bundle looks like this:

2000.title=Parse exception
2000=Cannot parse input ''{0}''.
2000.details=The system is unable to parse input ''{0}'' at position {1}.

2001.title=Parse exception
2001=Cannot parse OGNL path in ''{0}''.
2001.details=The system is unable to parse the OGNL path in ''{0}'' at \
 position {1}.

2002.title=Parse exception
2002=Cannot parse parent attribute since separator is missing: ''{0}''
2002.details=The '='-sign to separate the key from the value is missing at \
 position {1}.

2003.title=Parse exception
2003=Cannot parse parent attribute since value is missing: ''{0}''
2003.details=The value of the property attribute is missing at position {1}.

2004.title=Parse exception
2004=Cannot parse parent attribute since index is missing: ''{0}''
2004.details=The index of the attribute is missing at position {1}.

The key is the exception code (without the component prefix). The value is the localized information.

There are five distinct pieces of information for the exception text:

Level Description
title (TITLE) This information is intended to provide a simple category to be displayed in window titles. More than one message has the same title.
summary (SUMMARY , no label) The summary is a short explanation of what has happened.
details (DETAILS) The details information gives more details on what has happened. Typical usage of this message type is to add parameter values that were passed to the module that throwed the exception of to give some technical details only relevant to users of the system that track the failure to its root cause.
implications (IMPLICATIONS_ON_CURRENT_TASK) The information about what implications the abort of the current task has on the work of the user.

While the summary and details section of the message explained what has happend, the implications show what this means for the current task being aborted. The reader of the message can e.g. be assured that his transaction has been rolled back and no money transfer has taken place.
todo (WHAT_TO_DO_NOW) The information about what the user can do now.

If the exception has been raised e.g. because of invalid user input this information can lead the user to what input has been expected. It can also give hints what configuration has lead to this problem in case a subsystem is not available.
url (URL) The URL that links to further information on the problem

The information references may provide even more details on the type of failure being reported. The referenced page may only have static content that does not quote parameters provided by the exception instance, but may provide structured information and links to related information on a help portal or FAQ.

The message type are defined in the de.smartics.exceptions.i18n.message.MessageType enumeration.

But how are the values for the place holder provided? See the next section...

Message place holder

Please refer to the API documentation of the de.smartics.exceptions.i18n.message.MessageParam#value for information how to use this annotation.

Please note that currently there is a public getter required for the property to be read at runtime.

The place holder defined in the message text (such as {0} ) is mapped to an exception field. Have a look at ParseException for a live example on how to use the de.smartics.exceptions.i18n.message.MessageParam annotation.

Access parent information

If you want to include information from the parent (such as the message or the cause) you have to provide a specific annotation at class level. Please refer to de.smartics.exceptions.i18n.message.ParentMessageParam for information how to use this annotation. The annotation is placed at class level.

Have a look at MethodAccessConfigurationException for a live example on how to use the de.smartics.exceptions.i18n.message.ParentMessageParam annotation.

Mapping Code to Exception Class

For reports it is necessary to give the documentation tool a reference from the code to the exception class that provides information for the place holders in the message templates.

The maven-sdoccode-plugin will export the place holder documentation if the enumeration element of the code is annotated with the de.smartics.exceptions.i18n.message.UsedBy annotation.

@UsedBy(MethodAccessConfigurationException.class)
CONFIGURATION_MISSING_GETTER(1000, 1)
        

Exception context

The following is some background information on how to configure the exception context. Normally the default configuration is serving most needs well. If you just want the whole thing get started, skip this section and come here later if there is a requirement to change the rendering or storage of messages.

The I18N library requires a special kind of exception context which is defined in de.smartics.exceptions.i18n.I18nExceptionContext . Basically you have to supply a de.smartics.exceptions.i18n.BundleProvider to access the provided message bundles and a de.smartics.exceptions.i18n.MessageComposer that fills the place holders with values.

The default implementations de.smartics.messages.core.ClassPathBundleProvider and de.smartics.exceptions.i18n.message.DefaultMessageComposer may serve most needs well.