JAX-RS - Annotation Inheritance

[Updated: Jun 23, 2017, Created: Jun 22, 2017]

JAX-RS annotations may be used on the methods and method parameters of a super-class or an implemented interface. Such annotations are inherited by a corresponding sub-class or implementation class method. Here following rules are applied:

  • Overriding methods should not have any JAX-RS annotations themselves, otherwise all annotations on super class/interface method are ignored.
  • Inheritance of class or interface annotations is not supported. That means only method level JAX-RS are inherited to the sub-classes.
  • Annotations on a super-class take precedence over those on an implemented interface.

Let's see an example, how to use this feature of JAX-RS.

Example

Creating a resource Interface

In this generic resource interface, we are going to provide various HTTP verb operations for a type T:

public interface AppResource<T> {

  @PUT
  @Path("{newId}")
  @Consumes(MediaType.APPLICATION_XML)
  String create(T t, @PathParam("newId") long newId);

  @DELETE
  @Path("{id}")
  String delete(@PathParam("id") long id);

  @POST
  @Consumes(MediaType.APPLICATION_XML)
  String update(T t);

  @GET
  @Produces(MediaType.APPLICATION_XML)
  List<T> list();

  @GET
  @Path("{id}")
  @Produces(MediaType.APPLICATION_XML)
  T byId(@PathParam("id") long id);
}

Implementing the interface

This implementation is going to have only one @Path annotation on the class.

@Path("employees")
public class EmployeeResource implements AppResource<Employee> {

  @Override
  public String create(Employee employee, long newId) {
      return EmployeeService.getInstance().create(employee, newId);
  }

  @Override
  public String delete(long id) {
      return EmployeeService.getInstance().delete(id);
  }

  @Override
  public String update(Employee employee) {
      return EmployeeService.getInstance().update(employee);
  }

  @Override
  public List<Employee> list() {
      return EmployeeService.getInstance().getEmployees();
  }

  @Override
  public Employee byId(long id) {
      return EmployeeService.getInstance().getEmployeeById(id);
  }
}

In above class, if we add any JAX-RS annotation on a method or a method parameters, then all annotations on the corresponding AppResource interface method will be ignored.

@XmlRootElement
public class Employee {
  private long id;
  private String name;
  private String dept;
    .............
}

To try examples, run embedded tomcat (configured in pom.xml of example project below):

mvn tomcat7:run-war

The client

Let's write JAX-RS client to test above resource:

public class EmployeeClient {
  private static Client client = ClientBuilder.newClient();
  private static WebTarget baseTarget = client.target("http://localhost:8080/employees");
  private static List<String> deptList = Arrays.asList("Admin", "IT", "Sell");

  public static void main(String[] args) {
      createEmployees();
      listEmployees();
      deleteEmployeeByIds(2, 4);
      Employee e = getEmployee(3);
      e.setDept("Marketing");
      updateEmployee(e);
      listEmployees();
  }

  private static Employee getEmployee(long id) {
      System.out.printf("-- getting employee by id: %s --%n", id);
      Employee e = baseTarget.path(Long.toString(id))
                             .request(MediaType.APPLICATION_XML)
                             .get(Employee.class);
      System.out.println("employee retrieved: " + e);
      return e;
  }

  private static void updateEmployee(Employee e) {
      System.out.println("-- updating employee --");
      System.out.println(e);
      String response = baseTarget.request(MediaType.APPLICATION_XML)
                                  .post(Entity.xml(e), String.class);
      System.out.println(response);
  }

  private static void deleteEmployeeByIds(long... ids) {
      System.out.printf("-- deleting employees: %s --%n",
              Arrays.toString(ids));
      for (long id : ids) {
          WebTarget target = baseTarget.path(Long.toString(id));
          Response r = target.request()
                             .delete();
          System.out.println(r.readEntity(String.class));
      }
  }

  private static void listEmployees() {
      System.out.println("-- getting employee list --");
      List<Employee> employees = baseTarget.request().get(
              new GenericType<List<Employee>>() {
              });
      employees.forEach(System.out::println);
  }

  private static void createEmployees() {
      System.out.println("-- making PUT requests --");
      for (int i = 1; i <= 5; i++) {
          Employee e = new Employee();
          e.setName("Employee" + i);
          int index = ThreadLocalRandom.current()
                                       .nextInt(0, 3);
          e.setDept(deptList.get(index));

          WebTarget target = baseTarget.path(Integer.toString(i));
          Response r = target.request()
                             .put(Entity.entity(e, MediaType.APPLICATION_XML));
          System.out.println(r.readEntity(String.class));
      }
  }
}

Output

-- making PUT requests --
Msg: employee created for id: 1
Msg: employee created for id: 2
Msg: employee created for id: 3
Msg: employee created for id: 4
Msg: employee created for id: 5
-- getting employee list --
Employee{id=1, name='Employee1', dept='Sell'}
Employee{id=2, name='Employee2', dept='Sell'}
Employee{id=3, name='Employee3', dept='Admin'}
Employee{id=4, name='Employee4', dept='IT'}
Employee{id=5, name='Employee5', dept='IT'}
-- deleting employees: [2, 4] --
Msg: employee deleted with id: 2
Msg: employee deleted with id: 4
-- getting employee by id: 3 --
employee retrieved: Employee{id=3, name='Employee3', dept='Admin'}
-- updating employee --
Employee{id=3, name='Employee3', dept='Marketing'}
employee updated : Employee{id=3, name='Employee3', dept='Marketing'}
-- getting employee list --
Employee{id=1, name='Employee1', dept='Sell'}
Employee{id=3, name='Employee3', dept='Marketing'}
Employee{id=5, name='Employee5', dept='IT'}

Example Project

Dependencies and Technologies Used :

  • jersey-server 2.25.1: Jersey core server implementation.
  • jersey-container-servlet 2.25.1: Jersey core Servlet 3.x implementation.
  • JDK 1.8
  • Maven 3.3.9

Annotation Inheritance Example Select All Download
  • annotation-inheritance
    • src
      • main
        • java
          • com
            • logicbig
              • example

See Also