[JAVA] I want to control the default error message of Spring Boot

Purpose

I want to control the default error message returned when an error occurs in the REST API created by Spring Boot.

background

Suppose you have prepared the following RestController.

MyRestController.java


package demo;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyRestController {
    
    @RequestMapping(value="/test/{id}")
    private String hello(@PathVariable String id){
        if ("0000".equals(id)) {
            throw new MyCustomException(); //Expected Exception
        }
        
        return "Hello world!!";
    }

    @RequestMapping(value="/test-null")
    private String hello(){
        String s = null;
        s.equals("hoge"); //Inadvertent NPE outbreak
        
        return "Hello world!!";
    }
}

Spring Boot will then return the following error message by default.

$ curl http://localhost:8080/test/0000 #Expected MyCustomError
{"timestamp":1526654632290,"status":500,"error":"Internal Server Error","exception":"my.spring.MySpringBootSample.MyCustomError","message":"No message available","path":"/test/0000"}%
$ curl http://localhost:8080/test-null #NPE that I accidentally put out
{"timestamp":1526654636310,"status":500,"error":"Internal Server Error","exception":"java.lang.NullPointerException","message":"No message available","path":"/test-null"}%
$ curl http://localhost:8080/wrong-path #Wrong path
{"timestamp":1526654639289,"status":404,"error":"Not Found","message":"No message available","path":"/wrong-path"}%

However, it's too cool and not good for security to see the NullPointerException that happened accidentally to the user. I'm also exposed to using Spring Boot.

Controlling possible errors

By preparing a class with @ControllerAdvice annotation, it is possible to control error messages across RestController.

MyControllerAdvice.java


package demo;

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

@ControllerAdvice
public class MyControllerAdvice {

    /**
     *Handler when MyCustomException occurs
     * 
     * @return response
     */
    @ExceptionHandler(MyCustomException.class)
    public ResponseEntity<String> handleControllerException() {
        return new ResponseEntity<String>("customized message for MyCustomError.", HttpStatus.INTERNAL_SERVER_ERROR);
    }
}
$ curl http://localhost:8080/test/0000
customized message for MyCustomError.%

Control against unexpected errors

In addition to the above, if you create an ExceptionHandler that receives Exception.class, it is possible to return a custom error message uniformly for all unexpected errors that occur in RestController.

MyControllerAdvice.java


package demo;

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

@ControllerAdvice
public class MyControllerAdvice {

    /**
     *Handler when MyCustomException occurs
     * 
     * @return response
     */
    @ExceptionHandler(MyCustomException.class)
    public ResponseEntity<String> handleControllerException() {
        return new ResponseEntity<String>("customized message for MyCustomError.", HttpStatus.INTERNAL_SERVER_ERROR);
    }
    
    /**
     *Handler when an Exception occurs
     * 
     * @return response
     */
    @ExceptionHandler(Exception.class)
    public ResponseEntity<String> handleControllerException2() {
        return new ResponseEntity<String>("customized message for any unexpected exception.", HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

However, this method does not control errors before entering RestController, such as incorrect paths.

$ curl http://localhost:8080/test/0000
customized message for MyCustomError.%
$ curl http://localhost:8080/test-null
customized message for any unexpected exception.%
$ curl http://localhost:8080/wrong-path #Default error is returned for wrong path
{"timestamp":1526655182855,"status":404,"error":"Not Found","message":"No message available","path":"/wrong-path"}%

When I looked it up, it was [Official](https://docs.spring.io/spring-boot/docs/1.5.3.RELEASE/reference/html/boot-features-developing-web-applications.html#boot-features -error-handling) has the following description.

Spring Boot provides an /error mapping by default that handles all errors in a sensible way, and it is registered as a ‘global’ error page in the servlet container.

The point is that every error is mapped under / error by default. If you want to control it as you like, realize ErrorController, so prepare the following class.

MyErrorController.java


package demo;

import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyErrorController implements ErrorController {

    @RequestMapping("/error")
    public ResponseEntity<String> handleError() {
        return new ResponseEntity<String>("customized message for any unhandled error.", HttpStatus.INTERNAL_SERVER_ERROR);
    }

    @Override
    public String getErrorPath() {
        return "/error";
    }
}

Then, the default error message disappeared.

$ curl http://localhost:8080/test/0000
customized message for MyCustomError.%
$ curl http://localhost:8080/test-null
customized message for any unexpected exception.%
$ curl http://localhost:8080/wrong-path
customized message for any unhandled error.%

Recommended Posts

I want to control the default error message of Spring Boot
05. I tried to stub the source of Spring Boot
I tried to reduce the capacity of Spring Boot
I want to understand the flow of Spring processing request parameters
I want to control the maximum file size in file upload for each URL in Spring Boot
I want to output the day of the week
The story of raising Spring Boot 1.5 series to 2.1 series
I want to display an error message when registering in the database
I want to know the Method of the Controller where the Exception was thrown in the ExceptionHandler of Spring Boot
I want to control the start / stop of servers and databases with Alexa
I want to know the answer of the rock-paper-scissors app
I want to be aware of the contents of variables!
I want to return the scroll position of UITableView!
The story of raising Spring Boot from 1.5 series to 2.1 series part2
About the function of Spring Boot due to different versions
I want to change the log output settings of UtilLoggingJdbcLogger
I want to narrow down the display of docker ps
[Ruby] I want to reverse the order of the hash table
I want to temporarily disable the swipe gesture of UIPageViewController
Going out of message (Spring boot)
I want to control the display of the upper management navigation bar (Control menu) in Liferay 7 / DXP
I want to change the color of the upper control navigation bar (Control menu) in Liferay 7 / DXP
The story of Collectors.groupingBy that I want to keep for posterity
I tried to translate the error message when executing Eclipse (Java)
What I did in the migration from Spring Boot 1.4 series to 2.0 series
I want to limit the input by narrowing the range of numbers
What I did in the migration from Spring Boot 1.5 series to 2.0 series
I want to change the value of Attribute in Selenium of Ruby
I want to eliminate duplicate error messages
[Spring Boot] I want to add my own property file and get the value with env.getProperty ().
I want to make the frame of the text box red when there is an input error
About the error message Invalid redeclaration of'***'
How to split Spring Boot message file
I want to write JSP in Emacs more easily than the default.
I want to display the number of orders for today using datetime.
Spring Boot + MyBatis I get this error if I don't set the database
Procedure to make the value of the property file visible in Spring Boot
I want to know the JSP of the open portlet when developing Liferay
[Ruby] I want to extract only the value of the hash and only the key
I used Docker to solidify the template to be developed with spring boot.
I want to pass the argument of Annotation and the argument of the calling method to aspect
My memorandum that I want to make ValidationMessages.properties UTF8 in Spring Boot
I want to get the field name of the [Java] field. (Old tale tone)
I want you to use Enum # name () for the Key of SharedPreference
How to find the cause of the Ruby error
[FCM] Implementation of message transmission using FCM + Spring boot
I wanted to gradle spring boot with multi-project
[Spring Boot] How to refer to the property file
I want to get the value in Ruby
I want to get the value of Cell transparently regardless of CellType (Apache POI)
03. I sent a request from Spring Boot to the zip code search API
When you want to notify an error somewhere when using graphql-spring-boot in Spring Boot
I tried to clone a web application full of bugs with Spring Boot
Starting with Spring Boot 2.3, the default error page no longer contains detailed error information
How to set environment variables in the properties file of Spring boot application
I want to separate the handling of call results according to the API caller (call trigger)
[Ruby on Rails] How to Japaneseize the error message of Form object (ActiveModel)
I want to see the contents of Request without saying four or five
I want to recursively get the superclass and interface of a certain class
[Ruby] I want to make a program that displays today's day of the week!
Rails The concept of view componentization of Rails that I want to convey to those who want to quit