I've implemented a RESTful web service with Spring. The service responds in XML or JSON based on the Accept header. Here's the context.xml mapping:
<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller"/>
<bean id="xmlMessageConverter"
class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<constructor-arg ref="xstreamMarshaller"/>
<property name="supportedMediaTypes" value="application/xml"/>
</bean>
<bean id="jsonHttpMessageConverter"
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="prefixJson" value="false"/>
<property name="supportedMediaTypes" value="application/json"/>
</bean>
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<util:list id="beanList">
<ref bean="xmlMessageConverter"/>
<ref bean="jsonHttpMessageConverter"/>
</util:list>
</property>
</bean>
Here is my controller method:
#Controller
#RequestMapping(value = "/entityService")
class RestfulEntityService {
#Resource
private EntityService entityService;
#ResponseBody
#RequestMapping(value = "/getAllEntities", method = RequestMethod.GET)
public List<Entity> getAllEntities() {
return entityService.getAllEntities();
}
}
The XML response is valid, however, when the client sets the Accept header to application/json, the response is invalid JSON.
Here is the JSON response sample:
[{"id":3,"attributes":[{"id":18,"attributeValue":null,"attributeName":"mobile","attributeType":"varchar(40)","entity":{"id":3,"attributes":[{"id":18,"attributeValue":null,"attributeName":"mobile","attributeType":"varchar(40)","entity":{"id":3,"attributes":[{"id":18,"attributeValue":null,"attributeName":"mobile","attributeType":"varchar(40)","entity":{"id":3,"attributes": ..... repeats for a while and then stops..
You're using XStream to serialize XML responses and Jackson JSON to serialize JSON responses. Looking at the JSON output you posted, it seems like there's a circular reference issue at hand. I'm guessing Entity has a list of attributes, each pointing to their respective entity. XStream handles circular references transparently by using XPath, this allows to preserve references when deserializing back to objects. Jackson is able to handle circular references since v1.6, but you need to help it by annotating your serialized entities with #JsonManagedReference and #JsonBackReference. I think Jackson is unique in allowing back references in JSON serialization.
See Jackson's documentation on handling bi-directional references using declarative methods for reference.
Related
in my spring mvc application, we are using the below object mapper configuration.
<property name="objectMapper">
<bean class="com.fasterxml.jackson.databind.ObjectMapper">
<property name="propertyNamingStrategy">
<bean class="com.fasterxml.jackson.databind.PropertyNamingStrategy$PascalCaseStrategy" /></property>
</bean></property>
This configuration is applying for all java entity classes. i want to exclude one java entity(ie,when we pass one dto, it should not be changed by this object mapper configuration).Please let me know how to do this.
I have a rest endpoint(A) that returns a large json object. I have to return it to another rest api(B) in a different format. Would it be beneficial to map it to an object, transform the data into the object the other REST API(B) is expecting?
Would it be better to use a json library and pull out the parts I need and transform the data that way?
Thanks
I use Spring for my web apps. in my context config, I have:
<bean id="jacksonMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jacksonMessageConverter"/>
</list>
</property>
</bean>
Then in my controller code, I use:
#RequestMapping(...)
public #ResponseBody MyPojo getMyPojo(#PathVariable("id") Integer id, #RequestBody MyOtherPojo) {
MyPojo myPojo = new MyPojo();
// do some business methods
return myPojo
}
The #ResponseBody MyPojo tells the jacksonMessageConverter to convert the MyPojo to a JSON object, and the #RequestBody tells the jacksonMessageConverter to convert a JSON variable into an instance of MyOtherPojo.
I have a problem un-marshalling simalar xml (same root element but different fields) to different objects with Spring3 and Jaxb2
I am using spring to define my xml converters as follows:
<bean id="xmlConverter" class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="jaxbMarshaller"></property>
<property name="unmarshaller" ref="jaxbMarshaller"></property>
<property name="supportedMediaTypes" value="text/xml" />
</bean>
<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.my.project.Object1</value>
<value>com.my.project.Object2</value>
<value>com.my.project.Object3</value>
</list>
</property>
So the problem comes down to each of the objects have the same #XmlRootElement(name = "xml") but completely different fields.
When i have only one object defined each object unmarshalls correctly, but when i add more than one, it keeps assuming the last one, some overriding issue i am guessing.
Anyone have an idea of how to get around this issue?
EDIT: Solution I created one Larger object with all fields, this solves the problem. Not the best solution but it works well.
Use a different namespace for each object. For example:
#XmlRootElement(name = "xml", namespace="com.my.project.obj1")
#XmlRootElement(name = "xml", namespace="com.my.project.obj2")
#XmlRootElement(name = "xml", namespace="com.my.project.obj3")
Using namespace, the marshaller can differentiate between the different objects.
I have inherited a spring MVC project that basically has several controllers. I came across a declaration in an xml file. Apparently, this declaration allows for writing rest-based services and clients. Could someone explain with an example the apparent magic these declarations allow for?
<bean id="restClient" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<util:list>
<bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
<bean id="formMessageConverter" class="org.springframework.http.converter.FormHttpMessageConverter"/>
</util:list>
</property>
</bean>
Thank you in advance.
resttemplate by spring , provided to convert your java object to desired output(html string, xml, json etc) during the service call over the network, and inturn the received response from the service will be unmarshalled back to java object or desired datatype.
<property name="messageConverters">
<util:list>
<bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
<bean id="formMessageConverter" class="org.springframework.http.converter.FormHttpMessageConverter"/>
<bean id="messageConverter"
class="org.springframework.http.converter.StringHttpMessageConverter" />
</util:list>
//marhsaller and unmarshaller
<bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="jaxbMarshaller"></property>
<property name="unmarshaller" ref="jaxbMarshaller"></property>
<property name="supportedMediaTypes">
<list>
<value>application/xml</value>
<value>text/xml</value>
<value>json</value>
</list>
</property>
through above configuration resttemplate will use those appropriate converters to handle different datatypes, as i said it may be html, json or application xml
all we are doing is, with out writing java code , we are configuring the resttemplate and will be in spring context , this configuration applies where ever your resttemplate been used.
i have example here
let us say we invoke a service to check an user is valid user or not
class User{
string userId;
string password;
}
and service response with some code as 1 is valid and 0 as invalid
class ValidUser{
int validCode;
}
first you need to marshall into any of the acceptable datatype , let us have application/xml
all i am doing here is through config file
to above configuration i am adding jaxb marshaller and unmarshaller (see above config)
i have configured both marshaller and unmarshaller, and i am telling the acceptable datatypes which both should use while marshalling and unmarshalling
and finally, the below configuration tells the java objects which are acceptable during marshalling (request.User will be converted to xml) and unmarshalling (xml to convert back to response.validUser)
<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.request.user</value>
<value>com.response.validUser</value>
</list>
</property>
</bean>
on here comes the java code
here you directly pass your java object , and your resttemplate will marshall it without any hassle !!!
User user = new User();
user.setName('test');
user.setPassword('password');
// setting media type as xml, and telling convert my user java obj to xml
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
HttpEntity<User> entity = new HttpEntity<User> (user , headers);
ResponseEntity<validUser> responseEntity = rest.exchange(URL, HttpMethod.POST, entity, validUser.class);
// let us assume that service response for valid user <validCode>1<validCode>
//then validuserreponse obj will have code as 1, let us say valid user.
ValidUser validUserResponse = responseEntity.getBody();
like wise you can also handle plain html text
headers.setContentType(MediaType.TEXT_HTML);
HttpEntity<String> entity = new HttpEntity<String>(htmlString, headers);
ResponseEntity<String> htmlStringresponse = rest.postForEntity(URL, entity, String.class);
if you see, the above java code, dont have any message converter code, marshaller and unmarshaller logic, all done in one liner with use of spring configuration.
I am developing a web application using spring MVC, Hiberbate and MySQL database. I am trying to send data to server from a client, but I can not do it.
In detail,
I want to send my JSON data to http://localhost:8080/app/test . In my test controller I want to get the data which comes from the client and write it to screen or save it to db. I have been searching about 3 days and I have tried many strategies to do it, but I can not.
You must explicitly tell spring to use a json parser.
For instance, here is a piece of my DispatcherServlet config :
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonConverter" />
</list>
</property>
</bean>
<bean id="jsonConverter"
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="supportedMediaTypes" value="application/json" />
</bean>
Jackson Must be in your classpath.
Then you write a method like this one in your annotated controller :
#RequestMapping(value = "/test", method = RequestMethod.POST)
public void myMethod(#RequestBody MyObject object) {
//... do what you want with the object
}
You just have to send an JSON object with properties that match the ones in MyObject, via a POST request.