2015-05-28 10 views
4

У меня есть сервер, который предоставляет ресурсы через Spring-data-rest, и это использует, насколько я понимаю HAL или HATEOAS. Но когда я пытаюсь использовать его в сочетании с Feign, я, похоже, не могу зарегистрировать выбранный Jackson2HalModule.Feign и HAL/resources

Есть ли что-то, что мне нужно сделать, чтобы подключить «клиент» Feign к новому конвертеру? Использует ли он другой объект ObjectMapper, чем тот, который я получил здесь?

Код:

@Inject 
public void configureObjectMapper(ObjectMapper mapper, RestTemplate template) { 
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 
    mapper.registerModule(new Jackson2HalModule()); 

    MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); 
    converter.setSupportedMediaTypes(MediaType.parseMediaTypes("application/hal+json")); 
    converter.setObjectMapper(mapper); 

    template.getMessageConverters().add(converter); 
} 

Ответ сервера:

{ 
    "_links" : { 
    "self" : { 
     "href" : "http://localhost:13372/user{?page,size,sort}", 
     "templated" : true 
    }, 
    "search" : { 
     "href" : "http://localhost:13372/user/search" 
    } 
    }, 
    "_embedded" : { 
    "user" : [ { 
     "id" : "5567613e5da543dba4201950", 
     "version" : 0, 
     "created" : "2015-05-28T18:41:02.685Z", 
     "createdBy" : "system test", 
     "edited" : "2015-05-28T18:41:02.713Z", 
     "editedBy" : "system test", 
     "username" : "devuser", 
     "email" : "[email protected]", 
     "roles" : [ "USER" ], 
     "_links" : { 
     "self" : { 
      "href" : "http://localhost:13372/user/5567613e5da543dba4201950" 
     } 
     } 
    } ] 
    }, 
    "page" : { 
    "size" : 20, 
    "totalElements" : 1, 
    "totalPages" : 1, 
    "number" : 0 
    } 
} 

Исключение:

Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of START_OBJECT token 
at [Source: [email protected]; line: 1, column: 1] 
    at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148) 
    at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:762) 
    at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:758) 
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.handleNonArray(CollectionDeserializer.java:275) 
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:216) 
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:206) 
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:25) 
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3066) 
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2221) 
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:205) 

ответ

4

Я нашел проблему. Исключение произошло из-за того, что ответ API REST был единственным ответом. Таким образом, он не видел его как Список сущностей.

Когда я добавил (основываясь на коде выше):

mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); 

Он работает

Edit: На стороне записки, я реализовал FeignClient так:

@Service 
@FeignClient(UsersConstants.USER_SERVICE_NAME) 
public interface UsersServices { 

    @RequestMapping(method = RequestMethod.GET, value = "/user") 
    List<User> getUsers(); 
} 

Но как это должно быть, поскольку это ресурс, который можно перечислить:

@Service 
@FeignClient(UsersConstants.USER_SERVICE_NAME) 
public interface UsersServices { 

    @RequestMapping(method = RequestMethod.GET, value = "/user") 
    List<PagedResources<User>> getUsers(); 
} 

PagedResource находится в пределах HATEOAS зависимости:

<dependency> 
    <groupId>org.springframework.hateoas</groupId> 
    <artifactId>spring-hateoas</artifactId> 
</dependency> 

Он также имеет много других классов, которые могут помочь, например, как ресурс, ресурсов и так далее.

+0

Я пробовал то же самое, но я не могу заставить его работать. Должен ли я писать метод @inject в другом классе или достаточно в основном классе, где у меня есть аннотация @SpringBootApplication. @ LG87 –

+0

Насколько я знаю, он должен работать в любом классе, управляемом Spring как компонент – LG87

0

Вы должны определить bean-фасоль feignDecoder в своем приложении. Если у вас есть spring-hateoas в вашей среде, то попробуйте что-то вроде этого:

@Bean 
public Decoder feignDecoder() { 
    ObjectMapper mapper = new ObjectMapper() 
      .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) 
      .registerModule(new Jackson2HalModule()); 

    return new ResponseEntityDecoder(new JacksonDecoder(mapper)); 
} 

Затем вы можете потреблять ваш HAL, как PagedResource.

5

Это работает для меня:

@EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL) 
@SpringBootApplication 
@EnableFeignClients 
public class Application { 
.... 
} 

Обратите внимание на @EnableHypermediaSupport

@FeignClient(url = "http://localhost:8080") 
public interface PersonClient { 
    @RequestMapping(method = RequestMethod.GET, value = "/persons") 
    Resources<Person> getPersons(); 

    @RequestMapping(method = RequestMethod.GET, value = "/persons/{id}") 
    Resource<Person> getPerson(@PathVariable("id") long id); 
} 

Я создал полностью рабочий пример здесь: https://github.com/jtdev/spring-feign-data-rest-example

Заметьте, что просто switchen в Maven POM с весны -boot to spring-cloud (без изменения кода), может легко привести к ошибкам json.

+0

, можем ли мы сопоставить все запросы от конечной точки остатка данных весны до одного клиента faign? В приведенном выше примере все методы, такие как GET, POST, PATCH, находятся в одной конечной точке без объявления их в интерфейсе? –

+0

Я посмотрел ваш пример кода, и это хорошо, когда вам не нужно возиться с ObjectMapper и Converters. Теперь, каково минимальное изменение, которое вы добавили бы, чтобы добавить поле Java 8 ZonedDateTime в свой объект Person? –

+0

Добавление '@ EnableHypermediaSupport' сработало для меня. Странно, что это необходимо для Фейнга; У меня сначала было другое решение, которое работало с 'RestTemplate', которое не требовало этого. – Jesper

0

Я получил эту работу для меня (спасибо @Devabc, ты пример помог мне):

Я хотел получить PagedResources ресурса для пользователя.

Не забудьте добавить @EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL) в ваш основной класс приложения.

Мой Feign клиент выглядит следующим образом:

@FeignClient("user-microservice") 
public interface UserClient { 
    @RequestMapping(method = RequestMethod.GET, value = "/user") 
    PagedResources<Resource<User>> findAll(); 
} 

запомнить Также добавить по умолчанию и параметризацию конструктор для вашей модели. (в моем случае User) Я не уверен, почему, но это, похоже, исправить мою проблему сериализации, которая у меня была.

Наконец я использовал эту версию симулировать

<dependency> 
    <groupId>org.springframework.cloud</groupId> 
    <artifactId>spring-cloud-starter-feign</artifactId> 
    <version>1.1.5.RELEASE</version> 
</dependency> 
0

Проверьте link

Ниже комментарий от Грег Turnquist сделал работу для типа коллекции возвращения

C) типа для извлечения из коллекция должна быть Resources<Resource<Question>>. Коллекция имеет ссылки, как и каждая запись коллекции.

Смежные вопросы