Validation of request body AND request parameter in 1 step? - java

a question to validation of put calls to a REST endpoint using spring boot and javax.validation (not the spring validation).
You have the following method in the resource:
#PutMapping(...)
public Response getResult(#RequestBody #Valid myBody, #PathVariable #MyIdValidation long id) {
}
When I call the method, myBody gets validated and I get a MethodArgumentNotValidException in my exception handler. But parameter id gets not validated!
Only if myBody is valid, id gets validated as well.
The only solution I found is to not use #Valid, and implement the validation of the body myself.
Are there better solutions?
TIA
Kibu

I don't think its doable by Spring MVC framework itself because framework handles #RequestBody and others like #RequestParam or #PathVariable differently by using different components. Also, both pieces need to be disconnected because you might not like to validate all arguments of a method.
#RequestBody is handled by org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor and validations are called from there & for params or path variable validations are done by org.springframework.validation.beanvalidation.MethodValidationInterceptor.
So in my opinion, method arguments of a controller method are handled one by one by framework & are disconnected in logic so these validations can't be clubbed together.

I've put some effort into this issue and started a project on github
It's possible to validate in one stop, but you need a different approach. Check out the project and test it.
Kibu

Related

How does Spring routing work? Is there a way to access it?

I'm building a rest API in Spring. Is there a way to tap into the routing to do a lookup?
Is there a table somewhere?
Given a full route /someobject/a with an ACCEPT header of "whatever", is there a way I can tell what controller and method it will get routed to, Or do I need to build that map myself?
I asked a similar question in a different way and was suggested to use Spring AOP which I tried with #Before, but it doesn't work in some of the cases I need. Specifically, if there are validation annotations on the method parameters and the validation fails, it doesn't make it to the join point. Doesn't make it to the #AfterThrowing either.
For those trying to figure this out in the future, yes it is indeed possible. The routing is exposed as a bean:
#Autowired
private RequestMappingHandlerMapping requestMappingHandlerMapping;
You need the HttpServletRequest object which you can get from here if you don't have it already:
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest();
Then you just call:
HandlerMethod handlerMethod = (HandlerMethod)requestMappingHandlerMapping.getHandler(request).getHandler();
My specific need was to get the PreAuthorize attribute, but you can do anything with the HandlerMethod object:
PreAuthorize preauthorize = handlerMethod.getMethodAnnotation(PreAuthorize.class);

How do I configure validation check in Spring MVC with JSP?

I need a quick help regarding validation check in Spring MVC. I have a basic HTML form not the JSTL Tag form. How do I check or implement a straight forward data validation check in Spring MVC? One way in my mind coming right now is to use regex to verify the user name is alphanumeric [a-zA-Z0-9].
But I have seen people use Validator do this job. I want to use Validator as it seems more profession.
Second question,
I'm trying to get a Exception handling working properly but it is not working. I want the absolute basic response to happen, the response throws a HTTP.404 response. My simple method:
#RequestMapping(value="/request/view/{id}",method=RequestMethod.GET)
public String requestSubmit(Model model)
Now with my response String, how can I do it? After search on Stackoverflow. They said to create a generic class such as NotFoundException and extend it RunTimeException. But I still don't know how to I set the response intentionally to be 404 or any other response actually, even Http.BANDWIDTH_EXCEEEDED_RESPONSE
Fist thing you should know: it's better to use POST instead of GET in form submitting. Because when you use GET, all your model properties sent as url parameter and it's not a good practice.
For using validation, you can use #Valid as this:
public String requestSubmit(#Valid Model model)
Then you can use validation annotation like #NotNull, #Size, ... at every property of Model class you want to validate it.
When a user submits your form, if every form attribute has validation problem, spring throws MethodArgumentNotValidException automatically. For getting validation errors, you can use try-catch block in your controller or better way is to have central exception handler with #ControllerAdvice.

Spring #RequestBody annotation in Restful web service

Thanks to #RestController I don't need to add annotation #ResposneBody, cause spring knows that it is rest controller, and he will not generate view, but instead it will return json object.
Unfortunately there is one more annotation related to this topic. It is #RequestBody, when controller method accept json object as a parameter. And it will have to be pointed before that parameter.
My question is there a way to get rid of that annotation (#RequestBody).? If my controller is rest controller (#RestController instead of regular #Controller) it should be demanded from spring?
No, you'll have to specify #RequestBody. A Java method can have only a single return value, and so the #ResponseBody is unambiguous, but there are multiple possible ways that mapped controller parameters might be interpreted (in particular, using #ModelAttribute with form encoding is a very common alternative to #RequestBody with JSON), and you'll need to tell Spring how to map the incoming request.

Is there a way to access HttpRequest type inside a #Controller method

I have tried to find the answer to this, but I cannot seem to find what I am looking for. So I apologize if this question already exists.
PROBLEM:
I want to be able to access the request type of a request inside of a generic method within my Controller.
DESCRIPTION:
Using Spring ROO and Spring MVC, I have developed a small web service that will respond with certain tidbits from a database when queried. In one of my controller classes, I have some methods that handle some variety of GET, PUT, POST, etc., for the URIs that are mapped within the #RequestMapping parameter.
For example:
#RequestMapping(method = RequestMethod.Get, value = "/foo/bar")
#ResponseBody
public ResponseEntity<String> getFooBar() {
// stuff
}
If a request is made to the web service that it is not currently mapped, a 405 error is returned (which is correct), but I want to return more information along with a 405 response. Maybe respond with something like:
"I know you tried to execute a [some method], but this path only handles [list of proper methods]."
So I wrote a short method that only has the RequestMapping:
#RequestMapping(value = "/foo/bar")
I have found that the method with this mapping will catch all unhandled request types. But I am having trouble accessing the information of the request, specifically the type, from within the method.
QUESTION:
A. How can I access the request type from within the method? OR
B. Is this the right approach? What would be the right approach?
EDIT
ANSWER:
I added a HttpServletRequestobject to the method parameters. I was able to access the method type from that.
I tried using HttpRequest, but it didn't seem to like that much.
Thanks all!
You can add a method parameter of HttpServletRequest, but I think you'd be better off continuing to reply with 405. A client should then make an HTTP OPTIONS call (see How to handle HTTP OPTIONS with Spring MVC?) and you can return the list of allowed methods there.
A. you can access request if you mentioned it as parameter in controller method
public ... getFooBar(HttpRequest request) {
...
}
B. you do not need to add any other description as the 405 status is descriptive.
In answer to "A", just add "HttpRequest req" as an additional argument to your controller methods. Spring will automatically inject a reference to the request, and you can play with headers to your heart's content.
In answer to "B" - "What would be the right approach", how about this?
In order to return that 405, Spring has raised a MethodArgumentNotValidException. You can provide custom handling for this like so:
#ExceptionHandler(MethodArgumentNotValidException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ResponseBody
public MyMethodArgumentMessage handleMathodArgumentNotValidException(
MethodArgumentNotValidException ex) {
BindingResult result = ex.getBindingResult();
MyMethodArgumentMessage myMessage =
new MyMethodArgumentMessage(result.getFieldErrors());
return myMessage;
}
You should take a look at the #ExceptionHandler annotation. This lets you add methods such as the following to your controller. You can define your own exceptions and appropriate custom handlers for them. I use it to return well-structured XML and JSON from REST services. Although for it to work, you need to throw specific exceptions from your controller methods.
A good walk-through of using this was provided by Petri Kainulkainen in his blog:
http://www.petrikainulainen.net/programming/spring-framework/spring-from-the-trenches-adding-validation-to-a-rest-api/

Spring MVC - Is it possible to receive a strongly typed request object on a GET?

I have a Spring MVC controller which is servicing GET requests, to perform a search.
These requests have many optional parameters which may be passed on the query string.
For example:
#Data
public class SimpleSearchRequest implements SearchRequest {
private String term;
private List<Status> stati;
#JsonDeserialize(using=DateRangeDeserializer.class)
private Range<DateTime> dateRange;
}
If I were using a POST or PUT for this, I could nicely marshall the inbound request using a #RequestBody. However, because I'm using a GET, this doesn't seem to fit.
Instead, it seems I'm required to list all the possible parameters on the method signature as #RequestParam(required=false).
Aside from leading to ugly method signatures, I'm also losing out on all sorts of OO goodness by not using classes here.
Attempting to use #RequestBody fails (understandably so), and as discussed here and here, using an actual request body on a GET is not desirable.
Is there a way to get Spring MVC to support marshalling multiple #RequestParam's to a strongly typed object on GET requests?
It seems the answer was to simply remove the annotation.
This worked:
#RequestMapping(method=RequestMethod.GET)
public #ResponseBody List<Result> search(SearchRequest request) {}

Categories

Resources