When I send an HTTP post request to spring boot rest API from my angular application, request is failing with below error
Browser Error
HTTP Status 415 – Unsupported Media Type
Type Status Report
Description: The origin server is refusing to service the request because the payload is in a format
not supported by this method on the target resource
Spring boot console error
java.lang.IllegalArgumentException: No converter found for return value of type: class java.util.LinkedHashMap
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:187) ~[spring-webmvc-4.3.8.RELEASE.jar:4.3.8.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor.handleReturnValue(HttpEntityMethodProcessor.java:203) ~[spring-webmvc-4.3.8.RELEASE.jar:4.3.8.RELEASE]
at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:81) ~[spring-web-4.3.8.RELEASE.jar:4.3.8.RELEASE]
.......
What I have tried so far
As this solution mentioned, i have added the necessary headers to the request from angular end
this.http.post(ipUrl, args, { headers: new HttpHeaders({'Content-Type': 'application/json', 'Accept': 'application/json', 'Access-Control-Allow-Headers': 'Content-Type'})});
As this answer, I have added getters/setters to the Model objects
I want to know where i went wrong and how to resolve this issue?
UPDATE
Springboot Rest Controller method
#PostMapping("/login")
public #ResponseBody ResponseWrapper<WebUser> login(#RequestBody LoginData loginData){
try {
return loginService.loginProcess(loginData);
}
catch (Exception ex){
ProgrammerAlert.printStackTrace(ex);
return new ResponseWrapper<>(ResponseWrapper.ERROR, ex.getMessage());
}
}
Could you write your controller in this way. and see if it responds.
#ResponseBody
#RequestMapping(value = "/login",
method = RequestMethod.POST)
public ResponseWrapper<WebUser> login(...){
.
.
.
}
Is there a reason that you do not want to use RequestMapping ?
Is there any reasons not to add produces and consumes properties?
#PostMapping("/login", produces = MediaType.APPLICATION_JSON_UTF8, consumes = MediaType.APPLICATION_JSON_UTF8)
public #ResponseBody ResponseWrapper<WebUser> login(#RequestBody LoginData loginData){
try {
return loginService.loginProcess(loginData);
}
catch (Exception ex){
ProgrammerAlert.printStackTrace(ex);
return new ResponseWrapper<>(ResponseWrapper.ERROR, ex.getMessage());
}
}
or,
Did you add any JSON message converter, like jackson? Check your application has below dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
your return object should be converted to JSON properly. Add Jackson to you pom (separately from starter web) and retry.
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.2</version>
</dependency>
As per your recent edit, you're now getting 406 Not Acceptable, to fix this error, keep the media type of your Spring boot application's response same as the Accept header of your client. Try the following.
Change the value of produces to MediaType.APPLICATION_JSON as you have accept header in client as "application/json". Also please note:
APPLICATION_JSON_UTF8 is deprecated in favor of APPLICATION_JSON
Reference: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/http/MediaType.html
For those who are facing a similar issue, you can also check if there is any typo in Accept header as I often face this problem.
I also came across the same issue, I guess the answer of this question is very clear
HTTP Status 415 – Unsupported Media Type
while sending the request make the content type json instead of text
Related
I am working on a REST application built with Jackson-2.2.3.
Here is the Dependency:
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.2.3</version>
</dependency>
I have a simple endpoint to create a User as below:
#POST
#Path(value = "/addUser")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Response createUser(User user) {
...
}
As this endpoint consumes JSON, when api users send JSON Jackson will desearilize to User object.
If user invoke the endpoint with faulty JSON like, missing a property or bad structure. I want to log the fault JSON as a string and ERROR.
How can I achieve that?
I tried using Filters but didn't work.
Consider handling the JsonParseException:
Exception type for parsing problems, used when non-well-formed content (content that does not conform to JSON syntax as per specification) is encountered.
To achieve it, you could use an ExceptionMapper:
#Slf4j
#Provider
public class JsonParseExceptionMapper implements ExceptionMapper<JsonParseException> {
#Override
public Response toResponse(JsonParseException exception) {
log.error("Cannot parse JSON", exception);
return Response.status(Response.Status.BAD_REQUEST)
.entity("Cannot parse JSON")
.type(MediaType.TEXT_PLAIN)
.build();
}
}
For logging purposes, you may also be interested in getting some details from JsonLocation using exception.getLocation().
To register the exception mapper in Jersey, refer to this answer.
I have a webservice which calls another WS and returns the response from the second WS. It looks like so:
// MyController
public ResponseEntity<Foo> requestFooController(#RequestBody #Valid Bar request) {
return this.myService.requestFooService(request);
}
//MyService
ResponseEntity<Foo> requestFooService(Bar request) {
Buzz improvedRequest = ...
return this.secondWS.secondRequestFoo(improvedRequest);
}
When I call the API through Postman, I receive a HTTP OK response with an empty body. Yet, when I'm in debug mode I can see that the service is returning a ResponseEntity with a body. The headers are not lost though.
I changed my code like so and it works fine:
// MyController
public ResponseEntity<Foo> requestFooController(#RequestBody #Valid Bar request) {
ResponseEntity<Foo> tmp = this.myService.requestFooService(request);
return ResponseEntity.status(tmp.getStatusCode()).body(tmp.getBody());
}
Now through Postman I do have the expected body. However, I don't understand the behaviour. I thought that maybe it's due to the fact that the body is some kind of stream that can be read once or something similar. But from reading the source code I don't see anything that could explain this behaviour.
I'm using the Netflix-stack (so HTTP calls between the two WS are made through a Feign client).
Any idea why I'm getting this result?
EDIT:
More details on my stask:
SpringBoot 1.5.3.RELEASE
Feign 2.0.5
There is a bug that causes the named body of an HTTP MultiPart POST to fail. The symptom of this is that you make a POST request with a body, and Spring-Boot can't match it up to an endoint. The exception I see is:
2019-01-23 15:22:45.046 DEBUG 1639 --- [io-8080-exec-10] .w.s.m.m.a.ServletInvocableHandlerMethod : Failed to resolve argument 3 of type 'org.springframework.web.multipart.MultipartFile'
org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present
Zuul is doing caching of the request in order to re-try multiple times. In this process, it fails to preserve the named field for the binary body. You may find it working if you preface the request with zuul. So instead of http://myserver.com/myservice/endpoint use zuul in the path: http://myserver.com/zuul/myservice/endpoint
That will effectively avoid the saving of the request and the retry mechanism.
More details are available on this issue in Zuul's GitHub Bug List.
I have following Spring controller mapping:
#RequestMapping(value="/isSomethingHappening", method = RequestMethod.POST)
public #ResponseBody JsonResponse isSomethingHappening(HttpServletRequest httpRequest,#RequestParam("employeeId") String employeeId,
ModelMap model) throws IOException{
If I invoke this as below then I get 400 response.
var requestData = {"employeeId":XYZ.application.employeeId};
XYZ.network.fireAjaxRequestAsync("application/json", "forms/testing/isSomethingHappening", requestData, function(response, status, xhr){
But if I invoke this as below then I get success response.
var requestData = {"employeeId":XYZ.application.employeeId};
XYZ.network.fireAjaxRequestAsync("application/x-www-form-urlencoded", "forms/testing/isSomethingHappening", requestData, function(response, status, xhr){
I figured the fix but I am not able to understand why first one gave me error when my request data object var requestData = {"employeeId":XYZ.application.employeeId}; remained unchanged and I just changed the content type. To me application/json looks more appropriate content type because my request data is a JSON object.
Also, I have other instances where my controller mapping is as below:
#RequestMapping(value = "/getOnFlyResults", method = RequestMethod.POST)
public #ResponseBody JsonResponse getOnFlyResults(HttpServletRequest httpRequest,
#RequestBody testingRequestVO testingRequestVO, ModelMap modelMap) throws IOException{
And for invoking this, I send request as below:
var requestData = {"employeeId":XYZ.application.employeeId,
"fName":XYZ.application.fName,
"lName": XYZ.application.lName,
"telephoneNumber":telephoneNumber,
"testMode":XYZ.constant.onFly};
XYZ.network.fireAjaxRequestAsync("application/json", "forms/testing/startTest", JSON.stringify(requestData), function(response, status, xhr){
I don't understand that why I have to stringify the data using JSON.stringify(requestData), if I do not do this then I will get 400.
Once I stringify then it becomes a string then my content type should have been text/plain but it works with application/json
Please note that I know the code fixes, but I want to understand the concept. I have read this and it doesn't explain the concept in details and queries I have.
It is common to use Jackson library in your Spring application to process JSON.
If you are using Ant, try adding Jackson to your libraries.
You can download the Jackson library directly from Maven Central. Here is an example Maven dependency block (but get the latest version):
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
Make sure you have the annotation-driven tag in your Spring configuration:
<annotation-driven />
With or without Jackson, it may also help to specify that the controller endpoint produces or consumes JSON;
#RequestMapping(value="/getjson",
produces=MediaType.APPLICATION_JSON_VALUE, consumes=MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody MyObject getJSON(){
return new MyObject();
}
I need help creating a POST request to my Java Spring Restcontroller.
This is my controller -
#RestController
#RequestMapping("hedgesimulator/")
public class HedgeSimulatorController {
#RequestMapping(value = "hedgesim/", method = RequestMethod.POST)
#ResponseBody
public HedgeSimulatorLog putHedgeSimulation(
#RequestBody HedgeSimulatorLog hedgeSimulatorLog) {
System.out.println(hedgeSimulatorLog.toJsonString());
return hedgeSimulatorLog;
}
}
I am using Chrome's "Advanced Rest Client" Plugin to POST my request to my URL (I am sure my localhost is running properly, etc.)
What do I need to add to my header?
I receive an error for "HTTP 400 - Status report: The request sent by the client was syntactically incorrect"
Please help!
To pass an object to controller you must configure HttpMessageConverter which helds serialization and deserealization of this object. For example, if you want to pass an object to controller as JSON, set a MappingJackson2HttpMessageConverter as parameter in your mvc declaration in spring config file.
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
If http message converter configured properly, maybe request was improperly formed.
#RequestMapping(value = "/hedgesim/", method = RequestMethod.POST)
Try with following, hope you might resolve the issue:
Since you are using #RestController annotation, so no need to use #ResponseBody annotation again, which is redundant.
If you are using spring boot, then make sure you have added the below dependency .
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
If the project is not spring boot, then add dependency for jackson : com.fasterxml.jackson.databind.ObjectMapper
Just to make sure the request body is correct, what you can do is, execute request method first, get the JSON response, pass the same JSON for POST, so this might avoid some typo/human error while creating JSON data.
Hope, it helps.
You can do the following checks.
Validate the request body you are sending through some online tool like
JSonLint.
Check whether MappingJackson2HttpMessageConverter is registered or not. By default, Spring registers this converter if you have the jar in the classpath.
No need to use #ResponseBody if you are using #RestController. So remove it.
For a complete example on creating and consuming REST Service using Spring 4.0, you can visit Techno Spots.
I am currently developing a webservice which will always return json as a response to any request(all good request are working already). I would like to return a json when the http status of the request is a bad request(status 400 to be exact). I used the #ControllerAdvice of spring mvc to do the job:
#ControllerAdvice
public class RestErrorHandler {
#ExceptionHandler(Exception.class)
#ResponseStatus(value=HttpStatus.BAD_REQUEST, reason="Something went wrong. Please check your JSON REQUEST!")
public #ResponseBody ErrorClass processValidationError() {
// some stuff in setting the error response
return new ErrorClass();
}
But what happen is that it returns the default Tomcat 7 error message for bad request and not the json I set. processValidationError() will return an ErrorClass instance which will automatically be in json format using jackson plugin. Did I missed something?