using multiple values HttpStatus in #ResponseStatus - java

I am using the Spring annotation #ResponseStatus in my Exception like
#ResponseStatus(value=HttpStatus.UNAUTHORIZED)
public class UnauthorizedException extends Exception{
}
Problem is I want to throw the same error for a number of values like HttpStatus.SC_SERVICE_UNAVAILABLE, etc..
Is there any way to use multiple values in #ResponseStatus? Thanks in advance.

No. You can't have multiple http status codes. Check http spec
If you actually want to set different status codes in different scenarios (but only one status code per response), then remove the annotation, and add it via code:
public X method(HttpServletResponse response) {
if (..) {
response.setStatus(..);
} else {
response.setStatus(..);
}
}

The only workaround that comes to mind is not using the #ResponseStatus annotation. Consider writing your own error handling code in the controller that catches the relevant exception sets the error code in the way you would prefer for that class. If it's in several controllers, consider writing an interceptor or using AOP.

You can set the response code in the HttpServletResponse class with the .setStatus() method, that you could get from the applicationContext.

Why not just create multiple exception classes and throw the appropriate one?

Related

Controller advice in Spring MVC

I have some problems regarding Controller usage in Spring.
Preferably, I would like to keep the Controller methods small and simply use them to call a Service function as follows:
#Controller
class controllerClass {
#RequestMapping("/foo/")
public void foo(Model model) {
Data returnedData = fooServiceFunction();
model.addAttribute("data", returnedData);
}
}
#Service
class serviceClass {
fooServiceFunction() {
Data data = methodCall();
methodCall2();
methodCall3();
return data;
}
}
However, in practise I have found this implementation difficult because I have found myself needing to check if the methods called from within the fooServiceFunction() succeeded or failed. I have been returning a custom 'Status' class from these functions which is passed to the controller to signal if the methods have executed successfully and/or any errors that have occurred (validation errors, etc.).
Now, this is fine if I do not need to return any data. But if I want to return data from the Service function and pass it to the Controller, this would mean I would need to make a custom class for EVERY Controller method which would contain:
a) the data.
b) the success status
which just seems unreasonable.
I have considered just throwing Exceptions to indicate a failure, but this doesn't seem proper.
Is there a better way? What is the optimal way to handle these situations? Or should I just write fat Controller methods that implement more of the application/business logic?
Thank you.
I think the best approach would be to throw a custom exception and then use a class annotated with
#ControllerAdvice
to deal with that exception and make it return a ResponseEntity customized according to your needs. This way the line
return data;
will only occur if there are no exceptions

Spring: Annotate a method with both #RequestMapping and #ExceptionHandler?

I recently stumbled upon some code that I had not seen in this form before. Maybe someone here can help me understand better what's going on.
Namely, I found a method annotated both with #RequestMapping and #ExceptionHandler. I thought that the former were for handling requests, while the latter were for handling exceptions, so I would have thought one normally uses either of both annotations, but not both at the same time.
I found the code snippet here: https://github.com/shopizer-ecommerce/shopizer/blob/2.5.0/sm-shop/src/main/java/com/salesmanager/shop/store/api/exception/RestErrorHandler.java#L24
The code snippet is:
#RequestMapping(produces = "application/json")
#ExceptionHandler(Exception.class)
#ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public #ResponseBody ErrorEntity handleServiceException(Exception exception) {
log.error(exception.getMessage(), exception);
ErrorEntity errorEntity = createErrorEntity(null, exception.getMessage(),
exception.getLocalizedMessage());
return errorEntity;
}
I have two questions:
According to the Spring documentation on #RequestMapping, un-annotated method parameters (that are not of some special type) of a #RequestMapping method are implicitly annotated with #ModelAttribute (see "Any other argument" at the end of the table under the above link). So in the above code snippet, is the Exception parameter implicitly annotated with #ModelAttribute as well? And if yes, does that make sense?
Can it generally make sense to annotate a method with both #RequestMapping and #ExceptionHandler (e.g., to handle both requests and exceptions), or would that be bad form?
good question.
I would say try this. on a controller, take two methods. on one method use just RequestMethod and write a code by accepting a model attribute from page.
On this method, create a scenario for a NullPointerException.
On method 2, annotate both RequestMapping and ExceptionHandler. And you can see whether you are getting the request, response with ModelAttributes from method one to method 2.
if yes, then this would help us evaluate the exception and handle invalid scenarios where we would need the model attribute values.
Also as per the explanation that you have pasted above, ModelAttribute is implicit for RequestMapping, not for all annotations on a controller method.
Please let us know.

Catching all exceptions and returning an exception with list of messages

I'm wondering if there is any elegant way to catch all exceptions (specifically custom runtime exceptions) and return an exception containing a list of the messages.
Instead of having a String message, the big exception would then contain String[] message for example.
Scenario:
A REST request is made to the back-end with a JSON object containing a bunch of fields. I want to validate these fields on the backend and return a list of errors if any exceptions occur.
If both the name and lastname field are not acceptable input, I don't want to throw an exception on the invalid name and have the user change the name and submit again only to get an error message that the lastname is invalid too.
Hence why I want to collect all invalid input and return a list of these in the form of an exception.
Spring collects JSR-303/JSR-349 bean validation failures into a BindException:
Thrown when binding errors are considered fatal. Implements the BindingResult interface (and its super-interface Errors) to allow for the direct analysis of binding errors.
Instead of developing your own mechanism for bean validation you might want to read 3. Validation, Data Binding, and Type Conversion and follow the standards.
With Spring Boot, you can use the following annotation to handle any kind of Exception for a class or a method :
#ExceptionHandler(YourExceptionHandler.class)
And you can create a class that let you regroup all your custom exception management like this (if you want to gather it) :
#ControllerAdvice
class GlobalControllerExceptionHandler {
#ResponseStatus(HttpStatus.CONFLICT) // 409
#ExceptionHandler(DataIntegrityViolationException.class)
public void handleConflict() {
// Nothing to do
}
}
You can also implement the interface HandlerExceptionResolver to manage all Exceptions that ARE NOT handled by the Controllers (all the others runtime Exceptions)
public interface HandlerExceptionResolver {
ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex);
}
Everything is explained in details here : https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
EDIT: I just read that you added up scenario. Actually, for your special case, you should just parse the object, and return one exception (like bad object format, along with a 400 HTTP status code error, with a custom message containing all the fields that are invalid. I guess.

How to define RequestMapping prioritization

I have a situation where I need the following RequestMapping:
#RequestMapping(value={"/{section}"})
...method implementation here...
#RequestMapping(value={"/support"})
...method implementation here...
There is an obvious conflict. My hope was that Spring would resolve this automatically and map /support to the second method, and everything else to the first, but it instead maps /support to the first method.
How can I tell Spring to allow an explicit RequestMapping to override a RequestMapping with a PathVariable in the same place?
Edit 2: It seems that it would work if the /support mapping came before the /{section} mapping. Unfortunately we have dozens of controllers containing numerous methods with RequestMapping. How can I make sure that the controller with the /{section} mapping is initialized last? Or would a pre-interceptor be the way to go?
Edit 1: This is simplified, I know that having those two RequestMapping alone wouldn't make much sense)
Using Spring you can extend the org.springframework.web.HttpRequestHandler to support your scenario.
Implement the method:
#Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}
Use it to analyze the incoming request, determine if the request url is part of your special subset of request url's and forward to the appropriate location.
Ex:
#Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/** You will want to check your array of values and have this data cached **/
if (urlPath.contains("/sectionName")) {
RequestDispatcher requestDispatcher = request.getRequestDispatcher("sections" + "/" + urlPath);
requestDispatcher.forward(request, response);
}
}
And setup your sections such as:
#RequestMapping(value={"/sections/{sectionName}"})
This will not interfere with any of your pre-existing controller mappings.
If 2 these methods are defined in 2 different controllers your problem is that you have 2 controllers mapped to same URL. You do not control the order of controllers initialization right now, so the order is random.
I think you need /support mapping to be initialized before /{section}.
To achieve this try to define that controller "section" depends on controller "support". If this will not help try to put both methods together to one controller and put method mapped to "support" before "section"
I this does not work here is other suggestion. What "section" is? If it can accept limited number of values it should be defined as enum. I believe that in this case everything will work as required if support and section methods are in one controller or in separate controllers.
Good luck.
This not seems to be a problem, this is a valid mapping. If you have a look to http://static.springsource.org/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping-uri-templates
In the section 16.3.2 Mapping Requests With #RequestMapping exists two methods doing exactly the same that you are trying.
To be sure that your classes are being compiled try to add a #RequestMapping("/someprefix") at class level to see if the URL is being exposed as you want.
I verify your example locally using the version 3.1.0.RELEASE and no issue were present.
As a workaround (and also to provide a well-understand REST URI add some context to your second mapping:
#RequestMapping(value={"client/support"}) // i.e: if you are working with clients
public ModelAndView getsupport(#PathVariable Long supportId){
// do your code here something here
}
Of course that this is valid if this is the unique controller present in the system, otherwise you must use RequestMapping at class level as I suggested above.
I hope this helps.
I am not seeing this behavior with Spring 3.1.2, it could potentially have been a bug with an older Spring version. Here is a gist which runs through without any issues for me - https://gist.github.com/3802254

Global Exception Handling in Jersey

Is there a way to have global exception handling in Jersey? Instead of individual resources having try/catch blocks and then calling some method that then sanitizes all of the exceptions to be sent back to the client, I was hoping there was a way to put this where the resources are actually called. Is this even possible? If so, how?
Instead of, where sanitize(e) would throw some sort of Jersey-configured exception to the Jersey servlet:
#GET
public Object getStuff() {
try {
doStuff();
} catch (Exception e) {
ExceptionHandler.sanitize(e);
}
}
Having:
#GET
public Object getStuff() throws Exception {
doStuff();
}
where the exception would get thrown to something that I can intercept and call sanitize(e) from there.
This is really just to simplify all the Jersey resources and to guarantee that the exceptions going back to the client are always in some sort of understandable form.
Yes. JAX-RS has a concept of ExceptionMappers. You can create your own ExceptionMapper interface to map any exception to a response. For more info see: https://jersey.github.io/documentation/latest/representations.html#d0e6352
javax.ws.rs.ext.ExceptionMapper is your friend.
Source: https://jersey.java.net/documentation/latest/representations.html#d0e6665
Example:
#Provider
public class EntityNotFoundMapper implements ExceptionMapper<javax.persistence.EntityNotFoundException> {
public Response toResponse(javax.persistence.EntityNotFoundException ex) {
return Response.status(404).
entity(ex.getMessage()).
type("text/plain").
build();
}
}
All the answers above are still valid. But with latest versions of spring Boot consider one of below approaches.
Approach 1 :
#ExceptionHandler- Annotate a method in a controller with this annotation.
Drawback of this approach is we need to write a method with this annotation in each controller.
We can work around this solution by extending all controllers with base controller (that base controller can have a method annotated with #ExceptionHandler. But it may not be possible all the times.
Approach 2 :
Annotating a class with #ControllerAdvice and define methods with #ExceptionHandler
This is similar to Controller based exception (refer approach 1) but this is used when controller class is not handling the exception.
This approach is good for global handling of exceptions in Rest Api

Categories

Resources