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(" "); DataOutputStream dos = new DataOutputStream(entityStream); dos.writeUTF(sb.toString()); } } ").append(myBool.toString()).append("
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!
The code is broken... Have you ever tried running it?
ReplyDeleteIt's been almost a year but yes, the code ran fine last year when I wrote this.
ReplyDeleteCan you be more specific on what's failing and maybe I can help?