Can someone please help clarify and show how to properly go about this issue?
What I understand so far is that the Spring framework uses Message Converters when a method is annotated with #ResponseBody to convert the return Java object to a format that can be accepted by the Client. If the clients' HTTP request Accept Header includes "application/json", it will use Jackson and the Jackson converter to convert the object and return it in a json format. Similarly if the Accept Header includes "application/xml", then the Message Converter will use Jaxb and the corresponding converter to convert the object to xml.
Now my issue is that I include both the Jackson and Jaxb libraries as specified in Spring documentation so that the corresponding converters can work. This should be enough for Spring to employ #ResponseBody as its supposed to. However, when I send an HTTP Request with the Accept header "application/xml" I get a 406 status code and when I send one with "application/json" I receive a correct json response.
From my research online, I see that some people use the ContentNegotiation technique to work around this, but I would like to use the Message Converter for now. However, every technique to make the Message Converter technique to respond to json and xml resource requests involve formatting my POJO with JAXB annotation. Is this really necessary?
I guess what I am asking is how would one set up their project properly so that Spring can use the Message Converter technique to respond to json and xml requests? What libraries must be included? Does one need to add JAXB annotations or is there an automatic way for Spring to format an object into xml the way it does for json?
I thank you for your time and help with this, but so far I am really loving Spring's implementation of JAX-RS!
Related
We are using spring-integation (xml based configuration), In which we are performing below steps
Convert the payload (java-object) to json
Make the rest api call
Convert back to java-object
<int:object-to-json-transformer content-type="test.Request" input-channel="objectToJsonChannel" output-channel="apiChannel"/>
<int-http:outbound-gateway id="apiChannel"
request-channel="apiChannel"
reply-channel="jsonToObjectChannel"
....
/>
<int:json-to-object-transformer type="test.Response" input-channel="jsonToObjectChannel" output-channel="responseChannel"/>
Above code works till spring-integration version 5.1. When I upgrade to 5.2. It starts to throw the exception as
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [test.Request] to type [test.Response].
I have noticed that object-to-json-transformer add class type on the header with key json__TypeId__. Then it uses that class type for json-to-object-transformer.
But it is expected that type attribute mentioned on json-to-object-transformer should be used if mentioned.
Please suggest on fixing this issue or Is it really bug on spring integration (5.2).
Consider to add a <header-filter header-names="json_*" /> before calling your REST service. The <int:object-to-json-transformer> populates JsonHeaders to let downstream to know what the real type of JSON we curry in the payload.
A <int:json-to-object-transformer> prefers those headers instead of static type option.
But since the payload is already a different representation than those request headers it does a wrong thing.
I would suggest an option on the <int:json-to-object-transformer> to make a preference, but that would not be fully logical. Since we have changed a payload, it would be better to change its respective headers. Otherwise we just lying to ourselves.
On the other hand a HTTP Outbound Gateway can take care for your to convert request into a JSON for network and back from JSON response to some POJO type.
See https://docs.spring.io/spring-integration/docs/5.2.3.RELEASE/reference/html/http.html#http-outbound and its expected-response-type. As long as a contentType header is an application/json, you are good to avoid those <int:object-to-json-transformer> & <int:json-to-object-transformer>.
I want to write an #ExceptionHandler so JSON requests will get an error response in JSON as well. For non-JSON requests, I want the servlet container to send its default HTML response.
To do this, I'll need to do some content negotiation. Spring MVC handles it for normal requests via annotations, but no such annotation is available for #ExceptionHandlers.
I am wondering how can I programmatically call the content negotiation code?
So apparently, content negotiation happens after the error handler is called, so I have to do most of the heavy lifting myself.
The method to use is ContentNegotiationManager.resolveMediaTypes(), which gives a list of types that one will have to go through and make a decision.
An example of how to do this can be found the source of ContentNegotiatingViewResolver.getMediaTypes()
All examples that I have found around internet were about to use content negotiation with json, xml etc. Is there any chance to have only one method producing all kind of contents, like:
#RequestMapping(produces={"text/html","application/json"})
public List<Product> list() {
return productDAO.list();
}
I tried to use the ContentNegotiationManager, but nothing worked for me.
One method can return responses of different content types. Some you can get with default settings, some you have to additionally configure. Take for example a following method, quite similar to yours,
#RequestMapping(value="/response", method=RequestMethod.GET, produces={MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
public #ResponseBody Foo multipleTypes() {
return new Foo();
}
this method is capable of returning both XML and JSON, even more Spring MVC will automatically configure the converters if you have JAXB2 and Jackson libs on the classpath.
When reasoning whether it will return an XML or JSON its where content negotiation comes to play. If the request is suffixed with a path e.g. /response.json or /response.xml the response will be set based on it. The resolution can be based on a parameter as well, so /response?format=xml. Finally, if the request has an Accept header set to XML or JSON a response will be converted to the respective type. This constitutes a PPA strategy (Path, Parameter, Accept).
In other words, if you provide a proper converter implementations and configure them properly (some are available out of the box), you can get a single method that returns different representations, that you can control based on the PPA strategy.
Content Negotiation Using Spring MVC is a great post on Spring's Blog site with working examples.
We have a Resteasy webservice.
I use Jackson provider for JSON, both outgoing JSON in response and incoming JSON in request.
Is it possible to have a PostProcessInterceptor to be executed after JSON-Jackson serialization?
My PostProcessInterceptor has to change the JSON content for every outgoing response. But when the PostProcessInterceptor is executed if I print the entity response.getEntity().toString(); I see the toString method of the java.lang.Object, not the JSON String. That's because the Object has not yet been serialized by Jackson.
Is it possible to serialize with Resteasy/Jackson before running the PostProcessInterceptor?
I've also tried to use #Precedence annotation on my PostProcessInterceptor. But it doesn't work, even using "DECODER" precedence (which is the last one).
Any idea? Thanks in advance.
I would go for a CDI interceptor instead. You can get the intercepted method parameters from the InvocationContext and change them if necessary.
I am creating a Web Service that will handle incoming request properly (I knew, it is a description) I found some sample code which present SOAP WS and looks like:
#SoapAction("some fine url")
#ResponsePayload
public CertResponse getCert(#RequestPayload Cert param)
{...}
It takes Cert object from request and manages it properly. I want to do it in the REST approach and I changed this class to look like:
#RequestMapping(value="getCert", method = RequestMethod.POST)
#ResponseBody
public CertResponse getCert(#RequestBody Cert param)
{...}
But I have no idea how or even if it is possible to write a client that can send object through HTTP Post.
Can anyone give me a hint how can i send object Cert? Or if i have to stay with #SoapAction what should I do to make it work? I guess removing #Controller is not enough.
In SOAP approach, there is a well defined way to convert each class object to SOAP formatted XML. Thus, there is no effort.
If you will use RESTful approach, you have to describe how your Cert or CertResponse objects will be written to/read from the response/request.
Basically you have three options:
Use JSON or XML or plain String. Convert your Web service descriptor so that the request and response are one of those (JSON, XML, String). Then your getCert method should convert the request to Cert object, prepare your response as CertResponse object and convert it to an appropriate response type.
Leave your getCert method as is. But you need to specify "how Cert objects are read from request" and "how CertResponse objects are written to response" You need to define classes that extend interfaces MessageBodyReader and MessageBodyWriter. In these classes a similar conversion logic should be implemented that converts your objects to/from JSON or XML or String.
In any of these two options you need to implement two things : A method that converts JSON/XML/String to Cert, a method that converts CertResponse object to JSON/XML/String.
You can do a text based implementation, which parses/constructs the request/response by text processing and uses String class only. Or you can use some library such as JSON library with JSONObject class, or Java SAX or DOM based XML libraries that come with the Java bundle.
Check out for application frameworks such as Spring. They might provide ways to automatically convert your objects to JSON or XML, reducing the programming effort necessary.
Spring allows you to pass JSON objects from the client as a request parameters, it will convert them into your objects automatically. This discussion have some examples.
SOAP services are not really compatible with REST semantics. And it's not clear what SOAP framework do you use. Typically most SOAP frameworks offer you one way or another to generate a SOAP client code for you WSDL. You can check cxf.apache.org.
For REST services use something like Jersey or Spring MVC