Skip to content

Commit 88052a8

Browse files
RicardoRdzGkdavisk6
authored andcommitted
Allow decoding of parameterizedTypes (generics) Fixes #759 (#758)
* Allow decoding of parameterizedTypes (generics) * Allow decoding of parameterizedTypes (generics)
1 parent d7a5929 commit 88052a8

File tree

2 files changed

+48
-5
lines changed

2 files changed

+48
-5
lines changed

jaxb/src/main/java/feign/jaxb/JAXBDecoder.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import feign.codec.DecodeException;
1919
import feign.codec.Decoder;
2020
import java.io.IOException;
21+
import java.lang.reflect.ParameterizedType;
2122
import java.lang.reflect.Type;
2223
import javax.xml.bind.JAXBException;
2324
import javax.xml.bind.Unmarshaller;
@@ -35,13 +36,13 @@
3536
*
3637
* <pre>
3738
* JAXBContextFactory jaxbFactory = new JAXBContextFactory.Builder()
38-
* .withMarshallerJAXBEncoding("UTF-8")
39-
* .withMarshallerSchemaLocation("http://apihost http://apihost/schema.xsd")
39+
* .withMarshallerJAXBEncoding(&quot;UTF-8&quot;)
40+
* .withMarshallerSchemaLocation(&quot;http://apihost http://apihost/schema.xsd&quot;)
4041
* .build();
4142
*
4243
* api = Feign.builder()
4344
* .decoder(new JAXBDecoder(jaxbFactory))
44-
* .target(MyApi.class, "http://api");
45+
* .target(MyApi.class, &quot;http://api&quot;);
4546
* </pre>
4647
*
4748
* <p>The JAXBContextFactory should be reused across requests as it caches the created JAXB
@@ -66,6 +67,10 @@ private JAXBDecoder(Builder builder) {
6667
public Object decode(Response response, Type type) throws IOException {
6768
if (response.status() == 404) return Util.emptyValueOf(type);
6869
if (response.body() == null) return null;
70+
while (type instanceof ParameterizedType) {
71+
ParameterizedType ptype = (ParameterizedType) type;
72+
type = ptype.getRawType();
73+
}
6974
if (!(type instanceof Class)) {
7075
throw new UnsupportedOperationException(
7176
"JAXB only supports decoding raw types. Found " + type);

jaxb/src/test/java/feign/jaxb/JAXBCodecTest.java

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,11 @@ public void decodesXml() throws Exception {
188188

189189
@Test
190190
public void doesntDecodeParameterizedTypes() throws Exception {
191-
thrown.expect(UnsupportedOperationException.class);
191+
thrown.expect(feign.codec.DecodeException.class);
192192
thrown.expectMessage(
193-
"JAXB only supports decoding raw types. Found java.util.Map<java.lang.String, ?>");
193+
"java.util.Map is an interface, and JAXB can't handle interfaces.\n"
194+
+ "\tthis problem is related to the following location:\n"
195+
+ "\t\tat java.util.Map");
194196

195197
class ParameterizedHolder {
196198

@@ -210,6 +212,42 @@ class ParameterizedHolder {
210212
new JAXBDecoder(new JAXBContextFactory.Builder().build()).decode(response, parameterized);
211213
}
212214

215+
@XmlRootElement
216+
static class Box<T> {
217+
218+
@XmlElement private T t;
219+
220+
public void set(T t) {
221+
this.t = t;
222+
}
223+
}
224+
225+
@Test
226+
public void decodeAnnotatedParameterizedTypes() throws Exception {
227+
JAXBContextFactory jaxbContextFactory =
228+
new JAXBContextFactory.Builder().withMarshallerFormattedOutput(true).build();
229+
230+
Encoder encoder = new JAXBEncoder(jaxbContextFactory);
231+
232+
Box<String> boxStr = new Box<>();
233+
boxStr.set("hello");
234+
Box<Box<String>> boxBoxStr = new Box<>();
235+
boxBoxStr.set(boxStr);
236+
RequestTemplate template = new RequestTemplate();
237+
encoder.encode(boxBoxStr, Box.class, template);
238+
239+
Response response =
240+
Response.builder()
241+
.status(200)
242+
.reason("OK")
243+
.request(Request.create("GET", "/api", Collections.emptyMap(), null, Util.UTF_8))
244+
.headers(Collections.<String, Collection<String>>emptyMap())
245+
.body(template.body())
246+
.build();
247+
248+
new JAXBDecoder(new JAXBContextFactory.Builder().build()).decode(response, Box.class);
249+
}
250+
213251
/** Enabled via {@link feign.Feign.Builder#decode404()} */
214252
@Test
215253
public void notFoundDecodesToEmpty() throws Exception {

0 commit comments

Comments
 (0)