Jersey GET请求可以返回多态实体吗​​?

Eri*_*rik 6 java rest jax-rs jersey

我有一个Resource类,试图返回一个接口类型,比如说"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();
    }
}
Run Code Online (Sandbox Code Playgroud)

试验上面的内容,我看到服务器正在返回XML,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<circle>
...
</circle>
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好.问题是,客户端不知道如何取消编组.我越来越:

com.sun.jersey.api.client.ClientHandlerException: A message body for Java type, interface Shape, and MIME media type, application/xml, was not found
Run Code Online (Sandbox Code Playgroud)

给定一个WebResource,并要求Shape.class的实体类型会导致异常.

服务器似乎正在做正确的事情.我一直在努力争取如何让客户端反序列化这个类.我甚至尝试包装接口,我真的试图通过这里概述的包装器:https://jaxb.dev.java.net/guide/Mapping_interfaces.html.那也行不通.

我的客户端代码如下所示:

    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;
Run Code Online (Sandbox Code Playgroud)

非常感谢任何见解或指导.提前致谢.

bdo*_*han 2

问题可能不在于您正在使用的 JAXB 的实现,因为消息已正确编组。

相反,问题出在以下调用上:

return response.getEntity(Shape.class); 
Run Code Online (Sandbox Code Playgroud)

我不确定这是如何实现的,但我可以想象它会执行类似以下的操作,这是无效的:

jaxbContext.createUnmarshaller.unmarshal(xmlSource, Shape.class);
Run Code Online (Sandbox Code Playgroud)

由于您的所有 Shape 实现似乎都用 @XmlRootElement 进行了注释,因此我们需要一种方法来触发对 JAXB 的以下调用:

jaxbContext.createUnmarshaller.unmarshal(xmlSource);
Run Code Online (Sandbox Code Playgroud)

您可以在 Jersey 客户端 API 之外执行此操作:

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();
Run Code Online (Sandbox Code Playgroud)

因此应该有一种方法可以使用 Jersey 客户端 API 来实现这一点。