Tag Archives: Spring MVC

Spring REST API hardening – exceptions handling

For some time now there’s a lot of discussion over the internet on the definition of a unified RESTful API standard (architecture, design, interfaces, etc.). RFC’s are being discussed by IETF committees trying to come up with a standard, work continues on re-designing the HTTP protocol itself (HTTPbis, by the IETF HTTPbis WG chaired by Mark Nottingham), but what we have thus far are only good and bad practices…

 

What i’d like to address in this post are good practices related to exceptions handling in a Java Spring MVC based RESTful API application.

 

Let’s start with this: In order to make your REST API more developer-friendly, you may want your MVC controllers to return (within the body of the response), some information that can assist the client developer while using your API.

 

Using a JSON data format, a sample controller response in situation of an exception may look like this:

{
    "code" : "SAE00202",
    "status" : "SECURITY_AUTHORITY_ERROR",
    "errors" : [ "Security Exception: Insufficient Authorization Level. Access denied" ]
}

 

Here’s an example of how you can achieve that easily using Spring MVC’s @ControllerAdvice annotation (which indicates the annotated class assists a “Controller” and serves as a specialization of @Component annotation, allowing implementation classes to be auto-detected through classpath scanning).

@ControllerAdvice
public class BusinessExceptionHandler extends DefaultExceptionHandler {

    @ExceptionHandler(IncompleteUserProfileException.class)
    @ResponseStatus(value = HttpStatus.PRECONDITION_FAILED)
    @ResponseBody DefaultErrorMessage handleIncompleteUserProfileException(IncompleteUserProfileException e) {

        if(debug) logException(e);

        String error = getResourceBundle().getMessage("exception.user.profile.incomplete", null, Locale.getDefault());

        return new DefaultErrorMessage("RS00302", "BUSINESS_ERROR", error);

    }

}

 

Aside from the fact that you may want to write custom handlers like the one above for your application-specific exceptions (Business/Security/Validation related, etc.), you may also want to “go deeper” and extend the ResponseEntityExceptionHandler class (abstract), and override the default implementation of the exceptions below; thrown usually by MVC Controllers:

Spring MVC ResponseEntityExceptionHandler Exceptions

 

In order to do that, first you have to start with a simple POJO representing your default error message:

public class DefaultErrorMessage {
    private String code;
    private String status;
    private List errors = new ArrayList<>();

    public DefaultErrorMessage(String code, String status, String error) {
        this.code = code;
        this.status = status;
        this.errors.add(error);
    }

    public DefaultErrorMessage(String code, String status, List errors) {
        this.code = code;
        this.status = status;
        this.errors = errors;
    }

    // getters and setters omitted
}

 

Having this in place, a custom implementation of BindException may look like this:

@ControllerAdvice
public class CustomResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {

    @Override
    protected ResponseEntity<Object> handleBindException(BindException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

        List<String> errors = new ArrayList<>(ex.getAllErrors().size());
        List<FieldError> fieldErrors = ex.getFieldErrors();
        StringBuilder sb;

        for (FieldError fieldError : fieldErrors) {
            sb = new StringBuilder();
            sb.append("Field: ").append(fieldError.getField()).append(", ");
            sb.append("Value: ").append(fieldError.getRejectedValue()).append(", ");
            sb.append("Message: ").append(fieldError.getDefaultMessage());
            errors.add(sb.toString());
        }

        List<ObjectError> globalErrors = ex.getGlobalErrors();

        for (ObjectError objectError : globalErrors) {
            sb = new StringBuilder();
            sb.append("Object: ").append(objectError.getObjectName()).append(", ");
            sb.append("Code: ").append(objectError.getCode()).append(", ");
            sb.append("Message: ").append(objectError.getDefaultMessage());
            errors.add(sb.toString());
        }

        DefaultErrorMessage errorMessage = new DefaultErrorMessage("RQ00051", "RQ_BODY_VALIDATION_ERROR", errors);
        return new ResponseEntity(errorMessage, headers, status);

    }

}

 

I think you see the direction it’s heading in…

 

Happy coding 🙂

Cheers!

 

 

Resources:

Advertisements

Spring localized exception handling in REST API

In today’s post i’ll share with you the way we’re handling Internationalization (i18n) and Localization (L10n) in our REST API which is based on Spring MVC (3.2.3.RELEASE).

Our front-end web client is an SPA (Single Page Application) built using AngularJS framework and occasionally it needs to handle Java exceptions messages thrown by the back-end. The way it has been implemented is that it intercepts JSON error responses, wraps them in a pre-defined web page template and displays to the user in a unified and nice way.

“Localization” of back-end related error messages happens …at the back-end level.

 

After this quick intro let’s get familiar with following two definitions:

  • Internationalization – process of designing software applications so that they can be adapted to various languages and regions without engineering changes.
  • Localization – process of adapting internationalized applications for a specific region or language by adding locale-specific components and translating text.

OK, this is how message bundles look like:

// messages.properties
exception.npe=Unrecognized error: We're sorry.
(...)

and the project view so you get a feel on how maven-managed multi-module project is structured (i use IntelliJ IDEA)

Spring REST API

 

The ‘resourceBundle’ spring bean is located in ‘spring-locale-context.xml’

<bean id="resourceBundle"
      class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
      p:basename="classpath:locale/messages"
      p:cacheSeconds="5"
      p:defaultEncoding="UTF-8" />

 

As you can see i’m using ‘ReloadableResourceBundleMessageSource‘ which i prefer over ‘ResourceBundleMessageSource‘ – here’s why (according to Spring framework spec.)

  • ResourceBundleMessageSource – MessageSource implementation that accesses resource bundles using specified basenames. This class relies on the underlying JDK’s ResourceBundle implementation, in combination with the JDK’s standard message parsing provided by MessageFormat. This MessageSource caches both the accessed ResourceBundle instances and the generated MessageFormats for each message. It also implements rendering of no-arg messages without MessageFormat, as supported by the AbstractMessageSource base class. The caching provided by this MessageSource is significantly faster than the built-in caching of the java.util.ResourceBundle class. Unfortunately, java.util.ResourceBundle caches loaded bundles forever: Reloading a bundle during VM execution is not possible. As this MessageSource relies on ResourceBundle, it faces the same limitation. Consider ReloadableResourceBundleMessageSource for an alternative that is capable of refreshing the underlying bundle files.
  • ReloadableResourceBundleMessageSource – Spring-specific MessageSource implementation that accesses resource bundles using specified basenames, participating in the Spring ApplicationContext‘s resource loading. In contrast to the JDK-based ResourceBundleMessageSource, this class uses Properties instances as its custom data structure for messages, loading them via a PropertiesPersister strategy from Spring Resource handles. This strategy is not only capable of reloading files based on timestamp changes, but also of loading properties files with a specific character encoding. It will detect XML property files as well. In contrast to ResourceBundleMessageSource, this class supports reloading of properties files through the "cacheSeconds" setting, and also through programmatically clearing the properties cache. Since application servers typically cache all files loaded from the classpath, it is necessary to store resources somewhere else (for example, in the “WEB-INF” directory of a web app). Otherwise changes of files in the classpath will not be reflected in the application. This MessageSource implementation is usually slightly faster than ResourceBundleMessageSource, which builds on ResourceBundle – in the default mode, i.e. when caching forever. With “cacheSeconds” set to 1, message lookup takes about twice as long – with the benefit that changes in individual properties files are detected with a maximum delay of 1 second. Higher “cacheSeconds” values usually do not make a significant difference.

 

Now, let’s make our resourceBundle accessible to exception handlers:

public class AbstractExceptionHandler {

    @Autowired
    private ReloadableResourceBundleMessageSource resourceBundle;

    public ReloadableResourceBundleMessageSource getResourceBundle() {
        return resourceBundle;
    }

    public void setResourceBundle(ReloadableResourceBundleMessageSource resourceBundle) {
        this.resourceBundle = resourceBundle;
    }

}

 

Create an MVC REST Controller:

@Controller
@RequestMapping(value = "/users")
public class UserController {

    @Autowired
    private UserService service;

    /**
     * Handling GET request to retrieve all {@link User}'s
     * @return Collection<User> a collection of users
     */
    @RequestMapping(method = RequestMethod.GET)
    public @ResponseBody
    Collection<User> getUsers() {
        return service.findAllUsers();
    };

}

 

…and an exception handler that will intercept (NPE in this case) exceptions thrown by the controller:

@ControllerAdvice
public class BusinessExceptionHandler extends AbstractExceptionHandler {

    @ExceptionHandler(NullPointerException.class)
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody DefaultErrorMessage handleNullPointerException() {

        String error = getResourceBundle().getMessage("exception.npe", null, Locale.getDefault());

        return new DefaultErrorMessage("RS00230", "SYSTEM_ERROR", error);

    }

}

 

As you can see above, I did two things:

  • fed the error string with exception.npe message that comes from the message bundle and used Locale.getDefault()
  • and defined a custom DefaultErrorMessage which basically is a POJO send over to the client as a JSON response which looks like this:
{
  "code" : "RS00230",
  "status" : "SYSTEM_ERROR",
  "errors" : [ "Unrecognized error: We're sorry." ]
}

 

Hope you find this brief example helpful. Cheers!

 

 

Resources: