Enterprise Java

Creating a simple JAX-RS MessageBodyWriter

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!
 

Mike Miller

Mike is a software developer who loves to learn how things work. A Java programmer who caught the Groovy & Grails itch and is always looking for opportunities to include them as part of the solution.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Leonid Ovanesbekov
Leonid Ovanesbekov
8 years ago

Mr. Mike Miller!
Thank you very much!
Yours example really help me!

With best wishes from Russia, Moscow,
Leonid O

prashant
prashant
7 years ago

How can I send the JSON response with writeto

Back to top button