Close

JAX-RS - Returning GenericEntity to preserve generic type

[Last Updated: May 27, 2017]

During runtime, type erasure removes generic type information. For example an object of type List<Order> appears to contain a raw List<?> at runtime.

In JAX-RS, wrapping a response object (like List<Order>) in Response, removes the generic type information. Because of that, some MessageBodyWriter implementations cannot be selected without the generic information. Wrapping the entity in GenericEntity preserves the generic type. Let's see an example to understand the problem and then how to use GenericEntity.

Example

First, we will wrap our entity object directly in Response:

@Path("/")
public class OrderResource {

  @Path("/orders")
  @Produces(MediaType.APPLICATION_XML)
  @GET
  public Response handle() {
      List<Order> orders = getOrders();
      Response r = Response.ok(orders)
                           .header("someHeader", "someHeaderValue")
                           .build();
      return r;
  }

  public List<Order> getOrders() {
      Order o1 = new Order(1, new BigDecimal(15));
      Order o2 = new Order(2, new BigDecimal(20));
      return Arrays.asList(o1, o2);
  }
    .............
}
@XmlRootElement
public class Order {
  private int id;
  private BigDecimal amount;
    .............
}

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

mvn tomcat7:run
public class MyClient1 {
  public static void main(String[] args) {

      Client client = ClientBuilder.newClient();
      WebTarget target = client.target("http://localhost:8080/orders");
      String response = target.request()
                              .get(String.class);
      System.out.println(response);
  }
}

Output

Caused by: javax.ws.rs.InternalServerErrorException: HTTP 500 Internal Server Error
at org.glassfish.jersey.client.JerseyInvocation.convertToException(JerseyInvocation.java:1032)
at org.glassfish.jersey.client.JerseyInvocation.translate(JerseyInvocation.java:819)
at org.glassfish.jersey.client.JerseyInvocation.access$700(JerseyInvocation.java:92)
at org.glassfish.jersey.client.JerseyInvocation$2.call(JerseyInvocation.java:701)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:444)
at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:697)
at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:420)
at org.glassfish.jersey.client.JerseyInvocation$Builder.get(JerseyInvocation.java:316)
at com.logicbig.example.MyClient1.main(MyClient1.java:13)
... 6 more

In the server console:

May 27, 2017 1:45:03 AM org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor aroundWriteTo
SEVERE: MessageBodyWriter not found for media type=application/xml, type=class java.util.Arrays$ArrayList, genericType=class java.util.Arrays$ArrayList.

Using GenericEntity

@Path("/")
public class OrderResource {
    .............
  @Path("/orders2")
  @Produces(MediaType.APPLICATION_XML)
  @GET
  public Response handle2() {
      List<Order> orders = getOrders();
      GenericEntity<List<Order>> genericEntity = new GenericEntity<List<Order>>(orders) {
      };//needs empty body to preserve generic type
      Response r = Response.ok(genericEntity)
                           .header("someHeader", "someHeaderValue")
                           .build();
      return r;
  }
}
public class MyClient2 {
  public static void main(String[] args) {
      Client client = ClientBuilder.newClient();
      WebTarget target = client.target("http://localhost:8080/orders2");
      String s = target.request().get(String.class);
      System.out.println(s);
  }
}

Output

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><orders><order><amount>15</amount><id>1</id></order><order><amount>20</amount><id>2</id></order></orders>

Example Project

Dependencies and Technologies Used:

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

Generic Entity Example Select All Download
  • generic-entity-example
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • OrderResource.java

    See Also