post json to spring mvc controller - java

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.

Related

Content-Type is missing with Spring GET/POST method

I am new to Spring and I am trying to do the basic GET and POST method.
This is how I am trying to do the methods:
#RestController
public class DeskController {
#Autowired
private DeskDao dao;
#GetMapping("desks")
public List<Desk> getDesks() {
System.out.println(dao.findById(1L));
return dao.findAll();
}
#PostMapping("desks")
public Desk save(#RequestBody #Valid Desk desk) {
Desk deskObj = dao.save(desk);
System.out.println(deskObj);
return deskObj;
}
When I am calling the POST method like this I get the pring with the actual object that I had called it with so it is working fine, but I also get this error:
javax.ws.rs.ProcessingException: Content-Type is missing
And when trying to call GET it tells me that:
org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' not supported
I am aware that I have not included the whole code, but I will add what is needed to resolve this error since there are a lot of classes.
My questions are, what do I do against the first error and why is GET method not supported?
Two things you need to change :
Use a / to indicate that for this path you will perform an
operation. For eg : (/desks)
Use the annotation #Consumes to
indicate that this method accepts the payload in particular format. For eg : #Consumes(MediaType.APPLICATION_JSON) annotated over your save() method.

How to validate long PathParam in Spring

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.

Spring MVC RequestMapping Post method

few days ago I passed SpringMVC level evaluation test on my company, and I found that I don't have enough knowledge to answer one question. But I'm wondering what is the correct answer??? So it will be awesome if You help me!
You have the following PersonController class and correctly defined web.xml and Spring context
The following request has been submitted using POST method:
http://xxxx/person/add?name=John
Please, fill the placeholders so that submitted request would result into person object being saved successfully and method addPerson would be called only in case request doesn't contain "id" parameter. Values in placeholders should not contain spaces.
PLACEHOLDER1 :
#Controller
#RequestMapping("person")
PLACEHOLDER2 :
#RequestMapping(value = "add", method = RequestMethod.POST)
And you can read document from Spring official site.
Edited:
About id, if you request url is like http://xxxx/person/add/12345?name=John, then you can do it like this:
#RequestMapping(value = "add/{id}", method = RequestMethod.POST)
public String addPerson(#RequestParam("name") String name, #PathVariable("id") String id)
here you can get 12345 as id.

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)

How to use #RequestBody with a JSONP request?

I am trying to perform an ajax request using the jsonp data type due to cross domain issues in a clustered environment.
I can make jsonp requests to methods mapped with no #RequestBody parameters, but when I do try to implement a RequestMapping with a #RequestBody parameter I get a 415 Unsupported Media Type error.
Usually when I get this problem it is due to some property not mapping correctly between the json object posted and the Java object it is mapped to in Spring. But the only discrepency I can find is that using jsonp it adds a parm named callback and one with the name of an underscore "_"
So I added the tag #JsonIgnoreProperties(ignoreUnknown = true) to my Java object and figured that should solve that, however it is still throwing this error.
Is there anything else I need to do?
EDIT: I am now seeing this stack trace in the debug log output from Spring:
org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/octet-stream' not supported
$.ajax({
url : 'http://blah/blah.html',
data : { abc : '123' }, (I also tried to JSON.stringify the object but no difference)
dataType : 'jsonp',
success : function(response) {
alert('ok '+JSON.stringify(response));
},
fail : function(response) {
alert('error'+JSON.stringify(response));
}
});
The Spring controller is:
#RequestMapping({ "blah/blah" })
#ResponseBody
public ReturnObject getBlahBlah (#RequestBody MyObject obj) throws Exception {
}
The parameter object is:
#JsonIgnoreProperties(ignoreUnknown = true)
public class MyObject {
private String abc;
// getter and setter for abc auto generated by MyEclipse
}
I have a breakpoint on the Controller method which is never hit.
JSONP means that jQuery will create a <script> element with src pointing to your controller URL.
As you can see, this approach doesn't allow you to pass any data in request body, all data should be passed in URL as query parameters. data : { abc : '123' } means that abc=123 is added to the URL.
At controller side you need to use either #RequestParam (to bind inidividual parameters) or #ModelAttribute (to bind multiple parameters into an object):
public ReturnObject getBlahBlah (#RequestParam("abc") int abc) throws Exception { ... }

Categories

Resources