Handling invalid URL's when using #ParamValue in Spring MVC - java

I am using #ParamValue annotation in my controller (Spring MVC).
Say My valid URL's are:
www.temp.com/test/a,
www.temp.com/test/b and
www.temp.com/test/c
So, my RequestMapping is:
#RequestMapping(value = "/test/{value}", method = RequestMethod.GET)
Now, my problem is that if anyone types a wrong URL like this :
www.temp.com/test/youarebroken
then I have to manually handle such a case in my controller to show 404 or not found.
Isn't there something inbuilt that sends a "not found or 404" notification to server that I can use directly ?

The simplest solution is to define a custom exception handler and to throw the custom exception when a validation fails within your controller. That would require that you manage the conditions manually as you stated you do not want to do.
A different solution is to use a global exception handler and define it to deal with the HTTP errors that are handled by Spring built-in.
In this link you can see both approaches: http://www.journaldev.com/2651/spring-mvc-exception-handling-exceptionhandler-controlleradvice-handlerexceptionresolver-json-response-example
However, from your question I understand you would like to return automatically an exception when certain condition in your param value does not meet, and you do not want to validate this manually within your controller. For this, you can add custom validation for an specific class and then set #Valid before the #ParamValue.
You can check this link for DataBinding http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html
And this link for specific validation on param attributes: Spring Web MVC - validate individual request params
So, in plain a solution would be to define a custom validator that throws a custom exception when fails. To set #Valid for the parameters (check link) and to adjust the custom exception to handle HTTP errors (e.g. HttpStatus.NOT_FOUND).

You can use a regex in your #RequestMapping URL. Example:
#RequestMapping(value = "/test/{value:[a-z]}", method = RequestMethod.GET)

Related

how to create json response in spring boot java like this as shown when the following attributes are not present in json request

I am creating an controller where there is certain attributes in json which is an doing in postman a POST request like this if all attributes are posted then its fine
if one then is missing then it would look like this
i want this response when some attribute is missing how to implement this
This is normally implemented in two steps:
Implement a validation mechanism for the method that handles the incoming request. Normally you would throw an exception here if the input is incorrect, in your example a missing JSON key.
Implement a global error handler that will process the exception from point 1 and format the response as JSON.
For point 1 the usual choice is the Java Bean Validation framework because it's integrated with Spring Boot and allows to define validation constraints with annotations like #NotEmpty. You can take a look at this example.
For point 2 the usual choice is #RestControllerAdvice or #ControllerAdvice. You would have to understand your service web server setup to implement it properly e.g. it might behave differently if you use Spring WebFlux.

Use checkstyle to force a parameter to be present on any method with specific annotation

I want that all my rest services has as an input parameter HttpServletRequest httpRequest that I need later for some loggin purposes. This parameter sometimes is forgotten to be added and some methods are not logged. As are all rest services, and I am using Spring, all of them has some very specific annotations. I was thinking on using checkstyles to force the parameter to be present.
A little more of explanation of want I want to achieve. I am developing some rest servicies, and I am interested on logging some header that are sent to the rest services with some extra information. For this purpose, I have added HttpServletRequest request to each rest services as follows:
#GetMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(HttpStatus.OK)
public Status get(HttpServletRequest request, #PathVariable("id") Integer id) {
....
}
This paremeter is correctly retrieved and I can read the headers correctly (everything automated using AspectJ). My problem now is that is for a new rest service, I forgot to add the parameter, no logs will be shown. As the parameter is optional (you can or cannot add to the rest service without any error) and all logging is automated by AspectJ, is possible that I can forget it for future rest services and no notice the miss until late.
The scope is to ensure that always is present in all my rest services. My first thought was using checkstyle as I am already using for other different purposes.
Is it possible using checkstyle or any similar tool to force that a parameter is present on any method that has an annotation? If not, there is any other different way to achive my objective?

AspectJ with Spring : intercepted methods lose their parameters annotations

I recently added AOP with aspectJ and spring-aop to my existent spring project. The goal was to actually intercept controller calls to modify the response they send back, in order to bind some values to this response I didn't want to add manually to each and everyone of my controllers, for example the expiration date of the actual token used by the end-user (which I wasn't even able to showcase within my controller in any case). I actually managed to get it working until I started my unit tests :
In my unit tests I call directly my controller methods using Reflection feature from java, then replicate usual process (calling the filter chain, pre handler and post handlers, and the controller method itself which is first manually validated using spring validator when annotation #Valid is present on one of my parameters. All this process works fine and gets executed properly). The problem is that now that the controller method is intercepted by spring-aop, it's mentionned as coming from the proxy controller created, and all of my parameters annotations disapear. Here is a controller example :
#Override
public ResponseEntity<Object> editPassword(#Valid #RequestBody PasswordEditForm passwordEditForm, HttpServletRequest request) {
return factorizedUserBaseController.editPassword(passwordEditForm, request, User.class);
}
the parameter PasswordEditForm has the annotation #Valid so in my test cases it was first validated before any other step, but now as I double checked it, the #Valid annotation is not present on the proxy method, and therefore the parameter doesn't get validated, any clue for how to fix this and make my parameters annotation still understandable from my test point of view?
Note : when running the spring through mvn spring-boot:run, parameters with #Valid annotation gets correctly validated and then goes to my error handler method properly.
Problem Solved : from several other stackoverflow posts I understand that CGLIB (aop proxy lib used by Spring) doesn't support annotations. ( see Retain annotations on CGLIB proxies?). But my problem wasn't here, I was literally sure I was finding the method using the controller class itself (the one I coded) but what I was wrong about is that I was giving the controller instance as a parameter to some other parts of my code which in turn would use this controller class to find the method which of course wasn't working because thanks to Spring proxies, it wasn't anymore my controller itself but a proxy class extending my own controller class. Instead, I just had to replace :
Class<?> controllerClass = controllerInstanciationContainer
.getController()
.getClass();
with
Class<?> controllerClass = controllerInstanciationContainer
.getController()
.getClass()
.getSuperclass();

Does Spring generate code for validaiton?

lately I was trying to understand how spring processes #Valid annotation. For example look at the following controller's method:
#RequestMapping(value = "/create", method = RequestMethod.POST)
public ModelAndView createEmployee(#Valid EmployeeForm form, Errors errors) {
if(errors.hasErrors()) {
//validation errors
}
//method code
}
I am struggling to understand how errors instance is getting populated with validation errors in real-time. Does Spring, during compilation of the controller, inject code responsible for validation at the beginning of the createEmployee method? If so how this code would look?
I really tried to find an example of how this validation is performed in real life but it's just impossible. Help me please.
Everything happens at runtime. See the reference for more details on doing validation or this post for extra explanations.
Basically this is part of how Spring works internally. When you start your application Spring registers some beans, bean processors, can scan your classpath for annotated classes, registers those found annotated classes, builds proxies for some of them etc and uses all of them to build a context.
When handling a request, the request is handled on some predetermined execution path that starts with the DispatcherServlet, picking up other beans from the context as needed to handle the request (like validation for example) then forwarding to you controller in the createEmployee (which was registered as startup because Spring found your #RequestMapping annotations on your controller). When you return from the method the flow continues by building a model, selecting a view to display and then generating the response to the client.
For your example, Spring basically finds the #Valid annotation, looks for an already configured validator (configured by you or by a provided implementation for e.g. JSR-303), runs the validator and stores the validation result inside the Errors object. It does this when the request is processed, as mentioned above, it does not generate code.
If your question is to know exactly how Spring does this, in all it's details, you could take the Spring source code and have a look/debug it.

How can I see if the request path matched but Accept did not in a catch-all handler?

Normally spring will return a 404 response for a request mapping where the path did not match, and return a 406 if the path did match but the "Accept" header did not match.
I have a default controller which acts as a "catch-all" which handles rest faults by returning faults in the Accepted format. Controller is of the form:
#Controller
public class DefaultController {
#RequestMapping("/**")
public void unmappedRequest(HtpServletRequest req) {
throw new ResourceNotFoundException();
}
}
Trouble is if I do get a match here, I can't tell if it matched elsewhere. I want to return the correct error to the client and tell them the Acceptable types they may retry with. Currently all I can do is throw a general ResourceNotFound exception.
Is this something I can do in a #Controller or am I going to need to resort to writing some sort of filter chain for this?
FWIW I'm using the ReST exception handling pattern demonstrated by Stormpath
I don't think a catch all controller is good way to handle "unmapped urls" at all.
I would suggest implementing a custom implementation of AbstractHandlerExceptionResolver, and not relying on the Default implementation provided by Spring. The doResolveException can be extended to do almost anything you want with the request and response.
If you want this custom ExceptionResolver to apply only to specific controllers (REST controllers), you can set mappedHandlerClasses on the exception resolver with a list of controllers you want. Also, you can set the order of the custom exception resolver such that it sits before the default resolver.
If you think I'm off topic here, please let me know.

Categories