Browse Source

support usage of gson without using dagger

pull/76/head
adriancole 11 years ago
parent
commit
7fb20174fb
  1. 3
      CHANGES.md
  2. 51
      README.md
  3. 12
      gson/README.md
  4. 48
      gson/src/main/java/feign/gson/GsonCodec.java
  5. 49
      gson/src/main/java/feign/gson/GsonModule.java
  6. 4
      gson/src/test/java/feign/gson/GsonModuleTest.java
  7. 4
      gson/src/test/java/feign/gson/examples/GitHubExample.java

3
CHANGES.md

@ -1,3 +1,6 @@ @@ -1,3 +1,6 @@
### Version 5.2.0
* Support usage of `GsonCodec` via `Feign.Builder`
### Version 5.1.0
* Correctly handle IOExceptions wrapped by Ribbon.
* Miscellaneous findbugs fixes.

51
README.md

@ -25,7 +25,9 @@ static class Contributor { @@ -25,7 +25,9 @@ static class Contributor {
}
public static void main(String... args) {
GitHub github = Feign.create(GitHub.class, "https://api.github.com", new GsonModule());
GitHub github = Feign.builder()
.decoder(new GsonCodec())
.target(GitHub.class, "https://api.github.com");
// Fetch and print a list of the contributors to this library.
List<Contributor> contributors = github.contributors("netflix", "feign");
@ -35,8 +37,6 @@ public static void main(String... args) { @@ -35,8 +37,6 @@ public static void main(String... args) {
}
```
Feign includes a fully functional json codec in the `feign-gson` extension. See the `Decoder` section for how to write your own.
### Customization
Feign has several aspects that can be customized. For simple cases, you can use `Feign.builder()` to construct an API interface with your custom components. For example:
@ -83,9 +83,14 @@ Feign intends to work well within Netflix and other Open Source communities. Mo @@ -83,9 +83,14 @@ Feign intends to work well within Netflix and other Open Source communities. Mo
### Gson
[GsonModule](https://github.com/Netflix/feign/tree/master/gson) adds default encoders and decoders so you get get started with a JSON api.
Integration requires you pass `new GsonModule()` to `Feign.create()`, or add it to your graph with Dagger:
Add `GsonCodec` to your `Feign.Builder` like so:
```java
GitHub github = Feign.create(GitHub.class, "https://api.github.com", new GsonModule());
GsonCodec codec = new GsonCodec();
GitHub github = Feign.builder()
.encoder(codec)
.decoder(codec)
.target(GitHub.class, "https://api.github.com");
```
### Sax
@ -119,26 +124,16 @@ MyService api = Feign.create(MyService.class, "https://myAppProd", new RibbonMod @@ -119,26 +124,16 @@ MyService api = Feign.create(MyService.class, "https://myAppProd", new RibbonMod
```
### Decoders
The last argument to `Feign.create` allows you to specify additional configuration such as how to decode a responses, modeled in Dagger.
`Feign.builder()` allows you to specify additional configuration such as how to decode a response.
If any methods in your interface return types besides `Response` or `void`, you'll need to configure a `Decoder`.
The `GsonModule` in the `feign-gson` extension configures a `Decoder` which parses objects from JSON using reflection.
Here's how to configure json decoding (using the `feign-gson` extension):
Here's how you could write this yourself, using whatever library you prefer:
```java
@Module(library = true)
static class JsonModule {
@Provides Decoder decoder(final JsonParser parser) {
return new Decoder() {
@Override public Object decode(Response response, Type type) throws IOException {
return parser.readJson(response.body().asReader(), type);
}
};
}
}
GitHub github = Feign.builder()
.decoder(new GsonCodec())
.target(GitHub.class, "https://api.github.com");
```
### Advanced usage and Dagger
@ -166,15 +161,9 @@ Where possible, Feign configuration uses normal Dagger conventions. For example @@ -166,15 +161,9 @@ Where possible, Feign configuration uses normal Dagger conventions. For example
#### Logging
You can log the http messages going to and from the target by setting up a `Logger`. Here's the easiest way to do that:
```java
@Module(overrides = true)
class Overrides {
@Provides @Singleton Logger.Level provideLoggerLevel() {
return Logger.Level.FULL;
}
@Provides @Singleton Logger provideLogger() {
return new Logger.JavaLogger().appendToFile("logs/http.log");
}
}
GitHub github = Feign.create(GitHub.class, "https://api.github.com", new GsonGitHubModule(), new Overrides());
GitHub github = Feign.builder()
.decoder(new GsonCodec())
.logger(new Logger.JavaLogger().appendToFile("logs/http.log"))
.logLevel(Logger.Level.FULL)
.target(GitHub.class, "https://api.github.com");
```

12
gson/README.md

@ -3,7 +3,17 @@ Gson Codec @@ -3,7 +3,17 @@ Gson Codec
This module adds support for encoding and decoding json via the Gson library.
Add this to your object graph like so:
Add `GsonCodec` to your `Feign.Builder` like so:
```java
GsonCodec codec = new GsonCodec();
GitHub github = Feign.builder()
.encoder(codec)
.decoder(codec)
.target(GitHub.class, "https://api.github.com");
```
Or.. to your object graph like so:
```java
GitHub github = Feign.create(GitHub.class, "https://api.github.com", new GsonModule());

48
gson/src/main/java/feign/gson/GsonCodec.java

@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
package feign.gson;
import com.google.gson.Gson;
import com.google.gson.JsonIOException;
import feign.RequestTemplate;
import feign.Response;
import feign.codec.Decoder;
import feign.codec.Encoder;
import javax.inject.Inject;
import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.Type;
import static feign.Util.ensureClosed;
public class GsonCodec implements Encoder, Decoder {
private final Gson gson;
public GsonCodec() {
this(new Gson());
}
@Inject public GsonCodec(Gson gson) {
this.gson = gson;
}
@Override public void encode(Object object, RequestTemplate template) {
template.body(gson.toJson(object));
}
@Override public Object decode(Response response, Type type) throws IOException {
if (response.body() == null) {
return null;
}
Reader reader = response.body().asReader();
try {
return gson.fromJson(reader, type);
} catch (JsonIOException e) {
if (e.getCause() != null && e.getCause() instanceof IOException) {
throw IOException.class.cast(e.getCause());
}
throw e;
} finally {
ensureClosed(reader);
}
}
}

49
gson/src/main/java/feign/gson/GsonModule.java

@ -18,7 +18,6 @@ package feign.gson; @@ -18,7 +18,6 @@ package feign.gson;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.InstanceCreator;
import com.google.gson.JsonIOException;
import com.google.gson.TypeAdapter;
import com.google.gson.internal.ConstructorConstructor;
import com.google.gson.internal.bind.MapTypeAdapterFactory;
@ -27,21 +26,16 @@ import com.google.gson.stream.JsonReader; @@ -27,21 +26,16 @@ import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import dagger.Provides;
import feign.Feign;
import feign.RequestTemplate;
import feign.Response;
import feign.codec.Decoder;
import feign.codec.Encoder;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import static feign.Util.ensureClosed;
import static feign.Util.resolveLastTypeParameter;
/**
@ -52,20 +46,20 @@ import static feign.Util.resolveLastTypeParameter; @@ -52,20 +46,20 @@ import static feign.Util.resolveLastTypeParameter;
* to read numbers in a {@code Map<String, Object>} as Integers. You can
* customize further by adding additional set bindings to the raw type
* {@code TypeAdapter}.
*
* <p/>
* <br>
* Here's an example of adding a custom json type adapter.
*
* <p/>
* <pre>
* &#064;Provides(type = Provides.Type.SET)
* TypeAdapter upperZone() {
* return new TypeAdapter&lt;Zone&gt;() {
*
*
* &#064;Override
* public void write(JsonWriter out, Zone value) throws IOException {
* throw new IllegalArgumentException();
* }
*
*
* &#064;Override
* public Zone read(JsonReader in) throws IOException {
* in.beginObject();
@ -91,41 +85,6 @@ public final class GsonModule { @@ -91,41 +85,6 @@ public final class GsonModule {
return codec;
}
static class GsonCodec implements Encoder, Decoder {
private final Gson gson;
@Inject GsonCodec(Gson gson) {
this.gson = gson;
}
@Override public void encode(Object object, RequestTemplate template) {
template.body(gson.toJson(object));
}
@Override public Object decode(Response response, Type type) throws IOException {
if (response.body() == null) {
return null;
}
Reader reader = response.body().asReader();
try {
return fromJson(new JsonReader(reader), type);
} finally {
ensureClosed(reader);
}
}
private Object fromJson(JsonReader jsonReader, Type type) throws IOException {
try {
return gson.fromJson(jsonReader, type);
} catch (JsonIOException e) {
if (e.getCause() != null && e.getCause() instanceof IOException) {
throw IOException.class.cast(e.getCause());
}
throw e;
}
}
}
@Provides @Singleton Gson gson(Set<TypeAdapter> adapters) {
GsonBuilder builder = new GsonBuilder().setPrettyPrinting();
for (TypeAdapter<?> adapter : adapters) {

4
gson/src/test/java/feign/gson/GsonModuleTest.java

@ -52,8 +52,8 @@ public class GsonModuleTest { @@ -52,8 +52,8 @@ public class GsonModuleTest {
EncoderAndDecoderBindings bindings = new EncoderAndDecoderBindings();
ObjectGraph.create(bindings).inject(bindings);
assertEquals(bindings.encoder.getClass(), GsonModule.GsonCodec.class);
assertEquals(bindings.decoder.getClass(), GsonModule.GsonCodec.class);
assertEquals(bindings.encoder.getClass(), GsonCodec.class);
assertEquals(bindings.decoder.getClass(), GsonCodec.class);
}
@Module(includes = GsonModule.class, injects = EncoderBindings.class)

4
gson/src/test/java/feign/gson/examples/GitHubExample.java

@ -17,7 +17,7 @@ package feign.gson.examples; @@ -17,7 +17,7 @@ package feign.gson.examples;
import feign.Feign;
import feign.RequestLine;
import feign.gson.GsonModule;
import feign.gson.GsonCodec;
import javax.inject.Named;
import java.util.List;
@ -38,7 +38,7 @@ public class GitHubExample { @@ -38,7 +38,7 @@ public class GitHubExample {
}
public static void main(String... args) throws InterruptedException {
GitHub github = Feign.create(GitHub.class, "https://api.github.com", new GsonModule());
GitHub github = Feign.builder().decoder(new GsonCodec()).target(GitHub.class, "https://api.github.com");
System.out.println("Let's fetch and print a list of the contributors to this library.");
List<Contributor> contributors = github.contributors("netflix", "feign");

Loading…
Cancel
Save