Skip to content

Commit dc581cf

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 #120
1 parent 12e671b commit dc581cf

Some content is hidden

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

48 files changed

+529
-1639
lines changed

CHANGELOG.md

+4
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

+45-59
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

-1
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

+1-2
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

+10-9
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import static feign.Util.CONTENT_LENGTH;
2020
import static feign.Util.ENCODING_GZIP;
2121

22-
import dagger.Lazy;
2322
import feign.Request.Options;
2423
import java.io.IOException;
2524
import java.io.InputStream;
@@ -31,7 +30,6 @@
3130
import java.util.List;
3231
import java.util.Map;
3332
import java.util.zip.GZIPOutputStream;
34-
import javax.inject.Inject;
3533
import javax.net.ssl.HostnameVerifier;
3634
import javax.net.ssl.HttpsURLConnection;
3735
import javax.net.ssl.SSLSocketFactory;
@@ -49,12 +47,11 @@ public interface Client {
4947
Response execute(Request request, Options options) throws IOException;
5048

5149
public static class Default implements Client {
52-
private final Lazy<SSLSocketFactory> sslContextFactory;
53-
private final Lazy<HostnameVerifier> hostnameVerifier;
50+
private final SSLSocketFactory sslContextFactory;
51+
private final HostnameVerifier hostnameVerifier;
5452

55-
@Inject
56-
public Default(
57-
Lazy<SSLSocketFactory> sslContextFactory, Lazy<HostnameVerifier> hostnameVerifier) {
53+
/** Null parameters imply platform defaults. */
54+
public Default(SSLSocketFactory sslContextFactory, HostnameVerifier hostnameVerifier) {
5855
this.sslContextFactory = sslContextFactory;
5956
this.hostnameVerifier = hostnameVerifier;
6057
}
@@ -70,8 +67,12 @@ HttpURLConnection convertAndSend(Request request, Options options) throws IOExce
7067
(HttpURLConnection) new URL(request.url()).openConnection();
7168
if (connection instanceof HttpsURLConnection) {
7269
HttpsURLConnection sslCon = (HttpsURLConnection) connection;
73-
sslCon.setSSLSocketFactory(sslContextFactory.get());
74-
sslCon.setHostnameVerifier(hostnameVerifier.get());
70+
if (sslContextFactory != null) {
71+
sslCon.setSSLSocketFactory(sslContextFactory);
72+
}
73+
if (hostnameVerifier != null) {
74+
sslCon.setHostnameVerifier(hostnameVerifier);
75+
}
7576
}
7677
connection.setConnectTimeout(options.connectTimeoutMillis());
7778
connection.setReadTimeout(options.readTimeoutMillis());

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

+3-10
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import java.util.LinkedHashMap;
2727
import java.util.List;
2828
import java.util.Map;
29-
import javax.inject.Named;
3029

3130
/** Defines what annotations and values are valid on interfaces. */
3231
public interface Contract {
@@ -177,16 +176,10 @@ protected boolean processAnnotationsOnParameter(
177176
boolean isHttpAnnotation = false;
178177
for (Annotation annotation : annotations) {
179178
Class<? extends Annotation> annotationType = annotation.annotationType();
180-
if (annotationType == Param.class || annotationType == Named.class) {
181-
String name =
182-
annotationType == Param.class
183-
? ((Param) annotation).value()
184-
: ((Named) annotation).value();
179+
if (annotationType == Param.class) {
180+
String name = ((Param) annotation).value();
185181
checkState(
186-
emptyToNull(name) != null,
187-
"%s annotation was empty on param %s.",
188-
annotationType.getSimpleName(),
189-
paramIndex);
182+
emptyToNull(name) != null, "Param annotation was empty on param %s.", paramIndex);
190183
nameParam(data, name, paramIndex);
191184
if (annotationType == Param.class) {
192185
Class<? extends Param.Expander> expander = ((Param) annotation).expander();

0 commit comments

Comments
 (0)