Hi I am using spring boot micro service in my project. I have created a controller annotated with RestController something like this
@RestController
public class SellerStateResource implements ISellerStateResource {
public ApiResponseEntity getSellerSate()
And then I have created global controller Advice class
@ControllerAdvice(annotations = RestController.class)
public class SelfHelpControllerAdvice extends ResponseEntityExceptionHandler{
@SuppressWarnings("rawtypes")
@ExceptionHandler(Exception.class)
public ApiResponseEntity handleGenericException(Exception ex, HttpServletRequest request) {
long startTime = System.currentTimeMillis();
ApiResponseEntity response = new ApiResponseEntity<>();
ApiResponseMetaData responseMetaData = ApiResponseMetaDataGenerator
.getResponseMetadata(System.currentTimeMillis() - startTime, false, request.getRequestURI(), "test");
response.setResponseMetadata(responseMetaData);
System.out.println(response);
return response;
}
When ever I get an exception,it comes over here but then it returns spring boot by default resposne
{
"timestamp": 1459879962341,
"status": 404,
"error": "Not Found",
"exception": "java.io.IOException",
"message": "No message available",
"path": "/sellers/state"
}
but whenever i place this ExceptionHandler in RestController ,it gives me custom response.
Comment From: wilkinsona
@iveeshal It's hard to know what's going on as you haven't provided details of everything that's involved. Can you please provide a small sample app that reproduces the problem?
Comment From: spring-projects-issues
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Comment From: spring-projects-issues
Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.
Comment From: anddero
I have the same issue. I have a huge project with an ErrorController
and an @ExceptionHandler
method inside the @ControllerAdvice
bean. But when an exception is thrown from a controller, it is handled by my ErrorController
implementation without reaching the @ExceptionHandler
. But we know the @ExceptionHandler
is detected, because only if the ErrorController
further throws the exception, then it reaches the @ExceptionHandler
. But shouldn't the @ExceptionHandler
be preferred by Spring Boot in the first place? Even when I remove my ErrorController
, Spring Boot prefers its BasicErrorController
to my @ExceptionHandler
.
It is very difficult to reproduce this issue, because when I create a fresh Spring Boot project, this issue does not occur, and @ExceptionHandler
is preferred to the custom ErrorController
implementation.
Because you are the developers and know more about the implementation details. What do you suggest could be the issue? I am trying as hard as I can to reproduce it meanwhile to provide you an answer.
Comment From: anddero
Okay, I have found the reason.
The Issue
Your @ControllerAdvice
extends ResponseEntityExceptionHandler
which defines several methods to handle different kind of exceptions (including your 404 case).
Therefore, if you use that class as your base class, without overriding those methods, then they will get handled in the default way.
The Solution
Either remove the extends ResponseEntityExceptionHandler
and your method will be used...
OR
Override all the methods of ResponseEntityExceptionHandler
with your custom implementation.
(I personally prefer the first solution, because it is simpler and you can have a more general approach like @ExceptionHandler(Throwable.class)
to return an error response without much repeated code.)
Comment From: mun-creative
@RestControllerAdvice is not working .
Controller: package com.apps.developerblog.app.ws.ui.controller;
import java.util.HashMap; import java.util.Map; import java.util.UUID;
import javax.validation.Valid;
import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;
import com.apps.developerblog.app.ws.ui.model.request.UpdateUserRequestModel; import com.apps.developerblog.app.ws.ui.model.request.UserDetailsRequestModel; import com.apps.developerblog.app.ws.ui.model.response.UserRest;
@RestController
@RequestMapping("/users") // http://localhost
public class UserController {
Map
@GetMapping(path = "/{userId}", produces = { MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<UserRest> getUser(@PathVariable("userId") String userId) {
/*
* UserRest user = new UserRest(); user.setFirstName("Medha");
* user.setLastName("Pundir"); user.setEmail("medha.pundir@gmail.com");
* user.setUserId(userId);
*/
// return ResponseEntity.ok(user);
try {
String firstName = null;
int firstNameLength = firstName.length();
if (users.containsKey(userId)) {a
return new ResponseEntity<UserRest>(users.get(userId), HttpStatus.OK);
} else {
return new ResponseEntity<UserRest>(HttpStatus.NO_CONTENT);
}
} catch (Exception e) {
throw e;
}
}
/*
* @GetMapping public String getUsers(@RequestParam(value = "page", defaultValue
* = "2") int page,
*
* @RequestParam(value = "limit") int limit,
*
* @RequestParam(value = "sort", defaultValue = "desc", required = false) String
* sort) { return "get User was called with page=" + page + " limit =" + limit +
* " and sort=" + sort; }
*/
@PostMapping(consumes = { MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE }, produces = {
MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<UserRest> createUser(@Valid @RequestBody UserDetailsRequestModel userDetails) {
String userId = UUID.randomUUID().toString();
UserRest returnValue = new UserRest();
returnValue.setEmail(userDetails.getEmail());
returnValue.setFirstName(userDetails.getFirstName());
returnValue.setLastName(userDetails.getLastName());
returnValue.setUserId(userId);
if (users == null)
users = new HashMap<>();
users.put(userId, returnValue);
return new ResponseEntity<UserRest>(returnValue, HttpStatus.OK);
}
@PutMapping(path = "/{userId}", consumes = { MediaType.APPLICATION_XML_VALUE,
MediaType.APPLICATION_JSON_VALUE }, produces = { MediaType.APPLICATION_XML_VALUE,
MediaType.APPLICATION_JSON_VALUE })
public UserRest updateUser(@PathVariable String userId,
@Valid @RequestBody UpdateUserRequestModel userDetailsRequestModel) {
UserRest storedUserDetails = users.get(userId);
storedUserDetails.setFirstName(userDetailsRequestModel.getFirstName());
storedUserDetails.setLastName(userDetailsRequestModel.getLastName());
users.put(userId, storedUserDetails);
return storedUserDetails;
}
@DeleteMapping(path = "/{userId}")
public ResponseEntity<String> deleteUser(@PathVariable String userId) {
if (users.containsKey(userId)) {
users.remove(userId);
return new ResponseEntity<String>("User Deleted ", HttpStatus.OK);
} else {
return new ResponseEntity<String>("User Not Deleted ", HttpStatus.NOT_FOUND);
}
}
}
ExceptionHandler: package com.apps.developerblog.ws.exception;
import javax.validation.ConstraintViolationException;
import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.servlet.NoHandlerFoundException;
/* * * / @RestControllerAdvice public class GlobalControllerExceptionHandler {
@ExceptionHandler(value = { ConstraintViolationException.class })
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiErrorResponse constraintViolationException(ConstraintViolationException ex) {
return new ApiErrorResponse(500, 5001, ex.getMessage());
}
@ExceptionHandler(value = { NoHandlerFoundException.class })
@ResponseStatus(HttpStatus.NOT_FOUND)
public ApiErrorResponse noHandlerFoundException(Exception ex) {
return new ApiErrorResponse(404, 4041, ex.getMessage());
}
@ExceptionHandler(value = { Exception.class })
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ApiErrorResponse unknownException(Exception ex) {
return new ApiErrorResponse(500, 5002, ex.getMessage());
}
}
Error Class: package com.apps.developerblog.ws.exception;
/* * / public class ApiErrorResponse {
private int status;
private int code;
private String message;
public ApiErrorResponse(int status, int code, String message) {
this.status = status;
this.code = code;
this.message = message;
}
public int getStatus() {
return status;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
@Override
public String toString() {
return "ApiErrorResponse{" + "status=" + status + ", code=" + code + ", message=" + message + '}';
}
}
pom.xml
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml/jackson-xml-databind -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.9.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
application.properties:
spring.mvc.throw-exception-if-no-handler-found=true spring.resources.add-mappings=false
Comment From: mun-creative
Please help
Comment From: bclozel
@mun-creative please create a question on StackOverflow. We're using this issue tracker for bugs and enhancement requests only.
You'll need a minimal project that reproduces the problem - this often help to find the configuration problem, or at least makes it easier for others to help you.
Thanks!
Comment From: mun-creative
ok thanks