ResponseEntityExceptionHandler error with new Spring Boot version - java

Although I could use ResponseEntityExceptionHandler with the previous Spring Boot versions as shown on this example, I get the following error for the handleExceptionInternal method when I implement the same exception handler in my new app (Spring Boot version 3.0.2):
Method does not override method from its superclass
So, I can fix the problem by not extending ResponseEntityExceptionHandler, but I am not sure if there is a better way to fix this problem.
Any idea for this problem?

The signature of the method is different so now you get that error. Check signature here.
Basically what you need to change is: HttpStatus --> HttpStatusCode
Here is an example of overriding this method:
#Override
protected ResponseEntity<Object> handleExceptionInternal(Exception ex,
Object body,
HttpHeaders headers,
HttpStatusCode statusCode,
WebRequest request){
//your code here....
}

Related

Spring Boot: Custom exception adds prefix to the exception message

In a Spring Boot app, I created a custom GlobalExceptionHandler and add the following method to handle ConstraintViolationException for invalid file type during upload process:
#ExceptionHandler(ConstraintViolationException.class)
#ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
public ResponseEntity<Object> handleConstraintViolationException(
ConstraintViolationException ex,
WebRequest request) {
log.error("Invalid file type.", ex);
return buildErrorResponse(ex, HttpStatus.UNPROCESSABLE_ENTITY, request);
}
My buildErrorResponse works correctly and build proper responses for other handle methods. However, It adds "uploadFile.file:" prefix to my error message.
My questions:
Is there any problem with my handleConstraintViolationException implementation? If not, how can I fix that problem?
I think there is no need to create custom exception class as shown below for the exceptions that is already defined in javax.validation like ConstraintViolationException. Is that true?
Note: If you need to have a look at my GlobalExceptionHandler, it is something like on this GitHub.
Answer For Question 1: Your implementation not wrong but have some missing properties. For best practice to my opinion you can create a class to use it for error response which can contains like statusCode,timestamp,message,description.
You can use method like this in your handleConstraintViolationException method:
private ResponseEntity<ErrorMessage>generateErrorMessage(ConstraintViolationException ex, WebRequest request){
ErrorMessage errorMessage = new ErrorMessage.ErrorMessageBuilder()
.statusCode(HttpStatus.BAD_REQUEST.value())
.timeStamp(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss").format(LocalDateTime.now()))
.message(ex.getMessage())
.description(request.getDescription(false))
.build();
return new ResponseEntity<>(errorMessage, HttpStatus.BAD_REQUEST);
}

Spring boot change override exception responses

I am trying to customize exception responses and use my own response structure, I am using below way :
#ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler
{
#ExceptionHandler(RuntimeException.class)
#ResponseBody
public ResponseEntity<String> handle(Exception ex, HttpServletRequest request)
{
...
}
}
But I have not accessed to the status code, I need status code that defined in exceptions via ResponseStatus:
#ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
public class ExtendSubscriptionReminderNotExistException extends RuntimeException
{
}
With java reflection mechanism, you can do it like so:
#ExceptionHandler(RuntimeException.class)
#ResponseBody
public ResponseEntity<String> handle(Exception ex, HttpServletRequest request) {
if (ex instanceOf ExtendSubscriptionReminderNotExistException) {
ResponseStatus status = ExtendSubscriptionReminderNotExistException.class.getAnnotation(ResponseStatus.class);
return ResponseEntity.status(status.value()).body(ex.getMessage());
}else{
//if it's not ExtendSubscriptionReminderNotExistException, do sth different
}
}
Here is an useful article on how to read annotation in java: Java Reflection - Annotations
If you want to override ResponseStatusExceptionResolver, then you should extends AbstractHandlerExceptionResolver and implement your own doResolveException like ResponseStatusExceptionResolver did, then create a configuration extending WebMvcConfigurationSupport and override configureHandlerExceptionResolvers, then spring will pick up your own exception resolver over the default one. The logic behind this is here.
we cannot change exception messages. However determine we can change the code and class, and throw a new one by overriding the same class with the same code and different message.
I may be wrong on this one, but to me it doesn't really make sense to use #ResponseStatus annotation and a custom ErrorHandler at the same time.
Annotations are supposed to make your code easier to understand and to avoid using such handlers.
If you really want to use the handler, I'd suggest to drop the annotation and store the corresponding status code in each exception (as a final static attribute for example).

Swagger - Render response status for declared exception

I'm doing my REST documentation with swagger. I've set it up and got access on SwaggerUi and also see all my configured REST resources with their supported methods.
In my backend I have a ControllerAdvice, which does a global exception handling for all my controllers. A example exception which gets handled in the controller advice is ResourceAlreadyExistsException, when I try to create a resource which already exists, obviously. In that case my exception handler responds with a 409 CONFLICT status code.
#ExceptionHandler(value = ResourceAlreadyExistsException.class)
#ResponseStatus(HttpStatus.CONFLICT)
protected ErrorResponse handleResourceAlreadyExists(ResourceAlreadyExistsException ex, WebRequest request) {
return new ErrorResponse(ex.getMessage());
}
With this pre-condition, my create method which is mapped in the REST controller looks like this:
#RequestMapping(method = POST)
#ResponseStatus(HttpStatus.CREATED)
public RoleDto createRole(#RequestBody RoleDto roleDto) throws ResourceAlreadyExistsException {
return roleManager.createRole(roleDto);
}
With the default configuration, Swagger only shows me 201 as possible response code. Although 409 is possible too.
Of course I could add the #ApiResponse(code = 409, message = "Role already exists") definition to the createRole() method, but this seems double information as I already imply that by throwing the exception.
How can I tell swagger, that if a ResourceAlreadyExistsException can be be thrown, 409 is also a possible response code?
I've tried defining #ApiResponse on the ResourceAlreadyExistsException, but that didn't work.
That feature does not exist yet in SpringFox, although they have been looking for someone to implement it for quite some time now.
https://github.com/springfox/springfox/issues/521

Spring Boot how to ignore HttpStatus Exceptions

I'm building an Application using Spring Boot. This application is distributed, which means I have multiple API's that call each others.
One of my underlying services interacts with a database and responds with the requested data. If a request to an unexisting ID is made, I response with a 404 HttpStatus:
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
(Same with 400 error on certain operations, or 204 for deleting an entry etc).
The problem is that I have some other Spring Boot applications that call these API's, throw an org.springframework.web.client.HttpClientErrorException: 404 Not Found Exception when they request, in this example, an unexisting entry. But the 404 status code is intended and should not return this exception (causing my Hystrix circuit breaker to call its fallback function).
How can I solve this problem?
The call to the service is implemented like this in my code: ResponseEntity<Object> data = restTemplate.getForEntity(url, Object.class);
My RestTemplate is set up like this:
private RestTemplate restTemplate = new RestTemplate();
Spring's RestTemplate uses a ResponseErrorHandler to handle errors in responses. This interface provides both a way to determine if the response has an error (ResponseErrorHandler#hasError(ClientHttpResponse)) and how to handle it (ResponseErrorHandler#handleError(ClientHttpResponse)).
You can set the RestTemplate's ResponseErrorHandler with RestTemplate#setErrorHandler(ResponseErrorHandler) whose javadoc states
By default, RestTemplate uses a DefaultResponseErrorHandler.
This default implementation
[...] checks for the status code on the
ClientHttpResponse: any code with series
HttpStatus.Series.CLIENT_ERROR or HttpStatus.Series.SERVER_ERROR is
considered to be an error. This behavior can be changed by overriding
the hasError(HttpStatus) method.
In case of an error, it throws the exception you are seeing.
If you want to change this behavior, you can provide your own ResponseErrorHandler implementation (maybe by overriding DefaultResponseErrorHandler) which doesn't consider 4xx as an error or that doesn't throw an exception.
For example
restTemplate.setErrorHandler(new ResponseErrorHandler() {
#Override
public boolean hasError(ClientHttpResponse response) throws IOException {
return false; // or whatever you consider an error
}
#Override
public void handleError(ClientHttpResponse response) throws IOException {
// do nothing, or something
}
});
You can then check the status code of the ResponseEntity returned by getForEntity and handle it yourself.

Returning JSON with spring on 404 in XML free project

I am currently setting up a Spring MVC application (version 4.1.4.RELEASE) and I want the application to return a JSON string on a 404 error rather than the default html response. I am using Tomcat 8 as my server. I have what I think should be correct, however it isn't behaving in the manner that I expect. What I'm trying to do is based off of this answer.
public class SpringWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer{
...
#Override
protected void customizeRegistration(ServletRegistration.Dynamic registration){
registration.setInitParameter("throwExceptionIfNoHandlerFound","true");
}
}
and then I have an exception controller (which is different than the question I based my solution off of, however I don't believe that is an issue as I am under the impression that #ControllerAdvice is an acceptable way to manage this based off of the Spring Docs. It looks something like:
#ControllerAdvice
public class GlobalExceptionController{
#ResponseStatus(value=HttpStatus.NOT_FOUND)
#ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public Message handleMethodNotSupported(HttpServletRequest request){
...
}
#ResponseStatus(value=HttpStatus.NOT_FOUND)
#ExceptionHandler(NoSuchRequestHandlingMethodException.class)
public Message handleBadRequest(HttpServletRequest request){
...
}
#ResponseStatus(value=HttpStatus.NOT_FOUND)
#ExceptionHandler(NoHandlerFoundException.class)
public Message requestHandlingNoHandlerFound(HttpServletRequest request){
...
}
...
}
It continues to send back the default response. I know for a fact that it is hitting my customizeRegistration() function because breakpoints stop it, however, any breakpoints that I have in my GlobalException class are not hit. Also, the GlobalException class is within a package that is hit by a #ComponentScan() annotation, so I am fairly confident that it is also being handled by spring.
I assume I'm missing something obvious, any help would be greatly appreciated.
I don't think the return type you're trying to use is supported. Have you tried changing your return value to ResponseEntity or adding a #ResponseBody annotation?
From the docs:
A ModelAndView object (Servlet MVC or Portlet MVC).
A Model object, with the view name implicitly determined through a RequestToViewNameTranslator.
A Map object for exposing a model, with the view name implicitly determined through a RequestToViewNameTranslator.
A View object.
A String value which is interpreted as view name.
#ResponseBody annotated methods (Servlet-only) to set the response content. The return value will be converted to the response stream
using message converters.
An HttpEntity or ResponseEntity object (Servlet-only) to set response headers and content. The ResponseEntity body will be
converted and written to the response stream using message converters.
void if the method handles the response itself (by writing the response content directly, declaring an argument of type
ServletResponse / HttpServletResponse / RenderResponse for that
purpose) or if the view name is supposed to be implicitly determined
through a RequestToViewNameTranslator (not declaring a response
argument in the handler method signature; only applicable in a Servlet
environment).

Categories