@@ -178,27 +178,25 @@ protected boolean isHandler(Class<?> beanType) {
178
178
@ Override
179
179
public Mono <HandlerMethod > getHandlerInternal (ServerWebExchange exchange ) {
180
180
if (this .apiVersionStrategy != null ) {
181
- Comparable <?> requestVersion = exchange .getAttribute (API_VERSION_ATTRIBUTE );
182
- if (requestVersion == null ) {
183
- requestVersion = getApiVersion (exchange , this .apiVersionStrategy );
184
- if (requestVersion != null ) {
185
- exchange .getAttributes ().put (API_VERSION_ATTRIBUTE , requestVersion );
181
+ Comparable <?> version = exchange .getAttribute (API_VERSION_ATTRIBUTE );
182
+ if (version == null ) {
183
+ version = getApiVersion (exchange , this .apiVersionStrategy );
184
+ if (version != null ) {
185
+ exchange .getAttributes ().put (API_VERSION_ATTRIBUTE , version );
186
186
}
187
187
}
188
188
}
189
189
return super .getHandlerInternal (exchange );
190
190
}
191
191
192
- private static @ Nullable Comparable <?> getApiVersion (
193
- ServerWebExchange exchange , ApiVersionStrategy versionStrategy ) {
194
-
195
- String value = versionStrategy .resolveVersion (exchange );
192
+ private static @ Nullable Comparable <?> getApiVersion (ServerWebExchange exchange , ApiVersionStrategy strategy ) {
193
+ String value = strategy .resolveVersion (exchange );
196
194
if (value == null ) {
197
- return versionStrategy .getDefaultVersion ();
195
+ return strategy .getDefaultVersion ();
198
196
}
199
197
try {
200
- Comparable <?> version = versionStrategy .parseVersion (value );
201
- versionStrategy .validateVersion (version , exchange );
198
+ Comparable <?> version = strategy .parseVersion (value );
199
+ strategy .validateVersion (version , exchange );
202
200
return version ;
203
201
}
204
202
catch (Exception ex ) {
@@ -242,42 +240,43 @@ public Mono<HandlerMethod> getHandlerInternal(ServerWebExchange exchange) {
242
240
}
243
241
244
242
private @ Nullable RequestMappingInfo createRequestMappingInfo (AnnotatedElement element ) {
245
- RequestMappingInfo requestMappingInfo = null ;
243
+
244
+ List <AnnotationDescriptor > descriptors =
245
+ MergedAnnotations .from (element , SearchStrategy .TYPE_HIERARCHY , RepeatableContainers .none ()).stream ()
246
+ .filter (MergedAnnotationPredicates .typeIn (RequestMapping .class , HttpExchange .class ))
247
+ .filter (MergedAnnotationPredicates .firstRunOf (MergedAnnotation ::getAggregateIndex ))
248
+ .map (AnnotationDescriptor ::new )
249
+ .distinct ()
250
+ .toList ();
251
+
252
+ RequestMappingInfo info = null ;
246
253
RequestCondition <?> customCondition = (element instanceof Class <?> clazz ?
247
254
getCustomTypeCondition (clazz ) : getCustomMethodCondition ((Method ) element ));
248
255
249
- List <AnnotationDescriptor > descriptors = getAnnotationDescriptors (element );
256
+ List <AnnotationDescriptor > mappingDescriptors =
257
+ descriptors .stream ().filter (desc -> desc .annotation instanceof RequestMapping ).toList ();
250
258
251
- List <AnnotationDescriptor > requestMappings = descriptors .stream ()
252
- .filter (desc -> desc .annotation instanceof RequestMapping ).toList ();
253
- if (!requestMappings .isEmpty ()) {
254
- if (requestMappings .size () > 1 && logger .isWarnEnabled ()) {
255
- logger .warn ("Multiple @RequestMapping annotations found on %s, but only the first will be used: %s"
256
- .formatted (element , requestMappings ));
257
- }
258
- requestMappingInfo = createRequestMappingInfo ((RequestMapping ) requestMappings .get (0 ).annotation , customCondition );
259
+ if (!mappingDescriptors .isEmpty ()) {
260
+ checkMultipleAnnotations (element , mappingDescriptors );
261
+ info = createRequestMappingInfo ((RequestMapping ) mappingDescriptors .get (0 ).annotation , customCondition );
259
262
}
260
263
261
- List <AnnotationDescriptor > httpExchanges = descriptors .stream ()
262
- .filter (desc -> desc .annotation instanceof HttpExchange ).toList ();
263
- if (!httpExchanges .isEmpty ()) {
264
- Assert .state (requestMappingInfo == null ,
265
- () -> "%s is annotated with @RequestMapping and @HttpExchange annotations, but only one is allowed: %s"
266
- .formatted (element , Stream .of (requestMappings , httpExchanges ).flatMap (List ::stream ).toList ()));
267
- Assert .state (httpExchanges .size () == 1 ,
268
- () -> "Multiple @HttpExchange annotations found on %s, but only one is allowed: %s"
269
- .formatted (element , httpExchanges ));
270
- requestMappingInfo = createRequestMappingInfo ((HttpExchange ) httpExchanges .get (0 ).annotation , customCondition );
264
+ List <AnnotationDescriptor > exchangeDescriptors =
265
+ descriptors .stream ().filter (desc -> desc .annotation instanceof HttpExchange ).toList ();
266
+
267
+ if (!exchangeDescriptors .isEmpty ()) {
268
+ checkMultipleAnnotations (element , info , mappingDescriptors , exchangeDescriptors );
269
+ info = createRequestMappingInfo ((HttpExchange ) exchangeDescriptors .get (0 ).annotation , customCondition );
271
270
}
272
271
273
- if (requestMappingInfo != null && this .apiVersionStrategy instanceof DefaultApiVersionStrategy davs ) {
274
- String version = requestMappingInfo .getVersionCondition ().getVersion ();
272
+ if (info != null && this .apiVersionStrategy instanceof DefaultApiVersionStrategy davs ) {
273
+ String version = info .getVersionCondition ().getVersion ();
275
274
if (version != null ) {
276
275
davs .addMappedVersion (version );
277
276
}
278
277
}
279
278
280
- return requestMappingInfo ;
279
+ return info ;
281
280
}
282
281
283
282
/**
@@ -316,6 +315,28 @@ public Mono<HandlerMethod> getHandlerInternal(ServerWebExchange exchange) {
316
315
return null ;
317
316
}
318
317
318
+ private void checkMultipleAnnotations (
319
+ AnnotatedElement element , List <AnnotationDescriptor > mappingDescriptors ) {
320
+
321
+ if (logger .isWarnEnabled () && mappingDescriptors .size () > 1 ) {
322
+ logger .warn ("Multiple @RequestMapping annotations found on %s, but only the first will be used: %s"
323
+ .formatted (element , mappingDescriptors ));
324
+ }
325
+ }
326
+
327
+ private static void checkMultipleAnnotations (
328
+ AnnotatedElement element , @ Nullable RequestMappingInfo info ,
329
+ List <AnnotationDescriptor > mappingDescriptors , List <AnnotationDescriptor > exchangeDescriptors ) {
330
+
331
+ Assert .state (info == null ,
332
+ () -> "%s is annotated with @RequestMapping and @HttpExchange annotations, but only one is allowed: %s"
333
+ .formatted (element , Stream .of (mappingDescriptors , exchangeDescriptors ).flatMap (List ::stream ).toList ()));
334
+
335
+ Assert .state (exchangeDescriptors .size () == 1 ,
336
+ () -> "Multiple @HttpExchange annotations found on %s, but only one is allowed: %s"
337
+ .formatted (element , exchangeDescriptors ));
338
+ }
339
+
319
340
/**
320
341
* Create a {@link RequestMappingInfo} from the supplied
321
342
* {@link RequestMapping @RequestMapping} annotation, meta-annotation,
@@ -510,24 +531,16 @@ private String resolveCorsAnnotationValue(String value) {
510
531
}
511
532
}
512
533
513
- private static List <AnnotationDescriptor > getAnnotationDescriptors (AnnotatedElement element ) {
514
- return MergedAnnotations .from (element , SearchStrategy .TYPE_HIERARCHY , RepeatableContainers .none ())
515
- .stream ()
516
- .filter (MergedAnnotationPredicates .typeIn (RequestMapping .class , HttpExchange .class ))
517
- .filter (MergedAnnotationPredicates .firstRunOf (MergedAnnotation ::getAggregateIndex ))
518
- .map (AnnotationDescriptor ::new )
519
- .distinct ()
520
- .toList ();
521
- }
522
534
523
535
private static class AnnotationDescriptor {
524
536
525
537
private final Annotation annotation ;
538
+
526
539
private final MergedAnnotation <?> root ;
527
540
528
- AnnotationDescriptor (MergedAnnotation <Annotation > mergedAnnotation ) {
529
- this .annotation = mergedAnnotation .synthesize ();
530
- this .root = mergedAnnotation .getRoot ();
541
+ AnnotationDescriptor (MergedAnnotation <Annotation > annotation ) {
542
+ this .annotation = annotation .synthesize ();
543
+ this .root = annotation .getRoot ();
531
544
}
532
545
533
546
@ Override
0 commit comments