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

Spring/json: Преобразование типизированной коллекции, например List <MyPojo>

Я пытаюсь упорядочить список: List<Pojo> объектов через шаблон Spring Rest.

Я могу передать простые объекты Pojo, но я не могу найти документацию, описывающую, как отправить объекты List<Pojo>.

Spring использует Jackson JSON для реализации HttpMessageConverter. Документация Jackson описывает это:

В дополнение к привязке к POJO и "простых" типов, есть один дополнительный вариант: привязка к общие (типизированные) контейнеры. Это дело требует специальной обработки из-за так называемый тип Erasure (используемый Java для реализации дженериков в несколько обратный совместимый способ), который препятствует вам использовать что-то вроде Collection<String>.class (что делает не компилировать).

Итак, если вы хотите привязать данные к Map<String,User> вам нужно будет использовать:

Map<String,User> result = mapper.readValue(src, new TypeReference<Map<String,User>>() {});

где TypeReference требуется только определение общего типа (через любой внутренний класс в этом случае): важная часть <Map<String,User>>, который определяет тип для привязки к.

Можно ли это сделать в шаблоне Spring? Я взглянул на код, и это делает меня не так, но, может быть, я просто не знаю какой-то трюк.


Решение

Конечным решением, благодаря полезным ответам ниже, было не отправлять список, а скорее отправить один объект, который просто расширяет список, например: class PojoList extends ArrayList<Pojo>. Spring может успешно маршалировать этот объект, и он выполняет то же самое, что и отправку List<Pojo>, хотя он будет немного менее чистым от решения. Я также разместил JIRA в Spring, чтобы устранить этот недостаток в интерфейсе HttpMessageConverter.

4b9b3361

Ответ 1

Если я правильно прочитал docs для MappingJacksonHttpMessageConverter, вам нужно будет создать и зарегистрировать подкласс MappingJacksonHttpMessageConverter и переопределить getJavaType(Class<?>) метод:

Возвращает JavaType Jackson для определенного класса. Реализация по умолчанию возвращается TypeFactory.type(java.lang.reflect.Type), но это можно переопределить в подклассы, чтобы общая обработка коллекции. Для пример:

protected JavaType getJavaType(Class<?> clazz) {
   if (List.class.isAssignableFrom(clazz)) {
     return TypeFactory.collectionType(ArrayList.class, MyBean.class);
   } else {
     return super.getJavaType(clazz);
   }
}

Ответ 2

В Spring 3.2 теперь поддерживаются общие типы, используя новые exchange() -методы на RestTemplate:

 ParameterizedTypeReference<List<MyBean>> typeRef = new ParameterizedTypeReference<List<MyBean>>() {};
 ResponseEntity<List<MyBean>> response = template.exchange("http://example.com", HttpMethod.GET, null, typeRef);

Работает как шарм!

Ответ 3

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

static class MyStringList extends ArrayList<String> { }

и вернуть экземпляр этого списка.

Так почему же это имеет значение? Поскольку информация общего типа сохраняется только в нескольких местах: метод и объявления полей, а также объявления типа супер. Таким образом, в то время как "raw" List не содержит никакой информации о типе времени выполнения, определение класса "MyStringList" делает через свои объявления супертипа. Обратите внимание, что присваивания, казалось бы, типизированных переменных не помогают: он просто создает больше синтаксического сахара времени компиляции: информация о реальном типе передается только с экземплярами класса (или расширениями, предоставляемыми lib, такими как JavaType и TypeReference в случае с Джексоном).

Кроме этого, вам нужно будет выяснить, как передать Джексону либо JavaType, либо TypeReference для сопровождения значения.