Как Джерси извлекает универсальный тип из коллекций для вызова javax.ws.rs.ext.MessageBodyWriter # writeTo ()? - PullRequest
2 голосов
/ 23 июня 2010

В службе отдыха, использующей спецификацию JAX-RS, я могу определить универсальную службу, такую ​​как

@GET
@Path("something")
@Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public List<MyPojo> getMyPojoList() {
    ...
}

Что-то волшебное происходит в Джерси, потому что при вызове

javax.ws.rs.ext.MessageBodyWriter#writeTo(T t,
        Class<?> type,
        Type genericType,
        Annotation annotations[], 
        MediaType mediaType, 
        MultivaluedMap<String, Object> httpHeaders,
        OutputStream entityStream) throws IOException, WebApplicationException;

при анализе genericType легко увидеть, что его значение равно class MyPojo.

Я пытался прочитать исходный код Джерси, чтобы понять, как они извлекают тип Collection Generic, прежде чем вызывать метод writeTo из javax.ws.rs.ext.MessageBodyWriter, но я заблудился, когда прибыл, чтобы прочитать класс GenericEntity.

Может ли кто-нибудь помочь мне понять, какую магию они там используют? Заранее спасибо !!!

Ответы [ 2 ]

1 голос
/ 20 августа 2011

Некоторая общая информация сохраняется через компилятор во время выполнения. Взгляните на документацию по рефлексии Java. В этом случае они, вероятно, используют getGenericReturnType , хотя существует множество методов, относящихся к типам параметров и даже к универсальным параметрам класса.

Наиболее очевидным недостатком здесь является то, что может храниться только информация времени компиляции - в частности, вы не можете надежно проверить Список, чтобы определить, является ли он List<Integer> или List<String>.

0 голосов
/ 02 июля 2018

Вам нужно использовать магические классы платформы JAX-RS, чтобы сохранить информацию, которую вы ищете.Мне потребовалось довольно много времени, чтобы на самом деле заставить это работать и над моим проектом, но я решил эту проблему следующим образом:

Сначала, внутри своего класса Resource, передайте универсальную коллекцию как таковую (обратите внимание, я использую объекты Response Objects):

public Response findAll() {
  Collection<MyType> entities = service.findAll(); // whatever code you need to load it.
  GenericEntity<Collection<MyType>> list = new GenericEntity<Collection<MyType>>(entities) {}; // This line is key!
  return Response.ok.entity(list).build();
}

Затем вы можете создать нормальную MessageBodyWriter реализацию и выполнить проверку типа в методе, который отвечает за проверку пригодности вашей реализации.

public class MyTypeMessageBodyWriter implements MessageBodyWriter<MyType> {
    public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        if (Collection.class.isAssignableFrom(type) && genericType instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) genericType;
            Type[] actualTypeArgs = parameterizedType.getActualTypeArguments();
            return (actualTypeArgs.length == 1 && actualTypeArgs[0].equals(MyType.class));
        } else {
            return false;
        }
    }
}

Вы можете усовершенствовать метод isWriteable, чтобы выполнять больше проверок, таких как двойная проверка, например, правильная ли MediaType, а также наличие некоторых аннотаций и т. Д., В зависимости от ваших требований.

Но подведем итог:

  • Оберните вашу коллекцию в оболочку GenericEntity<> для сохранения информации общего типа о типе
  • Выполните правильные приведения в MessageBodyWriter, чтобы определить тип.1021 *
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...