Commit 8983c9bc by Luke Tornquist

Add support for Wildcard Types in Feign Client. Fixes gh-1676

parent ced1f36d
...@@ -16,13 +16,10 @@ ...@@ -16,13 +16,10 @@
package org.springframework.cloud.netflix.feign.support; package org.springframework.cloud.netflix.feign.support;
import static org.springframework.cloud.netflix.feign.support.FeignUtils.getHttpHeaders; import feign.FeignException;
import feign.Response;
import java.io.IOException; import feign.codec.DecodeException;
import java.io.InputStream; import feign.codec.Decoder;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.ObjectFactory;
import org.springframework.boot.autoconfigure.web.HttpMessageConverters; import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
...@@ -30,10 +27,13 @@ import org.springframework.http.HttpStatus; ...@@ -30,10 +27,13 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.client.ClientHttpResponse;
import org.springframework.web.client.HttpMessageConverterExtractor; import org.springframework.web.client.HttpMessageConverterExtractor;
import feign.FeignException; import java.io.IOException;
import feign.Response; import java.io.InputStream;
import feign.codec.DecodeException; import java.lang.reflect.ParameterizedType;
import feign.codec.Decoder; import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import static org.springframework.cloud.netflix.feign.support.FeignUtils.getHttpHeaders;
/** /**
* @author Spencer Gibb * @author Spencer Gibb
...@@ -49,7 +49,7 @@ public class SpringDecoder implements Decoder { ...@@ -49,7 +49,7 @@ public class SpringDecoder implements Decoder {
@Override @Override
public Object decode(final Response response, Type type) throws IOException, public Object decode(final Response response, Type type) throws IOException,
FeignException { FeignException {
if (type instanceof Class || type instanceof ParameterizedType) { if (type instanceof Class || type instanceof ParameterizedType || type instanceof WildcardType) {
@SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressWarnings({ "unchecked", "rawtypes" })
HttpMessageConverterExtractor<?> extractor = new HttpMessageConverterExtractor( HttpMessageConverterExtractor<?> extractor = new HttpMessageConverterExtractor(
type, this.messageConverters.getObject().getConverters()); type, this.messageConverters.getObject().getConverters());
......
...@@ -16,13 +16,9 @@ ...@@ -16,13 +16,9 @@
package org.springframework.cloud.netflix.feign; package org.springframework.cloud.netflix.feign;
import static org.junit.Assert.assertEquals; import lombok.AllArgsConstructor;
import static org.junit.Assert.assertNotNull; import lombok.Data;
import static org.junit.Assert.assertNull; import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
...@@ -36,13 +32,16 @@ import org.springframework.http.HttpStatus; ...@@ -36,13 +32,16 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import lombok.AllArgsConstructor; import java.util.ArrayList;
import lombok.Data; import java.util.List;
import lombok.NoArgsConstructor; import java.util.Map;
import static org.junit.Assert.*;
/** /**
* @author Spencer Gibb * @author Spencer Gibb
...@@ -109,6 +108,19 @@ public class SpringDecoderTests extends FeignClientFactoryBean { ...@@ -109,6 +108,19 @@ public class SpringDecoderTests extends FeignClientFactoryBean {
} }
@Test @Test
@SuppressWarnings("unchecked")
public void testWildcardTypeDecode() {
ResponseEntity<?> wildcard = testClient().getWildcard();
assertNotNull("wildcard was null", wildcard);
assertEquals("wrong status code", HttpStatus.OK, wildcard.getStatusCode());
Object wildcardBody = wildcard.getBody();
assertNotNull("wildcardBody was null", wildcardBody);
assertTrue("wildcard not an instance of Map", wildcardBody instanceof Map);
Map<String, String> hello = (Map<String, String>) wildcardBody;
assertEquals("first hello didn't match", "wildcard", hello.get("message"));
}
@Test
public void testResponseEntityVoid() { public void testResponseEntityVoid() {
ResponseEntity<Void> response = testClient().getHelloVoid(); ResponseEntity<Void> response = testClient().getHelloVoid();
assertNotNull("response was null", response); assertNotNull("response was null", response);
...@@ -156,6 +168,9 @@ public class SpringDecoderTests extends FeignClientFactoryBean { ...@@ -156,6 +168,9 @@ public class SpringDecoderTests extends FeignClientFactoryBean {
@RequestMapping(method = RequestMethod.GET, value = "/hellonotfound") @RequestMapping(method = RequestMethod.GET, value = "/hellonotfound")
ResponseEntity<String> getNotFound(); ResponseEntity<String> getNotFound();
@GetMapping("/helloWildcard")
ResponseEntity<?> getWildcard();
} }
@Configuration @Configuration
...@@ -199,6 +214,11 @@ public class SpringDecoderTests extends FeignClientFactoryBean { ...@@ -199,6 +214,11 @@ public class SpringDecoderTests extends FeignClientFactoryBean {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body((String) null); return ResponseEntity.status(HttpStatus.NOT_FOUND).body((String) null);
} }
@Override
public ResponseEntity<?> getWildcard() {
return ResponseEntity.ok(new Hello("wildcard"));
}
public static void main(String[] args) { public static void main(String[] args) {
new SpringApplicationBuilder(Application.class) new SpringApplicationBuilder(Application.class)
.properties("spring.application.name=springdecodertest", .properties("spring.application.name=springdecodertest",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment