Browse Source

Allows @Param value in default contract to be taken from param names. (#1309)

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.
pull/1332/head
Krzysztof Krasoń 4 years ago committed by GitHub
parent
commit
17885da9ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      README.md
  2. 9
      core/src/main/java/feign/Contract.java
  3. 2
      core/src/main/java/feign/Param.java
  4. 21
      core/src/test/java/feign/DefaultContractTest.java
  5. 15
      pom.xml

2
README.md

@ -107,7 +107,7 @@ should work. Feign's default contract defines the following annotations: @@ -107,7 +107,7 @@ should work. Feign's default contract defines the following annotations:
| Annotation | Interface Target | Usage |
|----------------|------------------|-------|
| `@RequestLine` | Method | Defines the `HttpMethod` and `UriTemplate` for request. `Expressions`, values wrapped in curly-braces `{expression}` are resolved using their corresponding `@Param` annotated parameters. |
| `@Param` | Parameter | Defines a template variable, whose value will be used to resolve the corresponding template `Expression`, by name. |
| `@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). |
| `@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. |
| `@QueryMap` | Parameter | Defines a `Map` of name-value pairs, or POJO, to expand into a query string. |
| `@HeaderMap` | Parameter | Defines a `Map` of name-value pairs, to expand into `Http Headers` |

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

@ -271,7 +271,14 @@ public interface Contract { @@ -271,7 +271,14 @@ public interface Contract {
data.template().headers(toMap(headersOnMethod));
});
super.registerParameterAnnotation(Param.class, (paramAnnotation, data, paramIndex) -> {
final String name = paramAnnotation.value();
final String annotationName = paramAnnotation.value();
final Parameter parameter = data.method().getParameters()[paramIndex];
final String name;
if (emptyToNull(annotationName) == null && parameter.isNamePresent()) {
name = parameter.getName();
} else {
name = annotationName;
}
checkState(emptyToNull(name) != null, "Param annotation was empty on param %s.",
paramIndex);
nameParam(data, name, paramIndex);

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

@ -28,7 +28,7 @@ public @interface Param { @@ -28,7 +28,7 @@ public @interface Param {
/**
* The name of the template parameter.
*/
String value();
String value() default "";
/**
* How to expand the value of this parameter, if {@link ToStringExpander} isn't adequate.

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

@ -200,6 +200,21 @@ public class DefaultContractTest { @@ -200,6 +200,21 @@ public class DefaultContractTest {
entry(2, asList("type")));
}
@Test
public void autoDiscoverParamNames() throws Exception {
final MethodMetadata md = parseAndValidateMetadata(AutoDiscoverParamNames.class,
"recordsByNameAndType", int.class, String.class,
String.class);
assertThat(md.template())
.hasQueries(entry("name", asList("{name}")), entry("type", asList("{type}")));
assertThat(md.indexToName()).containsExactly(
entry(0, asList("domainId")),
entry(1, asList("name")),
entry(2, asList("type")));
}
@Test
public void bodyWithTemplate() throws Exception {
final MethodMetadata md = parseAndValidateMetadata(FormParams.class,
@ -517,6 +532,12 @@ public class DefaultContractTest { @@ -517,6 +532,12 @@ public class DefaultContractTest {
@Param("type") String typeFilter);
}
interface AutoDiscoverParamNames {
@RequestLine("GET /domains/{domainId}/records?name={name}&type={type}")
Response recordsByNameAndType(@Param int domainId, @Param String name, @Param() String type);
}
interface FormParams {
@RequestLine("POST /")

15
pom.xml

@ -417,6 +417,21 @@ @@ -417,6 +417,21 @@
<target>${main.java.version}</target>
</configuration>
</execution>
<execution>
<id>default-test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
<configuration>
<fork>true</fork>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
<source>${main.java.version}</source>
<target>${main.java.version}</target>
</configuration>
</execution>
</executions>
</plugin>

Loading…
Cancel
Save