Подтвердить что ты не робот

Получение ресурсов REST в виде списка <T> с Джерси

Я пытаюсь написать универсальную функцию в Джерси, которая может быть использована для извлечения списка объектов одного типа через REST. Я основывался на информации, найденной на этом форуме: ссылка

@Override
public <T> List<T> fetchResourceAsList(String url) {
  ClientConfig cc = new DefaultClientConfig();
  Client c = Client.create(cc);
  if (userName!=null && password!=null) {
    c.addFilter(new HTTPBasicAuthFilter(userName, password)); 
  }
  WebResource resource = c.resource(url);
  return resource.get(new GenericType<List<T>>() {});
}

Однако это не работает. Если я попытаюсь выполнить его, я получаю следующую ошибку: SEVERE: A message body reader for Java class java.util.List, and Java type java.util.List<T>, and MIME media type application/xml was not found.

Однако, если я напишу эту функцию без шаблонов (заменив T на фактическое имя класса), она просто отлично работает. Разумеется, эта функция теряет смысл.

Есть ли способ исправить это?

4b9b3361

Ответ 1

Я нашел решение https://java.net/projects/jersey/lists/users/archive/2011-08/message/37

public <T> List<T> getAll(final Class<T> clazz) {

    ParameterizedType parameterizedGenericType = new ParameterizedType() {
        public Type[] getActualTypeArguments() {
            return new Type[] { clazz };
        }

        public Type getRawType() {
            return List.class;
        }

        public Type getOwnerType() {
            return List.class;
        }
    };

    GenericType<List<T>> genericType = new GenericType<List<T>>(
            parameterizedGenericType) {
    };

    return service.path(Path.ROOT).path(clazz.getSimpleName())
            .accept(MediaType.APPLICATION_XML).get(genericType);
}

Ответ 2

См. класс GenericType трикотажа, который также может помочь вам

Unmarshaller должен знать, какой тип объекта есть, прежде чем он сможет отменить возвращенный контент. Поскольку информация о дженериках недоступна во время выполнения, то то, что вы просите, невозможно. Он не может сказать, что ничего не знает о нем.

лучше всего вы можете:

public <T> List<T> fetchResourceAsList(Class<?> beanClass, String url) {
    ...

   if(beanCLass.equals(MyBean.class)){
      return resource.get(new GenericType<List<MyBean>>()
   }else if(...){
      ...
   }...
}

или с предупреждениями общего характера (я не уверен, что это сработает)

public List fetchResourceAsList(String url) {
    ...
      return resource.get(new GenericType<List<Serializable>>()
}

Ответ 3

Расширение на user2323189, вы можете использовать Collection вместо List.class, чтобы вы могли сериализовать все типы, расширяющие Collection. Я создаю простой getter в моем базовом клиентском классе и могу просто использовать его для извлечения любого типа коллекции. Не переменная clazz поставляется в моем конструкторе, поэтому она не является аргументом. Вероятно, вы можете превратить это в статический метод и использовать подпись GenericType > с параметром для класса, чтобы сделать его еще более общим.

public GenericType<Collection<T>> getParameterizedCollectionType() {
        ParameterizedType parameterizedGenericType = new ParameterizedType() {
            public Type[] getActualTypeArguments() {
                return new Type[] { clazz };
            }

            public Type getRawType() {
                return Collection.class;
            }

            public Type getOwnerType() {
                return Collection.class;
            }
        };
        return new GenericType<Collection<T>>(parameterizedGenericType){};
    }