I'm creating a REST API that will accept JSON requests.
I'm testing it out using CURL:
curl -i -POST -H 'Accept: application/json' -d '{"id":1,"pan":11111}' http://localhost:8080/PurchaseAPIServer/api/purchase
But getting the following error:
HTTP/1.1 415 Unsupported Media Type
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Length: 1051
Date: Wed, 25 Apr 2012 21:36:14 GMT
The server refused this request because the request entity is in a format not supported by the requested resource for the requested method ().
When debugging it never even gets into my create action in the controller.
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import com.app.model.Purchase;
import com.app.service.IPurchaseService;
#Controller
public class PurchaseController {
#Autowired
private IPurchaseService purchaseService;
#RequestMapping(value = "purchase", method = RequestMethod.GET)
#ResponseBody
public final List<Purchase> getAll() {
return purchaseService.getAll();
}
#RequestMapping(value = "purchase", method = RequestMethod.POST)
#ResponseStatus( HttpStatus.CREATED )
public void create(#RequestBody final Purchase entity) {
purchaseService.addPurchase(entity);
}
}
UPDATE
I added Jackson config to AppConfig.java:
#Configuration
#ComponentScan(basePackages = "com.app")
public class AppConfig {
#Bean
public AnnotationMethodHandlerAdapter annotationMethodHandlerAdapter()
{
final AnnotationMethodHandlerAdapter annotationMethodHandlerAdapter = new AnnotationMethodHandlerAdapter();
final MappingJacksonHttpMessageConverter mappingJacksonHttpMessageConverter = new MappingJacksonHttpMessageConverter();
HttpMessageConverter<?>[] httpMessageConverter = { mappingJacksonHttpMessageConverter };
String[] supportedHttpMethods = { "POST", "GET", "HEAD" };
annotationMethodHandlerAdapter.setMessageConverters(httpMessageConverter);
annotationMethodHandlerAdapter.setSupportedMethods(supportedHttpMethods);
return annotationMethodHandlerAdapter;
}
}
My GETs are working correctly now:
curl -i -H "Content-Type:application/json" -H "Accept:application/json" http://localhost:8080/PurchaseAPIServer/api/purchase
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/json
Transfer-Encoding: chunked
Date: Thu, 26 Apr 2012 21:19:55 GMT
[{"id":1,"pan":111}]
But I get the following when attempting a POST:
curl -i -X POST -H "Content-Type:application/json" -H "Accept:application/json" http://localhost:8080/PurchaseAPIServer/api/purchaseMe -d "{"id":2,"pan":122}"
HTTP/1.1 400 Bad Request
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Length: 971
Date: Thu, 26 Apr 2012 21:29:56 GMT
Connection: close
The request sent by the client was syntactically incorrect ().
My Model:
#Entity
#XmlRootElement
public class Purchase implements Serializable {
/**
*
*/
private static final long serialVersionUID = 6603477834338392140L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private Long pan;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getPan() {
return pan;
}
public void setPan(Long pan) {
this.pan = pan;
}
}
Any ideas where I'm going wrong?
Thanks
As sdouglass suggested, Spring MVC automatically detects Jackson and sets up a MappingJacksonHttpMessageConverter to handle conversion to/from JSON. But I did need explicity configure the converter to get it to work as he also pointed out.
I added the following and my CURL GET requests were working..Hooray.
AppConfig.java
#Configuration
#ComponentScan(basePackages = "com.app")
public class AppConfig {
#Bean
public AnnotationMethodHandlerAdapter annotationMethodHandlerAdapter()
{
final AnnotationMethodHandlerAdapter annotationMethodHandlerAdapter = new AnnotationMethodHandlerAdapter();
final MappingJacksonHttpMessageConverter mappingJacksonHttpMessageConverter = new MappingJacksonHttpMessageConverter();
HttpMessageConverter<?>[] httpMessageConverter = { mappingJacksonHttpMessageConverter };
String[] supportedHttpMethods = { "POST", "GET", "HEAD" };
annotationMethodHandlerAdapter.setMessageConverters(httpMessageConverter);
annotationMethodHandlerAdapter.setSupportedMethods(supportedHttpMethods);
return annotationMethodHandlerAdapter;
}
}
curl -i -H "Content-Type:application/json" -H "Accept:application/json" http://localhost:8080/PurchaseAPIServer/api/purchase
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/json
Transfer-Encoding: chunked
Date: Thu, 26 Apr 2012 21:19:55 GMT
[{"id":1,"pan":111}]
But the following CURL POST was still not working (Never hitting the controller action and giving no console debug info.
curl -i -X POST -H "Content-Type:application/json" http://localhost:8080/PurchaseAPIServer/api/purchaseMe -d "{"id":2,"pan":122}"
HTTP/1.1 400 Bad Request
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Length: 971
Date: Thu, 26 Apr 2012 21:29:56 GMT
Connection: close
The request sent by the client was syntactically incorrect ().
So I added Logback to get some detailed debugging started.
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>/home/thomas/springApps/purchaseapi.log</file>
<encoder>
<pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n
</pattern>
</encoder>
</appender>
<logger name="org.hibernate" level="DEBUG" />
<logger name="org.springframework" level="TRACE" />
<logger name="org.springframework.transaction" level="INFO" />
<logger name="org.springframework.security" level="INFO" /> <!-- to debug security related issues (DEBUG) -->
<logger name="org.springframework.web.servlet.mvc" level="TRACE" /> <!-- some serialization issues are at trace level here: org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod -->
<!-- our service -->
<logger name="com.app" level="DEBUG" />
<!-- <logger name="com.app" level="INFO" /> --><!-- to follow if setup is being executed -->
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</configuration>
Adding TRACE level debugging to org.springframework.web.servlet.mvc gave me the answer to the problem.
2012-04-28 14:17:44,579 DEBUG [http-bio-8080-exec-3] o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor [AbstractMessageConverterMethodArgumentResolver.java:117] Reading [com.app.model.Purchase] as "application/json" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter#74a14fed]
2012-04-28 14:17:44,604 TRACE [http-bio-8080-exec-3] o.s.w.s.m.m.a.ServletInvocableHandlerMethod [InvocableHandlerMethod.java:159] Error resolving argument [0] [type=com.app.model.Purchase]
HandlerMethod details:
Controller [com.app.controller.PurchaseController]
Method [public void com.app.controller.PurchaseController.create(com.app.model.Purchase)]
org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Unexpected character ('p' (code 112)): was expecting double-quote to start field name
I changed my CURL POSTs to the following an it all worked:
curl -i -X POST -H "Content-Type:application/json" http://localhost:8080/PurchaseAPIServer/api/purchase -d '{"pan":11111}'
HTTP/1.1 201 Created
Server: Apache-Coyote/1.1
Content-Length: 0
Date: Sat, 28 Apr 2012 13:19:40 GMT
Hopefully someone finds this useful.
If I recall correctly the Spring docs say that Spring MVC will automatically detect Jackson on the classpath and set up a MappingJacksonHttpMessageConverter to handle conversion to/from JSON, but I think I have experienced situations where I had to manually/explictly configure that converter to get things to work. You may want to try adding this to your MVC config XML:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
</list>
</property>
</bean>
UPDATE: It was this plus properly formatting the JSON being posted, see https://stackoverflow.com/a/10363876/433789
Its 2014 and I wanted to add a few updates to this question which helped me solve the same problem.
Code update to replace deprecated AnnotationMethodHandlerAdapter in Spring 3.2
#Configuration
public class AppConfig {
#Bean
public RequestMappingHandlerAdapter annotationMethodHandlerAdapter()
{
final RequestMappingHandlerAdapter annotationMethodHandlerAdapter = new RequestMappingHandlerAdapter();
final MappingJackson2HttpMessageConverter mappingJacksonHttpMessageConverter = new MappingJackson2HttpMessageConverter();
List<HttpMessageConverter<?>> httpMessageConverter = new ArrayList<HttpMessageConverter<?>>();
httpMessageConverter.add(mappingJacksonHttpMessageConverter);
String[] supportedHttpMethods = { "POST", "GET", "HEAD" };
annotationMethodHandlerAdapter.setMessageConverters(httpMessageConverter);
annotationMethodHandlerAdapter.setSupportedMethods(supportedHttpMethods);
return annotationMethodHandlerAdapter;
}
}
HTTP/1.1 415 Unsupported Media Type error
After spending many hours trying to figure out why I am STILL GETTING a 415 error even after adding the correct JSON configuration I finally realized that the problem was NOT with the server side but with the client side. In order for Spring to accept your JSON you MUST make sure that you are sending both "Content-Type : application/json" and "Accept: application/json" as part of your http headers. for me specifically it was an android application HttpUrlConnection which I had to set as:
public static String doPost(final String urlString,final String requestBodyString) throws IOException {
final URL url = new URL(urlString);
final HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
urlConnection.setReadTimeout(10000 /* milliseconds */);
urlConnection.setConnectTimeout(15000 /* milliseconds */);
urlConnection.setRequestProperty("Content-Type", "application/json");
urlConnection.setRequestProperty("Accept", "application/json");
urlConnection.setDoOutput(true);
urlConnection.setRequestMethod("POST");
urlConnection.setChunkedStreamingMode(0);
urlConnection.connect();
final PrintWriter out = new PrintWriter(urlConnection.getOutputStream());
out.print(requestBodyString);
out.close();
final InputStream in = new BufferedInputStream(urlConnection.getInputStream());
final String response = readIt(in);
in.close(); //important to close the stream
return response;
} finally {
urlConnection.disconnect();
}
}
Try adding a descriptor of what's in your POST request. That is, add to curl the header:
Content-Type: application/json
If you don't add it, curl will use the default text/html regardless of what you actually send.
Also, in PurchaseController.create() you have to add that the type accepted is application/json.
I had the same problem, which was solved by two changes in my code :
Missing #PathVariable in my method argument, my method didn't have any
Following method in my SpringConfig class since the one I had with handler interceptor was deprecated and giving some issue:
public RequestMappingHandlerAdapter RequestMappingHandlerAdapter()
{
final RequestMappingHandlerAdapter requestMappingHandlerAdapter = new RequestMappingHandlerAdapter();
final MappingJacksonHttpMessageConverter mappingJacksonHttpMessageConverter = new MappingJacksonHttpMessageConverter();
final String[] supportedHttpMethods = { "POST", "GET", "HEAD" };
requestMappingHandlerAdapter.getMessageConverters().add(0, mappingJacksonHttpMessageConverter);
requestMappingHandlerAdapter.setSupportedMethods(supportedHttpMethods);
return requestMappingHandlerAdapter;
}
Here is a unit test solution similar to yoram givon's answer - https://stackoverflow.com/a/22516235/1019307.
public class JSONFormatTest
{
MockMvc mockMvc;
// The controller used doesn't seem to be important though YMMV
#InjectMocks
ActivityController controller;
#Before
public void setup()
{
MockitoAnnotations.initMocks(this);
this.mockMvc = standaloneSetup(controller).setMessageConverters(new MappingJackson2HttpMessageConverter())
.build();
}
#Test
public void thatSaveNewDataCollectionUsesHttpCreated() throws Exception
{
String jsonContent = getHereJSON02();
this.mockMvc
.perform(
post("/data_collections").content(jsonContent).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)).andDo(print()).andExpect(status().isCreated());
}
private String getHereJSON01()
{
return "{\"dataCollectionId\":0,\"name\":\"Sat_016\",\"type\":\"httpUploadedFiles\"," ...
}
}
Run the unit test and the print() should print out the MockHttpServletRequest including the Exception.
In Eclipse (not sure about how to do this in other IDEs), click on the Exception link and a properties dialog for that exception should open. Tick the 'enabled' box to break on that exception.
Debug the unit test and Eclipse will break on the exception. Inspecting it should reveal the problem. In my case it was because I had two of the same entity in my JSON.
I experienced once and finally solved it by adding the jar file jackson-mapper-asl.jar. Go check if you have included all these dependencies although the exception itself does not tell u that.
And you really don't need to explicitly configure the bean, and you don't need to put "consumes" in #RequestMapping statement. I'm using Spring 3.1 btw.
contentType : "application/json" is the only one you need to configure. yes, client side.
Try to add the following code in your app configuration
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
</mvc:message-converters>
I had the same problem and I resolved it.
1 add MappingJackson2HttpMessageConverter as described in that thread (see also section 4 http://www.baeldung.com/spring-httpmessageconverter-rest)
2 use correct command (with escape symbols):
curl -i -X POST -H "Content-Type:application/json" -d "{\"id\":\"id1\",\"password\":\"password1\"}" http://localhost:8080/user
Related
I am newbie in implementing SpringBoot+RestfulWebservice.In my project, exceptions are handled globally using #ControllerAdvice and Custom class is created to set the error code and error message in String format.We are passing the error object to HTTPResponse and returing the response.But I am wondering how the errormessages are converted in JSON format as , we are not explicitly using any httpMessageConverter.
- Is Spring Boot internally do the conversion?
Please help me in understanding the behavior. Give me some insights,though you feel like its basic question.
Basically Spring Boot defaults to JSON for all the things when you don't provide specifics around content-type negotiation.
As per the spring boot documentation on error handling here using #ControllerAdvice defaults to producing JSON formatted errors. From the docs:
You can also define a class annotated with #ControllerAdvice to customize the JSON document to return for a particular controller and/or exception type, as shown in the following example:
This page on mkyong.com has a good write up about how to customise the ControllerAdvice error handling.
As an example of JSON usage, this very bare bones controller will do its best to render any POJO as JSON (note if you just provide a primitive like a long it will simply return the primitive in text, but set the content-type as application/json)
#RequestMapping("api/time")
#RestController
public class TestApi {
#GetMapping
public Map<String, Long> time(){
Map<String, Long> res = new HashMap<String, Long>();
res.put("time_in_nanos", System.nanoTime());
return res;
}
}
example:
$ curl -v http://localhost:8080/api/time
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET /api/time HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 200
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Tue, 04 Feb 2020 04:18:35 GMT
<
* Connection #0 to host localhost left intact
{"time_in_nanos":47078744054692}
That's for default requests (ie no Accept header, or Accept: */*), if you specify application/xml or something else it typically wont work:
$ curl -v http://localhost:8080/api/time --header 'Accept: application/xml'
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET /api/time HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.1
> Accept: application/xml
>
< HTTP/1.1 406
< Content-Length: 0
< Date: Tue, 04 Feb 2020 04:17:38 GMT
<
* Connection #0 to host localhost left intact
* Closing connection 0
By default springboot registers the following HttpMessageConverters on startup :
ByteArrayHttpMessageConverter – converts byte arrays
StringHttpMessageConverter – converts Strings
ResourceHttpMessageConverter – converts org.springframework.core.io.Resource for any type of octet stream
SourceHttpMessageConverter – converts javax.xml.transform.Source
FormHttpMessageConverter – converts form data to/from a MultiValueMap<String, String>.
Jaxb2RootElementHttpMessageConverter – converts Java objects to/from XML (added only if JAXB2 is present on the classpath)
MappingJackson2HttpMessageConverter – converts JSON (added only if Jackson 2 is present on the classpath)
MappingJacksonHttpMessageConverter – converts JSON (added only if Jackson is present on the classpath)
AtomFeedHttpMessageConverter – converts Atom feeds (added only if Rome is present on the classpath)
RssChannelHttpMessageConverter – converts RSS feeds (added only if Rome is present on the classpath)
So, if you are returning an object from your controller advice , spring will automatically by default call the Jackson converter to convert the object into a valid Json response.
Basically springboot checks the MIME type to decide which implementation of HttpMessageConverter to use.Also, it will depend on the "Accept" header to decide the type of data that the caller is expecting.If it's a request thatis received springboot will use the "Content-type" header to decide the type of data that is send.
i created a small json example... all worked quite fine, i'am just not able to send complex multiparameter to a service-method. With just one parameter it works... at the moment i'm not sure that my json call is wrong or something in my source/config is wrong.
First of all my lib-Dependencies:
org.springframework.spring-webmvc 4.0.6.RELEASE
org.springframework.spring-context 4.0.0.RELEASE
com.fasterxml.jackson.core.jackson-databind 2.2.3
Here is my spring-config:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Configure to plugin JSON as request and response in method handler -->
<annotation-driven>
<message-converters>
<beans:bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<beans:property name="objectMapper">
<beans:bean class="com.test.webservice.EnvironmentObjectMapper" />
</beans:property>
</beans:bean>
</message-converters>
</annotation-driven>
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by #Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<!-- only components from this package can be wired by spring -->
<context:component-scan base-package="com.test.*" />
</beans:beans>
Here is the used ObjectMapper:
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
public class EnvironmentObjectMapper extends ObjectMapper{
/**
*
*/
private static final long serialVersionUID = -4831947927759735004L;
public EnvironmentObjectMapper() {
this.setVisibilityChecker(
getSerializationConfig().
getDefaultVisibilityChecker().
withFieldVisibility(JsonAutoDetect.Visibility.ANY).
withGetterVisibility(JsonAutoDetect.Visibility.NONE).
withSetterVisibility(JsonAutoDetect.Visibility.NONE).
withCreatorVisibility(JsonAutoDetect.Visibility.NONE).
withIsGetterVisibility(JsonAutoDetect.Visibility.NONE));
this.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
}
}
Here is a Simple-Test Code:
#RequestMapping(value = "/rest/test1", method = RequestMethod.POST)
public void test(#RequestBody String name, #RequestBody String name2){
System.out.println("Test - name: "+ name + " name2: " + name2);
}
To call this method i use the Firefox RESTClient. Header is set to Content-Type:application/json
Body is set to: {"name":"karl", "name2:"fritz"}
I get this response:
Status Code: 400 Bad Request
Cache-Control: must-revalidate,no-cache,no-store
Content-Length: 1379
Content-Type: text/html;charset=ISO-8859-1
Server: Jetty(7.2.0.v20101020)
and at the server this:
15:32:30.588 [qtp1879112077-17] DEBUG o.s.web.servlet.DispatcherServlet - DispatcherServlet with name 'appServlet' processing POST request for [/rest/test1]
15:32:30.588 [qtp1879112077-17] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Looking up handler method for path /rest/test1
15:32:30.588 [qtp1879112077-17] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Returning handler method [public void com.test.webservice.JustAServiceController.test(java.lang.String,java.lang.String)]
15:32:30.588 [qtp1879112077-17] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'justAServiceController'
15:32:30.588 [qtp1879112077-17] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Reading [class java.lang.String] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter#3d467064]
15:32:30.588 [qtp1879112077-17] DEBUG o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver - Resolving exception from handler [public void com.test.webservice.JustAServiceController.test(java.lang.String,java.lang.String)]: org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: org.eclipse.jetty.server.HttpInput#309efc1f; line: 1, column: 1]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: org.eclipse.jetty.server.HttpInput#309efc1f; line: 1, column: 1]
15:32:30.588 [qtp1879112077-17] DEBUG o.s.w.s.m.a.ResponseStatusExceptionResolver - Resolving exception from handler [public void com.test.webservice.JustAServiceController.test(java.lang.String,java.lang.String)]: org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: org.eclipse.jetty.server.HttpInput#309efc1f; line: 1, column: 1]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: org.eclipse.jetty.server.HttpInput#309efc1f; line: 1, column: 1]
15:32:30.588 [qtp1879112077-17] DEBUG o.s.w.s.m.s.DefaultHandlerExceptionResolver - Resolving exception from handler [public void com.test.webservice.JustAServiceController.test(java.lang.String,java.lang.String)]: org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: org.eclipse.jetty.server.HttpInput#309efc1f; line: 1, column: 1]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: org.eclipse.jetty.server.HttpInput#309efc1f; line: 1, column: 1]
15:32:30.588 [qtp1879112077-17] DEBUG o.s.web.servlet.DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'appServlet': assuming HandlerAdapter completed request handling
15:32:30.588 [qtp1879112077-17] DEBUG o.s.web.servlet.DispatcherServlet - Successfully completed request
I have tried many different variants to set the parameters into the request body. But nothing worked. Anybody an idea what i did wrong? Thank you very much in advance.
You cannot have multiple #RequestBody annotations. #RequestBody annotated parameter is expected to hold the entire body of the request and bind to one object.
You should use different approach such as
Introduce a wrapper object that encapsulates your strings, and change your signature. e.g
Wrapper Object
class MyWrapper{
String name, name2;
//ToDo: Create constructors
String getname(){
return name;
}
String getName2(){
return name2;
}
//ToDo: create Setters
}
Your test code
#RequestMapping(value = "/rest/test1", method = RequestMethod.POST)
public void test(#RequestBody MyWrapper wrapper){
System.out.println("Test - name: "+ wrapper.getName() + " name2: " + wrapper.getName2());
}
Other options would be to pass the data with the URI path, or define custom annotations (which is more complex) see Passing multiple variables in #RequestBody to a Spring MVC controller using Ajax
I'm using dropwizard 0.6.2 for my service. The healthcheck response from dropwizard returns plain text. And I found a question in stackoverflow which had an answer that says we can pass a ObjectMapper to a healthcheck. But I couldn't able to find a way to pass the ObjectMapper to the HealthCheck.
Is there a way to return the healthcheck response in JSON?
As of Dropwizard 0.7, the /healthcheck path returns a JSON response:
HTTP/1.1 200 OK
Cache-Control: must-revalidate,no-cache,no-store
Content-Length: 299
Content-Type: application/json
Date: Thu, 14 Aug 2014 07:55:29 GMT
{
"My custom HealthCheck":
{
"healthy": true,
"message": "your message here"
},
"deadlocks":
{
"healthy": true
},
"storage":
{
"healthy": true
}
}
The Dropwizard use the codehale HealthCheck class.
You can call Result.healthy() and passing for parameter your JSON string.
In the method that you call the healthcheck you can use:
Result.healthy("your json");
I have some problem with sending request to spring mvc controller.
I have got entity:
public class Person {
private String name;
private int age;
private String city;
//..getters setters
}
and SpringMvc controller:
#Controller
#RequestMapping("/companies")
public class FirmaController {
#RequestMapping(value = "/addPerson", method = RequestMethod.POST, headers = {"Content-type=application/json"})
public String addPerson(#RequestBody Person person) {
return "person";
}
}
When i would like to send request to server with curl:
curl -i -X POST -HContent-Type:application/json -HAccept:application/json http://localhost:8080/api/companies/addPerson -d "{ 'name': 'Gerry', 'age': 20, 'city': 'Sydney' }"
i have got a HTTP/1.1 400 Bad Request:
HTTP/1.1 400 Bad Request
Content-Type: text/html;charset=ISO-8859-1
Cache-Control: must-revalidate,no-cache,no-store
Content-Length: 1392
Server: Jetty(8.1.10.v20130312)
What I do wrong?
The data you send is not valid JSON. Strings have to be wrapped in double quotes " not single quotes ' like in your example.
If you don't have an old version of Spring you should use consumes = "application/json" instead of headers=....
This one is correct:
curl -i -X POST -HContent-Type:application/json
-HAccept:application/json
http://localhost:8080/api/companies/addPerson
-d '{ "name": "Gerry", "age": 20, "city": "Sydney" }'
I have a ASP.NET MVC3 application, which uses JSON to comunicate with a Flash UI.
I´m use an ActionFilterAttribute to handle JSON exceptions (from Handle JSON Exceptions Gracefully in ASP.NET MVC 2: http://www.dotnetcurry.com/ShowArticle.aspx?ID=496):
public class HandleJsonExceptionAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Exception != null)
{
filterContext.HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError;
filterContext.Result = new JsonResult()
{
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
Data = new
{
filterContext.Exception.Message,
}
};
filterContext.ExceptionHandled = true;
}
}
}
It´s works ok when executes on localhost, details from fiddler:
HTTP/1.1 500 Internal Server Error
Cache-Control: private
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNetMvc-Version: 3.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Mon, 11 Apr 2011 19:05:21 GMT
Content-Length: 34
{"Message":"No está autenticado"}
But, when executed from remote clients, on the LAN for example, I get the response in "Content-Type: text/html" instead "Content-Type: application/json;" and the content is a standard html error page:
500 - Internal server error.
There is a problem with the resource you are looking for, and it cannot be displayed.
HTTP/1.1 500 Internal Server Error
Cache-Control: private
Content-Type: text/html
Server: Microsoft-IIS/7.5
X-AspNetMvc-Version: 3.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Mon, 11 Apr 2011 19:07:53 GMT
Content-Length: 1208
What or where I need to configure something to get the JSON response on remote requests?
I need the flash UI receive a http 500 error, but with the json message instead the html.
Looking at the article the javascript only seems to be wire up for local requests.
What you need is to be using jsonp. (json with padding). This will allow you to do proper cross domain request returning a json object.
Further info can be found here and here.
I had a same problem, I solved with this code in web.config
<httpErrors existingResponse="PassTrough"></httpErrors>