JAX-RS Request specific media type - java

Lets say I have the following REST method:
#GET
#Path("get/{id}")
#Produces({"application/json", "application/xml"})
public Entity getEntity(#PathParam("id") int id) {
//do stuff
Entity entity = find(id);
return entity;
}
When I hit the rest endpoint with any browser by default I get back XML. Is there a way I can specify at the request which media type I want returned? or must I somehow include that information in the path?

You have to specify the Accept header with the media type you want in addition to the Content-Type header that states what is the content type of your request.
So use the Accept header instead of Content-Type header:
Accept: application/xml

You should manually prepare your response. For example if you want JSON answer, you should convert your Entity class to Json and return String.
You can use https://code.google.com/p/google-gson/ for conversion.
In fact it is your decision and your work to prepare the answer. The only thing to take in consideration that Rest works on top of HTTP, so some sort of text(JSON, XML, Plain text) is the most "friendly" format of information.

May be this example can help
RestClientWithAcceptHeader
RestClient client = new RestClient();
ClientResponse response = client.resource("http://example.com/resources/resource1").header("Accept", "application/json;q=1.0, application/xml;q=0.8").get();
// find what format was sent back
String contentType = response.getHeaders().getFirst("Content-Type");
if (contentType.contains("application/json")) {
JSONObject entity = response.getEntity(JSONObject.class); /* or use a String, InputStream, or other provider that supports the entity media type */
} else if (contentType.contains("application/xml") {
String entity = response.getEntity(String.class); /* or use a JAXB class, InputStream, etc. */
More here and here

Related

JAX-RS (REST Easy) InMemoryClientExecutor/ClientRequest Exception

I'm trying to use the InMemoryClientExecutor to call services on my local JVM which return javax.ws.rs.core.Response objects. I can get this to work but only by specifying the String type like so:
String response = new ClientRequest("/myService", executor)
.get(String.class)
.getEntity();
Since the signature of the service is like so:
#GET
#Path("/myService")
public Response getSomeData(#Form MyFormBean bean) {
//...blah...
}
However I would like to get the actual Response objects back so that I can get the entities out and return those objects in my new "aggregate" response. When I just return the string the Jackson Parser doesn't see this as JSON, just a regular string so it does things like encoding line breaks into \n, etc.
Whenever I do something like:
String response = new ClientRequest("/myService",executor)
.get(Response.class)
.getEntity();
or even this to just get the plain request object:
String response = new ClientRequest("/myService", executor).get().getEntity();
I get the following Exception:
Exception Occured: org.jboss.resteasy.client.ClientResponseFailure: Unable to find a MessageBodyReader of content-type application/json and type null
at org.jboss.resteasy.client.core.BaseClientResponse.createResponseFailure(BaseClientResponse.java:523)
at org.jboss.resteasy.client.core.BaseClientResponse.createResponseFailure(BaseClientResponse.java:514)
at org.jboss.resteasy.client.core.BaseClientResponse.readFrom(BaseClientResponse.java:415)
at org.jboss.resteasy.client.core.BaseClientResponse.getEntity(BaseClientResponse.java:377)
at org.jboss.resteasy.client.core.BaseClientResponse.getEntity(BaseClientResponse.java:338)
Also present further down is:
Servlet.service() for servlet Resteasy threw exception: org.jboss.resteasy.spi.LoggableFailure: Unable to find contextual data of type: javax.servlet.http.HttpServletRequest
at org.jboss.resteasy.core.ContextParameterInjector$GenericDelegatingProxy.invoke(ContextParameterInjector.java:56)
at $Proxy210.getScheme(Unknown Source)
Where am I going wrong?
There is no Response object being returned from the server, just a data stream that, in your case, is the representation of some entity, in JSON format. Trying to deserialize this data back into a Response object on the client side will not work, because effectively you are saying the JSON represents a Response object, which it doesn't (it represents the entity that *used to be contained in the Response).
Good news is, there are other ways to obtain the entity, which do not require trying to back-spin it into a Response. You will need to have the entities on the classpath of your client:
MyEntity response = new ClientRequest("/myService", executor)
.get(MyEntity.class)
.getEntity();
Replace MyEntity with the type of the actual entity you are expecting to receive.

Restlet response type

How can I return Restlet response in desired format?
I am using the method:
#Get ("json")
public Address sendResponse(){
Address add = getAddress();
return add;
}
Right now I have to explicitly convert java object to a json string as a response to browser. Can't it be taken care by Restlet framework itself?
Spring MVC's Restful implementation can do it. I am looking similar implementation in Restlet too.
In fact, there are two ways to do that with Restlet:
the explicit one using JSON representations. The JSONRepresentation if you use objects from org.json or the JacksonRepresentation if you want JSON / Object mapping. You can find below an example:
#Get ("json")
public Representation sendResponse(){
Address add = getAddress();
return new JacksonRepresentation<Address>(address);
}
the implicit one using converter. In this case, it's the code you gave. You must have in your classpath an appropriate converter such as the one provided by the org.restlet.ext.jackson extension. It will detect that a JSON content needs to be returned and implicitly convert your Address object to a JSON content.
Just for hint, the json media specified in the GET annotation tells Restlet to use the associated method to handle the request when application/json is defined for conneg (content negociation) with the accept header.
Hope it helps you.
Thierry
Try setting the response type to application/json instead of just json. Normally, you need to specify the correct MIME type. As you say, if you set the MIME type correctly, other frameworks will do the conversion automatically.

How can I pass a List of annoted Objects from client to Server using Jersey

I am using jersey, and I want to send (in a POST) a list of objects to the server. This is the scenario:
#XmlRootElement
class Myclass{
//some primitive attributes + empty constructor + getter/setters
}
MyClass is both on server and client side.
#XmlRootElement
class MyClasses{
private List<MyClass> classes = new ArrayList<MyClass>();
// put some MyClass into the list
}
class Sender{
MyClasses list = new MyClasses();
// after client initialization i want to send this list in a POST to server
WebResource service = client.resource(baseURI());
//I tried
service.type("application/xml").accept("application/xml").post(ClientResponse.class,list);
}
//on server side
#path("/tosend")
class receiver{
public Response posted(JAXBElement<MyClasses> vals){
//work with vals.getValue() as the list of all Objects
}
}
Unfortunately, I have this error :
ContainerRequest getEntity : A Message body reader for JAXBElement and JAXBElement
and MIME Type application/octet-stream was not found.
How can I fix that?
Are you sure your code looks exactly as written above? The exception suggests you are not setting the content type of the request. Don't use JAXBElement, and make sure the content type of the request is set to application/xml. In your code snippet you seem to be doing it. But the exception says the media type is application/octet-stream. So either the code snippet does not match your real code or the exception is coming from a different section of the code or you have some filters that change the message headers before it reaches the posted() method. Annotate the method with #Consumes(MediaType.APPLICATION_XML).
Btw, you don't need to use the MyClasses wrapper class. You can simply send List and it will work as well.
Use MyClasses as the type for vals set the the consumed type.
#POST
#Consumes( { MediaType.APPLICATION_XML })
public Response posted(MyClasses vals) {
//
return Response.ok.build();
}

Receive two types of data from a request payload with resteasy / jax-rs

I'm sending json-formatted data to my Java server via http requests. I've had great success in receiving the requests with functions like
Boolean deleteUsers(List<Long> userIds) {
// ...
return true;
}
I'm using RESTEasy on a Java server, and it cheerfully converts the payload of the request into this List<Long> that's so convenient.
Now I want to send a String and a list of numbers! Ideally, my receiving function would look something like
Boolean deleteUsers(String string, List<Long>userIds) {
// ....
return true;
}
Alas, RESTEasy doesn't seem to know what I mean, and chokes on the payload.
How can I receive multiple types of data from a payload?
Depending on your specific use case, you might simply add the first parameter ("string") to the #Path annotation such as
#POST
#Path("{string:.*}")
#Consume(MediaType.APPLICATION_JSON)
#Produce(MediaType.APPLICATION_JSON)
Boolean deleteUsers(#PathParam("string") String string, List<Long>userIds) {
...
}
This would result in the following URL form:
/service/<string>/
with the payload containing your userid list (as json).
As you might realize, #POST method type is suggested since the service construction method won't be idempotent. Otherwise, #DELETE would have been favoured.
It seems that a wrapper object is needed.
class TwoObjectDTO {
String string;
List<Long> listOfNumbers;
}
#POST
Boolean deleteUsers(TwoObjectDTO object) {
...
}

how to mime type of the url

I am using cxf as a webservice.It supports xml and json format output of the requested data.I want to know that if some exception has occured in my code then i want to return him back the error code either in xml or json format.But i dont know when to give json and xml ,it depends on the requested url that user has asked.
example
#Path("/reports/ad-view/loginId/{loginId}/publisher/")
PublisherReports getPublisherReportsAdView(
#PathParam("loginId") String loginId,
#QueryParam("fromDate") String fromDate,
#QueryParam("toDate") String toDate,
#QueryParam("filterValue") String filterValue);
If you mean you want to detect the mime type used to make the request, then you can use the #Consumes annotation to dictate which method handles which type of request. So you could write:
// Called when an XML request is made
#Path("/reports/ad-view/loginId/{loginId}/publisher/")
#Consumes("application/xml")
PublisherReports getPublisherReportsAdViewXml(...
and:
// Called when a JSON request is made
#Path("/reports/ad-view/loginId/{loginId}/publisher/")
#Consumes("application/json")
PublisherReports getPublisherReportsAdViewJson(...
Then have each variant of the getPublisherReportsAdView() method call a common method to perform the actual processing logic but still handle exceptions differently depending on the method that gets called.
An alternative approach, which doesn't require additional methods, would be to add a parameter which is annotated with the #HeaderParam annotation and use that to hold the value of the 'Content-Type' request header.
e.g.:
PublisherReports getPublisherReportsAdView(
#PathParam("loginId") String loginId,
#QueryParam("fromDate") String fromDate,
#QueryParam("toDate") String toDate,
#QueryParam("filterValue") String filterValue,
#HeaderParam("Content-Type") String contentType)
{
...
The value of contentType will likely also include charset information, for example: application/json; charset=UTF-8 so you'll need to ignore that when working out if the request contained JSON or XML.

Categories