Spring / JSON: конвертировать типизированную коллекцию, такую ​​как List <MyPojo> - PullRequest
32 голосов
/ 30 мая 2011

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

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

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

В дополнение к привязке к POJO и «простые» типы, есть один дополнительный вариант: привязка к универсальные (типизированные) контейнеры. Этот случай требует специальной обработки из-за так называемое стирание типа (используется 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, чтобы они могли устранить этот недостаток в интерфейсе HttpMessageConverter.

Ответы [ 3 ]

40 голосов
/ 15 февраля 2013

В 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);

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

23 голосов
/ 30 мая 2011

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

static class MyStringList extends ArrayList<String> { }

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

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

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

10 голосов
/ 30 мая 2011

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

Возвращает Джексон JavaType для конкретный класс. Реализация по умолчанию возвращается 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);
   }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...