Damion Brown's Blog

D97A 07F3 DCB1 302D

Java REST API with Jackson Annotations and Jackson JSON


  • Fri 23 March 2018
  • Tech

In extension to the previous post about Java RESTful APIs with JAX-RS, Jetty, and Jersey two additional libraries provide critically useful functionality: Jackson Annotations & JSON provider .

Jackson Annotations allows us to tag fields within a class as mappable properties of a corresponding datatype, IE: JSON. In other wording, we can bind Java Objects to JSON Objects 1:1 using only annotations. (See "SimpleModel.java" below.)

Jackson JSON Provider works with Jackson Annotation as a provider of Java<->JSON Readers/Writers. You'll need this to serve MediaType.APPLICATION_JSON to HTTP Clients. (See "HelloJsonApp.java" below.)

Github repo of the full working sourcecode can be found here.


Application.java: (Source)

This is the same Jetty application supplier described in more detail in the previous post referenced above.

// Construct a server
final Server server = new Server(new InetSocketAddress("localhost", 8080));

ServletContextHandler handler = new ServletContextHandler();
ServletHolder helloJsonServlet = new ServletHolder(new ServletContainer(new HelloJsonApp()));

// Required symbol '*' grants scope to servlet application.
handler.addServlet(helloJsonServlet, "/app2/*");

server.setHandler(handler);

// start the server
try {
        server.start();
        server.join();
} catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
}

HelloJsonApp.java: (Source)

This JAX-RS Application loads the JacksonJsonProvider via c.add(JacksonJsonProvider.class);

This makes MediaType.APPLICATION_JSON available for usage.

@ApplicationPath("/")
public class HelloJsonApp extends Application {
        private final Set<Class<?>> classes;

        public HelloJsonApp() {
                System.out.println("HelloJsonApp Contruct");
                HashSet<Class<?>> c = new HashSet<Class<?>>();
                c.add(HelloJson.class);
                /*
                 * com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider
                 *
                 * Binder for JSON<->POJO, this providers readers and writers for
                 * MediaType.APPLICATION_JSON
                 */
                c.add(JacksonJsonProvider.class);
                classes = Collections.unmodifiableSet(c);
        }

        @Override
        public Set<Class<?>> getClasses() {
                return classes;
        }

}

HelloJson.java: (Source)

The method getModel(@PathParam("id") int id) recieves the id from http://127.0.0.1:8080/app2/getmodel/{id} and returns a JSON object retrieved from SimpleModel via ModelHolder.

The JSON object will be the HTTP response to the query. This is all automatically hanlded by the @Annotations.

@Path("/")
public class HelloJson {

        @GET
        @Path("hellojson")
        @Produces(MediaType.TEXT_PLAIN)
        public String heyjson() {
                return "Hey JSON!";
        }

        @GET
        @Produces({ MediaType.APPLICATION_JSON })
        @Path("/getmodel/{id}")
        public Response getModel(@PathParam("id") int id) {

                SimpleModel sm = ModelHolder.getHolder().getSimpleModel(id);

                if (sm == null) {
                        return Response.status(Status.NOT_FOUND).build();
                }

                return Response.ok(sm).build();
        }

        @GET
        @Produces({ MediaType.TEXT_PLAIN })
        @Path("/setmodel/{id}/{string}")
        public Response setModel(@PathParam("id") int id, @PathParam("string") String string) {

                ModelHolder.getHolder().setSimpleModel(new SimpleModel(id, string));

                return Response.ok("OK").build();
        }
}

SimpleModel.java: (Source)

This is our Java Object <-> JSON Object. We can return this SimpleModel as seen in HelloJson.java and it will automagically be converted to JSON.

Additioanlly, we can recieve a JSON Object via HTTP and pass it as a SimpleModel Java Object. Super cool stuff.

public class SimpleModel {

        public SimpleModel(int id, String string) {
                this.id = id;
                this.string = string;
        }

        private int id;
        private String string;

        @JsonProperty("id")
        public int getId() {
                return id;
        }

        @JsonProperty("id")
        public void setId(int id) {
                this.id = id;
        }

        @JsonProperty("string")
        public String getString() {
                return string;
        }

        @JsonProperty("string")
        public void setString(String string) {
                this.string = string;
        }

}

ModelHolder.java: (Source)

This is part of the demonstration code - it holds multipul SimpleModel Java Objects and aids in exampling how JSON<->JAVA Object handling works.

It must be accessed statically as Jersey loads our JAX-RS Application from a Set<Class> and thus it is not possible to pass objects in constructors.

public class ModelHolder {

        private HashMap<Integer, SimpleModel> SimpleModelHolder;

        static ModelHolder mh;

        public ModelHolder() {
                System.out.println("ModelHolder Constructed");
                this.SimpleModelHolder = new HashMap<Integer, SimpleModel>();
                ModelHolder.mh = this;
        }

        public SimpleModel getSimpleModel(int id) {
                for (Integer i : SimpleModelHolder.keySet()) {
                        System.out.println(i + " : " + SimpleModelHolder.get(i).getString());
                }
                if (SimpleModelHolder.containsKey(id)) {
                        return SimpleModelHolder.get(id);
                }
                return null;
        }

        public void setSimpleModel(SimpleModel simpelModel) {
                SimpleModelHolder.put(simpelModel.getId(), simpelModel);
        }

        /**
         * Gets a ModelHolder or creates one if none exists.
         *
         * @return instanceof ModelHodler.
         */
        public static ModelHolder getHolder() {
                if (mh == null) {
                        new ModelHolder();
                }
                return ModelHolder.mh;
        }

}