David Cobo
9 years ago
committed by
Adrian Cole
8 changed files with 186 additions and 2 deletions
@ -0,0 +1,27 @@ |
|||||||
|
Jackson-Jaxb Codec |
||||||
|
=================== |
||||||
|
|
||||||
|
This module adds support for encoding and decoding JSON via JAXB. |
||||||
|
|
||||||
|
Add `JacksonJaxbJsonEncoder` and/or `JacksonJaxbJsonDecoder` to your `Feign.Builder` like so: |
||||||
|
|
||||||
|
```java |
||||||
|
GitHub github = Feign.builder() |
||||||
|
.encoder(new JacksonJaxbJsonEncoder()) |
||||||
|
.decoder(new JacksonJaxbJsonDecoder()) |
||||||
|
.target(GitHub.class, "https://api.github.com"); |
||||||
|
``` |
||||||
|
|
||||||
|
If you want to customize the `ObjectMapper` that is used, provide it to the `JacksonJaxbJsonEncoder` and `JacksonJaxbJsonDecoder`: |
||||||
|
|
||||||
|
```java |
||||||
|
ObjectMapper mapper = new ObjectMapper() |
||||||
|
.setSerializationInclusion(JsonInclude.Include.NON_NULL) |
||||||
|
.configure(SerializationFeature.INDENT_OUTPUT, true) |
||||||
|
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); |
||||||
|
|
||||||
|
GitHub github = Feign.builder() |
||||||
|
.encoder(new JacksonJaxbJsonEncoder(mapper)) |
||||||
|
.decoder(new JacksonJaxbJsonDecoder(mapper)) |
||||||
|
.target(GitHub.class, "https://api.github.com"); |
||||||
|
``` |
@ -0,0 +1,13 @@ |
|||||||
|
apply plugin: 'java' |
||||||
|
|
||||||
|
sourceCompatibility = 1.6 |
||||||
|
|
||||||
|
dependencies { |
||||||
|
compile project(':feign-core') |
||||||
|
compile 'javax.ws.rs:jsr311-api:1.1.1' |
||||||
|
compile 'com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:2.6.1' |
||||||
|
testRuntime 'com.sun.jersey:jersey-client:1.19' // for RuntimeDelegateImpl |
||||||
|
testCompile 'junit:junit:4.12' |
||||||
|
testCompile 'org.assertj:assertj-core:1.7.1' // last version supporting JDK 7 |
||||||
|
testCompile project(':feign-core').sourceSets.test.output // for assertions |
||||||
|
} |
@ -0,0 +1,31 @@ |
|||||||
|
package feign.jackson.jaxb; |
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||||
|
import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.lang.reflect.Type; |
||||||
|
|
||||||
|
import feign.FeignException; |
||||||
|
import feign.Response; |
||||||
|
import feign.codec.Decoder; |
||||||
|
|
||||||
|
import static com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider.DEFAULT_ANNOTATIONS; |
||||||
|
import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; |
||||||
|
|
||||||
|
public final class JacksonJaxbJsonDecoder implements Decoder { |
||||||
|
private final JacksonJaxbJsonProvider jacksonJaxbJsonProvider; |
||||||
|
|
||||||
|
public JacksonJaxbJsonDecoder() { |
||||||
|
this.jacksonJaxbJsonProvider = new JacksonJaxbJsonProvider(); |
||||||
|
} |
||||||
|
|
||||||
|
public JacksonJaxbJsonDecoder(ObjectMapper objectMapper) { |
||||||
|
this.jacksonJaxbJsonProvider = new JacksonJaxbJsonProvider(objectMapper, DEFAULT_ANNOTATIONS); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Object decode(Response response, Type type) throws IOException, FeignException { |
||||||
|
return jacksonJaxbJsonProvider.readFrom(Object.class, type, null, APPLICATION_JSON_TYPE, null, response.body().asInputStream()); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,40 @@ |
|||||||
|
package feign.jackson.jaxb; |
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||||
|
import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider; |
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream; |
||||||
|
import java.io.IOException; |
||||||
|
import java.lang.reflect.Type; |
||||||
|
import java.nio.charset.Charset; |
||||||
|
|
||||||
|
import feign.RequestTemplate; |
||||||
|
import feign.codec.EncodeException; |
||||||
|
import feign.codec.Encoder; |
||||||
|
|
||||||
|
import static com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider.DEFAULT_ANNOTATIONS; |
||||||
|
import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; |
||||||
|
|
||||||
|
public final class JacksonJaxbJsonEncoder implements Encoder { |
||||||
|
private final JacksonJaxbJsonProvider jacksonJaxbJsonProvider; |
||||||
|
|
||||||
|
public JacksonJaxbJsonEncoder() { |
||||||
|
this.jacksonJaxbJsonProvider = new JacksonJaxbJsonProvider(); |
||||||
|
} |
||||||
|
|
||||||
|
public JacksonJaxbJsonEncoder(ObjectMapper objectMapper) { |
||||||
|
this.jacksonJaxbJsonProvider = new JacksonJaxbJsonProvider(objectMapper, DEFAULT_ANNOTATIONS); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException { |
||||||
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); |
||||||
|
try { |
||||||
|
jacksonJaxbJsonProvider.writeTo(object, bodyType.getClass(), null, null, APPLICATION_JSON_TYPE, null, outputStream); |
||||||
|
template.body(outputStream.toByteArray(), Charset.defaultCharset()); |
||||||
|
} catch (IOException e) { |
||||||
|
throw new EncodeException(e.getMessage(), e); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,69 @@ |
|||||||
|
package feign.jackson.jaxb; |
||||||
|
|
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
import java.util.Collection; |
||||||
|
import java.util.Collections; |
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlAccessType; |
||||||
|
import javax.xml.bind.annotation.XmlAccessorType; |
||||||
|
import javax.xml.bind.annotation.XmlElement; |
||||||
|
import javax.xml.bind.annotation.XmlRootElement; |
||||||
|
|
||||||
|
import feign.RequestTemplate; |
||||||
|
import feign.Response; |
||||||
|
|
||||||
|
import static feign.Util.UTF_8; |
||||||
|
import static feign.assertj.FeignAssertions.assertThat; |
||||||
|
|
||||||
|
public class JacksonJaxbCodecTest { |
||||||
|
|
||||||
|
@Test |
||||||
|
public void encodeTest() { |
||||||
|
JacksonJaxbJsonEncoder encoder = new JacksonJaxbJsonEncoder(); |
||||||
|
RequestTemplate template = new RequestTemplate(); |
||||||
|
|
||||||
|
encoder.encode(new MockObject("Test"), MockObject.class, template); |
||||||
|
|
||||||
|
assertThat(template).hasBody("{\"value\":\"Test\"}"); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void decodeTest() throws Exception { |
||||||
|
Response response = |
||||||
|
Response.create(200, "OK", Collections.<String, Collection<String>>emptyMap(), "{\"value\":\"Test\"}", UTF_8); |
||||||
|
JacksonJaxbJsonDecoder decoder = new JacksonJaxbJsonDecoder(); |
||||||
|
|
||||||
|
assertThat(decoder.decode(response, MockObject.class)) |
||||||
|
.isEqualTo(new MockObject("Test")); |
||||||
|
} |
||||||
|
|
||||||
|
@XmlRootElement |
||||||
|
@XmlAccessorType(XmlAccessType.FIELD) |
||||||
|
static class MockObject { |
||||||
|
|
||||||
|
@XmlElement |
||||||
|
private String value; |
||||||
|
|
||||||
|
MockObject() { |
||||||
|
} |
||||||
|
|
||||||
|
MockObject(String value) { |
||||||
|
this.value = value; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean equals(Object obj) { |
||||||
|
if (obj instanceof MockObject) { |
||||||
|
MockObject other = (MockObject) obj; |
||||||
|
return value.equals(other.value); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int hashCode() { |
||||||
|
return value != null ? value.hashCode() : 0; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -1,6 +1,7 @@ |
|||||||
rootProject.name='feign' |
rootProject.name='feign' |
||||||
include 'core', 'sax', 'gson', 'httpclient', 'jackson', 'jaxb', 'jaxrs', 'okhttp', 'ribbon', 'slf4j' |
include 'core', 'sax', 'gson', 'httpclient', 'jackson', 'jaxb', 'jaxrs', 'okhttp', 'ribbon', 'slf4j', 'jackson-jaxb' |
||||||
|
|
||||||
rootProject.children.each { childProject -> |
rootProject.children.each { childProject -> |
||||||
childProject.name = 'feign-' + childProject.name |
childProject.name = 'feign-' + childProject.name |
||||||
} |
} |
||||||
|
|
||||||
|
Loading…
Reference in new issue