RESTfu­­l Jav­a­ wit­h ­JAX­-­­RS 2.­0­ (Second Edition)

Injection Annotations (1)

This project is a simple example showing usage of JAX-RS injection annotations.

System Requirements:

  • Maven 3.0.4 or higher

Building the project:

  1. In root directory mvn clean install

This will build a WAR and run it with embedded Jetty.

Source Code

Hierarchy

ex05_1
|-- pom.xml
`-- src
    |-- main
    |   |-- java
    |   |   `-- com
    |   |       `-- restfully
    |   |           `-- shop
    |   |               |-- domain
    |   |               |   `-- Customer.java
    |   |               `-- services
    |   |                   |-- CarResource.java
    |   |                   |-- CustomerResource.java
    |   |                   `-- ShoppingApplication.java
    |   `-- webapp
    |       `-- WEB-INF
    |           `-- web.xml
    `-- test
        `-- java
            `-- com
                `-- restfully
                    `-- shop
                        `-- test
                            `-- InjectionTest.java

Details

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <parent>
        <groupId>com.oreilly.rest.workbook</groupId>
        <artifactId>jaxrs-2.0-workbook-pom</artifactId>
        <version>1.0</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.oreilly.rest.workbook</groupId>
    <artifactId>jaxrs-2.0-workbook-ex05_1</artifactId>
    <version>2.0</version>
    <packaging>war</packaging>
    <name>ex05_1</name>
    <description/>

    <dependencies>
        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-jaxrs</artifactId>
            <version>3.0.12.Final-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-client</artifactId>
            <version>3.0.12.Final-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>async-http-servlet-3.0</artifactId>
            <version>3.0.12.Final-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>jaxrs-api</artifactId>
            <version>3.0.12.Final-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-servlet-initializer</artifactId>
            <version>3.0.12.Final-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
    <finalName>ex05_1</finalName>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-deploy-plugin</artifactId>
            <configuration>
                <skip>true</skip>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-maven-plugin</artifactId>
            <version>9.0.6.v20130930</version>
            <configuration>
                <webApp>
                    <contextPath>/</contextPath>
                </webApp>
                <scanIntervalSeconds>10</scanIntervalSeconds>
                <stopKey>foo</stopKey>
                <stopPort>9999</stopPort>
                <stopWait>1</stopWait>
            </configuration>
            <executions>
                <execution>
                    <id>start-jetty</id>
                    <phase>pre-integration-test</phase>
                    <goals>
                        <goal>run</goal>
                    </goals>
                    <configuration>
                        <scanIntervalSeconds>0</scanIntervalSeconds>
                        <daemon>true</daemon>
                    </configuration>
                </execution>
                <execution>
                    <id>stop-jetty</id>
                    <phase>post-integration-test</phase>
                    <goals>
                        <goal>stop</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <configuration>
                <skip>true</skip>
            </configuration>
            <executions>
                <execution>
                    <id>surefire-it</id>
                    <phase>integration-test</phase>
                    <goals>
                        <goal>test</goal>
                    </goals>
                    <configuration>
                        <skip>false</skip>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.6</source>
                <target>1.6</target>
            </configuration>
        </plugin>
    </plugins>
    </build>
</project>

src/main/webapp/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
      version="3.0">
</web-app>

src/main/java/com/restfully/shop/domain/Customer.java

package com.restfully.shop.domain;

public class Customer
{
   private int id;
   private String firstName;
   private String lastName;
   private String street;
   private String city;
   private String state;
   private String zip;
   private String country;

   public int getId()
   {
      return id;
   }

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

   public String getFirstName()
   {
      return firstName;
   }

   public void setFirstName(String firstName)
   {
      this.firstName = firstName;
   }

   public String getLastName()
   {
      return lastName;
   }

   public void setLastName(String lastName)
   {
      this.lastName = lastName;
   }

   public String getStreet()
   {
      return street;
   }

   public void setStreet(String street)
   {
      this.street = street;
   }

   public String getCity()
   {
      return city;
   }

   public void setCity(String city)
   {
      this.city = city;
   }

   public String getState()
   {
      return state;
   }

   public void setState(String state)
   {
      this.state = state;
   }

   public String getZip()
   {
      return zip;
   }

   public void setZip(String zip)
   {
      this.zip = zip;
   }

   public String getCountry()
   {
      return country;
   }

   public void setCountry(String country)
   {
      this.country = country;
   }
}

src/main/java/com/restfully/shop/services/CustomerResource.java

package com.restfully.shop.services;

import com.restfully.shop.domain.Customer;

import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.StreamingOutput;
import javax.ws.rs.core.UriInfo;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

@Path("/customers")
public class CustomerResource
{
   private Map<Integer, Customer> customerDB = Collections.synchronizedMap(new LinkedHashMap<Integer, Customer>());

   public CustomerResource()
   {
      Customer customer;
      int id = 1;

      customer = new Customer();
      customer.setId(id);
      customer.setFirstName("Bill");
      customer.setLastName("Burke");
      customer.setStreet("263 Clarendon Street");
      customer.setCity("Boston");
      customer.setState("MA");
      customer.setZip("02115");
      customer.setCountry("USA");
      customerDB.put(id++, customer);

      customer = new Customer();
      customer.setId(id);
      customer.setFirstName("Joe");
      customer.setLastName("Burke");
      customer.setStreet("263 Clarendon Street");
      customer.setCity("Boston");
      customer.setState("MA");
      customer.setZip("02115");
      customer.setCountry("USA");
      customerDB.put(id++, customer);

      customer = new Customer();
      customer.setId(id);
      customer.setFirstName("Monica");
      customer.setLastName("Burke");
      customer.setStreet("263 Clarendon Street");
      customer.setCity("Boston");
      customer.setState("MA");
      customer.setZip("02115");
      customer.setCountry("USA");
      customerDB.put(id++, customer);

      customer = new Customer();
      customer.setId(id);
      customer.setFirstName("Steve");
      customer.setLastName("Burke");
      customer.setStreet("263 Clarendon Street");
      customer.setCity("Boston");
      customer.setState("MA");
      customer.setZip("02115");
      customer.setCountry("USA");
      customerDB.put(id++, customer);
   }

   @GET
   @Produces("application/xml")
   public StreamingOutput getCustomers(final @QueryParam("start") int start,
                                       final @QueryParam("size") @DefaultValue("2") int size)
   {
      return new StreamingOutput()
      {
         public void write(OutputStream outputStream) throws IOException, WebApplicationException
         {
            PrintStream writer = new PrintStream(outputStream);
            writer.println("<customers>");
            synchronized (customerDB)
            {
               int i = 0;
               for (Customer customer : customerDB.values())
               {
                  if (i >= start && i < start + size) outputCustomer("   ", writer, customer);
                  i++;
               }
            }
            writer.println("</customers>");
         }
      };
   }

   @GET
   @Produces("application/xml")
   @Path("uriinfo")
   public StreamingOutput getCustomers(@Context UriInfo info)
   {
      int start = 0;
      int size = 2;
      if (info.getQueryParameters().containsKey("start"))
      {
         start = Integer.valueOf(info.getQueryParameters().getFirst("start"));
      }
      if (info.getQueryParameters().containsKey("size"))
      {
         size = Integer.valueOf(info.getQueryParameters().getFirst("size"));
      }
      return getCustomers(start, size);
   }

   protected void outputCustomer(String indent, PrintStream writer, Customer cust) throws IOException
   {
      writer.println(indent + "<customer id=\"" + cust.getId() + "\">");
      writer.println(indent + "   <first-name>" + cust.getFirstName() + "</first-name>");
      writer.println(indent + "   <last-name>" + cust.getLastName() + "</last-name>");
      writer.println(indent + "   <street>" + cust.getStreet() + "</street>");
      writer.println(indent + "   <city>" + cust.getCity() + "</city>");
      writer.println(indent + "   <state>" + cust.getState() + "</state>");
      writer.println(indent + "   <zip>" + cust.getZip() + "</zip>");
      writer.println(indent + "   <country>" + cust.getCountry() + "</country>");
      writer.println(indent + "</customer>");
   }

}

src/main/java/com/restfully/shop/services/ShoppingApplication.java

package com.restfully.shop.services;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import java.util.HashSet;
import java.util.Set;

@ApplicationPath("/services")
public class ShoppingApplication extends Application
{
   private Set<Object> singletons = new HashSet<Object>();

   public ShoppingApplication()
   {
      singletons.add(new CustomerResource());
      singletons.add(new CarResource());
   }

   @Override
   public Set<Object> getSingletons()
   {
      return singletons;
   }
}

src/main/java/com/restfully/shop/services/CarResource.java

package com.restfully.shop.services;

import javax.ws.rs.GET;
import javax.ws.rs.MatrixParam;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.PathSegment;
import javax.ws.rs.core.UriInfo;
import java.util.List;

/**
 * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
 * @version $Revision: 1 $
 */
@Path("/cars")
public class CarResource
{
   public static enum Color
   {
      red,
      white,
      blue,
      black
   }

   @GET
   @Path("/matrix/{make}/{model}/{year}")
   @Produces("text/plain")
   public String getFromMatrixParam(@PathParam("make") String make,
                                    @PathParam("model") PathSegment car,
                                    @MatrixParam("color") Color color,
                                    @PathParam("year") String year)
   {
      return "A " + color + " " + year + " " + make + " " + car.getPath();
   }


   @GET
   @Path("/segment/{make}/{model}/{year}")
   @Produces("text/plain")
   public String getFromPathSegment(@PathParam("make") String make,
                                    @PathParam("model") PathSegment car,
                                    @PathParam("year") String year)
   {
      String carColor = car.getMatrixParameters().getFirst("color");
      return "A " + carColor + " " + year + " " + make + " " + car.getPath();
   }

   @GET
   @Path("/segments/{make}/{model : .+}/year/{year}")
   @Produces("text/plain")
   public String getFromMultipleSegments(@PathParam("make") String make,
                                         @PathParam("model") List<PathSegment> car,
                                         @PathParam("year") String year)
   {
      String output = "A " + year + " " + make;
      for (PathSegment segment : car)
      {
         output += " " + segment.getPath();
      }
      return output;
   }

   @GET
   @Path("/uriinfo/{make}/{model}/{year}")
   @Produces("text/plain")
   public String getFromUriInfo(@Context UriInfo info)
   {
      String make = info.getPathParameters().getFirst("make");
      String year = info.getPathParameters().getFirst("year");
      PathSegment model = info.getPathSegments().get(3);
      String color = model.getMatrixParameters().getFirst("color");

      return "A " + color + " " + year + " " + make + " " + model.getPath();
   }
}

src/test/java/com/restfully/shop/test/InjectionTest.java

package com.restfully.shop.test;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;


/**
 * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
 * @version $Revision: 1 $
 */
public class InjectionTest
{
   private static Client client;

   @BeforeClass
   public static void initClient()
   {
      client = ClientBuilder.newClient();
   }

   @AfterClass
   public static void closeClient()
   {
      client.close();
   }

   @Test
   public void testCarResource() throws Exception
   {
      System.out.println("**** CarResource Via @MatrixParam ***");
      String car = client.target("http://localhost:8080/services/cars/matrix/mercedes/e55;color=black/2006").request().get(String.class);
      System.out.println(car);

      System.out.println("**** CarResource Via PathSegment ***");
      car = client.target("http://localhost:8080/services/cars/segment/mercedes/e55;color=black/2006").request().get(String.class);
      System.out.println(car);

      System.out.println("**** CarResource Via PathSegments ***");
      car = client.target("http://localhost:8080/services/cars/segments/mercedes/e55/amg/year/2006").request().get(String.class);
      System.out.println(car);

      System.out.println("**** CarResource Via PathSegment ***");
      car = client.target("http://localhost:8080/services/cars/uriinfo/mercedes/e55;color=black/2006").request().get(String.class);
      System.out.println(car);
   }

   @Test
   public void testCustomerResource() throws Exception
   {
      System.out.println("**** CustomerResource No Query params ***");
      String customer = client.target("http://localhost:8080/services/customers").request().get(String.class);
      System.out.println(customer);

      System.out.println("**** CustomerResource With Query params ***");
      String list = client.target("http://localhost:8080/services/customers")
                          .queryParam("start", "1")
                          .queryParam("size", "3")
                          .request().get(String.class);
      System.out.println(list);

      System.out.println("**** CustomerResource With UriInfo and Query params ***");
      list = client.target("http://localhost:8080/services/customers/uriinfo")
                   .queryParam("start", "2")
                   .queryParam("size", "2")
                   .request().get(String.class);
   }
}