@@ -178,27 +178,25 @@ protected boolean isHandler(Class<?> beanType) {
178178 @ Override
179179 public Mono <HandlerMethod > getHandlerInternal (ServerWebExchange exchange ) {
180180 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 );
186186 }
187187 }
188188 }
189189 return super .getHandlerInternal (exchange );
190190 }
191191
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 );
196194 if (value == null ) {
197- return versionStrategy .getDefaultVersion ();
195+ return strategy .getDefaultVersion ();
198196 }
199197 try {
200- Comparable <?> version = versionStrategy .parseVersion (value );
201- versionStrategy .validateVersion (version , exchange );
198+ Comparable <?> version = strategy .parseVersion (value );
199+ strategy .validateVersion (version , exchange );
202200 return version ;
203201 }
204202 catch (Exception ex ) {
@@ -242,42 +240,43 @@ public Mono<HandlerMethod> getHandlerInternal(ServerWebExchange exchange) {
242240 }
243241
244242 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 ;
246253 RequestCondition <?> customCondition = (element instanceof Class <?> clazz ?
247254 getCustomTypeCondition (clazz ) : getCustomMethodCondition ((Method ) element ));
248255
249- List <AnnotationDescriptor > descriptors = getAnnotationDescriptors (element );
256+ List <AnnotationDescriptor > mappingDescriptors =
257+ descriptors .stream ().filter (desc -> desc .annotation instanceof RequestMapping ).toList ();
250258
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 );
259262 }
260263
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 );
271270 }
272271
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 ();
275274 if (version != null ) {
276275 davs .addMappedVersion (version );
277276 }
278277 }
279278
280- return requestMappingInfo ;
279+ return info ;
281280 }
282281
283282 /**
@@ -316,6 +315,28 @@ public Mono<HandlerMethod> getHandlerInternal(ServerWebExchange exchange) {
316315 return null ;
317316 }
318317
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+
319340 /**
320341 * Create a {@link RequestMappingInfo} from the supplied
321342 * {@link RequestMapping @RequestMapping} annotation, meta-annotation,
@@ -510,24 +531,16 @@ private String resolveCorsAnnotationValue(String value) {
510531 }
511532 }
512533
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- }
522534
523535 private static class AnnotationDescriptor {
524536
525537 private final Annotation annotation ;
538+
526539 private final MergedAnnotation <?> root ;
527540
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 ();
531544 }
532545
533546 @ Override
0 commit comments