Can a Jersey GET request return a polymorphic object?

I have a Resource class that is trying to return an interface type, like "Shape":

public interface Shape {...} @XmlRootElement public class Circle implements Shape {...} @Path("/api/shapes") public class ShapeResource { @GET @Path("/{shapeId}") public Shape get(@PathParam("shapeId") String shapeId) { .... return new Circle(); } } 

Experimenting with the above, I see that the server returns XML as follows:

 <?xml version="1.0" encoding="UTF-8"?> <circle> ... </circle> 

So far so good. The problem is that the client does not know how to undo this. I get:

 com.sun.jersey.api.client.ClientHandlerException: A message body for Java type, interface Shape, and MIME media type, application/xml, was not found 

Given a WebResource and requesting an entity type of Shape.class, an exception is thrown.

The server seems to be doing the right thing. I struggled for many hours on how to get the Client to deserialize this class. I even tried wrapping the interface that I really try to get in the shell as described here: https://jaxb.dev.java.net/guide/Mapping_interfaces.html . That didn't work either.

My client code is as follows:

  ClientResponse response = get(wr, ClientResponse.class); // wr == WebResource try { return response.getEntity(Shape.class); // <-- FAIL } catch (Exception e) { e.printStackTrace(); // com.sun.jersey.api.client.ClientHandlerException: A message body reader for Java type, interface Shape, and MIME media type, application/xml, was not found } try { return response.getEntity(Circle.class); // <-- WIN, but hacky and forces me to try every concrete type } catch (Exception e) {} return null; 

Any insight or guidance is appreciated. Thanks in advance.

+6
java rest jersey jax-rs
source share
1 answer

The problem is probably not related to the JAXB implementation that you are using, as the message is sorted correctly.

Instead, the problem is the following call:

 return response.getEntity(Shape.class); 

I'm not sure how this is implemented, but I can imagine that he is doing something like the following, which would be wrong:

 jaxbContext.createUnmarshaller.unmarshal(xmlSource, Shape.class); 

Since it seems that all of your Shape implementations are annotated with @XmlRootElement, we need a way to invoke the following JAXB call:

 jaxbContext.createUnmarshaller.unmarshal(xmlSource); 

You can do this outside of the Jersey client APIs:

 URL url = new URL("http://www.example.com/api/shapes/123"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setRequestProperty("Accept", "application/xml"); JAXBContext jaxbContext = JAXBContext.newInstance(Circle.class, Square.class, Triangle.class); Shape shape = (Shape) jaxbContext.createUnmarshaller().unmarshal(connection.getInputStream()); connection.disconnect(); 

So there should be a way to do this using the client APIs.

+2
source share

All Articles