We are building a REST service with CXF where we send and receive data in both JSON and XML
In the JSON version we dont want to bother our clients with using the '#' notation for attributes and using the "attributesToElements" parameter on the JsonProvider (org.apache.cxf.jaxrs.provider.json.JSONProvider) ensures we dont send these attributes to the client that way.
However when receiving the data back (same format) the JsonProvider is unable to UnMarshall the received data correctly because it doesnt realize the attribute values are attributes (and treats them as elements instead).
In issue 3475 of the cxf bug tracker this problem is acknowledged and marked resolved because its a a problem to handle on the receiving end. there is being referred to using the transformation feature of the Jsonprovider, however i cant seem to get it to work.
i tried to configure the transform in beans.xml with several variations like:
<property name="inTransformElements">
<map>
<entry key="fieldname" value="#fieldname"/>
<entry key="fieldname" value="{#}fieldname"/>
</map>
</property>
but with no succes.
Is it possible with the cxf JsonProvider to transform elements back to attributes?
And if so how?
JUst to understand the question,
XML shown above is the output
<property name="inTransformElements">
<map>
<entry key="fieldname" value="#fieldname"/>
<entry key="fieldname" value="{#}fieldname"/>
</map>
</property>
Did you try with latest version of CXF?
Related
I am writing RESTFul webservices which support both XML and JSON format. I need to add schema validation in the webservices. My beans are auto generated using JAX-B. As suggested at CXF's site at Schema validation, I am using org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider as JSON provider and org.apache.cxf.jaxrs.provider.JAXBElementProvider as JAX-B provider. The request and response is working fine but now I want to add schema validation.
The sample code at above CXF link is not working for me for JSON schema validation (its working for XML schema validation). They shown it for org.apache.cxf.jaxrs.provider.json.JSONProvider (under 'Schema Validation' section) which doesn't work for me as my beans are JAX-B generated, so I am using JacksonJaxbJsonProvider.
Is there any solution for this problem? Could somebody please suggest some approach that I can try?
Below is the XML configuration:
<bean id="jsonProvider" class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider"/>
<bean id="schemaHolder" class="org.apache.cxf.jaxrs.utils.schemas.SchemaHandler">
<property name="schemas" ref="theSchemas"/>
</bean>
<util:list id="theSchemas">
<value>classpath:/WEB-INF/classes/po.xsd</value>
</util:list>
<!-- Person REST Service Configurations -->
<bean id="personRESTServiceImpl" class="com.abc.webservices.service.rest.PersonRESTService" />
<jaxrs:server id="personRESTService" address="/person-rest-service">
<jaxrs:serviceBeans>
<ref bean="personRESTServiceImpl" />
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean="jaxbProvider" />
<ref bean='jsonProvider' />
</jaxrs:providers>
</jaxrs:server>
Your classpath is wrong, in web application classpath is WEB-INF/classes
Hence you can use following configuration
<jaxrs:schemaLocations>
<jaxrs:schemaLocation>classpath:po.xsd</jaxrs:schemaLocation>
</jaxrs:schemaLocations>
if you have xsd directory in classes directory then classpath:xsd/po.xsd
I am trying to figure out how I will manage to return a JSON output from a Controller.
For the time being, I am returning my results and getting them with the use of freemarker view resolver.
The code inside my controller is the following:
#RequestMapping(value = "query", method = RequestMethod.GET)
public ModelAndView search(
#RequestParam(required = true) String q
){
ModelAndView mv = new ModelAndView(getPartial("template"));
mv.addObject("terms",q.replace(","," "));
mv.addObject("results",getResultsForQuery(q));
return mv;
}
and the configuration for the freemarker:
<!-- freemarker config -->
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/freemarker/"/>
<property name="freemarkerSettings">
<props>
<prop key="locale">en_US</prop>
</props>
</property>
</bean>
<bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="order" value="1"/>
<property name="exposeSpringMacroHelpers" value="true"/>
<property name="cache" value="false"/>
<property name="suffix" value=".ftl"/>
<property name="contentType" value="text/html;charset=UTF-8"/>
</bean>
As far as I have understood so far, there are two ways of returning a JSON object, a)by modifying the controller and b)without modifying it by changing the configuration.
Moreover, I have read about returning JSON throuh ResponseBody but not sure what should I change to configuration. Could anyone first of all, verify whether the above conclusions are valid or not, and second help me returning JSON from this GET method?
*UPDATE**
If I use ResponseBody and configuration like this:
<!-- json config -->
<bean id="viewName" class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
should I remove the freemarker confiuration?
Thank you in advance for your help.
There are several ways you can return JSON. My preferred way is to include the Jackson libs in your classpath, configure your Controller's handler method to return the object, and mark the return as #ResponseBody. Spring MVC will connect all the dots, serialize the response to JSON, and all will be good. You can even use annotations and/or direct code from Jackson to control how the serialization occurs.
The next way I would consider is to serialize to JSON myself, either with Jackson or some other lib, but you could also do this with a StringBuffer and brute force. To do so, change the return type from the above to String, leave the #ResponseBody on the return, and optionally drop the Jackson libs. In this case, you are responsible for generating the JSON. It is up to you to ensure it's well-formed, because whatever you return for the String will get returned to the browser directly. You will probably also want to change the Content-Type header to reflect you are returning JSON.
The next way would be to return either a ModelAndView or a View. I personally don't like this way, as it's a rather old way of doing Spring MVC. But, it's supported, so I will discuss. In this case, you would create either an instance of a JSON-enabled View object, or some other custom View, and return that (either directly or as part of a ModelAndView). I have used this method to return CSV files in which I want to optionally send the user to an error page if the CSV generation fails, which I can do since I can flop out the views conditionally. Not my favorite approach, however, as to me it requires quite a bit of extra coding on my part. I am lazy...sue me.
Option 4: Simply have a JSP/Thymeleaf/etc view that "looks" like JSON. JSPs don't necessarily have to produce HTML. It just needs to parse. One could, in theory, use JSTL and such to output something JSON-esque. I think this would be a sloppy way to do it, though.
There may be some other ways, but I think those are the top 4 I can think of. I think, given the fact that you will need to modify code anyhow, that the first option would be the one I would go with. Makes the code look nice a clean, and in my opinion, easier for people to understand what's happening.
You have a few options, depending on what you want to do.
The most flexible way would be to avoid #ResponseBody and stick to using Spring MVC's view system.
This would allow you to use the same controllers for XML, JSON, JasperReports, and HTML views.
For JSON, you should use the MappingJackson2JsonView, and make sure Jackson is in your classpath.
If you only want to return JSON, then the MappingJackson2JsonView view should be your only view. If you want to return multiple content types depending on the request, you should use the ContentNegotiatingViewResolver, with other views such as MarshallingView for XML or FreeMarkerViewResolver.
create an instance of MappingJackson2JsonView
set view as above instance for the returned ModelAndView
I am using Spring 3.2.5 to create a RESTful web service. To implement it I've used #ResponseBody tag. When I use InternalResourceViewResolver and try to load Html response then it is working fine. But when I call a URL which is marked as #ResponseBody then it gives HTTP 406 error code with error text as
The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers.
I have included Jackson jar files in my lib directory as well.
Here is my controller method which handles service request.
#ResponseBody
#RequestMapping (value = "/resp.htm")
public Data jsonResp() {
Data d = new Data();
d.setName("TEst");
d.setAddr("Address....");
return d;
}
There are lots of questions have been asked & answered, I've tried many of them, but it still gives the same result. Then I came across a new kind of answer, which was stating to use ContentNegotiatingViewResolver. By using it I am able to view response in intended format. That is JSON format.
After using ContentNegotiatingViewResolver, servlet dispatcher code looks like this:
<bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order" value="1" />
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
</map>
</property>
<property name="defaultViews">
<list>
<!-- JSON View -->
<bean
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
</bean>
</list>
</property>
<property name="ignoreAcceptHeader" value="true" />
</bean>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="order" value="2" />
<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".jsp" />
</bean>
So, my question is, whenever we require to use Spring's Web Service feature, do we must require to have ContentNegotiatingViewResolver?
Add gson in your class path. as well as jackson
I had a similar issue while calling a spring rest service from angular 8 for uploading a file. I was using ResponseEntity to encapsulate the success or failure message for which I was having the 406 response. all I did was in the UI side this.httpClient.post(url, formData,{responseType: 'text'}) and I was able accept the string as response from the service response.
The annotation #ResponseBody used with custom class types, generally uses MappingJackson2HttpMessageConverter to convert the object to JSON and return it in application/json content.
Since your request doesn't contain an Accept header for application/json, Spring deems the content it's creating as unacceptable and instead returns a 406.
You could simply change your request to add the Accept header. (You can't do this easily in a browser).
In my case the request had .html suffix and received this error. Once removed, it worked fine.
All you need to do is to add jackson libraries to your classpath find them Here
I'm transforming XML request to SOAP via XSLT in WSO2ESB, just wondering is it possible to make request parameter available to be used in response?
E.g.
<request>
<test>123</test>
<param1>testing</param1>
</request>
-> converted to SOAP
<?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">#S:Body><ns2:testrequest xmlns:ns2="http://xml.testing.com/test"><teststring>testing</teststring></ns2:testrequest></S:Body></S:Envelope></soapenv:Body></soapenv:Envelope>
In the response
<?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:testresponse xmlns:ns2="http://xml.testing.com/test"><responsestring>success</responsestring></ns2:testresponse></S:Body></S:Envelope></soapenv:Body></soapenv:Envelope>
I want to return in XML
<responsestring>
<test>123</test>
<return1>success</return1>
</responsestring>
As you see, 123 isn't send to the server and has not received from the server. However, client is sending this parameter and i would like to just use this parameter in request and send back in response, is this possible? By how? I'm very new to synapse and very new to WSO2ESB, could anyone please enlighten me?
Thanks.
Yes it is possible. You can use property mediator in the Insequence to set the required value as a property and then add it in the outsequence to response using enrich mediator.
Got it working now.
Simply by adding the property mediator in both insequence and outsequence together with the XSLT, where the xslt is trying to get the value from test property. That's it!
Insequence
<property xmlns:ns="http://org.apache.synapse/xsd" name="TEST" expression="//request/*[local-name()=test]" scope="default"/>
outsequence
<xslt key="xxxx.xslt">
<property name="test" expression="get-property('TEST')"/>
</xslt>
I am writing a Spring Restful webservices application using Spring MVC. I have used content negotiating viewer to respond multiple data formats for eg. If some one requests a URL with .xml extension an XML will be sent in response body similarly if someone requests with an .json extension, an json will be sent in response body.
Now, I want the same process inwards, say if some body wants to post a Json or xml or a simple post from a webpage form using post method to same action, it should be able to handle all these.
This way i will be able to write a Web Service+Web Application in a single Spring MVC+Restful Application.
Thanks in advance for the help :)
You can use headers attribute of #RequestMapping annotation.
#RequestMapping(value = "/pets", method = RequestMethod.POST, headers="content-type=text/*")
to narrow content-type of requests your method is going to serve.
edit:
If you want to sent different content type in request body, then the only thing you need to do is to define MessageConverter (I assume you already did that) and annotate your method parameter with
#RequestBody
Spring should deserialize the body of your request using the MessageConverter you defined.
So assuming you have something like:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<util:list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
</util:list>
</property>
</bean>
<bean id="contentNegotiatingViewResolver" class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<util:map>
<entry key="json" value="application/json"/>
</util:map>
</property>
<property name="defaultViews">
<util:list>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"/>
</util:list>
</property>
</bean>
in your spring context.
Annotating your method like this:
#RequestMapping(method=PUT, value="/user/{user_id}")
public void putUser(#RequestBody User user, #PathVariable int user_id) {
...
}
should do the job.
You don't have to do anything. You register converts and they will in turn tell "spring" what Content-types they can handle. XStream registers application/xml and text/xml (perhaps more), jackson registers application/json and so on.
It's all available at http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-ann-responsebody
I also don't like the filename-standard, I prefer to leave that to the same converter. In that case it will look at the Accept-header. If you want json, set Accepts: application/json.