So I've been having some issues with #RequestBody in Spring. I've had no problems at all when it comes to returning objects and having Spring automatically parse them. I have no issue if I only declare a String as an argument for the method. Here is the code, I'll begin with what I want to receive:
public class ToParse {
private String name;
ToParse() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Here is the controller:
#RestController
#RequestMapping("/test")
public class ConcreteTestController implements TestController {
#RequestMapping(method = RequestMethod.POST, consumes = {"application/json"})
#ResponseStatus(value = HttpStatus.OK)
#Override
public ToParse getSilly(#RequestBody ToParse toParse) {
ToParse toReturn = new ToParse();
toReturn.setName("stuff");
return toReturn;
}
#RequestMapping(method = RequestMethod.GET)
#ResponseStatus(value = HttpStatus.OK)
#Override
public ToParse getSilly(String test) {
ToParse toReturn = new ToParse();
toReturn.setName(test);
return toReturn;
}
}
Note that the second method works just fine. The header I am sending in is "application/json" for the first method and the JSON is:
{
“name”:”blablabla”
}
I get a 415 error when trying to call the first method using the rest client in intelliJ. My configuration is in XML and it is .
What am I doing wrong? There are many answers to these types of question but usually they are resolved by fixing header or Springconfig. I cannot see what I have done wrong.
You are getting a HTTP Error 415 Unsupported media type because you are sending a POST request without adding the Content-Type: application/json header.
The Content-Type entity-header field indicates the media type of the entity-body sent to the recipient
https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17
Related
I am getting this error while calling an API from postman, after I hosted my spring app in VM. Locally it works. But Get methods in my VMs are working.
[http-nio-8081-exec-4] PageNotFound - Request method 'GET' not supported
My controller method looks like this:
#RestController
#RequestMapping("/orders/")
public class OrdersController {}
#PostMapping(value = "create", produces = "text/plain")
private String createOrder(#RequestBody POCreationRequest request) throws ParseException {
The API request running forever and dont get any response. I found the exception in my log. Any idea on this issue?
You created two urls there:
url/orders/ -> accepts get/post/etc... (though its not implemented)
url/orders/create -> accepts post
#RestController
#RequestMapping("/orders")
public class OrdersController {
#PostMapping(value = "create", produces = "text/plain")
private String createOrder(#RequestBody POCreationRequest request) throws ParseException {
System.out.println(request)}
}
You can try the above code.
You are trying to make a GET request on an only POST endpoint, thus then not loading the page. Your endpoint should be of type GET. You can also have the same endpoint for GET and POST requests as follows:
#RestController
#RequestMapping("/orders/")
public class OrdersController {}
#PostMapping(value = "create", produces = "text/plain")
private String createOrder(#RequestBody POCreationRequest request) throws ParseException {
//Parse post requests
}
#GetMapping(value= "create")
private String servePage() {
return create; //create is the name of the html view.
}
Now when going to localhost:8080/orders/create it should serve the view.
You can also make the GET mapping return a JSON object by:
#GetMapping(value= "create")
private String serveJSON() {
return "{\"hello\": \"world\"}"; //The string is treated as JSON and not as a view.
}
I have a spring RestController and want to redirect to POST method in same controller with RequestBody.
any solution welcomes, not only redirect.
MyController:
#RequestMapping(value = "/addCompany", method = RequestMethod.POST)
public String addCompany(#Valid Company company, BindingResult result,
HttpServletRequest request, Model model) throws Exception {
//some logic
//need to pass Company Object as RequestBody
return "redirect:/app/postmethod/";
}
//Method to redirected
#RequestMapping(value = "/postmethod", method = {RequestMethod.POST, RequestMethod.GET})
public String getData( #RequestBody(required=false) Company compnay, HttpServletRequest request, Model model) throws Exception {
//some logic
//required company object
return "htmlpage";
}
I need to redirect my request to /postmethod from addCompany method in the same controller, I am open to use any feasible solution.
Check here:
https://www.baeldung.com/spring-redirect-and-forward#redirecting-an-http-post-request
As per HTTP 1.1 protocol reference, status codes 301 (Moved
Permanently) and 302 (Found) allow the request method to be changed
from POST to GET. The specification also defines the corresponding 307
(Temporary Redirect) and 308 (Permanent Redirect) status codes that
don't allow the request method to be changed from POST to GET.
#PostMapping("/redirectPostToPost")
public ModelAndView redirectPostToPost(HttpServletRequest request) {
request.setAttribute(
View.RESPONSE_STATUS_ATTRIBUTE, HttpStatus.TEMPORARY_REDIRECT);
return new ModelAndView("redirect:/redirectedPostToPost");
}
#PostMapping("/redirectedPostToPost")
public ModelAndView redirectedPostToPost() {
return new ModelAndView("redirection");
}
The request body will be passed. Here is an example using your code:
#RestController
#RequestMapping("app")
public class TestController {
#PostMapping("/addCompany")
public ModelAndView addCompany(#RequestBody Company company, HttpServletRequest request) {
System.out.println("First method: " + company.name);
request.setAttribute(
View.RESPONSE_STATUS_ATTRIBUTE, HttpStatus.TEMPORARY_REDIRECT);
return new ModelAndView("redirect:/app/postmethod/");
}
#PostMapping("/postmethod")
public void getData(#RequestBody Company company) {
System.out.println("Redirected: " + company.name);
}
public static class Company {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
When using POST request to http://localhost:8080/app/addCompany with body {"name": "Test Company"}, in the output I receive next:
First method: Test Company
Redirected: Test Company
I found a good explanation on this page here.
For protecting users against inadvertently (re)submitting a POST transaction which they had not intended, or submitting a POST into a context which they would not have wanted.
So you can set the data in session and using get method to call post method if you want to do this.
I have spring boot application which used spring rest controller .
This is the controller , below is the response an getting. Am using postman tool for sending request to this controller. And am sending content type as application/json
#RequestMapping(value = "/test", method = RequestMethod.POST)
public String test(#RequestBody WebApp webapp, #RequestBody String propertyFiles, #RequestBody String) {
System.out.println("webapp :"+webapp);
System.out.println("propertyFiles :"+propertyFiles);
System.out.println("propertyText :"+propertyText);
return "ok good";
}
2018-03-21 12:18:47.732 WARN 8520 --- [nio-8099-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved exception caused by Handler execution: org.springframework.http.converter.HttpMessageNotReadableException: I/O error while reading input message; nested exception is java.io.IOException: Stream closed
This is my postman request
{
"webapp":{"webappName":"cavion17","path":"ud1","isQA":true},
"propertyFiles":"vchannel",
"propertytText":"demo property"}
I tried by removing the RequestBody annotation, then able to hit the service , but param objects are received as null.
So please suggest how to retrieve objects in the restcontroller?
You cannot use multiple #RequestBody annotations in Spring. You need to wrap all these in an object.
Some like this
// some imports here
public class IncomingRequestBody {
private Webapp webapp;
private String propertryFiles;
private String propertyText;
// add getters and setters here
}
And in your controller
#RequestMapping(value = "/test", method = RequestMethod.POST)
public String test(#RequestBody IncomingRequestBody requestBody) {
System.out.println(requestBody.getPropertyFiles());
// other statement
return "ok good";
}
Read more here
Passing multiple variables in #RequestBody to a Spring MVC controller using Ajax
Based on the sample postman payload you gave, you will need:
public class MyObject {
private MyWebapp webapp;
private String propertyFiles;
private String propertytText;
// your getters /setters here as needed
}
and
public class MyWebapp {
private String webappName;
private String path;
private boolean isQA;
// getters setters here
}
Then on your controller change it to:
#RequestMapping(value = "/test", method = RequestMethod.POST)
public String test(#RequestBody MyObject payload) {
// then access the fields from the payload like
payload.getPropertyFiles();
return "ok good";
}
I work with Java/ Spring MVC RESTful app and get 400 HTTP status error while doing a POST request. The #RestController method is provided,
#RequestMapping(value = "/generateAddress", method = RequestMethod.POST)
public ResponseEntity<WalletInfoWrapper> generateAddress(#RequestParam("walletName") String walletName,
#RequestParam("currencyName") String currencyName) {
logger.info("walletName {} and currencyName {}", walletName, currencyName);
// return if the wallet name or the currency is null
if (Objects.isNull(walletName) || Objects.isNull(currencyName)) {
return new ResponseEntity<WalletInfoWrapper>(HttpStatus.NOT_ACCEPTABLE);
}
WalletInfo walletInfo = walletService.generateAddress(walletName, currencyName);
if (Objects.isNull(walletInfo)) {
return new ResponseEntity<WalletInfoWrapper>(HttpStatus.NOT_ACCEPTABLE);
}
WalletInfoWrapper walletInfoWrapper = new WalletInfoWrapper();
walletInfoWrapper.setName(walletInfo.getName());
return new ResponseEntity<WalletInfoWrapper>(walletInfoWrapper, HttpStatus.CREATED);
}
The POST request in the Postman provided below,
The error message informs, Required String parameter 'walletName' is not present
I can also provide the code for the services and the dataase layers for observing the drop-down operations. What is the issue here?
UPDATE
I updated the Postman request like this and still having the same error,
UPDATE 1
I still have the same issue,
I POST with the data,
{"walletName":"puut","currencyName":"Bitcoin"}
The code is provided below,
#RequestMapping(value = "/generateAddress", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<WalletInfoWrapper> generateAddress(#RequestBody WalletWithMoneyRequest walletWithMoneyRequest) {
String walletName = walletWithMoneyRequest.getWalletName();
String currencyName = walletWithMoneyRequest.getCurrencyName();
logger.info("walletName {} and currencyName {}", walletName, currencyName);
// return if the wallet name or the currency is null
if (Objects.isNull(walletName) || Objects.isNull(currencyName)) {
return new ResponseEntity<WalletInfoWrapper>(HttpStatus.NOT_ACCEPTABLE);
}
WalletInfo walletInfo = walletService.generateAddress(walletName, currencyName);
if (Objects.isNull(walletInfo)) {
return new ResponseEntity<WalletInfoWrapper>(HttpStatus.NOT_ACCEPTABLE);
}
WalletInfoWrapper walletInfoWrapper = new WalletInfoWrapper();
walletInfoWrapper.setName(walletInfo.getName());
return new ResponseEntity<WalletInfoWrapper>(walletInfoWrapper, HttpStatus.CREATED);
}
The POJO is provided,
private class WalletWithMoneyRequest {
String walletName;
String currencyName;
public WalletWithMoneyRequest(String walletName, String currencyName) {
this.walletName = walletName;
this.currencyName = currencyName;
}
public WalletWithMoneyRequest() {
}
public String getWalletName() {
return walletName;
}
public String getCurrencyName() {
return currencyName;
}
public void setCurrencyName(String currencyName) {
this.currencyName = currencyName;
}
public void setWalletName(String walletName) {
this.walletName = walletName;
}
}
This is the error message,
Here ia the Tomcat server info,
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver: 08/19/2017 19:45:55 - Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `mobi.puut.controllers.WalletRestController$WalletWithMoneyRequest` (although at least one Creator exists): can only instantiate non-static inner class by using default, no-argument constructor; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `mobi.puut.controllers.WalletRestController$WalletWithMoneyRequest` (although at least one Creator exists): can only instantiate non-static inner class by using default, no-argument constructor
at [Source: (PushbackInputStream); line: 1, column: 2]
Tomcat Localhost log
Tomcat Catalina log
Edit
In your Postman request, instead of sending JSON, send the values as x-www-form-urlencoded.
Your controller is expecting 2 request parameters that normally look like this: /someurl?walletName=my-wallets-name¤cyName=dollars.
You're sending a json string in the post body, but no formal parameters. You need to update either your POST, or your controller to make the two ends agree. I think you probably want to replace the two #RequestParam annotated Strings, with a Java pojo that has two String members: walletName and currencyName, drop that pojo in your request method as an argument and precede it with the annotation #RequestBody. This will match your json post.
To have your controller accept the post with JSON in the body edit it like this:
#RequestMapping(value = "/generateAddress", method = RequestMethod.POST)
public ResponseEntity<WalletInfoWrapper> generateAddress(#RequestBody
WalletWithMoneyRequest myJsonRequestComingIn) {
logger.info("walletName {} and currencyName {}", myJsonRequestComingIn.getWalletName(), myJsonRequestComingIn.getCurrencyName());
And your pojo
public class WalletWithMoneyRequest{
private String walletName;
private String currencyName;
//getters and setters down here.
To elaborate on zerpsed's answer.
Change the signature to:
public ResponseEntity<WalletInfoWrapper> generateAddress(#ResponseBody WalletPOJO walletCurrency)
Where the WalletPOJO has the two fields walletName and currencyName
I believe the issue is solved for now. I have used a POJO as suggested with the #RequestBody parameter in the RESTful method. The catch here is I need to make the POJO out of the class (in the same file though) and later, put in the entity directory as an entity.
class WalletWithMoneyRequest {
String walletName;
String currencyName;
public WalletWithMoneyRequest(String walletName, String currencyName) {
this.walletName = walletName;
this.currencyName = currencyName;
}
public WalletWithMoneyRequest() {
}
public String getWalletName() {
return walletName;
}
public String getCurrencyName() {
return currencyName;
}
public void setCurrencyName(String currencyName) {
this.currencyName = currencyName;
}
public void setWalletName(String walletName) {
this.walletName = walletName;
}
}
The main issue is believe was an error in the HQL,
I wrote currency =: currency where it should be currency = :currency
I still can't have the data in the database as I will need to modify the method in the database layer.
En POSTMAN set variables in params
I've been trying to send an object from one application to another using rest.
Sender:
#Controller
public class Sender {
#RequestMapping(value = "/comMessageApp-api/getMessages")
public String restGetMessages() {
String url = "http://localhost:8079/comMessageApp-api/responseMessages";
HttpEntity<Dto2> entity = new HttpEntity<>(new Dto2());
ResponseEntity<Dto2> response = restTemplate.exchange(url, HttpMethod.POST, entity, Dto2.class);
}
}
Receiver:
#RestController
public class Receiver {
#RequestMapping(value = "/comMessageApp-api/responseMessages")
public void restResponseMessages(HttpEntity<Dto2> request) {
System.out.println(request.getBody());
}
}
DTO:
public class Dto2 {
private String string = "Test string";
public Dto2() {
}
public String getString() {
return string;
}
public void setString(String string) {
this.string = string;
}
}
Jackson is used serialization/deserialization.
Any ideas, why request.getBody() printed in the Receiver is null???
I tried to send the object inside HttpEntity and inside RequestEntity. No success in both cases. On the receiving side I always get null.
Your sender (client) side is very close but your server side doesn't return a value so change the type to Void:
ResponseEntity<Void> response = restOps.exchange(url, HttpMethod.POST, entity, Void.class);
Your receiver (server) side is not quite set up correctly either, you need to set the HTTP method to [edited] POST. You'll also need to tell Spring to map the body of the request (your rest payload) onto the parameter;
#RequestMapping(value = "/comMessageApp-api/responseMessages", method=RequestMethod.POST)
public void recieveDto (#RequestBody final Dto dto) {
System.out.println(dto.toString());
}
[EDIT] Brainfart, the http method should be set to POST on receive annotation.
[Further suggestion]
403 errors may be due to Spring Security, if you have it switched on (check your POM if you're not sure) try this;
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests().
antMatchers("/**").permitAll();
}
}
You'll want to be tightening up security once you know it works.
try to use #RequestMapping(method = RequestMethod.POST, produces = "application/json", consumes = "application/json")