Java Ninja Chronicles By Norris Shelton

Things I learned in the pursuit of code

I like to use SpringMVC for my JSON controllers. I do not prefer to return HTTP status codes other than 200, but sometimes you don’t have a choice. I was working on a project where the service would return the requested resource when it is available. If the resource is not found, then it is supposed to return an HTTP status of 404 with a messages. I thought this would be included right out of the box, but it wasn’t.

What Spring MVC offers and why it didn’t work

With Spring MVC, you have the ability to define an exception and have that exception return a specified HTTP status code when it reaches the controllers. Here is what an exception class would look like:

package com.twinspires.brisdataapi.bdsserver.exceptions;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

/**
 * @author norris.shelton
 */
@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class NotFoundException  extends RuntimeException {
    /**
     * Constructs a new runtime exception with the specified detail message.
     * The cause is not initialized, and may subsequently be initialized by a
     * call to {@link #initCause}.
     * @param message the detail message. The detail message is saved for later retrieval by the {@link #getMessage()}
     *                method.
     */
    public NotFoundException(String message) {
        super(message);
    }
}

This does provide a way to specify a message, but it doesn’t get displayed when a message is returned by the controllers. Ugh.

This would provide a good start, but I would need an exception handler to get the message. Unfortunately, all of the examples of the exception handlers show a method per exception.

Doing the least to make it work

This details the changes that I needed to make to allow the service to function correctly. I wanted to create as few classes as possible.

Define an exception

I created an exception that extends RuntimeException. I didn’t add a @ResponseStatus because I didn’t want to have to make an exception for each status code. I created a constructor that takes an HTTP status code and a message. This allows me to have one exception that I can reuse in all of my controllers and always return the correct status and message.

package com.twinspires.brisdataapi.bdsserver.exceptions;

import org.springframework.http.HttpStatus;

/**
 * @author norris.shelton
 */
@SuppressWarnings("ClassWithoutNoArgConstructor")
public class BdsServiceException extends RuntimeException {

    private HttpStatus httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;

    public HttpStatus getHttpStatus() {
        return httpStatus;
    }

    /**
     * Constructs a new runtime exception with the specified detail message.
     * The cause is not initialized, and may subsequently be initialized by a
     * call to {@link #initCause}.
     * @param message the detail message. The detail message is saved for later retrieval by the {@link #getMessage()}
     *                method.
     */
    public BdsServiceException(HttpStatus httpStatus, String message) {
        super(message);
        this.httpStatus = httpStatus;
    }
}

Define SpringMVC exception handler

Now that I have an exception that has all of the information that I want returned to the caller of my service, I need to define an exception handler. It is the same type of exception handler that you normally see, except it returns a ResponseEntity. With the ResponseEntity, I can return the retrieve the correct status code and message from the exception and return them to the caller.

package com.twinspires.brisdataapi.bdsserver.spring;

import com.twinspires.brisdataapi.bdsserver.exceptions.BdsServiceException;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class ExceptionHandlerAdvice { 
 
    @ExceptionHandler(BdsServiceException.class)
    public ResponseEntity handleException(BdsServiceException e) {
        // log exception 
        return ResponseEntity.status(e.getHttpStatus()).body(e.getMessage());
    }         
} 

Putting it to use

All that is left is throwing the exception. I threw the exception with the desired HTTP status code and the message.

            throw new ResourceException(HttpStatus.NOT_FOUND, "We were unable to find the specified resource.");

June 22nd, 2016

Posted In: Java, java ninja, Javaninja, Spring, Spring MVC

4 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

LinkedIn Auto Publish Powered By : XYZScripts.com