No message body reader has been found [duplicate] - json

I have a jaxrs client configured like this:
<jaxrs:client id="opaRestProxy" name="opaRestProxy"
address="${endpoint}" serviceClass="com.test.RestProxy"
inheritHeaders="true" threadSafe="true">
<jaxrs:headers>
<entry key="Accept" value="application/json" />
<entry key="Content-Type" value="application/json" />
</jaxrs:headers>
</jaxrs:client>
But when I send a request I get the following exception:
Caused by: org.apache.cxf.interceptor.Fault: .No message body writer has been found for class : class com.test.RequestObject, ContentType : application/json.
at org.apache.cxf.jaxrs.client.ClientProxyImpl$BodyWriter.handleMessage(ClientProxyImpl.java:646)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
at org.apache.cxf.jaxrs.client.ClientProxyImpl.doChainedInvocation(ClientProxyImpl.java:527)
... 47 more
My RestProxy class looks like this:
#Component
public interface RestProxy {
#POST
#Path("/getSomething")
String getSomething(RequestObject RequestObject);
}

If you are using Jackson JSON library you need to add these xml tags to your application context.
<jaxrs:providers>
<bean id="jacksonProvider" class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
</jaxrs:providers>
If you are using any other library add that bean to the providers tag. Hope that helps!

If you are consuming using javax.ws.rs.client.Client, please register the provider using client.register(new JacksonJsonProvider());

This answers point me in the right direction, yet i had to add on two parts to make it work on web.xml
<init-param>
<param-name>jaxrs.providers</param-name>
<param-value>
org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider
(writeXsiType=false)
</param-value>
</init-param>
And on the client call:
List<Object> providers = new ArrayList<>();
// add custom providers if any
providers.add(new JacksonJaxbJsonProvider());
WebClient client = WebClient.create(ENDPOINT_ADDRESS,providers);

Related

Spring Boot Microservice Jackson JSON serialisation NON NULL

I'm currently working on a Spring Boot ( Version 1.3.1 ) Microservice which connects to MongoDB backend and provides the backend data ( Ex: Provider object ) to the client via controller.
The project has got one class file which extends ResourceSupport ( Ex: ProviderResourceSupport ) and also another class which extends ResourceSupportAssembler class ( Ex: ProviderAssembler ) for generating Links to the Response objects.
Ideally my requirement is to customise the JSON objects on a need basis and as such using #JsonView ( followed this link - https://spring.io/blog/2014/12/02/latest-jackson-integration-improvements-in-spring ) and added Spring Jackson dependencies in the maven project.
I have also added spring.jackson.serialization-inclusion=non-null & spring.jackson.serialization.indent_output=true in the application.properties.
For one of the method in the controller, the response will be 'ResponseEntity< List< ProviderResourceSupport>>' , and this method is returning with a 'null' response if the data is not present.
I have added #JsonInclude(Include=NON_NULL) on my entity objects and controllers but still getting the 'null' response.
I don't want the 'null' as the response and request you to help me incase if anyone has faced the similar issue.
I fixed this null properties escaping from json response extending a Jackson Mapper Bean but I don't use Spring Boot, take a quickly look and check if this is suitable for you
public class Jackson2ObjectMapperCustom extends Jackson2ObjectMapperFactoryBean {
#Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
getObject().setSerializationInclusion(JsonInclude.Include.NON_NULL).setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
Hibernate5Module hibernateModule = new Hibernate5Module();
hibernateModule.disable(Feature.USE_TRANSIENT_ANNOTATION);
hibernateModule.enable(Feature.FORCE_LAZY_LOADING);
getObject().registerModules(new JavaTimeModule(), hibernateModule);
getObject().configure(SerializationFeature.INDENT_OUTPUT, true);
getObject().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
getObject().setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"));
}
}
And in my case I use Spring Xml configuration
<bean id="objectMapper" class="com.xxx.common.Jackson2ObjectMapperCustom" />
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="objectMapper"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>

Deserializing single-attribute JSON payload in Spring MVC controller

I want to create controller methods that semantically look like the following
public HttpEntity<?> deleteUser(String userId){
...
}
The client is going to pass the user ID as part of the JSON payload. If I try to annotate #RequestBody the string parameter and issue a {"userId":"foo"} payload, then I get an exception
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: java.io.PushbackInputStream#7311a203; line: 1, column: 1]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148) ~[jackson-databind-2.6.1.jar:2.6.1]
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:854) ~[jackson-databind-2.6.1.jar:2.6.1]
at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:62) ~[jackson-databind-2.6.1.jar:2.6.1]
at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:11) ~[jackson-databind-2.6.1.jar:2.6.1]
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3702) ~[jackson-databind-2.6.1.jar:2.6.1]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2798) ~[jackson-databind-2.6.1.jar:2.6.1]
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:221) ~[spring-web-4.2.0.RELEASE.jar:4.2.0.RELEASE]
And that is reasonable because JSON wants to deserialize a complex object (with namely one attribute) into a String.
I also know that "foo" is not valid JSON. And I know that I can use a Map<String,Object> or even better a ModelMap, and as a last resort I could use query string and #RequestParam, but today I have been clearly asked by my boss to find a way to use a plain string instead of an object, in order for code to look more readable.
How can I force Jackson/MVC to deserialize only the "username" property into a plain old String?
You will usually see this type of error when Spring MVC finds a request mapping that matches the URL path but the parameters (or headers or something) don't match what the handler method is expecting.
If you use the #RequestBody annotation then Spring MVC is expecting to map the entire body of the POST request to an Object,it dont work with String by default.
There are different way to do this as listed below:
1) Change method type of deleteUser() method type to GET instead of Post and use userId as String.
2) You could simply inject the HttpServletRequest into your method and read the body:
public void deleteUser(HttpServletRequest request) {
String userID = IOUtils.toString( request.getInputStream());
// do stuff
}
3) Use a wrapper (java model of the JSON object) that could replace the String parameter,and also this will work fine with the json coming in your post.
public class UserWrapper {
private String userId;
//getter setters
and then use in your controller as:
public void deleteUser(#RequestBody UserWrapper user) {
//do your stuff
}
4) Spring provides a way to configure multiple message converters as shown below:
Note: Then, requests to the various methods must specify the "content-type" header with an appropriate value. For those methods where the request body is mapped to a JAXB bean, specify "application/xml". And for those where the request body is a String, use "text/plain".
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonConverter" />
<ref bean="marshallingConverter" />
<ref bean="stringHttpMessageConverter" />
</list>
</property>
</bean>
<bean id="jsonConverter"
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="supportedMediaTypes" value="application/json" />
</bean>
<bean id="marshallingConverter"
class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<constructor-arg ref="jaxb2Marshaller" />
<property name="supportedMediaTypes" value="application/xml"/>
</bean>
<bean id="stringHttpMessageConverter"
class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes" value="text/plain"/>
</bean>
Hope this help you!

Spring MVC RESTful web services with Jackson: How to restrict to subset of URLs

Following the steps outlined here http://www.journaldev.com/2552/spring-restful-web-service-example-with-json-jackson-and-client-program , I've been able to setup my RESTful WS exactly how I want it.
Now, I want to make this app context a hybrid of RESTful WS (under a specific URL prefix /myapp/rest/) and standard MVC mappings for the rest of the site.
But from the servlet-context XML file, I can't really make out how to restrict MappingJackson2HttpMessageConverterto only apply to a certain URL prefix.
<!-- Configure to plugin JSON as request and response in method handler -->
<beans:bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<beans:property name="messageConverters">
<beans:list>
<beans:ref bean="jsonMessageConverter"/>
</beans:list>
</beans:property>
</beans:bean>
<!-- Configure bean to convert JSON to POJO and vice versa -->
<beans:bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
</beans:bean>
Is there anything else that I should be checking on here?
Thanks
Wong
You can have both SpringMVC style controllers and SpringMVC REST style controllers in the same application. In fact you can write one SpringMVC handler method and a REST Endpoint in same controller too.
#Controller
public class MyController
{
#RequestMapping("/home")
public String homePage(Model model)
{
model.addAttribute("data",someObject);
return "home"; //this will render the view home.jsp
}
#RequestMapping(value="/users", method=RequestMethod.POST)
#ResponseBody
public User saveUser(#RequestBody User user)
{
//persist user
return user; //this will return JSON/XML based representation of User object
}
}
Observe the use of #RequestBody and #ResponseBody annotations for REST style handler methods.

spring-mvc return raw json string

I want the convenience of automatically serializing objects into JSON and ability to return raw JSON string. I am using Gson instead of Jackson, since Gson has been in my app for a while and I have existing tweaks, converters, and annotations peppered throughout my app.
<mvc:annotation-driven >
<mvc:message-converters register-defaults="true">
<bean class="com.test.GSONHttpMessageConverter" />
</mvc:message-converters>
</mvc:annotation-driven>
I can automatically serialize pojo's:
#RequestMapping(value="foo/{name}", method = RequestMethod.GET)
public #ResponseBody Shop getShopInJSON(#PathVariable String name) {
return new Shop();
}
I want this to work also:
#RequestMapping(value="rawJsonTest/{name}", method = RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody String rawJsonTest(#PathVariable String name) {
return "{\"test\":5}";
}
Result right now is an escaped value:
"{\"test\":5}"
instead of:
{"test":5}
The problem is that your custom converter takes precedence over the default ones. It's thus called, considers the String as a raw String that must be converted to JSON, and thus escapes the double quotes.
I'm not sure if and how it's possible with XML to register a converter after (and not before) the default ones, but you could set register-defaults to false and provide an explicit list of all the converters you want to apply. If org.springframework.http.converter.StringHttpMessageConverter is registered before your custom one, it will be called first and will send the returned String as is.
Thanks for the correct answer, #JB Nizet
Order matters:
<mvc:annotation-driven >
<mvc:message-converters register-defaults="true">
<bean class = "org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes" value="application/json; charset=UTF-8" />
</bean>
<bean class="com.test.GSONHttpMessageConverter" />
</mvc:message-converters>

Spring 3.0.5 - Adding #ModelAttribute to handler method signature results in JsonMappingException

I'm not sure whether this is a misconfiguration on my part, a misunderstanding of what can be accomplished via #ModelAttribute and automatic JSON content conversion, or a bug in either Spring or Jackson. If it turns out to be the latter, of course, I'll file an issue with the appropriate folks.
I've encountered a problem with adding a #ModelAttribute to a controller's handler method. The intent of the method is to expose a bean that's been populated from a form or previous submission, but I can reproduce the issue without actually submitting data into the bean.
I'm using the Spring mvc-showcase sample. It's currently using Spring 3.1, but I first encountered, and am able to reproduce, this issue on my 3.0.5 setup. The mvc-showcase sample uses a pretty standard servlet-context.xml:
servlet-context.xml
<?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"
xsi:schemaLocation="
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC #Controller programming model -->
<annotation-driven conversion-service="conversionService">
<argument-resolvers>
<beans:bean class="org.springframework.samples.mvc.data.custom.CustomArgumentResolver"/>
</argument-resolvers>
</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>
<!-- Imports user-defined #Controller beans that process client requests -->
<beans:import resource="controllers.xml" />
<!-- Only needed because we install custom converters to support the examples in the org.springframewok.samples.mvc.convert package -->
<beans:bean id="conversionService" class="org.springframework.samples.mvc.convert.CustomConversionServiceFactoryBean" />
<!-- Only needed because we require fileupload in the org.springframework.samples.mvc.fileupload package -->
<beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />
</beans:beans>
The controllers.xml referenced in the file simply sets up the relevant component-scan and view-controller for the root path. The relevant snippet is below.
controllers.xml
<!-- Maps '/' requests to the 'home' view -->
<mvc:view-controller path="/" view-name="home"/>
<context:component-scan base-package="org.springframework.samples.mvc" />
The test bean which I am attempting to deliver is a dead-simple POJO.
TestBean.java
package org.springframework.samples.mvc.test;
public class TestBean {
private String testField = "test#example.com";
public String getTestField() {
return testField;
}
public void setTestField(String testField) {
this.testField = testField;
}
}
And finally, the controller, which is also simple.
TestController.java
package org.springframework.samples.mvc.test;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
#Controller
#RequestMapping("test/*")
public class TestController {
#ModelAttribute("testBean")
public TestBean getTestBean() {
return new TestBean();
}
#RequestMapping(value = "beanOnly", method = RequestMethod.POST)
public #ResponseBody
TestBean testBean(#ModelAttribute("testBean") TestBean bean) {
return bean;
}
#RequestMapping(value = "withoutModel", method = RequestMethod.POST)
public #ResponseBody
Model testWithoutModel(Model model) {
model.addAttribute("result", "success");
return model;
}
#RequestMapping(value = "withModel", method = RequestMethod.POST)
public #ResponseBody
Model testWithModel(Model model, #ModelAttribute("testBean") TestBean bean) {
bean.setTestField("This is the new value of testField");
model.addAttribute("result", "success");
return model;
}
}
If I call the controller via the mapped path /mvc-showcase/test/beanOnly, I get a JSON representation of the bean, as expected. Calling the withoutModel handler delivers a JSON representation of the Spring Model object associated with the call. It includes the implicit #ModelAttribute from the initial declaration in the return value, but the bean is unavailable to the method. If I wish to process the results of a form submission, for example, and return a JSON response message, then I need that attribute.
The last method adds the #ModelAttribute, and this is where the trouble comes up. Calling /mvc-showcase/test/withModel causes an exception.
In my 3.0.5 installation, I get a JsonMappingException caused by a lack of serializer for FormattingConversionService. In the 3.1.0 sample, the exception is caused by lack of serializer for DefaultConversionService. I'll include the 3.1 exception here; it seems to have the same root cause, even if the path is a bit different.
3.1 org.codehaus.jackson.map.JsonMappingException
org.codehaus.jackson.map.JsonMappingException: No serializer found for class org.springframework.format.support.DefaultFormattingConversionService and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: org.springframework.validation.support.BindingAwareModelMap["org.springframework.validation.BindingResult.testBean"]->org.springframework.validation.BeanPropertyBindingResult["propertyAccessor"]->org.springframework.beans.BeanWrapperImpl["conversionService"])
at org.codehaus.jackson.map.ser.StdSerializerProvider$1.failForEmpty(StdSerializerProvider.java:89)
at org.codehaus.jackson.map.ser.StdSerializerProvider$1.serialize(StdSerializerProvider.java:62)
at org.codehaus.jackson.map.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:272)
at org.codehaus.jackson.map.ser.BeanSerializer.serializeFields(BeanSerializer.java:175)
at org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:147)
at org.codehaus.jackson.map.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:272)
at org.codehaus.jackson.map.ser.BeanSerializer.serializeFields(BeanSerializer.java:175)
at org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:147)
at org.codehaus.jackson.map.ser.MapSerializer.serializeFields(MapSerializer.java:207)
at org.codehaus.jackson.map.ser.MapSerializer.serialize(MapSerializer.java:140)
at org.codehaus.jackson.map.ser.MapSerializer.serialize(MapSerializer.java:22)
at org.codehaus.jackson.map.ser.StdSerializerProvider._serializeValue(StdSerializerProvider.java:315)
at org.codehaus.jackson.map.ser.StdSerializerProvider.serializeValue(StdSerializerProvider.java:242)
at org.codehaus.jackson.map.ObjectMapper.writeValue(ObjectMapper.java:1030)
at org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.writeInternal(MappingJacksonHttpMessageConverter.java:153)
at org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:181)
at org.springframework.web.servlet.mvc.method.annotation.support.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:121)
at org.springframework.web.servlet.mvc.method.annotation.support.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:101)
at org.springframework.web.servlet.mvc.method.annotation.support.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:81)
at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:64)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:114)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodAdapter.invokeHandlerMethod(RequestMappingHandlerMethodAdapter.java:505)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodAdapter.handleInternal(RequestMappingHandlerMethodAdapter.java:468)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:560)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at
...
So, is there some configuration I am missing that should allow the Jackson converter to properly handle a response derived from a handler with #ModelAttribute in the method signature? If not, any thoughts as to whether this is more likely a Spring bug or a Jackson bug? I'm leaning toward Spring, at this point.
It looks like a Spring config problem, when serializing to JSON the DefaultFormattingConversionService is empty and Jackson (by default) will throw an exception if a bean is empty see FAIL_ON_EMPTY_BEANS in the features documentation. But I am not clear why the bean is empty.
It should work if you set FAIL_ON_EMPTY_BEANS to false, but still doesn't really explain why it is happening in the first place.
DefaultFormattingConversionService is new to 3.1 - it extends the FormattingConversionService which explains the different exceptions between 3.0.5 and 3.1.
I do not think it is a Jackson problem, although a new version of Jackson (1.8.0) was released only 3 days ago so you could try that also.
I will try to reproduce this locally.