Pass a string in payload of POST - spring

Usually we pass key-value pair in JSON payload for POST/PUT request. Is it possible to pass a sting only ex:
If so what do we set the object for #RequestBody? Would it be String type or JSONObject?

I did this:
#PostMapping(value = "businessdate", consumes = MediaType.TEXT_PLAIN_VALUE)
public void postBusinessDate(#RequestBody String businessDate) throws IOException, InterruptedException, SQLException {
businessDateService.updateBusinessDate(LocalDate.parse(businessDate));
}
and passed this:

It would be a String. Even though you choose content type as application/json

What worked for me is setting
#PutMapping(value = "/test/{id}", consumes = MediaType.APPLICATION_JSON_VALUE)
String updateInfo(#RequestHeader(#PathVariable("id") String id, #RequestBody String payload){...}
and passing the string payload by escacping the double quotes
updateInfo(token, id, "\"TEST\"");

Related

IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 2 path $; nested exception is com.google.gson.JsonSyntaxException

I'm doing a post request in SpringBoot and testing it with postman, but when I pass the body in Postman and try to read it in my application, it throws the error.
This is the method in Spring:
#PostMapping(path=PathConstants.START_ACTION)
public String start(#PathVariable String processDefinitionId, #RequestBody(required=false) String params){
if(params!=null) {
Gson gson = new Gson();
Map<String,Object> pvar = gson.fromJson(params, Map.class);
System.out.println(pvar);
}
}
In Postman I pass params this way:
I specified in the header the content-type as application/json.
But then, if I pass my params using "Param" tab
it works. But I need to pass them as body and not params. Where is the problem here?
Method 1 :
Header Content-Type is application-json. So Spring try to construct your json into a LinkedHashMap.
Now, try this...
#PostMapping(path=PathConstants.START_ACTION)
public String start(#PathVariable String processDefinitionId, #RequestBody(required=false) Map<String, Object> bodyObject){
if(MapUtils.isNotEmpty(bodyObject)) {
Map<String,Object> pvar = bodyObject;
}
instead of
#PostMapping(path=PathConstants.START_ACTION)
public String start(#PathVariable String processDefinitionId, #RequestBody(required=false) String params){
if(params!=null) {
Gson gson = new Gson();
Map<String,Object> pvar = gson.fromJson(params, Map.class);
System.out.println(pvar);
}
}
and pass header the content-type as application/json. this will work..
Method 2 ::
Now, if you still want to use your own old signature method like this ..
#PostMapping(path=PathConstants.START_ACTION)
public String start(#PathVariable String processDefinitionId, #RequestBody(required=false) String params){}
then in header the content-type as text/plain. then your older method will work also..

Feign - URL encode path params

This is my contract,
#RequestLine("GET /products/{id}")
#Headers({"Content-Type: application/json"})
ApiResponse getProduct(#Param("id") String productId) throws Exception;
I want to fetch the product with id = "a/b",
If I send this as a param to getProduct("a/b")
then the URL that is formed is http://api/products/a/b and I am getting a 404 instead the url should be http://api/products/a%2Fb
Is there a way around this?
A simple config did it,
#RequestLine(value = "GET /products/{id}", decodeSlash = false)
#Headers({"Content-Type: application/json"})
ApiResponse getProduct(#Param("id") String productId) throws Exception;
The path param was correctly getting encoded but the RequestTemplate was decoding the URL again (decodeSlash=true by default) before sending out the request which was causing the issue.
In my case, when code looks like this:
#GetMapping(path = "/document/{documentId}/files/{fileId}")
ResponseEntity<byte[]> getDocument(#PathVariable("documentId") String documentId, #PathVariable(value = "fileId") String fileId);
Also problem was that #PathVariable fileId could be 123/SGINED.
Setting application.property feign.client.decodeSlash=false helped.

Download A File On click of a link using spring mvc

When I click on any link the content should be downloaded
But this is what I get.
MastercourseController.java
#RequestMapping(value = { ControllerUriConstant.download_file }, method = RequestMethod.GET)
#ResponseBody
public void downloadingAFileById(#RequestParam("id") String id, Model model, HttpServletRequest request)
throws TechnoShineException, IOException {
String filePath = "D:/dev/testFIle.txt";
long download = Long.parseLong(id);
byte[] b = masterCourseFileFormService.getAllDownloadable(download);
OutputStream outputStream = new FileOutputStream(filePath);
outputStream.write(b);
outputStream.close();
}
MasterCourseService
public byte[] getAllDownloadable(long id) throws TechnoShineException
{
return masterCourseFormUploadDao.getAllDownloadableFiles(id);
}
MasterCourseDao
public byte[] getAllDownloadableFiles(long id) throws TechnoShineException
{
return masterCourseFormUploadMapper.getAllDownloadable(id);
}
MasterCourseMapper
public byte[] getAllDownloadable(long id) throws TechnoShineException;
You are writing the data returned by getAllDownloadable(..) to a hard-coded file. Are you sure that is what you want? I think you want to write the content returned by getAllDownloadable(..) to be written into the response. That can be done by adding a method parameter of the type HttpServletResponse to your mapping and writing into the output stream returned by HttpServletResponse#getOutputStream() and flushing (not closing!) that stream at the end.
Furthermore you have to remove the #ResponseBody annotation as this is meant to be used if the value that is returned by the mapping method returns the data that should directly be sent to the client (i.e. when sending a JSON data object or a string) without passing it to the template engine. As you are not returning anything you can remove this annotation.
Furthermore you have to set the content type of your response by invoking HttpServletResponse#setContentType(contentType: String).
In your case, the invocation would be the following:
response.setContentType("text/plain");
You complete method would look like this:
#RequestMapping(
value = ControllerUriConstant.download_file,
method = RequestMethod.GET
)
public void downloadingAFileById(#RequestParam("id") String id, HttpServletResponse response)
throws TechnoShineException, IOException {
long download = Long.parseLong(id);
byte[] b = masterCourseFileFormService.getAllDownloadable(download);
response.getOutputStream().write(b);
response.getOutputStream().flush();
}

Spring RestRemplate postforobject with request parameter having integer value

I have a method in Spring rest service.
#RequestMapping(value = "test/process", method = RequestMethod.POST)
public #ResponseBody MyResponse processRequest(String RequestId, int count)
I am using Spring RestTemplate to call this service like this.
RestTemplate restTemplate = this.getRestTemplate();
MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>();
map.add("RequestId", RequestId);
map.add("count", count);
restTemplate.postForObject(url, map,MyResponse.class);
When I try to invoke the client method I get the exception that no suitable HttpMessageConverter found for request type [java.lang.Integer]
org.springframework.http.converter.HttpMessageNotWritableException: Could not write request: no suitable HttpMessageConverter found for request type [java.lang.Integer]
at org.springframework.http.converter.FormHttpMessageConverter.writePart(FormHttpMessageConverter.java:310)
at org.springframework.http.converter.FormHttpMessageConverter.writeParts(FormHttpMessageConverter.java:270)
at org.springframework.http.converter.FormHttpMessageConverter.writeMultipart(FormHttpMessageConverter.java:260)
at org.springframework.http.converter.FormHttpMessageConverter.write(FormHttpMessageConverter.java:200)
at org.springframework.http.converter.FormHttpMessageConverter.write(FormHttpMessageConverter.java:1)
at org.springframework.web.client.RestTemplate$HttpEntityRequestCallback.doWithRequest(RestTemplate.java:596)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:444)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:409)
at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:287)
I know one of the ways is to pass all the parameters as String. But I might need to pass complex data types as parameters later.
What is the ways to achieve this.
I have googled and some option seem to be writing my own converters. How should I start about solving this problem.
The root cause of this error is that by specifying an Integer in the LinkedMultiValueMap, the RestTemplate will take that to mean that your request is a multipart request. There is no HttpMessageConverter registered by default that can handle writing values of type Integer to a request body.
As you said, you can handle this situation by changing the count to be a String. After all, there is no Integer type in HTTP request parameters. However, you were worried
But I might need to pass complex data types as parameters later.
Assume something like this
public #ResponseBody MyResponse processRequest(String RequestId, int count, Complex complex) {
with
public class Complex {
private String someValue;
private int intValue;
public String getSomeValue() {
return someValue;
}
public void setSomeValue(String someValue) {
this.someValue = someValue;
}
public int getIntValue() {
return intValue;
}
public void setIntValue(int intValue) {
this.intValue = intValue;
}
public String toString() {
return someValue + " " + intValue;
}
}
The the following will work just fine
MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>();
map.add("RequestId", "asd");
map.add("count", "42");
map.add("someValue", "complex");
map.add("intValue", "69");
restTemplate.postForObject(url, map,MyResponse.class);
Remember that the request parameters are used to populate the fields of model attributes by their names.
An even better solution would have you using a serialization standard like JSON or XML.

Using both #RequestBody and #RequestParam together in spring mvc3

I am using spring-mvc 3.1.0.RELEASE and for some reason, mapping POST with query params and request body does not work.
Here is how my controller method looks:
#RequestMapping(method = POST, value = "/post-to-me/")
public void handlePost(
#RequestBody Content content,
#RequestParam("param1") String param1,
#RequestParam("param2") String param2
){
//do stuff
}
However, if I convert all the request params to path params, mapping works. Has anyone run into something similar?
Thanks!
EDIT:
"does not work" == 404 when I try doing, POST /post-to-me?param1=x&param2=y
First, your POST url doen't match the controller method url, your POST url must be "/post-to-me/?param1=x&param2=y" not "/post-to-me?param1=x&param2=y"
Second, where did Content class come from?? I used a String and works fine for me
#RequestMapping(method = RequestMethod.POST, value = "/post-to-me/")
public void handlePost(#RequestBody String content,
#RequestParam("param1") String param1,
#RequestParam("param2") String param2, HttpServletResponse response) {
System.out.println(content);
System.out.println(param1);
System.out.println(param2);
response.setStatus(HttpServletResponse.SC_OK);
}
Note that I used HttpServletResponse to return a HTTP 200 code, but I think there is a better solution for return Http codes, check this: Multiple response http status in Spring MVC
Trailing slash at the end of your request mapping value might be the problem.
Try:
#RequestMapping(method = RequestMethod.POST, value = "/post-to-me")
or send your POST request to POST /post-to-me/?param1=x&param2=y

Resources