Может ли запрос GET Джерси вернуть полиморфную сущность? - PullRequest
6 голосов
/ 09 сентября 2010

У меня есть класс 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();
    }
}

Поэкспериментируя с вышесказанным, я вижу, что сервер возвращает XML примерно так:*

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

Пока все хорошо.Проблема в том, что клиент не знает, как это разобрать.Я получаю:

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

Учитывая 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;

Любое понимание или руководство очень ценится.Заранее спасибо.

1 Ответ

2 голосов
/ 10 сентября 2010

Проблема, вероятно, не в реализации используемой вами JAXB, поскольку сообщение корректно распределяется.

Вместо этого проблема заключается в следующем вызове:

return response.getEntity(Shape.class); 

Я не уверен, как это реализовано, но я могу представить, что он делает что-то вроде следующего, что было бы неверно:

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

Поскольку кажется, что все ваши реализации Shape аннотированы с помощью @XmlRootElement, нам нужен способ инициировать следующий вызов JAXB:

jaxbContext.createUnmarshaller.unmarshal(xmlSource);

Вы можете сделать этоэто за пределами клиентских 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();

Так что должен быть способ сделать это с клиентскими API Джерси.

...