Skip to content

Commit 2ea1698

Browse files
committed
Make possible for contracts to declare parameters as ignored
1 parent 7a2ddff commit 2ea1698

File tree

4 files changed

+68
-28
lines changed

4 files changed

+68
-28
lines changed

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

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

16+
import static feign.Util.checkState;
17+
import static feign.Util.emptyToNull;
1618
import java.lang.annotation.Annotation;
1719
import java.lang.reflect.*;
1820
import java.net.URI;
1921
import java.util.*;
20-
import java.util.function.BiConsumer;
21-
import java.util.function.BiFunction;
2222
import java.util.regex.Matcher;
2323
import java.util.regex.Pattern;
24-
import java.util.stream.Collectors;
25-
import feign.Contract.DeclarativeContract.ClassAnnotationProcessor;
2624
import feign.Request.HttpMethod;
27-
import static feign.Util.checkState;
28-
import static feign.Util.emptyToNull;
2925

3026
/**
3127
* Defines what annotations and values are valid on interfaces.
@@ -106,9 +102,15 @@ protected MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method me
106102
if (parameterAnnotations[i] != null) {
107103
isHttpAnnotation = processAnnotationsOnParameter(data, parameterAnnotations[i], i);
108104
}
105+
106+
if (isHttpAnnotation) {
107+
data.ignoreParamater(i);
108+
}
109+
109110
if (parameterTypes[i] == URI.class) {
110111
data.urlIndex(i);
111-
} else if (!isHttpAnnotation && parameterTypes[i] != Request.Options.class) {
112+
} else if (!isHttpAnnotation && parameterTypes[i] != Request.Options.class
113+
&& !data.isAlreadyProcessed(i)) {
112114
checkState(data.formParams().isEmpty(),
113115
"Body parameters cannot be used with form parameters.");
114116
checkState(data.bodyIndex() == null, "Method has too many Body parameters: %s", method);
@@ -220,6 +222,7 @@ public abstract class DeclarativeContract extends BaseContract {
220222
Map<Class<Annotation>, ParameterAnnotationProcessor<Annotation>> parameterAnnotationProcessors =
221223
new HashMap<>();
222224

225+
@Override
223226
public final List<MethodMetadata> parseAndValidatateMetadata(Class<?> targetType) {
224227
// any implementations must register processors
225228
return super.parseAndValidatateMetadata(targetType);
@@ -263,17 +266,17 @@ protected void processAnnotationOnMethod(MethodMetadata data,
263266
* @return true if you called {@link #nameParam(MethodMetadata, String, int)} after finding an
264267
* http-relevant annotation.
265268
*/
269+
@Override
266270
protected final boolean processAnnotationsOnParameter(MethodMetadata data,
267271
Annotation[] annotations,
268272
int paramIndex) {
269-
return Arrays.stream(annotations)
273+
Arrays.stream(annotations)
270274
.filter(
271275
annotation -> parameterAnnotationProcessors.containsKey(annotation.annotationType()))
272-
.map(annotation -> parameterAnnotationProcessors
276+
.forEach(annotation -> parameterAnnotationProcessors
273277
.getOrDefault(annotation.annotationType(), ParameterAnnotationProcessor.DO_NOTHING)
274-
.process(annotation, data, paramIndex))
275-
.collect(Collectors.reducing(Boolean::logicalOr))
276-
.orElse(false);
278+
.process(annotation, data, paramIndex));
279+
return false;
277280
}
278281

279282
@FunctionalInterface
@@ -332,7 +335,8 @@ protected <E extends Annotation> void registerMethodAnnotation(Class<E> annotati
332335
@FunctionalInterface
333336
public interface ParameterAnnotationProcessor<E extends Annotation> {
334337

335-
ParameterAnnotationProcessor<Annotation> DO_NOTHING = (ann, data, i) -> false;
338+
ParameterAnnotationProcessor<Annotation> DO_NOTHING = (ann, data, i) -> {
339+
};
336340

337341
/**
338342
* @param annotation present on the current parameter annotation.
@@ -342,7 +346,7 @@ public interface ParameterAnnotationProcessor<E extends Annotation> {
342346
* @return true if you called {@link #nameParam(MethodMetadata, String, int)} after finding an
343347
* http-relevant annotation.
344348
*/
345-
boolean process(E annotation, MethodMetadata metadata, int paramIndex);
349+
void process(E annotation, MethodMetadata metadata, int paramIndex);
346350
}
347351

348352
/**
@@ -424,20 +428,17 @@ public Default() {
424428
if (!data.template().hasRequestVariable(name)) {
425429
data.formParams().add(name);
426430
}
427-
return true;
428431
});
429432
super.registerParameterAnnotation(QueryMap.class, (queryMap, data, paramIndex) -> {
430433
checkState(data.queryMapIndex() == null,
431434
"QueryMap annotation was present on multiple parameters.");
432435
data.queryMapIndex(paramIndex);
433436
data.queryMapEncoded(queryMap.encoded());
434-
return true;
435437
});
436438
super.registerParameterAnnotation(HeaderMap.class, (queryMap, data, paramIndex) -> {
437439
checkState(data.headerMapIndex() == null,
438440
"HeaderMap annotation was present on multiple parameters.");
439441
data.headerMapIndex(paramIndex);
440-
return true;
441442
});
442443
}
443444

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

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,7 @@
1515

1616
import java.io.Serializable;
1717
import java.lang.reflect.Type;
18-
import java.util.ArrayList;
19-
import java.util.Collection;
20-
import java.util.LinkedHashMap;
21-
import java.util.List;
22-
import java.util.Map;
18+
import java.util.*;
2319
import feign.Param.Expander;
2420

2521
public final class MethodMetadata implements Serializable {
@@ -41,6 +37,7 @@ public final class MethodMetadata implements Serializable {
4137
new LinkedHashMap<Integer, Class<? extends Expander>>();
4238
private Map<Integer, Boolean> indexToEncoded = new LinkedHashMap<Integer, Boolean>();
4339
private transient Map<Integer, Expander> indexToExpander;
40+
private BitSet parameterToIgnore = new BitSet();
4441

4542
MethodMetadata() {}
4643

@@ -163,4 +160,50 @@ public MethodMetadata indexToExpander(Map<Integer, Expander> indexToExpander) {
163160
public Map<Integer, Expander> indexToExpander() {
164161
return indexToExpander;
165162
}
163+
164+
/**
165+
* @param i individual parameter that should be ignored
166+
* @return this instance
167+
*/
168+
public MethodMetadata ignoreParamater(int i) {
169+
this.parameterToIgnore.set(i);
170+
return this;
171+
}
172+
173+
public BitSet parameterToIgnore() {
174+
return parameterToIgnore;
175+
}
176+
177+
public MethodMetadata parameterToIgnore(BitSet parameterToIgnore) {
178+
this.parameterToIgnore = parameterToIgnore;
179+
return this;
180+
}
181+
182+
/**
183+
* @param i individual parameter to check if should be ignored
184+
* @return true when field should not be processed by feign
185+
*/
186+
public boolean shouldIgnoreParamater(int i) {
187+
return parameterToIgnore.get(i);
188+
}
189+
190+
/**
191+
* @param index
192+
* @return true if the parameter {@code index} was already consumed by a any
193+
* {@link MethodMetadata} holder
194+
*/
195+
public boolean isAlreadyProcessed(Integer index) {
196+
return index.equals(urlIndex)
197+
|| index.equals(bodyIndex)
198+
|| index.equals(headerMapIndex)
199+
|| index.equals(queryMapIndex)
200+
|| indexToName.containsKey(index)
201+
|| indexToExpanderClass.containsKey(index)
202+
|| indexToEncoded.containsKey(index)
203+
|| (indexToExpander != null && indexToExpander.containsKey(index))
204+
|| parameterToIgnore.get(index);
205+
}
206+
207+
208+
166209
}

jaxrs/src/main/java/feign/jaxrs/JAXRSContract.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,6 @@ protected void registerParamAnnotations() {
138138
checkState(emptyToNull(name) != null, "PathParam.value() was empty on parameter %s",
139139
paramIndex);
140140
nameParam(data, name, paramIndex);
141-
return true;
142141
});
143142
registerParameterAnnotation(QueryParam.class, (param, data, paramIndex) -> {
144143
final String name = param.value();
@@ -147,7 +146,6 @@ protected void registerParamAnnotations() {
147146
final String query = addTemplatedParam(name);
148147
data.template().query(name, query);
149148
nameParam(data, name, paramIndex);
150-
return true;
151149
});
152150
registerParameterAnnotation(HeaderParam.class, (param, data, paramIndex) -> {
153151
final String name = param.value();
@@ -156,15 +154,13 @@ protected void registerParamAnnotations() {
156154
final String header = addTemplatedParam(name);
157155
data.template().header(name, header);
158156
nameParam(data, name, paramIndex);
159-
return true;
160157
});
161158
registerParameterAnnotation(FormParam.class, (param, data, paramIndex) -> {
162159
final String name = param.value();
163160
checkState(emptyToNull(name) != null, "FormParam.value() was empty on parameter %s",
164161
paramIndex);
165162
data.formParams().add(name);
166163
nameParam(data, name, paramIndex);
167-
return true;
168164
});
169165
}
170166
}

jaxrs2/src/main/java/feign/jaxrs2/JAXRS2Contract.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ public JAXRS2Contract() {
2828
// this will prevent interfaces from becoming unusable entirely due to single (unsupported)
2929
// endpoints.
3030
// https://github.com/OpenFeign/feign/issues/669
31-
super.registerParameterAnnotation(Suspended.class, (ann, data, i) -> true);
32-
super.registerParameterAnnotation(Context.class, (ann, data, i) -> true);
31+
super.registerParameterAnnotation(Suspended.class, (ann, data, i) -> data.ignoreParamater(i));
32+
super.registerParameterAnnotation(Context.class, (ann, data, i) -> data.ignoreParamater(i));
3333
}
3434

3535
}

0 commit comments

Comments
 (0)