I've written a JAX-RS API that looks like:
#POST
#Path("findallbyname")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.TEXT_PLAIN)
Response findAllByName(String payload);
Where Response is javax.ws.rs.core.Response. The entity property of the Response is a List<String>, so this response just returns the JSON serialization of a list of strings.
In a separate app, I'm calling the API like so (using an http-remoting library found here):
Service service = JaxRsClient.builder().build(Service.class, "<user-agent>", "<uri>");
Response response = service.findAllByName("some string");
However, I get this error:
Caused by: com.fasterxml.jackson.databind.JsonMappingException:
Can not construct instance of javax.ws.rs.core.Response:
abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
at [Source: java.io.BufferedReader#2ef14fe; line: 1, column: 1]
Ok, this seems like a straightforward object serde problem -- it looks like since javax.ws.rs.core.Response is an abstract type, it can't deserialize on the client side (the request goes through and comes back with status 200, according to the server request logs).
My question is, since my original API was written to respond with the abstract Response object type, am I out of luck when it comes to deserializing the response object I get on the client side? I can change the API, but I wanted to ask and see if there was a better way to solve this deserialization problem on the client side first.
Related
I have to integrate our j2ee application with a REST webservice. And I wanted to use the RestEasy JAX-RS implementation from JBoss. The webservice returns an array in JSON format. I've this piece of code:
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://myservices.com/schemes/all");
Response response = target.request().get();
Can I map this "response" object to List<Scheme> using RestEasy? Thanks
Provided that your JSON provider is capable of converting JSON to appropriate entities, then yes. The get method you call in the code has an overloaded version which accepts the class of entity to which the result is to be converted. Since there are problems with serializing certain collections' implementations, your type has to be wrapped in GenericType class, like that:
List<Scheme> schema = [...].get(new GenericType<List<Scheme>>(){});
The above method should work with just about every JAX-RS-compliant implementation.
You can also use Jackson library, which allows you (amongst other things) to pass collections without need of wrapping them.
I'm in a current situations in which I have a REST endpoint that accepts POST of incoming JSON messages.
The thing is that I don't think I can specify the POJO object so Jackson can marshall the JSON into the POJO object. Reason for this is that I don't have control of what comes to that endpoint, and number of fields and type can change over time, thus, defining a POJO before hand seems not an option.
So I guess the question is....can I simply tell Jackson to don't do any marshalling and give the String of the response? I can deal with that later with JSONObject-JSONArray or Gson maybe. Say I'd have a method like this:
#POST
#Path("/callback")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Response facebookUpdate(String json) {
//Do something with the json response...
}
If this is not feasible with Jersey-JAX...any other alternatives?
Thanks!
Alejandro
The easiest is to simply not inject the json into the method and use the request object instead:
public Response facebookUpdate(#Context request) {
try(InputStream is=request.getEntityInputStream()) {
...
}
}
From the request you can then get an inputstream for the request and parse it whichever way you like.
For parsing I can recommend my own jsonj library, which was written specifically to support open ended scenarios like you describe and uses jackson to deserialize into heavily customised implementations of java.util.Map and java.util.List. Gson is also a very solid choice.
If you want to do this application wide, you can instead write your own #Provider and do the same there. This is how I use my library currently actually.
I've a method called createCustomer(),it is a POST method and it consumes both MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, now I want to check the actual MIME type of the request that came from client, it can be XML or JSON and based on the request's MIME type I want to call two different methods.
Can you please provide me the code to check the MIME type of the Incoming request and based on the type call two different methods.
The sample code looks like below:
#POST
#Path("/createCustomer")
#Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response createCustomer(Customer customer ) {
//if the request is in JSON then call the method createCustomerJSON()
//else if the request is in XML then call the method createCustomerXML()
//String output = output from either the method createCustomerJSON() or createCustomerXML()
return Response.status(200).entity(output).build();
}
First of all, it would have been great to have posted some code.
Secondly, one solution would be to create two methods with the same path, one consuming XML and one consuming JSON.
#POST
#Path("yourPath")
#Consumes(MediaType.APPLICATION_XML);
public Response createCustomerXML() {...}
#POST
#Path("yourPath")
#Consumes(MediaType.APPLICATION_JSON);
public Response createCustomerJSON() {...}
javax.ws.rs.Consumes annotation is probably what you need. By putting different annotations on different methods you can split handling of XML and JSON.
From javadoc:
Defines the media types that the methods of a resource class or MessageBodyReader can accept. If not specified, a container will assume that any media type is acceptable. Method level annotations override a class level annotation. A container is responsible for ensuring that the method invoked is capable of consuming the media type of the HTTP request entity body. If no such method is available the container must respond with a HTTP "415 Unsupported Media Type" as specified by RFC 2616.
I am currently working on a project which was maintained by some other team and now i need to maintain it. While i was going through the project i found some thing below:
In jax-rs controller it was annotated by #Consumes(MediaType.APPLICATION_JSON) but the method takes request body as String rather than JSON. Then what is the use of the annotation? Does it help in content negotiation anyway?
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response createCake(final String requestBody){.......}
How it is converting a JSON body to string?
My technology stack if it anyway helps to answer:
JAX-RS
Spring 3.2
Jersey 2.4
The #Consumes serves the following purpose. It restricts the mapping for your handlers. For example, you may have two handlers for the path /resource, one mapped to consume XML and the other mapped to consume json. The dispatcher will choose the right one based on the request's content-type.
The parameter type can be anything as long as there is an appropriate converter for the specified media type to the parameter type itself. In this case, there's very likely a converter from any media type to String.
I want to transfer a POJO Object with my CXF Rest Client. It already works for JAXB annotated objects. So I had a lot attempts for it.
I tried
reader.setEntityClass(ObjectPOJO.class);
and something like
reader.setEntityClass(JAXBElement<ObjectPOJO>.class);
Both doesnt work. For the second attempt the code is wrong. I dindt get it to set the entity class to jaxbelement. Maybe it works with it.
After sending the object with:
Response response = client.path(PATH).post(new JAXBElement<ObjectPOJO>(new QName("pojo"), ObjectPOJO.class, pojoObject));
i tried to get my entity with different attempts. Something like:
ObjectPOJO pojo = ((JAXBElement<TenantPOJO>) res.getEntity()).getValue();
Does someone know if I have to register the ObjectPOJO.class or the JAXBElement.class. If second attempt is right, how does it look right in code?
Whats the right code to get the entity out of the response?
My Service looks like this:
#POST
#Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response postPojo(JAXBElement<ObjectPOJO> pojo);
Edit:
Error
ERROR org.apache.cxf.jaxrs.client.AbstractClient - .Problem with reading the response message, class : class javax.ws.rs.core.Response, ContentType : application/xml.
To transfer objects (PoJos) between rest clients and rest services, there is no need to transfer it using the explicit JAXB conversion. The Jersey container is responsible for the necessary conversion provided the transfer objects are JAXB Annotated Objects.
Response response = client.path(PATH).post(postObject);
#XmlRootElement
public class PostObject
{
////
}