goldstift's blogspot my 2 cent

24 Oktober 2011

SpringRoo: Howto translate Java exceptions to user-friendly error messages

Introduction

This blog post belongs to a tutorial series on SpringRoo 1.2.0 which uses the sample application "photooapp" to provide practical examples.
Within this blog post I will try to explain how you can configure your SpringRoo application to translate well-known exceptions to user-friendly error messages.
By default SpringRoo's exception handling is very basic meaning the technical exception message is directly presented to the user. Our aim is to provide the user with human-readable error messages he (most probably) can understand and react upon.

Basics: Translations in Spring MVC

First of all we need to make ourselves familiar with the translation process in Spring MVC. To translate any given String to the currently set browser locale, Spring MVC uses so called "message codes". These codes are defined in property files which are located in "src/main/webapp/WEB-INF/i18n/application.properties". For each supported locale there will be a separate application.properties file, e.g. application_de.properties for german translations of the message codes. The "application.properties" file must always be used as the fallback reference.

Adding a sample Translation

So let's say, we wanted to translate a "org.hibernate.exception.ConstraintViolationException" which is thrown whenever the user tries to create a "duplicate entry".
Therefore we would add the following line to the application.properties file:
    exceptions.db.duplicateentry=The record could not be saved as there is already a record in the database having the same unique identifier\!

Customize exception JSP

Next we prepare the "uncaughtException.jspx" which is the default JSP for exception handling in Spring MVC. To keep it simple, we'll remove the lines with the "-" and add the ones with "+":
With the help of the little snipped '<spring:message code="${exception.message}" />' Spring searches for a property with the name of the Exception's message in the above named property file. Therefore we "only" need to find a way to set "exceptions.db.duplicateentry" as the Exception's message.

Spring MVC ExceptionResolver

The ExceptionResolver in Spring MVC is used to determine which JSP fits best whenever any Exception is thrown. In my opinion this is the perfect place to perform our little magic. To accomplish this and be able to handle any kind of Exception in the most flexible way I added the following three classes (links lead you to github):
The I18nMappingExceptionResolver is configured via a number of MessageMatchCriteria and wraps the original exception inside an AnalyzedApplicationException. The ladder will then have the translatable property as "message". The I18nMappingExceptionResolver has to be set as the default exception resolver which is done by changing the following in webmvc.xml:
The relevant change is the property "messageMapping" which contains a map of the a fore mentioned MessageMatchCriteria which are mapped to translatable properties. The "classNamePart" can hold a simple or fully qualified class name or just a part of it. The same applies to the "messagePart" attribute - as you can see in the sample above, the term "Duplicate entry" is part of the original exception message and if found will return a different property name than a normal ConstraintViolationException. I should mention that the classPart and the messagePart are searched in the complete stacktrace of the original exception.
Another thing to note is that the AnalyzedApplicationException makes it easy to access the originals root cause e.g. in the JSP as it's accessible via the attribute "rootCause". Therefore the variable "${exception.rootCause.message}" will resolve to the root cause's exception message.

Resume

All the changes have already been done to photooapp so you can review all the changes by taking a look at the following commit statement: https://github.com/aheusingfeld/photooapp/commit/eb9fb0d8b46c50c27a8fdb1e2c01a498fed4b136
Please leave a comment if you have any questions or good advice for improving the blog post series. Thanks in advance.

Further links

Other blog posts of this series

2 Kommentare:

  1. Thank you for posting this article! Even I have not much experience with Spring Roo yet because my last projects just used Spring directly or indirectly through Grails but the solution for a Spring Web MVC or Grails powered application looks nearly identical.

    While reading first I thought that mapping typical Spring exception classes to internationalized messages would not always lead to exactly one possible cause but you addressed this issue as you allow to find the correct message based on the exception class and a part of the original exception message.

    Thank you for sharing!
    Stefan

    AntwortenLöschen
  2. Thanks for sharing in English. Keep doing it please, my German is a little bit rusty. Tschüss.

    AntwortenLöschen