Polishing in RequestMappingHandlerMapping
This commit is contained in:
parent
7cc29d2019
commit
d045f44693
|
@ -178,27 +178,25 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
|
|||
@Override
|
||||
public Mono<HandlerMethod> getHandlerInternal(ServerWebExchange exchange) {
|
||||
if (this.apiVersionStrategy != null) {
|
||||
Comparable<?> requestVersion = exchange.getAttribute(API_VERSION_ATTRIBUTE);
|
||||
if (requestVersion == null) {
|
||||
requestVersion = getApiVersion(exchange, this.apiVersionStrategy);
|
||||
if (requestVersion != null) {
|
||||
exchange.getAttributes().put(API_VERSION_ATTRIBUTE, requestVersion);
|
||||
Comparable<?> version = exchange.getAttribute(API_VERSION_ATTRIBUTE);
|
||||
if (version == null) {
|
||||
version = getApiVersion(exchange, this.apiVersionStrategy);
|
||||
if (version != null) {
|
||||
exchange.getAttributes().put(API_VERSION_ATTRIBUTE, version);
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.getHandlerInternal(exchange);
|
||||
}
|
||||
|
||||
private static @Nullable Comparable<?> getApiVersion(
|
||||
ServerWebExchange exchange, ApiVersionStrategy versionStrategy) {
|
||||
|
||||
String value = versionStrategy.resolveVersion(exchange);
|
||||
private static @Nullable Comparable<?> getApiVersion(ServerWebExchange exchange, ApiVersionStrategy strategy) {
|
||||
String value = strategy.resolveVersion(exchange);
|
||||
if (value == null) {
|
||||
return versionStrategy.getDefaultVersion();
|
||||
return strategy.getDefaultVersion();
|
||||
}
|
||||
try {
|
||||
Comparable<?> version = versionStrategy.parseVersion(value);
|
||||
versionStrategy.validateVersion(version, exchange);
|
||||
Comparable<?> version = strategy.parseVersion(value);
|
||||
strategy.validateVersion(version, exchange);
|
||||
return version;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
|
@ -242,42 +240,43 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
|
|||
}
|
||||
|
||||
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 ?
|
||||
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()
|
||||
.filter(desc -> desc.annotation instanceof RequestMapping).toList();
|
||||
if (!requestMappings.isEmpty()) {
|
||||
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);
|
||||
if (!mappingDescriptors.isEmpty()) {
|
||||
checkMultipleAnnotations(element, mappingDescriptors);
|
||||
info = createRequestMappingInfo((RequestMapping) mappingDescriptors.get(0).annotation, customCondition);
|
||||
}
|
||||
|
||||
List<AnnotationDescriptor> httpExchanges = descriptors.stream()
|
||||
.filter(desc -> desc.annotation instanceof HttpExchange).toList();
|
||||
if (!httpExchanges.isEmpty()) {
|
||||
Assert.state(requestMappingInfo == null,
|
||||
() -> "%s is annotated with @RequestMapping and @HttpExchange annotations, but only one is allowed: %s"
|
||||
.formatted(element, Stream.of(requestMappings, httpExchanges).flatMap(List::stream).toList()));
|
||||
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);
|
||||
List<AnnotationDescriptor> exchangeDescriptors =
|
||||
descriptors.stream().filter(desc -> desc.annotation instanceof HttpExchange).toList();
|
||||
|
||||
if (!exchangeDescriptors.isEmpty()) {
|
||||
checkMultipleAnnotations(element, info, mappingDescriptors, exchangeDescriptors);
|
||||
info = createRequestMappingInfo((HttpExchange) exchangeDescriptors.get(0).annotation, customCondition);
|
||||
}
|
||||
|
||||
if (requestMappingInfo != null && this.apiVersionStrategy instanceof DefaultApiVersionStrategy davs) {
|
||||
String version = requestMappingInfo.getVersionCondition().getVersion();
|
||||
if (info != null && this.apiVersionStrategy instanceof DefaultApiVersionStrategy davs) {
|
||||
String version = info.getVersionCondition().getVersion();
|
||||
if (version != null) {
|
||||
davs.addMappedVersion(version);
|
||||
}
|
||||
}
|
||||
|
||||
return requestMappingInfo;
|
||||
return info;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -316,6 +315,28 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
|
|||
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
|
||||
* {@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 final Annotation annotation;
|
||||
|
||||
private final MergedAnnotation<?> root;
|
||||
|
||||
AnnotationDescriptor(MergedAnnotation<Annotation> mergedAnnotation) {
|
||||
this.annotation = mergedAnnotation.synthesize();
|
||||
this.root = mergedAnnotation.getRoot();
|
||||
AnnotationDescriptor(MergedAnnotation<Annotation> annotation) {
|
||||
this.annotation = annotation.synthesize();
|
||||
this.root = annotation.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -205,27 +205,25 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
|
|||
@Override
|
||||
protected @Nullable HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
|
||||
if (this.apiVersionStrategy != null) {
|
||||
Comparable<?> requestVersion = (Comparable<?>) request.getAttribute(API_VERSION_ATTRIBUTE);
|
||||
if (requestVersion == null) {
|
||||
requestVersion = getApiVersion(request, this.apiVersionStrategy);
|
||||
if (requestVersion != null) {
|
||||
request.setAttribute(API_VERSION_ATTRIBUTE, requestVersion);
|
||||
Comparable<?> version = (Comparable<?>) request.getAttribute(API_VERSION_ATTRIBUTE);
|
||||
if (version == null) {
|
||||
version = getApiVersion(request, this.apiVersionStrategy);
|
||||
if (version != null) {
|
||||
request.setAttribute(API_VERSION_ATTRIBUTE, version);
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.getHandlerInternal(request);
|
||||
}
|
||||
|
||||
private static @Nullable Comparable<?> getApiVersion(
|
||||
HttpServletRequest request, ApiVersionStrategy versionStrategy) {
|
||||
|
||||
String value = versionStrategy.resolveVersion(request);
|
||||
private static @Nullable Comparable<?> getApiVersion(HttpServletRequest request, ApiVersionStrategy strategy) {
|
||||
String value = strategy.resolveVersion(request);
|
||||
if (value == null) {
|
||||
return versionStrategy.getDefaultVersion();
|
||||
return strategy.getDefaultVersion();
|
||||
}
|
||||
try {
|
||||
Comparable<?> version = versionStrategy.parseVersion(value);
|
||||
versionStrategy.validateVersion(version, request);
|
||||
Comparable<?> version = strategy.parseVersion(value);
|
||||
strategy.validateVersion(version, request);
|
||||
return version;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
|
@ -275,42 +273,44 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
|
|||
}
|
||||
|
||||
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 ?
|
||||
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()
|
||||
.filter(desc -> desc.annotation instanceof RequestMapping).toList();
|
||||
if (!requestMappings.isEmpty()) {
|
||||
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);
|
||||
if (!mappingDescriptors.isEmpty()) {
|
||||
checkMultipleAnnotations(element, mappingDescriptors);
|
||||
info = createRequestMappingInfo((RequestMapping) mappingDescriptors.get(0).annotation, customCondition);
|
||||
}
|
||||
|
||||
List<AnnotationDescriptor> httpExchanges = descriptors.stream()
|
||||
.filter(desc -> desc.annotation instanceof HttpExchange).toList();
|
||||
if (!httpExchanges.isEmpty()) {
|
||||
Assert.state(requestMappingInfo == null,
|
||||
() -> "%s is annotated with @RequestMapping and @HttpExchange annotations, but only one is allowed: %s"
|
||||
.formatted(element, Stream.of(requestMappings, httpExchanges).flatMap(List::stream).toList()));
|
||||
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);
|
||||
List<AnnotationDescriptor> exchangeDescriptors =
|
||||
descriptors.stream().filter(desc -> desc.annotation instanceof HttpExchange).toList();
|
||||
|
||||
if (!exchangeDescriptors.isEmpty()) {
|
||||
checkMultipleAnnotations(element, info, mappingDescriptors, exchangeDescriptors);
|
||||
info = createRequestMappingInfo((HttpExchange) exchangeDescriptors.get(0).annotation, customCondition);
|
||||
}
|
||||
|
||||
if (requestMappingInfo != null && this.apiVersionStrategy instanceof DefaultApiVersionStrategy davs) {
|
||||
String version = requestMappingInfo.getVersionCondition().getVersion();
|
||||
if (info != null && this.apiVersionStrategy instanceof DefaultApiVersionStrategy davs) {
|
||||
String version = info.getVersionCondition().getVersion();
|
||||
if (version != null) {
|
||||
davs.addMappedVersion(version);
|
||||
}
|
||||
}
|
||||
|
||||
return requestMappingInfo;
|
||||
return info;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -343,6 +343,28 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
|
|||
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
|
||||
* {@link RequestMapping @RequestMapping} annotation, meta-annotation,
|
||||
|
@ -563,15 +585,6 @@ 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 {
|
||||
|
||||
|
|
Loading…
Reference in New Issue