Получение ресурсов 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 на фактическое имя класса), она просто отлично работает. Разумеется, эта функция теряет смысл.
Есть ли способ исправить это?
Ответы
Ответ 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){};
}