|
|
|
@ -178,27 +178,25 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public Mono<HandlerMethod> getHandlerInternal(ServerWebExchange exchange) { |
|
|
|
public Mono<HandlerMethod> getHandlerInternal(ServerWebExchange exchange) { |
|
|
|
if (this.apiVersionStrategy != null) { |
|
|
|
if (this.apiVersionStrategy != null) { |
|
|
|
Comparable<?> requestVersion = exchange.getAttribute(API_VERSION_ATTRIBUTE); |
|
|
|
Comparable<?> version = exchange.getAttribute(API_VERSION_ATTRIBUTE); |
|
|
|
if (requestVersion == null) { |
|
|
|
if (version == null) { |
|
|
|
requestVersion = getApiVersion(exchange, this.apiVersionStrategy); |
|
|
|
version = getApiVersion(exchange, this.apiVersionStrategy); |
|
|
|
if (requestVersion != null) { |
|
|
|
if (version != null) { |
|
|
|
exchange.getAttributes().put(API_VERSION_ATTRIBUTE, requestVersion); |
|
|
|
exchange.getAttributes().put(API_VERSION_ATTRIBUTE, version); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return super.getHandlerInternal(exchange); |
|
|
|
return super.getHandlerInternal(exchange); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static @Nullable Comparable<?> getApiVersion( |
|
|
|
private static @Nullable Comparable<?> getApiVersion(ServerWebExchange exchange, ApiVersionStrategy strategy) { |
|
|
|
ServerWebExchange exchange, ApiVersionStrategy versionStrategy) { |
|
|
|
String value = strategy.resolveVersion(exchange); |
|
|
|
|
|
|
|
|
|
|
|
String value = versionStrategy.resolveVersion(exchange); |
|
|
|
|
|
|
|
if (value == null) { |
|
|
|
if (value == null) { |
|
|
|
return versionStrategy.getDefaultVersion(); |
|
|
|
return strategy.getDefaultVersion(); |
|
|
|
} |
|
|
|
} |
|
|
|
try { |
|
|
|
try { |
|
|
|
Comparable<?> version = versionStrategy.parseVersion(value); |
|
|
|
Comparable<?> version = strategy.parseVersion(value); |
|
|
|
versionStrategy.validateVersion(version, exchange); |
|
|
|
strategy.validateVersion(version, exchange); |
|
|
|
return version; |
|
|
|
return version; |
|
|
|
} |
|
|
|
} |
|
|
|
catch (Exception ex) { |
|
|
|
catch (Exception ex) { |
|
|
|
@ -242,42 +240,43 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private @Nullable RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) { |
|
|
|
private @Nullable RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) { |
|
|
|
RequestMappingInfo requestMappingInfo = null; |
|
|
|
|
|
|
|
|
|
|
|
List<AnnotationDescriptor> descriptors = |
|
|
|
|
|
|
|
MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY, RepeatableContainers.none()).stream() |
|
|
|
|
|
|
|
.filter(MergedAnnotationPredicates.typeIn(RequestMapping.class, HttpExchange.class)) |
|
|
|
|
|
|
|
.filter(MergedAnnotationPredicates.firstRunOf(MergedAnnotation::getAggregateIndex)) |
|
|
|
|
|
|
|
.map(AnnotationDescriptor::new) |
|
|
|
|
|
|
|
.distinct() |
|
|
|
|
|
|
|
.toList(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RequestMappingInfo info = null; |
|
|
|
RequestCondition<?> customCondition = (element instanceof Class<?> clazz ? |
|
|
|
RequestCondition<?> customCondition = (element instanceof Class<?> clazz ? |
|
|
|
getCustomTypeCondition(clazz) : getCustomMethodCondition((Method) element)); |
|
|
|
getCustomTypeCondition(clazz) : getCustomMethodCondition((Method) element)); |
|
|
|
|
|
|
|
|
|
|
|
List<AnnotationDescriptor> descriptors = getAnnotationDescriptors(element); |
|
|
|
List<AnnotationDescriptor> mappingDescriptors = |
|
|
|
|
|
|
|
descriptors.stream().filter(desc -> desc.annotation instanceof RequestMapping).toList(); |
|
|
|
|
|
|
|
|
|
|
|
List<AnnotationDescriptor> requestMappings = descriptors.stream() |
|
|
|
if (!mappingDescriptors.isEmpty()) { |
|
|
|
.filter(desc -> desc.annotation instanceof RequestMapping).toList(); |
|
|
|
checkMultipleAnnotations(element, mappingDescriptors); |
|
|
|
if (!requestMappings.isEmpty()) { |
|
|
|
info = createRequestMappingInfo((RequestMapping) mappingDescriptors.get(0).annotation, customCondition); |
|
|
|
if (requestMappings.size() > 1 && logger.isWarnEnabled()) { |
|
|
|
|
|
|
|
logger.warn("Multiple @RequestMapping annotations found on %s, but only the first will be used: %s" |
|
|
|
|
|
|
|
.formatted(element, requestMappings)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
requestMappingInfo = createRequestMappingInfo((RequestMapping) requestMappings.get(0).annotation, customCondition); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
List<AnnotationDescriptor> httpExchanges = descriptors.stream() |
|
|
|
List<AnnotationDescriptor> exchangeDescriptors = |
|
|
|
.filter(desc -> desc.annotation instanceof HttpExchange).toList(); |
|
|
|
descriptors.stream().filter(desc -> desc.annotation instanceof HttpExchange).toList(); |
|
|
|
if (!httpExchanges.isEmpty()) { |
|
|
|
|
|
|
|
Assert.state(requestMappingInfo == null, |
|
|
|
if (!exchangeDescriptors.isEmpty()) { |
|
|
|
() -> "%s is annotated with @RequestMapping and @HttpExchange annotations, but only one is allowed: %s" |
|
|
|
checkMultipleAnnotations(element, info, mappingDescriptors, exchangeDescriptors); |
|
|
|
.formatted(element, Stream.of(requestMappings, httpExchanges).flatMap(List::stream).toList())); |
|
|
|
info = createRequestMappingInfo((HttpExchange) exchangeDescriptors.get(0).annotation, customCondition); |
|
|
|
Assert.state(httpExchanges.size() == 1, |
|
|
|
|
|
|
|
() -> "Multiple @HttpExchange annotations found on %s, but only one is allowed: %s" |
|
|
|
|
|
|
|
.formatted(element, httpExchanges)); |
|
|
|
|
|
|
|
requestMappingInfo = createRequestMappingInfo((HttpExchange) httpExchanges.get(0).annotation, customCondition); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (requestMappingInfo != null && this.apiVersionStrategy instanceof DefaultApiVersionStrategy davs) { |
|
|
|
if (info != null && this.apiVersionStrategy instanceof DefaultApiVersionStrategy davs) { |
|
|
|
String version = requestMappingInfo.getVersionCondition().getVersion(); |
|
|
|
String version = info.getVersionCondition().getVersion(); |
|
|
|
if (version != null) { |
|
|
|
if (version != null) { |
|
|
|
davs.addMappedVersion(version); |
|
|
|
davs.addMappedVersion(version); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return requestMappingInfo; |
|
|
|
return info; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -316,6 +315,28 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void checkMultipleAnnotations( |
|
|
|
|
|
|
|
AnnotatedElement element, List<AnnotationDescriptor> mappingDescriptors) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (logger.isWarnEnabled() && mappingDescriptors.size() > 1) { |
|
|
|
|
|
|
|
logger.warn("Multiple @RequestMapping annotations found on %s, but only the first will be used: %s" |
|
|
|
|
|
|
|
.formatted(element, mappingDescriptors)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static void checkMultipleAnnotations( |
|
|
|
|
|
|
|
AnnotatedElement element, @Nullable RequestMappingInfo info, |
|
|
|
|
|
|
|
List<AnnotationDescriptor> mappingDescriptors, List<AnnotationDescriptor> exchangeDescriptors) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Assert.state(info == null, |
|
|
|
|
|
|
|
() -> "%s is annotated with @RequestMapping and @HttpExchange annotations, but only one is allowed: %s" |
|
|
|
|
|
|
|
.formatted(element, Stream.of(mappingDescriptors, exchangeDescriptors).flatMap(List::stream).toList())); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Assert.state(exchangeDescriptors.size() == 1, |
|
|
|
|
|
|
|
() -> "Multiple @HttpExchange annotations found on %s, but only one is allowed: %s" |
|
|
|
|
|
|
|
.formatted(element, exchangeDescriptors)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Create a {@link RequestMappingInfo} from the supplied |
|
|
|
* Create a {@link RequestMappingInfo} from the supplied |
|
|
|
* {@link RequestMapping @RequestMapping} annotation, meta-annotation, |
|
|
|
* {@link RequestMapping @RequestMapping} annotation, meta-annotation, |
|
|
|
@ -510,24 +531,16 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static List<AnnotationDescriptor> getAnnotationDescriptors(AnnotatedElement element) { |
|
|
|
|
|
|
|
return MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY, RepeatableContainers.none()) |
|
|
|
|
|
|
|
.stream() |
|
|
|
|
|
|
|
.filter(MergedAnnotationPredicates.typeIn(RequestMapping.class, HttpExchange.class)) |
|
|
|
|
|
|
|
.filter(MergedAnnotationPredicates.firstRunOf(MergedAnnotation::getAggregateIndex)) |
|
|
|
|
|
|
|
.map(AnnotationDescriptor::new) |
|
|
|
|
|
|
|
.distinct() |
|
|
|
|
|
|
|
.toList(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static class AnnotationDescriptor { |
|
|
|
private static class AnnotationDescriptor { |
|
|
|
|
|
|
|
|
|
|
|
private final Annotation annotation; |
|
|
|
private final Annotation annotation; |
|
|
|
|
|
|
|
|
|
|
|
private final MergedAnnotation<?> root; |
|
|
|
private final MergedAnnotation<?> root; |
|
|
|
|
|
|
|
|
|
|
|
AnnotationDescriptor(MergedAnnotation<Annotation> mergedAnnotation) { |
|
|
|
AnnotationDescriptor(MergedAnnotation<Annotation> annotation) { |
|
|
|
this.annotation = mergedAnnotation.synthesize(); |
|
|
|
this.annotation = annotation.synthesize(); |
|
|
|
this.root = mergedAnnotation.getRoot(); |
|
|
|
this.root = annotation.getRoot(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
|