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);
}
} OutputCaused 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 ProjectDependencies and Technologies Used: - jersey-container-servlet 2.25.1: Jersey core Servlet 3.x implementation.
- JDK 1.8
- Maven 3.3.9
|