Skip to content

Commit fd7ab31

Browse files
committed
Allows @param value in default contract to be taken from param names.
JEP 118 introduced javac option `-parameters` that adds to bytecode method parameter names, so if code is compiled with that option and @param value is empty we can get that template parameter name from method parameter name. Fixes #1297.
1 parent 336f2ce commit fd7ab31

File tree

5 files changed

+46
-3
lines changed

5 files changed

+46
-3
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ should work. Feign's default contract defines the following annotations:
107107
| Annotation | Interface Target | Usage |
108108
|----------------|------------------|-------|
109109
| `@RequestLine` | Method | Defines the `HttpMethod` and `UriTemplate` for request. `Expressions`, values wrapped in curly-braces `{expression}` are resolved using their corresponding `@Param` annotated parameters. |
110-
| `@Param` | Parameter | Defines a template variable, whose value will be used to resolve the corresponding template `Expression`, by name. |
110+
| `@Param` | Parameter | Defines a template variable, whose value will be used to resolve the corresponding template `Expression`, by name provided as annotation value. If value is missing it will try to get the name from bytecode method parameter name (if the code was compiled with `-parameters` flag). |
111111
| `@Headers` | Method, Type | Defines a `HeaderTemplate`; a variation on a `UriTemplate`. that uses `@Param` annotated values to resolve the corresponding `Expressions`. When used on a `Type`, the template will be applied to every request. When used on a `Method`, the template will apply only to the annotated method. |
112112
| `@QueryMap` | Parameter | Defines a `Map` of name-value pairs, or POJO, to expand into a query string. |
113113
| `@HeaderMap` | Parameter | Defines a `Map` of name-value pairs, to expand into `Http Headers` |

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,14 @@ public Default() {
271271
data.template().headers(toMap(headersOnMethod));
272272
});
273273
super.registerParameterAnnotation(Param.class, (paramAnnotation, data, paramIndex) -> {
274-
final String name = paramAnnotation.value();
274+
final String annotationName = paramAnnotation.value();
275+
final Parameter parameter = data.method().getParameters()[paramIndex];
276+
final String name;
277+
if (emptyToNull(annotationName) == null && parameter.isNamePresent()) {
278+
name = parameter.getName();
279+
} else {
280+
name = annotationName;
281+
}
275282
checkState(emptyToNull(name) != null, "Param annotation was empty on param %s.",
276283
paramIndex);
277284
nameParam(data, name, paramIndex);

core/src/main/java/feign/Param.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
/**
2929
* The name of the template parameter.
3030
*/
31-
String value();
31+
String value() default "";
3232

3333
/**
3434
* How to expand the value of this parameter, if {@link ToStringExpander} isn't adequate.

core/src/test/java/feign/DefaultContractTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,21 @@ public void pathAndQueryParams() throws Exception {
200200
entry(2, asList("type")));
201201
}
202202

203+
@Test
204+
public void autoDiscoverParamNames() throws Exception {
205+
final MethodMetadata md = parseAndValidateMetadata(AutoDiscoverParamNames.class,
206+
"recordsByNameAndType", int.class, String.class,
207+
String.class);
208+
209+
assertThat(md.template())
210+
.hasQueries(entry("name", asList("{name}")), entry("type", asList("{type}")));
211+
212+
assertThat(md.indexToName()).containsExactly(
213+
entry(0, asList("domainId")),
214+
entry(1, asList("name")),
215+
entry(2, asList("type")));
216+
}
217+
203218
@Test
204219
public void bodyWithTemplate() throws Exception {
205220
final MethodMetadata md = parseAndValidateMetadata(FormParams.class,
@@ -517,6 +532,12 @@ Response recordsByNameAndType(@Param("domainId") int id,
517532
@Param("type") String typeFilter);
518533
}
519534

535+
interface AutoDiscoverParamNames {
536+
537+
@RequestLine("GET /domains/{domainId}/records?name={name}&type={type}")
538+
Response recordsByNameAndType(@Param int domainId, @Param String name, @Param() String type);
539+
}
540+
520541
interface FormParams {
521542

522543
@RequestLine("POST /")

pom.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,21 @@
417417
<target>${main.java.version}</target>
418418
</configuration>
419419
</execution>
420+
<execution>
421+
<id>default-test-compile</id>
422+
<phase>test-compile</phase>
423+
<goals>
424+
<goal>testCompile</goal>
425+
</goals>
426+
<configuration>
427+
<fork>true</fork>
428+
<compilerArgs>
429+
<arg>-parameters</arg>
430+
</compilerArgs>
431+
<source>${main.java.version}</source>
432+
<target>${main.java.version}</target>
433+
</configuration>
434+
</execution>
420435
</executions>
421436
</plugin>
422437

0 commit comments

Comments
 (0)