Skip to content

Commit 3746b23

Browse files
Add meta-annotations support for @RequestHeader in spring-webflux
1 parent 5d011d5 commit 3746b23

File tree

3 files changed

+53
-3
lines changed

3 files changed

+53
-3
lines changed

spring-webflux/src/main/java/org/springframework/web/reactive/result/method/HandlerMethodArgumentResolverSupport.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,31 @@ protected <A extends Annotation> boolean checkAnnotatedParamNoReactiveWrapper(
118118
return false;
119119
}
120120

121+
return checkAnnotatedParamNoReactiveWrapperCommon(parameter, annotation, typePredicate);
122+
}
123+
124+
125+
/**
126+
* Evaluate the {@code Predicate} on the method parameter type if it has the
127+
* given annotation, either directly declared or as a meta-annotation,
128+
* nesting within {@link java.util.Optional} if necessary,
129+
* but raise an {@code IllegalStateException} if the same matches the generic
130+
* type within a reactive type wrapper.
131+
*/
132+
protected <A extends Annotation> boolean checkNestedAnnotatedParamNoReactiveWrapper(
133+
MethodParameter parameter, Class<A> annotationType, BiPredicate<A, Class<?>> typePredicate) {
134+
135+
A annotation = parameter.getParameterNestedAnnotation(annotationType);
136+
if (annotation == null) {
137+
return false;
138+
}
139+
140+
return checkAnnotatedParamNoReactiveWrapperCommon(parameter, annotation, typePredicate);
141+
}
142+
143+
private <A extends Annotation> boolean checkAnnotatedParamNoReactiveWrapperCommon(
144+
MethodParameter parameter, A annotation, BiPredicate<A, Class<?>> typePredicate) {
145+
121146
parameter = parameter.nestedIfOptional();
122147
Class<?> type = parameter.getNestedParameterType();
123148

spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMethodArgumentResolver.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public RequestHeaderMethodArgumentResolver(@Nullable ConfigurableBeanFactory fac
6565

6666
@Override
6767
public boolean supportsParameter(MethodParameter param) {
68-
return checkAnnotatedParamNoReactiveWrapper(param, RequestHeader.class, this::singleParam);
68+
return checkNestedAnnotatedParamNoReactiveWrapper(param, RequestHeader.class, this::singleParam);
6969
}
7070

7171
private boolean singleParam(RequestHeader annotation, Class<?> type) {
@@ -74,7 +74,7 @@ private boolean singleParam(RequestHeader annotation, Class<?> type) {
7474

7575
@Override
7676
protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
77-
RequestHeader ann = parameter.getParameterAnnotation(RequestHeader.class);
77+
RequestHeader ann = parameter.getParameterNestedAnnotation(RequestHeader.class);
7878
Assert.state(ann != null, "No RequestHeader annotation");
7979
return new RequestHeaderNamedValueInfo(ann);
8080
}

spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMethodArgumentResolverTests.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616

1717
package org.springframework.web.reactive.result.method.annotation;
1818

19+
import java.lang.annotation.ElementType;
20+
import java.lang.annotation.Retention;
21+
import java.lang.annotation.RetentionPolicy;
22+
import java.lang.annotation.Target;
1923
import java.lang.reflect.Method;
2024
import java.time.Instant;
2125
import java.time.format.DateTimeFormatter;
@@ -68,6 +72,7 @@ class RequestHeaderMethodArgumentResolverTests {
6872
private MethodParameter paramInstant;
6973
private MethodParameter paramMono;
7074
private MethodParameter primitivePlaceholderParam;
75+
private MethodParameter paramWithNestedAnnotated;
7176

7277

7378
@BeforeEach
@@ -92,6 +97,7 @@ void setup() throws Exception {
9297
this.paramInstant = new SynthesizingMethodParameter(method, 7);
9398
this.paramMono = new SynthesizingMethodParameter(method, 8);
9499
this.primitivePlaceholderParam = new SynthesizingMethodParameter(method, 9);
100+
this.paramWithNestedAnnotated = new SynthesizingMethodParameter(method, 10);
95101
}
96102

97103

@@ -103,6 +109,8 @@ void supportsParameter() {
103109
assertThatIllegalStateException()
104110
.isThrownBy(() -> this.resolver.supportsParameter(this.paramMono))
105111
.withMessageStartingWith("RequestHeaderMethodArgumentResolver does not support reactive type wrapper");
112+
assertThat(resolver.supportsParameter(paramWithNestedAnnotated)).as("String parameter with nested annotated not supported").isTrue();
113+
106114
}
107115

108116
@Test
@@ -265,6 +273,16 @@ void instantConversion() {
265273
assertThat(result).isEqualTo(Instant.from(DateTimeFormatter.RFC_1123_DATE_TIME.parse(rfc1123val)));
266274
}
267275

276+
@Test
277+
void resolveStringWithNestedAnnotatedArgument() {
278+
String expected = "foo";
279+
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/").header("name", expected));
280+
281+
Mono<Object> mono = this.resolver.resolveArgument(
282+
this.paramWithNestedAnnotated, this.bindingContext, exchange);
283+
284+
assertThat(mono.block()).isEqualTo(expected);
285+
}
268286

269287
@SuppressWarnings("unused")
270288
public void params(
@@ -277,7 +295,14 @@ public void params(
277295
@RequestHeader("name") Date dateParam,
278296
@RequestHeader("name") Instant instantParam,
279297
@RequestHeader Mono<String> alsoNotSupported,
280-
@RequestHeader(value = "${systemProperty}", required = false) int primitivePlaceholderParam) {
298+
@RequestHeader(value = "${systemProperty}", required = false) int primitivePlaceholderParam,
299+
@NameRequestHeader String param6) {
300+
}
301+
302+
@Target(ElementType.PARAMETER)
303+
@Retention(RetentionPolicy.RUNTIME)
304+
@RequestHeader(name = "name", defaultValue = "bar")
305+
private @interface NameRequestHeader {
281306
}
282307

283308
}

0 commit comments

Comments
 (0)