Skip to content

Commit 2624885

Browse files
authored
Expose Method and Target on RequestTemplate (OpenFeign#1091)
* Expose Method and Target on RequestTemplate * Add test to check if method metadata is present * Annotated API changes as being experimental/not API-frozen
1 parent d5389a5 commit 2624885

File tree

9 files changed

+299
-55
lines changed

9 files changed

+299
-55
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ public MethodMetadata parseAndValidateMetadata(Method method) {
8080
*/
8181
protected MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
8282
MethodMetadata data = new MethodMetadata();
83+
data.targetType(targetType);
84+
data.method(method);
8385
data.returnType(Types.resolve(targetType, targetType, method.getGenericReturnType()));
8486
data.configKey(Feign.configKey(targetType, method));
8587

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* Copyright 2012-2019 The Feign Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5+
* in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License
10+
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11+
* or implied. See the License for the specific language governing permissions and limitations under
12+
* the License.
13+
*/
14+
package feign;
15+
16+
import java.lang.annotation.*;
17+
import java.lang.annotation.Target;
18+
19+
/**
20+
* Indicates that a public API (public class, method or field) is subject to incompatible changes,
21+
* or even removal, in a future release. An API bearing this annotation is exempt from any
22+
* compatibility guarantees made by its containing library. Note that the presence of this
23+
* annotation implies nothing about the quality or performance of the API in question, only the fact
24+
* that it is not "API-frozen."
25+
*
26+
* <p>
27+
* It is generally safe for <i>applications</i> to depend on beta APIs, at the cost of some extra
28+
* work during upgrades. However it is generally inadvisable for <i>libraries</i> (which get
29+
* included on users' CLASSPATHs, outside the library developers' control) to do so.
30+
*
31+
* "Inspired" on guava @Beta
32+
*/
33+
@Retention(RetentionPolicy.CLASS)
34+
@Target({
35+
ElementType.ANNOTATION_TYPE,
36+
ElementType.CONSTRUCTOR,
37+
ElementType.FIELD,
38+
ElementType.METHOD,
39+
ElementType.TYPE
40+
})
41+
@Documented
42+
public @interface Experimental {
43+
44+
}

core/src/main/java/feign/MethodMetadata.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package feign;
1515

1616
import java.io.Serializable;
17+
import java.lang.reflect.Method;
1718
import java.lang.reflect.Type;
1819
import java.util.*;
1920
import feign.Param.Expander;
@@ -39,8 +40,12 @@ public final class MethodMetadata implements Serializable {
3940
private transient Map<Integer, Expander> indexToExpander;
4041
private BitSet parameterToIgnore = new BitSet();
4142
private boolean ignored;
43+
private transient Class<?> targetType;
44+
private transient Method method;
4245

43-
MethodMetadata() {}
46+
MethodMetadata() {
47+
template.methodMetadata(this);
48+
}
4449

4550
/**
4651
* Used as a reference to this method. For example, {@link Logger#log(String, String, Object...)
@@ -213,4 +218,26 @@ public boolean isIgnored() {
213218
return ignored;
214219
}
215220

221+
@Experimental
222+
public MethodMetadata targetType(Class<?> targetType) {
223+
this.targetType = targetType;
224+
return this;
225+
}
226+
227+
@Experimental
228+
public Class<?> targetType() {
229+
return targetType;
230+
}
231+
232+
@Experimental
233+
public MethodMetadata method(Method method) {
234+
this.method = method;
235+
return this;
236+
}
237+
238+
@Experimental
239+
public Method method() {
240+
return method;
241+
}
242+
216243
}

core/src/main/java/feign/ReflectiveFeign.java

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
*/
1414
package feign;
1515

16-
import feign.template.UriUtils;
16+
import static feign.Util.checkArgument;
17+
import static feign.Util.checkNotNull;
1718
import java.lang.reflect.InvocationHandler;
1819
import java.lang.reflect.Method;
1920
import java.lang.reflect.Proxy;
@@ -22,12 +23,8 @@
2223
import feign.InvocationHandlerFactory.MethodHandler;
2324
import feign.Param.Expander;
2425
import feign.Request.Options;
25-
import feign.codec.Decoder;
26-
import feign.codec.EncodeException;
27-
import feign.codec.Encoder;
28-
import feign.codec.ErrorDecoder;
29-
import static feign.Util.checkArgument;
30-
import static feign.Util.checkNotNull;
26+
import feign.codec.*;
27+
import feign.template.UriUtils;
3128

3229
public class ReflectiveFeign extends Feign {
3330

@@ -150,25 +147,26 @@ static final class ParseHandlersByName {
150147
this.decoder = checkNotNull(decoder, "decoder");
151148
}
152149

153-
public Map<String, MethodHandler> apply(Target key) {
154-
List<MethodMetadata> metadata = contract.parseAndValidateMetadata(key.type());
150+
public Map<String, MethodHandler> apply(Target target) {
151+
List<MethodMetadata> metadata = contract.parseAndValidateMetadata(target.type());
155152
Map<String, MethodHandler> result = new LinkedHashMap<String, MethodHandler>();
156153
for (MethodMetadata md : metadata) {
157154
BuildTemplateByResolvingArgs buildTemplate;
158155
if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) {
159-
buildTemplate = new BuildFormEncodedTemplateFromArgs(md, encoder, queryMapEncoder);
156+
buildTemplate =
157+
new BuildFormEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target);
160158
} else if (md.bodyIndex() != null) {
161-
buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder, queryMapEncoder);
159+
buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target);
162160
} else {
163-
buildTemplate = new BuildTemplateByResolvingArgs(md, queryMapEncoder);
161+
buildTemplate = new BuildTemplateByResolvingArgs(md, queryMapEncoder, target);
164162
}
165163
if (md.isIgnored()) {
166164
result.put(md.configKey(), args -> {
167165
throw new IllegalStateException(md.configKey() + " is not a method handled by feign");
168166
});
169167
} else {
170168
result.put(md.configKey(),
171-
factory.create(key, md, buildTemplate, options, decoder, errorDecoder));
169+
factory.create(target, md, buildTemplate, options, decoder, errorDecoder));
172170
}
173171
}
174172
return result;
@@ -180,10 +178,13 @@ private static class BuildTemplateByResolvingArgs implements RequestTemplate.Fac
180178
private final QueryMapEncoder queryMapEncoder;
181179

182180
protected final MethodMetadata metadata;
181+
protected final Target<?> target;
183182
private final Map<Integer, Expander> indexToExpander = new LinkedHashMap<Integer, Expander>();
184183

185-
private BuildTemplateByResolvingArgs(MethodMetadata metadata, QueryMapEncoder queryMapEncoder) {
184+
private BuildTemplateByResolvingArgs(MethodMetadata metadata, QueryMapEncoder queryMapEncoder,
185+
Target target) {
186186
this.metadata = metadata;
187+
this.target = target;
187188
this.queryMapEncoder = queryMapEncoder;
188189
if (metadata.indexToExpander() != null) {
189190
indexToExpander.putAll(metadata.indexToExpander());
@@ -208,6 +209,7 @@ private BuildTemplateByResolvingArgs(MethodMetadata metadata, QueryMapEncoder qu
208209
@Override
209210
public RequestTemplate create(Object[] argv) {
210211
RequestTemplate mutable = RequestTemplate.from(metadata.template());
212+
mutable.feignTarget(target);
211213
if (metadata.urlIndex() != null) {
212214
int urlIndex = metadata.urlIndex();
213215
checkArgument(argv[urlIndex] != null, "URI parameter %s was null", urlIndex);
@@ -332,8 +334,8 @@ private static class BuildFormEncodedTemplateFromArgs extends BuildTemplateByRes
332334
private final Encoder encoder;
333335

334336
private BuildFormEncodedTemplateFromArgs(MethodMetadata metadata, Encoder encoder,
335-
QueryMapEncoder queryMapEncoder) {
336-
super(metadata, queryMapEncoder);
337+
QueryMapEncoder queryMapEncoder, Target target) {
338+
super(metadata, queryMapEncoder, target);
337339
this.encoder = encoder;
338340
}
339341

@@ -363,8 +365,8 @@ private static class BuildEncodedTemplateFromArgs extends BuildTemplateByResolvi
363365
private final Encoder encoder;
364366

365367
private BuildEncodedTemplateFromArgs(MethodMetadata metadata, Encoder encoder,
366-
QueryMapEncoder queryMapEncoder) {
367-
super(metadata, queryMapEncoder);
368+
QueryMapEncoder queryMapEncoder, Target target) {
369+
super(metadata, queryMapEncoder, target);
368370
this.encoder = encoder;
369371
}
370372

core/src/main/java/feign/Request.java

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ public static Request create(String method,
109109
Charset charset) {
110110
checkNotNull(method, "httpMethod of %s", method);
111111
final HttpMethod httpMethod = HttpMethod.valueOf(method.toUpperCase());
112-
return create(httpMethod, url, headers, body, charset);
112+
return create(httpMethod, url, headers, body, charset, null);
113113
}
114114

115115
/**
@@ -122,12 +122,13 @@ public static Request create(String method,
122122
* @param charset of the request, can be {@literal null}
123123
* @return a Request
124124
*/
125+
@Deprecated
125126
public static Request create(HttpMethod httpMethod,
126127
String url,
127128
Map<String, Collection<String>> headers,
128129
byte[] body,
129130
Charset charset) {
130-
return create(httpMethod, url, headers, Body.encoded(body, charset));
131+
return create(httpMethod, url, headers, Body.encoded(body, charset), null);
131132
}
132133

133134
/**
@@ -137,25 +138,51 @@ public static Request create(HttpMethod httpMethod,
137138
* @param url for the request.
138139
* @param headers to include.
139140
* @param body of the request, can be {@literal null}
141+
* @param charset of the request, can be {@literal null}
140142
* @return a Request
141143
*/
142144
public static Request create(HttpMethod httpMethod,
143145
String url,
144146
Map<String, Collection<String>> headers,
145-
Body body) {
146-
return new Request(httpMethod, url, headers, body);
147+
byte[] body,
148+
Charset charset,
149+
RequestTemplate requestTemplate) {
150+
return create(httpMethod, url, headers, Body.encoded(body, charset), requestTemplate);
151+
}
152+
153+
/**
154+
* Builds a Request. All parameters must be effectively immutable, via safe copies.
155+
*
156+
* @param httpMethod for the request.
157+
* @param url for the request.
158+
* @param headers to include.
159+
* @param body of the request, can be {@literal null}
160+
* @return a Request
161+
*/
162+
public static Request create(HttpMethod httpMethod,
163+
String url,
164+
Map<String, Collection<String>> headers,
165+
Body body,
166+
RequestTemplate requestTemplate) {
167+
return new Request(httpMethod, url, headers, body, requestTemplate);
147168
}
148169

149170
private final HttpMethod httpMethod;
150171
private final String url;
151172
private final Map<String, Collection<String>> headers;
152173
private final Body body;
174+
private final RequestTemplate requestTemplate;
153175

154-
Request(HttpMethod method, String url, Map<String, Collection<String>> headers, Body body) {
176+
Request(HttpMethod method,
177+
String url,
178+
Map<String, Collection<String>> headers,
179+
Body body,
180+
RequestTemplate requestTemplate) {
155181
this.httpMethod = checkNotNull(method, "httpMethod of %s", method.name());
156182
this.url = checkNotNull(url, "url");
157183
this.headers = checkNotNull(headers, "headers of %s %s", method, url);
158184
this.body = body;
185+
this.requestTemplate = requestTemplate;
159186
}
160187

161188
/**
@@ -318,4 +345,9 @@ public TimeUnit readTimeoutUnit() {
318345
}
319346

320347
}
348+
349+
@Experimental
350+
public RequestTemplate requestTemplate() {
351+
return this.requestTemplate;
352+
}
321353
}

0 commit comments

Comments
 (0)