Skip to content

Commit 8a0cba5

Browse files
author
Adrian Cole
committed
Removes Dagger 1.x Dependency and support for javax.inject.Named
Dagger 1.x and 2.x are incompatible. Rather than choose one over the other, this change removes Dagger completely. Users can now choose any injector, constructing Feign via its Builder. This change also drops support for javax.inject.Named, which has been replaced by feign.Param. see OpenFeign#120
1 parent 292a2ad commit 8a0cba5

48 files changed

Lines changed: 530 additions & 1542 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
### Version 8.0
2+
* Removes Dagger 1.x Dependency
3+
* Removes support for parameters annotated with `javax.inject.@Named`. Use `feign.@Param` instead.
4+
15
### Version 7.1
26
* Introduces feign.@Param to annotate template parameters. Users must migrate from `javax.inject.@Named` to `feign.@Param` before updating to Feign 8.0.
37
* Supports custom expansion via `@Param(value = "name", expander = CustomExpander.class)`

README.md

Lines changed: 45 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -50,35 +50,14 @@ interface Bank {
5050
Bank bank = Feign.builder().decoder(new AccountDecoder()).target(Bank.class, "https://api.examplebank.com");
5151
```
5252

53-
For further flexibility, you can use Dagger modules directly. See the `Dagger` section for more details.
54-
55-
### Request Interceptors
56-
When you need to change all requests, regardless of their target, you'll want to configure a `RequestInterceptor`.
57-
For example, if you are acting as an intermediary, you might want to propagate the `X-Forwarded-For` header.
58-
59-
```java
60-
static class ForwardedForInterceptor implements RequestInterceptor {
61-
@Override public void apply(RequestTemplate template) {
62-
template.header("X-Forwarded-For", "origin.host.com");
63-
}
64-
}
65-
...
66-
Bank bank = Feign.builder().decoder(accountDecoder).requestInterceptor(new ForwardedForInterceptor()).target(Bank.class, "https://api.examplebank.com");
67-
```
68-
69-
Another common example of an interceptor would be authentication, such as using the built-in `BasicAuthRequestInterceptor`.
70-
71-
```java
72-
Bank bank = Feign.builder().decoder(accountDecoder).requestInterceptor(new BasicAuthRequestInterceptor(username, password)).target(Bank.class, "https://api.examplebank.com");
73-
```
74-
7553
### Multiple Interfaces
7654
Feign can produce multiple api interfaces. These are defined as `Target<T>` (default `HardCodedTarget<T>`), which allow for dynamic discovery and decoration of requests prior to execution.
7755

7856
For example, the following pattern might decorate each request with the current url and auth token from the identity service.
7957

8058
```java
81-
CloudDNS cloudDNS = Feign.builder().target(new CloudIdentityTarget<CloudDNS>(user, apiKey));
59+
Feign feign = Feign.builder().build();
60+
CloudDNS cloudDNS = feign.target(new CloudIdentityTarget<CloudDNS>(user, apiKey));
8261
```
8362

8463
You can find [several examples](https://github.com/Netflix/feign/tree/master/core/src/test/java/feign/examples) in the test tree. Do take time to look at them, as seeing is believing!
@@ -87,7 +66,7 @@ You can find [several examples](https://github.com/Netflix/feign/tree/master/cor
8766
Feign intends to work well within Netflix and other Open Source communities. Modules are welcome to integrate with your favorite projects!
8867

8968
### Gson
90-
[GsonModule](https://github.com/Netflix/feign/tree/master/gson) adds default encoders and decoders so you get get started with a JSON api.
69+
[Gson](https://github.com/Netflix/feign/tree/master/gson) includes an encoder and decoder you can use with a JSON API.
9170

9271
Add `GsonEncoder` and/or `GsonDecoder` to your `Feign.Builder` like so:
9372

@@ -100,7 +79,7 @@ GitHub github = Feign.builder()
10079
```
10180

10281
### Jackson
103-
[JacksonModule](https://github.com/Netflix/feign/tree/master/jackson) adds an encoder and decoder you can use with a JSON API.
82+
[Jackson](https://github.com/Netflix/feign/tree/master/jackson) includes an encoder and decoder you can use with a JSON API.
10483

10584
Add `JacksonEncoder` and/or `JacksonDecoder` to your `Feign.Builder` like so:
10685

@@ -124,7 +103,7 @@ api = Feign.builder()
124103
```
125104

126105
### JAXB
127-
[JAXBModule](https://github.com/Netflix/feign/tree/master/jaxb) allows you to encode and decode XML using JAXB.
106+
[JAXB](https://github.com/Netflix/feign/tree/master/jaxb) includes an encoder and decoder you can use with an XML API.
128107

129108
Add `JAXBEncoder` and/or `JAXBDecoder` to your `Feign.Builder` like so:
130109

@@ -136,7 +115,7 @@ api = Feign.builder()
136115
```
137116

138117
### JAX-RS
139-
[JAXRSModule](https://github.com/Netflix/feign/tree/master/jaxrs) overrides annotation processing to instead use standard ones supplied by the JAX-RS specification. This is currently targeted at the 1.1 spec.
118+
[JAXRSContract](https://github.com/Netflix/feign/tree/master/jaxrs) overrides annotation processing to instead use standard ones supplied by the JAX-RS specification. This is currently targeted at the 1.1 spec.
140119

141120
Here's the example above re-written to use JAX-RS:
142121
```java
@@ -147,7 +126,7 @@ interface GitHub {
147126
```
148127
```java
149128
GitHub github = Feign.builder()
150-
.contract(new JAXRSModule.JAXRSContract())
129+
.contract(new JAXRSContract())
151130
.target(GitHub.class, "https://api.github.com");
152131
```
153132
### OkHttp
@@ -162,11 +141,12 @@ GitHub github = Feign.builder()
162141
```
163142

164143
### Ribbon
165-
[RibbonModule](https://github.com/Netflix/feign/tree/master/ribbon) overrides URL resolution of Feign's client, adding smart routing and resiliency capabilities provided by [Ribbon](https://github.com/Netflix/ribbon).
144+
[RibbonClient](https://github.com/Netflix/feign/tree/master/ribbon) overrides URL resolution of Feign's client, adding smart routing and resiliency capabilities provided by [Ribbon](https://github.com/Netflix/ribbon).
166145

167146
Integration requires you to pass your ribbon client name as the host part of the url, for example `myAppProd`.
168147
```java
169-
MyService api = Feign.create(MyService.class, "https://myAppProd", new RibbonModule());
148+
MyService api = Feign.builder().client(new RibbonClient()).target(MyService.class, "https://myAppProd");
149+
170150
```
171151

172152
### SLF4J
@@ -206,27 +186,45 @@ GitHub github = Feign.builder()
206186
.target(GitHub.class, "https://api.github.com");
207187
```
208188

209-
### Advanced usage and Dagger
210-
#### Dagger
211-
Feign can be directly wired into Dagger which keeps things at compile time and Android friendly. As opposed to exposing builders for config, Feign intends users to embed their config in Dagger.
189+
### Advanced usage
212190

213-
Where possible, Feign configuration uses normal Dagger conventions. For example, `RequestInterceptor` bindings are of `Provider.Type.SET`, meaning you can have multiple interceptors. Here's an example of multiple interceptor bindings.
191+
#### Logging
192+
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:
214193
```java
215-
@Provides(type = SET) RequestInterceptor forwardedForInterceptor() {
216-
return new RequestInterceptor() {
217-
@Override public void apply(RequestTemplate template) {
218-
template.header("X-Forwarded-For", "origin.host.com");
219-
}
220-
};
221-
}
194+
GitHub github = Feign.builder()
195+
.decoder(new GsonDecoder())
196+
.logger(new Logger.JavaLogger().appendToFile("logs/http.log"))
197+
.logLevel(Logger.Level.FULL)
198+
.target(GitHub.class, "https://api.github.com");
199+
```
222200

223-
@Provides(type = SET) RequestInterceptor userAgentInterceptor() {
224-
return new RequestInterceptor() {
225-
@Override public void apply(RequestTemplate template) {
226-
template.header("User-Agent", "My Cool Client");
227-
}
228-
};
201+
The SLF4JLogger (see above) may also be of interest.
202+
203+
204+
#### Request Interceptors
205+
When you need to change all requests, regardless of their target, you'll want to configure a `RequestInterceptor`.
206+
For example, if you are acting as an intermediary, you might want to propagate the `X-Forwarded-For` header.
207+
208+
```java
209+
static class ForwardedForInterceptor implements RequestInterceptor {
210+
@Override public void apply(RequestTemplate template) {
211+
template.header("X-Forwarded-For", "origin.host.com");
212+
}
229213
}
214+
...
215+
Bank bank = Feign.builder()
216+
.decoder(accountDecoder)
217+
.requestInterceptor(new ForwardedForInterceptor())
218+
.target(Bank.class, "https://api.examplebank.com");
219+
```
220+
221+
Another common example of an interceptor would be authentication, such as using the built-in `BasicAuthRequestInterceptor`.
222+
223+
```java
224+
Bank bank = Feign.builder()
225+
.decoder(accountDecoder)
226+
.requestInterceptor(new BasicAuthRequestInterceptor(username, password))
227+
.target(Bank.class, "https://api.examplebank.com");
230228
```
231229

232230
#### Custom Parameter Expansion
@@ -237,15 +235,3 @@ for example formatting dates.
237235
```java
238236
@RequestLine("GET /?since={date}") Result list(@Param(value = "date", expander = DateToMillis.class) Date date);
239237
```
240-
241-
#### Logging
242-
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:
243-
```java
244-
GitHub github = Feign.builder()
245-
.decoder(new GsonDecoder())
246-
.logger(new Logger.JavaLogger().appendToFile("logs/http.log"))
247-
.logLevel(Logger.Level.FULL)
248-
.target(GitHub.class, "https://api.github.com");
249-
```
250-
251-
The SLF4JModule (see above) may also be of interest.

build.gradle

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,5 @@ subprojects {
1212
repositories {
1313
jcenter()
1414
}
15-
apply from: rootProject.file('dagger.gradle')
1615
group = "com.netflix.${githubProjectName}" // TEMPLATE: Set to organization of project
1716
}

core/build.gradle

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@ apply plugin: 'java'
33
sourceCompatibility = 1.6
44

55
dependencies {
6-
testCompile 'com.google.code.gson:gson:2.2.4'
7-
testCompile 'com.fasterxml.jackson.core:jackson-databind:2.2.2'
86
testCompile 'junit:junit:4.12'
97
testCompile 'org.assertj:assertj-core:1.7.1'
108
testCompile 'com.squareup.okhttp:mockwebserver:2.2.0'
9+
testCompile 'com.google.code.gson:gson:2.2.4' // for example
1110
}

core/src/main/java/feign/Client.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,10 @@
2626
import java.util.Map;
2727
import java.util.zip.GZIPOutputStream;
2828

29-
import javax.inject.Inject;
3029
import javax.net.ssl.HostnameVerifier;
3130
import javax.net.ssl.HttpsURLConnection;
3231
import javax.net.ssl.SSLSocketFactory;
3332

34-
import dagger.Lazy;
3533
import feign.Request.Options;
3634

3735
import static feign.Util.CONTENT_ENCODING;
@@ -55,10 +53,11 @@ public interface Client {
5553
Response execute(Request request, Options options) throws IOException;
5654

5755
public static class Default implements Client {
58-
private final Lazy<SSLSocketFactory> sslContextFactory;
59-
private final Lazy<HostnameVerifier> hostnameVerifier;
56+
private final SSLSocketFactory sslContextFactory;
57+
private final HostnameVerifier hostnameVerifier;
6058

61-
@Inject public Default(Lazy<SSLSocketFactory> sslContextFactory, Lazy<HostnameVerifier> hostnameVerifier) {
59+
/** Null parameters imply platform defaults. */
60+
public Default(SSLSocketFactory sslContextFactory, HostnameVerifier hostnameVerifier) {
6261
this.sslContextFactory = sslContextFactory;
6362
this.hostnameVerifier = hostnameVerifier;
6463
}
@@ -72,8 +71,12 @@ HttpURLConnection convertAndSend(Request request, Options options) throws IOExce
7271
final HttpURLConnection connection = (HttpURLConnection) new URL(request.url()).openConnection();
7372
if (connection instanceof HttpsURLConnection) {
7473
HttpsURLConnection sslCon = (HttpsURLConnection) connection;
75-
sslCon.setSSLSocketFactory(sslContextFactory.get());
76-
sslCon.setHostnameVerifier(hostnameVerifier.get());
74+
if (sslContextFactory != null) {
75+
sslCon.setSSLSocketFactory(sslContextFactory);
76+
}
77+
if (hostnameVerifier != null) {
78+
sslCon.setHostnameVerifier(hostnameVerifier);
79+
}
7780
}
7881
connection.setConnectTimeout(options.connectTimeoutMillis());
7982
connection.setReadTimeout(options.readTimeoutMillis());

core/src/main/java/feign/Contract.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,12 @@
1515
*/
1616
package feign;
1717

18-
import java.util.LinkedHashMap;
19-
import javax.inject.Named;
2018
import java.lang.annotation.Annotation;
2119
import java.lang.reflect.Method;
2220
import java.net.URI;
2321
import java.util.ArrayList;
2422
import java.util.Collection;
23+
import java.util.LinkedHashMap;
2524
import java.util.List;
2625
import java.util.Map;
2726

@@ -168,10 +167,9 @@ protected boolean processAnnotationsOnParameter(MethodMetadata data, Annotation[
168167
boolean isHttpAnnotation = false;
169168
for (Annotation annotation : annotations) {
170169
Class<? extends Annotation> annotationType = annotation.annotationType();
171-
if (annotationType == Param.class || annotationType == Named.class) {
172-
String name = annotationType == Param.class ? ((Param) annotation).value() : ((Named) annotation).value();
173-
checkState(emptyToNull(name) != null,
174-
"%s annotation was empty on param %s.", annotationType.getSimpleName(), paramIndex);
170+
if (annotationType == Param.class) {
171+
String name = ((Param) annotation).value();
172+
checkState(emptyToNull(name) != null, "Param annotation was empty on param %s.", paramIndex);
175173
nameParam(data, name, paramIndex);
176174
if (annotationType == Param.class) {
177175
Class<? extends Param.Expander> expander = ((Param) annotation).expander();

0 commit comments

Comments
 (0)