4

For code, see my tiny 4 class github project

I am using Spring FeignClients to connect to a rest service. This is what the Feign client looks like in its basic (non-async) form:

@FeignClient(value="localhost:8080/products", decode404 = true)
public interface ProductClient {
    @RequestMapping(value="/{id}")
    Product getById(@PathVariable("id") String id);
}

Now I wanted to do that asynchronously, using an Observable. Information on this is severely lacking in the Spring docs, there is only a small paragraph that tells you to use a HystrixCommand. That's all, no explanation, no sampe code.

In another blog post, I was told to use a HystrixObservable instead. And so I tried that:

@FeignClient(value="localhost:8080/products", decode404 = true)
public interface ProductClient {
    @RequestMapping(value="/{id}")
    HystrixObservable<Product> getById(@PathVariable("id") String id);
}

Either way, with a HystrixCommand or HystrixObservable, it throws me the error: com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.netflix.hystrix.HystrixObservable

I understand why it is giving that error, since Spring Boot automatically attaches a Decoder to the FeignClient to deserialize the response using Jackson. And the type to deserialize the response into is derived from the return value.

I could try to configure a custome Decoder or manually build the Feign clients, but that kind-of defeats the whole purpose of Spring Boot: that it works automagically (albeit with a bit of configuration here and there).

And so my question is: how is this supposed to work?

Anne van Leyden
  • 139
  • 1
  • 9
  • As is shown in the [documentation](https://github.com/OpenFeign/feign/tree/master/hystrix), you need to construct the clients differently (via `HystrixFeign`). – Tassos Bassoukos Feb 18 '17 at 20:36
  • 2
    Yes, it is possible to manually build the Feign clients. But my question is about Spring + Feign. So how to make Spring generate the proper Feign clients? The Spring docs suggest that it can, but some vital details are left out. Also this [blog post](https://www.voxxed.com/blog/2016/03/netflix-stack-using-spring-boot-part-3-feign/#feignclientwithhystrixobservablewrapper) suggests exactly what I'm doing. – Anne van Leyden Feb 19 '17 at 07:57
  • @AnnevanderBom were you able to make it work? – Bogdan Timofeev May 17 '19 at 08:55
  • @BogdanTimofeev Unfortunately not. – Anne van Leyden May 28 '19 at 15:26

2 Answers2

1

If you specify the return type as a HystrixCommand<Product> or either of RxJava's Observable<Product> or Single<Product> rather than a HystrixObservable<Product> it should work.

I believe the reason using HystrixObservable doesn't work is because it's an interface and Jackson won't map to abstract types such as interfaces by default, as you might see in your stack trace:

> abstract types either need to be mapped to concrete types, have custom
> deserializer, or contain additional type information

HystrixCommand however, is an implementation of the HystrixObservable interface, so Jackson can map to it easily.

If you check out the HystrixInvocationHandler in Feign's Hystrix module, you'll see the other types which it is capable of returning; the ones I listed above as well as RxJava's Completable. The documentation linked by Tassos Bassoukos also lists the types.

If you're looking for something which is asynchronous and non-blocking it might be worth checking out Feign Vertx, as I believe Feign can be asynchronous but blocking. The discussion about non-blocking Feign is here.

Hope that helps!

  • Thanks for the anwser. Jackson should neither deserialize a HystrixCommand, nor a HystrixObservable, but a Product, because that is the payload in the response. Somewhere the return value in the request must be deserialized and the type to deserialize it into is taken from the return type of the method (a HystrixObservable in this case). But that is the wrong strategy here. It should look at the generic type. Which is rather hard in runtime thanks to type erasure. – Anne van Leyden Mar 17 '17 at 10:47
1

If anybody starts getting this error after upgrading to spring-cloud:1.3.+ make sure you have hystrix-feign enabled.

feign.hystrix.enabled=true

This was added so feign does not wrap calls in hystrix commands by default.

https://github.com/spring-cloud/spring-cloud-netflix/issues/1277