How can I specify the default MimeType returned by a REST resource with Jersey - rest

I am creating a REST interface and have a resource 'data'. Now I want that an user can specify whether he wants the data as XML or as JSON. Therefore I have created two methods for the same path, one produces application/xml, the other produces application/json. Everything works fine, but how can I specify what should be returned, if an user doesn't set the 'Accept' header field?
My tests have shown that it is not always the same. Yesterday the default was application/xml, today my tests have failed, because as default application/json was returned.
How can I specify a default?
Code Snippet:
#GET
#Path("/rest/data")
#Produces(MediaType.APPLICATION.XML)
public Object getDataAsXML() {
// return data in XML format
}
#GET
#Path("/rest/data")
#Produces(MediaType.APPLICATION_JSON)
public Object getDataAsJSON() {
// return data in JSON format
}
Cheers,
metalhamster

#Path("/myResource")
#Produces("text/plain")// doGetAsPlainText method defaults to the MIME type of the #Produces annotation at the class level.
public class SomeResource {
#GET
public String doGetAsPlainText() {
...
}
#GET
#Produces("text/html")
public String doGetAsHtml() {
...
}
}
The doGetAsPlainText method defaults to the MIME type of the #Produces annotation at the class level. The doGetAsHtml method's #Produces annotation overrides the class-level #Produces setting, and specifies that the method can produce HTML rather than plain text.
#GET
#Produces({"application/xml", "application/json"})
public String doGetAsXmlOrJson() {
...
}
The doGetAsXmlOrJson method will get invoked if either of the media types "application/xml" and "application/json" are acceptable. If both are equally acceptable then the former will be chosen because it occurs first.
#Produce

Related

Error returning custom object via GET method

I am trying to run a simple example in Jersey which has a GET method and returns a Custom object.
on calling GET I am getting following error
MessageBodyWriter not found for media type=text/plain
I have looked into few answers on stackoverflow where they are suggesting it to put a default constructor and jackson dependency in pom.xml. I have already done that but no luck. Can some one please suggest what I am doing wrong.
Resource Class
#Path("customdatatyperesource")
public class CustomDataTypeResource {
#GET
public CustomResource1 get(#Context UriInfo ui) {
return new CustomResource1();
}
}
Custom Class
#XmlRootElement
public class CustomResource1 {
#XmlElement
String res;
public CustomResource1() { }
#Override
public String toString(){
return "Custom : "+res;
}
}
pom.xml
Thanks
So I figured out that error is not in the code but in the request sent.
When I send the request with header accept: text/plain
I am getting the error MessageBodyWriter not found for media type=text/plain
The resolution is accept header needs to match with what resource can produce.
In this case our resource is capable of producing XML or JSON
A better and more comprehensive way to write this code would be to put produce annotation on the methods.
#Produces(MediaType.TEXT_XML)
and put correct accept header such as
accept: application/json

Different Jersey 2 response depending on media type (JSON/XML)

In a RESTful Glassfish 4 application (JERSEY 2.22.2, MOXY as JSON Provider), we have a resource method that is able to produce both JSON and XML outputs.
The method response passes through a MessageBodyWriter, but it's used to build an Object Graph only in certain cases. In these cases, independently from the requested media type from the client, the graph is applied correctly.
On the other hand, when the isWriteable() method of our MessageBodyWirter returns false, therefore passing on to the next writer in the writers list of the MessageBodyFactory, the behavior is different between a JSON media type request and an XML media type request (i.e. Accept: application/json and Accept: application/xml respectively in the request headers).
In the first case, the FilteringMoxyJsonProvider is selected as response writer, because the EntityFilteringFeature is registered. The response is written based on the entity filtering annotations.
Though when the client asks for an XML response, another MessageBodyWriter (org.glassfish.jersey.jaxb.internal.XmlRootElementJaxbProvider) is selected.
This is due to the ordering of the WriterModels in the MessageBodyFactory in which the FilteringMoxyJsonProvider is positioned after XmlRootElementJaxbProvider.
In this situation the XML response is written without having any filters applied to it.
We tried to look for a way to change the writers order, also tried to access to the EntityFieldProcessor class, without luck.
Is it possible to have both scenarios (i.e. JSON and XML response requests) work in the same way? Is it possible to exclude some writers from being registered or to change their order in the MessageBodyFactory?
Any help will be appreciated.
//Configuration
public class ApplicationConfigVersione1 extends ResourceConfig {
....
register(EntityFilteringFeature.class);
register(MyCustomWriter.class);
------------------------
#Produces({"application/json", "application/xml"})
public class MyCustomWriter implements MessageBodyWriter<MyCustomObject> {
....
#Override
public boolean isWriteable(Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType) {
if (mustUseCustomWriter()) {
return true;
} else {
return false;
//In this case, with request header accept=application/xml, the xml response is not filtered.
}
}
#Override
public void writeTo(MyCustomObject customObject, Class<?> type, Type genericType, Annotation[] annotations,
MediaType mediaType,
MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
throws IOException, WebApplicationException {
objectGraph = buildObjectGraph();
marshaller.setProperty(MarshallerProperties.OBJECT_GRAPH, objectGraph);
marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, mediaType.toString());
//**** objectGraph applies to XML and JSON media types
marshaller.marshall(object, entityStream);
I have also tried to use Jersey's Entity Filtering mechanism with resources producing both application/json and application/xml responses and see different result information according to the repsonse type.
I suspect this closed/wont-fix github issue for the moxy component is the cause of the behaviour we are seeing with filtering: https://github.com/jersey/jersey/issues/3036

#BeanParam gives exception A message body reader for Java class was not found

I am trying to make a jersey based web service. In this if i take input params using #FormParam it works fine:
#POST
#Consumes({MediaType.TEXT_PLAIN, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_HTML, "application/x-www-form-urlencoded"})
#Path("/registeruser")
public Response registerUser(#FormParam ("email") String email,#FormParam ("name") String name ){
System.out.println("Inside register device");
System.out.println("registered" + email);
return null;
}
but when I try using #BeanParam it does not works and gives me an exception
#POST
#Consumes({MediaType.TEXT_PLAIN, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_HTML, "application/x-www-form-urlencoded"})
#Path("/registeruser")
public Response registerUser(#BeanParam UserForm userForm ){
System.out.println("Inside register device");
service.registerUser(userForm);
System.out.println("registered" + userForm.getEmail());
return null;
}
A message body reader for Java class com.stc.dms.forms.UserForm, and Java type class com.stc.dms.forms.UserForm, and MIME media type application/octet-stream was not found.
You don't need to use #BeanParam to pass an object as input. Just pass it like this :
#POST
#Path("register")
#Consumes(MediaType.APPLICATION_JSON)
public Response registerUser(UserForm dto) {
// ...
}
Just make sure to include the libraries for producing/consuming json. If the client is in javascript you don't need anything else (just use JSON.stringify() on your form object), for the server add some json libraries such as Jackson
EDIT :
If you want to stick with #BeanParam, take a look at this tutorial here. Basically it seems that you don't need to specify the mediatype, as Jersey will handle that for you.

jaxrs/resteasy custom method paramater

I would like to have my JaxRs resource to take a custom method argument that is built from some parameter in the request.
Something to be used in conjunction with another object created from the body.
Something like:
#Resource
public class MyResource {
#Path("/resource")
public Object resource(MyResourceDTO body, AConfiguration conf){
}
}
For which the AConfiguration is created from some headers in the request.
How can I achive it?
I need something like th spring webargumentresovler: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/support/WebArgumentResolver.html
For my case MyResource is a subresource, the method should work also in this case...
If you add a DTO as parameter of your resource method your JAX-RS runtime will try to convert the body of the request into this type. You can additionally add any of the #xParam parameters like #QueryParam as parameters of your resource method. (The only exception is #FormParam as they are found in the body).
If you want to encapsulate multiple of your Params in one object you can use #BeanParam. Your Configuration class could look like this:
public class Configuration {
#QueryParam("foo")
private String foo;
#HeaderParam("bar")
private String bar;
// getters + setters
}
And can be used like this:
#POST
public Response someMethod(Dto dto, #BeanParam Configuration conf) {}
You can use something like below. Your conf object have be sent as json from the client. If the parameters in conf object have to change dynamically you have to follow the second approach.
#Resource
public class MyResource {
#POST
#Consumes("application/json")
#Path("/resource")
public Object resource(AConfiguration conf){
// This method can receive multiple objects here. Currently it receives
// conf object only as the payload of the post method.
}
}
To change the conf object dynamically, You can send json String.
public Object resource(String confJson){
// Collect parameters manually here.
}
In your pom.xml, you should include,
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson-provider</artifactId>
<version>2.3.1.GA</version>
</dependency>
Edit:
You can set a json string as a header param (But, not the best practice.) Or you can set different headers at you will and access them using HttpHeaders. Here is an example.
public Object resource(#Context HttpHeaders confHeaders){
// Collect parameters manually.
String confJson = confHeaders.getRequestHeader("confJson").get(0);
// cast your `confJson` to `AConfiguration aConf` here.
// process query params and set them to aConf here.
}

How to handle requests with unsupported content type correctly?

I have a REST interface build with Jersey. Actually I only support as content type only application/json for all incoming requests. That is why I defined my message body reader and writer as
#Provider
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public class MarshallerProvider
implements MessageBodyReader<Object>, MessageBodyWriter<Object>
{
}
Now I wrote a test where I try to get a document via GET and expected content type application/xml. Jersey answers this request with an MessageBodyProviderNotFoundException.
So what would be the best way to handle such unsupported requests correctly? Should I write an exception mapper? Since it is an internal exception I don't like this approach?
The solution should allow me to return an HTTP 415 (Unsupported Media Type).
Yes, avoid exception handlers, handle this case with methods:
#Path("example")
public class Example {
#GET
public Response getBadStuff() {
return Response.status(Response.Status.UNSUPPORTED_MEDIA_TYPE).build();
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public Object getGoodStuff() {
return myObject;
}
}