JAX-RS is really cool and with the help of JAXB a lot of response data types can be converted for you simply by adding annotating the data objects with JAXB annotations. I am fairly new at JAXB but some simple cut/paste of annotations will take you a long way.
There maybe some types of data that you can't or won't annotate for the purposes of returning that data type from a JAX-RS resource method. One simple example is returning either a boolean (primitive) or the wrapper Boolean class. I read a question on StackOverflow where someone asked if they could return a boolean from a resource method and since I didn't know the answer, I decided to try it! My version only returns XML, not JSON but you should get the idea.
I started with the Jersey
User's Guide HelloWorld example and starting modifying from there. I used the pom.xml and the only change was to uncomment a block to allow using JSON.
Main class
This the main class from the Hello World example without any changes.
package com.example;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;
import java.io.IOException;
import java.net.URI;
/**
* Main class.
*
*/
public class Main {
// Base URI the Grizzly HTTP server will listen on
public static final String BASE_URI = "http://localhost:8080/myapp/";
/**
* Starts Grizzly HTTP server exposing JAX-RS resources defined in this application.
* @return Grizzly HTTP server.
*/
public static HttpServer startServer() {
// create a resource config that scans for JAX-RS resources and providers
// in com.example package
final ResourceConfig rc = new ResourceConfig().packages("com.example");
// create and start a new instance of grizzly http server
// exposing the Jersey application at BASE_URI
return GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
}
/**
* Main method.
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
final HttpServer server = startServer();
System.out.println(String.format("Jersey app started with WADL available at "
+ "%sapplication.wadl\nHit enter to stop it...", BASE_URI));
System.in.read();
server.stop();
}
}
Resource class
I created a resource class that included a GET method to return a boolean and another GET method to return the wrapper Boolean class. Notice the getBool() and getBoolean() methods return XML as the first option.
package com.example;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
/**
* Root resource (exposed at "myresource" path)
*/
@Path("myresource")
public class MyResource {
/**
* Method handling HTTP GET requests. The returned object will be sent
* to the client as "text/plain" media type.
*
* @return String that will be returned as a text/plain response.
*/
@GET
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN})
public String getIt() {
return "Got it!";
}
@GET
@Path("/bool")
@Produces({MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN})
public boolean getBool() {
return false;
}
@GET
@Path("/Boolean")
@Produces({MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN})
public Boolean getBoolean() {
return Boolean.TRUE;
}
}
BooleanMessageBodyWriter class
Here's the interesting part, creating the
MessageBodyWriter class to allow the resource method to return XML for the boolean or Boolean.
package com.example;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.WebApplicationException;
import java.io.IOException;
import java.io.InputStream;
import java.io.DataOutputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
@Provider
@Produces("application/xml")
public class BooleanMessageBodyWriter implements MessageBodyWriter {
@Override
public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) {
System.out.println("isWriteable called...");
return type == Boolean.class;
}
@Override
public long getSize(Boolean myBool, Class type, Type genericType,
Annotation[] annotations, MediaType mediaType) {
// deprecated by JAX-RS 2.0 and ignored by Jersey runtime
return 0;
}
@Override
public void writeTo(Boolean myBool,
Class type,
Type genericType,
Annotation[] annotations,
MediaType mediaType,
MultivaluedMap httpHeaders,
OutputStream entityStream)
throws IOException, WebApplicationException {
StringBuilder sb = new StringBuilder();
sb.append("").append(myBool.toString()).append("");
DataOutputStream dos = new DataOutputStream(entityStream);
dos.writeUTF(sb.toString());
}
}
I haven't used Maven before but the following targets are all you need to compile and run the project, after installing maven (of course!).
- mvn compile - compiles the code
- mvn exec:java - starts the Grizzly HttpServer and deploys the restful service.
Hope this helps!