2010-09-09 9 views
6

J'ai une classe de ressources qui tente de retourner un type d'interface, dire « Forme »:Est-ce qu'une requête Jersey GET peut renvoyer une entité polymorphe?

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(); 
    } 
} 

Expérimenter avec ce qui précède, je vois que le serveur retourne XML comme ceci:

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

Jusqu'ici tout va bien. Le problème est, le client ne sait pas comment unmarshall ceci. Je reçois:

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

donné une WebResource, et en demandant un type d'entité de Shape.class provoque une exception.

Le serveur semble faire la bonne chose. J'ai lutté pendant des heures pour obtenir que le client désérialise cette classe. J'ai même essayé d'encapsuler l'interface que j'essaie vraiment d'obtenir dans un emballage comme indiqué ici: https://jaxb.dev.java.net/guide/Mapping_interfaces.html. Cela n'a pas fonctionné non plus.

Mon code client ressemble à ceci:

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; 

Toute idée ou d'orientation est grandement appréciée. Merci d'avance.

+0

Cela devrait fonctionner. Je l'ai fait assez souvent. Je pense que c'est un bug dans votre code client. Pouvez-vous l'afficher? –

+0

J'ai mis à jour le message original – Erik

+0

Hmm, que se passe-t-il lorsque vous ajoutez '@ XmlRootElement' à' Shape'? –

Répondre

2

Le problème n'est probablement pas lié à l'implémentation de JAXB que vous utilisez étant donné que le message est correctement organisé.

En revanche, le problème est avec l'appel suivant:

return response.getEntity(Shape.class); 

Je ne sais pas comment cela est mis en œuvre, mais je peux imaginer que cela fait quelque chose comme ce qui suit, ce qui serait invalide:

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

Comme il semble que toutes vos implémentations de forme sont annotés avec @XmlRootElement, nous avons besoin d'un moyen de déclencher l'appel suivant à JAXB:

jaxbContext.createUnmarshaller.unmarshal(xmlSource); 

Vous pouvez DOE ce en dehors des API clientes Jersey:

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(); 

Il devrait y avoir un moyen de le faire avec les API client Jersey.