How to validate long PathParam in Spring - java

I would like to validate input of following #RequestMapping:
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
#ResponseBody
public Response getCategory(#PathVariable("id") Long id) {
// some logic here
}
When consumer of the endpoint passes string following error occurs:
Failed to convert value of type [java.lang.String] to required type [java.lang.Long]; nested exception is java.lang.NumberFormatException: For input string: "null"
I could change it to string but I believe there is a better way to do it.

The answer from RC is a very good way to make sure your id will be made of digits.
In general if you want to validate incoming requests you could also create and register a custom interceptor by implementing HandlerInterceptor and then add your validation in the overridden preHandle method.

Related

#FeignClient is not failing in Type Mismatch

I am intentionally trying to simulate a failure condition. I have a service which returns JSON of a User object. However, in #FeignClient #RequestMapping I am returning another object i.e. Event.
In this case, I was expecting Feign to fail deserializing the JSON to the Event POJO. But it is not failing. Moreover, the response Event object is also not null.
So my question is, is this the behavior by design? What I can do to make Feign fail in this kind of situation.
Here is my FeignClient.
#FeignClient(name = "userProxy", url = "${securei.url}")
public interface UserProxy {
#RequestMapping(value = IUser.USER_LOGIN, method = RequestMethod.GET, params = {"u", "p"})
public Event login(#RequestParam("u") String username, #RequestParam("p") String password);
}
Here the actual login service returns the User JSON, however I have provided Event as the return type. Still, it is not failing.

Get request mapping object in spring interceptor, to get actual url string pattern

It might be hard to explain why, but I have this situation where I need to get the request url mapping string of currently requested url.
Like if I have a GET URL as "/Test/x/{number}"
I want to get "/Test/x/{number}" not "/Test/x/1"
can I get the actual declared url string in interceptor?
If this is possible how can I achieve this
You can implement a HanderInterceptor to intercept, pre or post, request and introspect the method being called.
public class LoggingMethodInterceptor implements HandlerInterceptor {
Logger log = LoggerFactory.getLogger(LoggingMethodInterceptor.class);
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HandlerMethod method = (HandlerMethod) handler;
GetMapping mapping = method.getMethodAnnotation(GetMapping.class);
log.info("URL is {}", Arrays.toString(mapping.value()));
return true;
}
}
This will output, URL is [/hello/{placeholder}]
Full example can be found here, https://github.com/Flaw101/spring-method-interceptor
You could add more logic to introspect only certain methods, certain types of requests etc. etc.
I think that you can get it with reflection and getting #RequestMapping anotations.
for example when you use
#RequestMapping(value = "/Test/x/{number}", method = RequestMethod.GET)
the value is what you are looking for if I got it right!
You only must find the controller class type.
Its possible I think but I didn't test it.
Check this:
In a Spring-mvc interceptor, how can I access to the handler controller method?
First it may be solved if the HandlerMethod was right but if you get cast error then you must get the controller class [I think].
When you get the controller class then you can looking for the method with according #RequestMapping annotation.
So
1- Find the controller class type
2- Search all methods with in the class by reflection
3- Check method annotations with specified url and specified method [GET / POST]
4- select the best candidate
If you have more than two URL parameter this method is not good!

How to validate request parameters in Spring REST controller

I am working on a Spring REST application.
This application has only REST controllers, no view part.
I want to know how can I validate a #RequestParam
For example
#RequestMapping(value = "", params = "from", method = RequestMethod.GET)
public List<MealReadingDTO> getAllMealReadingsAfter(#RequestParam(name = "from", required = true) Date fromDate) {
......
......
}
In the above example, my goal is to validate the Date. Suppose someone pass an invalid value, then I should be able to handle that situation.
Now it is giving and exception with 500 status.
PS
My question is not just about Date validation.
Suppose, there is a boolean parameter and someone passes tru instead of true by mistake, I should be able to handle this situation as well.
Thanks in advance :)
Spring will fail with an 500 status code, because it cannot parse the value.
The stages of request handling are:
receive request
identify endpoint
parse request params / body values and bind them to the detected objects
validate values if #Validated is used
enter method call with proper parameters
In your case the flow fails at the parse (3) phase.
Most probably you receive a BindException.
You may handle these cases by providing an exception handler for your controller.
#ControllerAdvice
public class ControllerExceptionHandler {
#ExceptionHandler(BindException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ResponseBody
public YourErrorObject handleBindException(BindException e) {
// the details which field binding went wrong are in the
// exception object.
return yourCustomErrorData;
}
}
Otherwise when parsing is not functioning as expected (especially a hussle with Dates), you may want to add your custom mappers / serializers.
Most probably you have to configure Jackson, as that package is responsible for serializing / deserializing values.

Automatic conversion of JSON form parameter in Spring MVC 4.0

I am trying to build a Spring MVC controller which will receive a POSTed form with a parameter in JSON format, and have Spring automatically convert it to a Java object.
Request content type is application/x-www-form-urlencoded
The name of the parameter that contains a JSON string is data.json
This is the controller:
#Controller
public class MyController {
#RequestMapping(value = "/formHandler", method = RequestMethod.POST)
public #ResponseBody String handleSubscription(
#RequestParam("data.json") MyMessage msg) {
logger.debug("id: " + msg.getId());
return "OK";
}
}
And this is what the MyMessage object looks like:
public class MyMessage {
private String id;
// Getter/setter omitted for brevity
}
Perhaps not surprisingly, posting a form with parameter data.json={"id":"Hello"} results in HTTP error 500 with this exception:
org.springframework.beans.ConversionNotSupportedException:
Failed to convert value of type 'java.lang.String' to required type 'MyMessage'
nested exception is java.lang.IllegalStateException:
Cannot convert value of type [java.lang.String] to required type [MyMessage]: no matching editors or conversion strategy found
If I read the MappingJackson2HttpMessageConverter docs correctly, Jackson JSON conversion is triggered by Content-Type application/json, which I obviously cannot use since this is a form POST (and I don't control the POSTing part).
Is it possible to get Spring to convert the JSON string into an instance of MyMessage, or should I just give up, read it as a String and perform the conversion myself?
Spring invokes your #RequestMapping methods with reflection. To resolve each argument it's going to pass to the invocation, it uses implementations of HandlerMethodArgumentResolver. For #RequestParam annotated parameters, it uses RequestParamMethodArgumentResolver. This implementation binds a request parameter to a single object, typically a String or some Number type.
However, your use case is a little more rare. You rarely receive json as a request parameter, which is why I think you should re-think your design, but if you have no other choice, you need to register a custom PropertyEditor that will take care of converting the request parameter's json value into your custom type.
Registration is simple in an #InitBinder annotated method in your #Controller class
#InitBinder
public void initBinder(WebDataBinder dataBinder) {
dataBinder.registerCustomEditor(MyMessage.class, new PropertyEditorSupport() {
Object value;
#Override
public Object getValue() {
return value;
}
#Override
public void setAsText(String text) throws IllegalArgumentException {
value = new Gson().fromJson((String) text, MyMessage.class);
}
});
}
In this particular case, we don't need all the methods of the PropertyEditor interface, so we can use PropertyEditorSupport which is a helpful default implementation of PropertyEditor. We simply implement the two methods we care about using whichever flavor of JSON parser we want. I used Gson because it was available.
When Spring sees that it has a request parameter that you requested, it will check the parameter type, find the type MyMessage and look for a registered PropertyEditor for that type. It will find it because we registered it and it it will then use it to convert the value.
You might need to implement other methods of PropertyEditor depending on what you do next.
My recommendation is to never send JSON as a request parameter. Set your request content type to application/json and send the json as the body of the request. Then use #RequestBody to parse it.
You can also use #RequestPart like this:
#RequestMapping(value = "/issues", method = RequestMethod.POST, headers = "Content-Type=multipart/form-data")
public String uploadIssue(#RequestParam("image") MultipartFile file, #RequestPart("issue") MyMessage issue)

post json to spring mvc controller

Controller signature (I have tried as requestbody as well) :
#RequestMapping(value = "/Lame", method = RequestMethod.POST)
public
#ResponseBody
boolean getLame(#RequestParam String strToMatchA, #RequestParam String strToMatchB) {}
And this as my json :
{
"strToMatchA": "EN",
"strToMatchB": "lon"
}
Not working, I receive the error :
org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'strToMatchA' is not present
Removing this first parameter from method signature then makes it work (the method gets called correctly), what should I be doing ?
When I change method parameters to be annotated with #RequestBody I get the following error :
java.io.IOException: Stream closed
Your json is fine but not the controller signature.
Create a class with setters matching the json.
Use it as argument instead of your strings.
Annotate it with requestbody. It should work.

Categories

Resources