Quickstart

If you do not bother with details (at least for the start) and just want to get the whole thing going, perform the following steps.

  1. Configure the System
  2. Write Error Codes
  3. Write Exception

Configure the System

Maven Configuration

Add the following dependency to your project.

<dependency>
  <groupId>de.smartics.exceptions</groupId>
  <artifactId>smart-exceptions-i18n</artifactId>
  <version>0.12.1</version>
</dependency>

Since clients also use core classes directly, you may also want to add the core library:

<dependency>
  <groupId>de.smartics.exceptions</groupId>
  <artifactId>smart-exceptions-core</artifactId>
  <version>0.12.1</version>
</dependency>

If you are not using Maven, make the smart-exceptions-i18n.jar available in your application's class path by your build process (and resolve the transient dependencies).

Write Error Codes

ApplicationNumberCode

Following best practices (read: this is not absolutely necessary), first create a class of constants listing your exception code ranges. This makes it easy to check which ranges are already used.

package de.smartics.example.util;

/**
 * Constants to define number code ranges.
 */
public final class ApplicationNumberCode
{
    /**
     * The start number of the system codes.
     */
    public static final int SYSTEM_CODE_START = 0;

    /**
     * The start number of the security codes.
     */
    public static final int SECURITY_CODE_START = 1000;

    /**
     * The start number of the validation codes.
     */
    public static final int VALIDATION_CODE_START = 2000;

		// ... add further code ranges here...

    /**
     * Constant class.
     */
    private ApplicationNumberCode()
    {
    }
}

Error Code Enumeration

Now we define the first error code group. In this example these are the codes dealing with security issues. The goal is to define the format of the error codes. In this example we select select NumberCodeInfo to handle the exception code information and do the formatting.

The implementation of error codes has always the following form (we might generate it in the future).

package de.smartics.example.service.security;

import de.smartics.example.util.ApplicationNumberCode;
import de.smartics.exceptions.code.NumberCode;
import de.smartics.exceptions.code.NumberCodeInfo;

/**
 * Enumeration of the security exception codes.
 */
public enum SecurityServiceNumberCode implements NumberCode {

    /**
     * The specified password is not valid.
     */
    PASSWORD_INVALID(0),

    /**
     * The password was not provided.
     */
    PASSWORD_MISSING(1);

    /**
     * The code information.
     */
    private final NumberCodeInfo info;

    /**
     * Default constructor.
     *
     * @param minorNumber
     *            the minor part of the error code.
     */
    private SecurityServiceNumberCode(final Integer minorNumber) {
        this.info = new NumberCodeInfo("Security",
                      ApplicationNumberCode.SECURITY_CODE_START, minorNumber);
    }

    @Override
    public String getCode() {
        return info.getCode();
    }

    @Override
    public String getComponentId() {
        return info.getComponentId();
    }

    @Override
    public String getDisplayId() {
        return info.toString();
    }

    @Override
    public Integer getMajorNumber() {
        return info.getMajorNumber();
    }

    @Override
    public Integer getMinorNumber() {
        return info.getMinorNumber();
    }

    /**
     * Returns the string representation of the object.
     *
     * @return the string representation of the object.
     */
    @Override
    public String toString() {
        return getDisplayId();
    }
}

We provide the name for the codes (e.g. PASSWORD_INVALID) with its minor code number (e.g. 0) as enumeration elements. In addition to that the major number (ApplicationNumberCode.SECURITY_CODE_START) and the component name ("Security") is provided. This information is required by NumberCodeInfo . If you choose another implementation you would provide other information.

The rest of the enumeration implementation simply realizes the NumberCode interface by delegating the method calls to the NumberCodeInfo instance and provides a toString method that returns the identifier to be displayed in the logfile, etc.

Write Exception

Now we implement an exception class and provide bundles for localization.

Write Exception Class

The exception class is written by deriving from a root exception. It is recommended that you implement a root exception class (e.g. ApplicationRootException) where all your application exceptions inherit from. For simplicity of this example our security exception inherits from AbstractLocalizedRuntimeException directly. As you probably expect, if we had chosen to use checked exceptions here, we would select AbstractLocalizedException as parent class.

package de.smartics.example.service.security;

/**
 * Thrown whenever a security constraint is not met.
 */
public class ApplicationSecurityException extends AbstractLocalizedRuntimeException {

    /**
     * The class version identifier.
     * <p>
     * The value of this constant is {@value}.
     */
    private static final long serialVersionUID = 1L;

    /**
     * Convenience constructor.
     *
     * @param code
     *            the error or exception code of the exception.
     */
    public ApplicationSecurityException(final SecurityServiceNumberCode code) {
        this(null, code);
    }

    /**
     * Default constructor.
     *
     * @param cause
     *            the cause (which is saved for later retrieval by the
     *            {@link #getCause()} method). (A <tt>null</tt> value is
     *            permitted, and indicates that the cause is nonexistent or
     *            unknown.)
     * @param code
     *            the error or exception code of the exception.
     */
    public ApplicationSecurityException(final Throwable cause, final SecurityServiceNumberCode code) {
        super(message, cause, code);
    }
}

This example provides no further information to the exception due to simplicity.

Provide Bundle for Messages

The message bundle de.smartics.example.service.security.SecurityServiceNumberCodeBundle (a properties file) provides localized texts for our exception.

1000.title=Access denied
1000=The provided password is invalid.
1000.details=Please check the password you have provided.

1001.title=Access denied
1001=No password has been provided.
1001.details=Please provide a valid password for authentication.

The key is the number code of the exception. In our example (we use the NumberCodeInfo implementation) the major and minor code is simply added (e.g. 1000 + 0 for PASSWORD_INVALID).

Usually the messages for all codes of an enumeration (SecurityServiceNumberCode in our example) are placed in the same message bundle (SecurityServiceNumberCodeBundle in our example). Both files are placed in the same package (de.smartics.example.service.security).

And now?

Changing Implementations

If you want a quick information how to adapt specific parts to your needs, please refer to the implementation section in the FAQ.

Localization and Placeholders

How to write I18N exceptions provides documentation on how to use place holders in message texts and provide content for them by annotating the exception field declarations.

Exception Code Reports

The exceptioncodes-maven-plugin generates reports for the Maven Site and XML.