Polishing in RequestMappingHandlerMapping
This commit is contained in:
parent
7cc29d2019
commit
d045f44693
|
@ -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
|
||||||
|
|
|
@ -205,27 +205,25 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
|
||||||
@Override
|
@Override
|
||||||
protected @Nullable HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
|
protected @Nullable HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
|
||||||
if (this.apiVersionStrategy != null) {
|
if (this.apiVersionStrategy != null) {
|
||||||
Comparable<?> requestVersion = (Comparable<?>) request.getAttribute(API_VERSION_ATTRIBUTE);
|
Comparable<?> version = (Comparable<?>) request.getAttribute(API_VERSION_ATTRIBUTE);
|
||||||
if (requestVersion == null) {
|
if (version == null) {
|
||||||
requestVersion = getApiVersion(request, this.apiVersionStrategy);
|
version = getApiVersion(request, this.apiVersionStrategy);
|
||||||
if (requestVersion != null) {
|
if (version != null) {
|
||||||
request.setAttribute(API_VERSION_ATTRIBUTE, requestVersion);
|
request.setAttribute(API_VERSION_ATTRIBUTE, version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.getHandlerInternal(request);
|
return super.getHandlerInternal(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static @Nullable Comparable<?> getApiVersion(
|
private static @Nullable Comparable<?> getApiVersion(HttpServletRequest request, ApiVersionStrategy strategy) {
|
||||||
HttpServletRequest request, ApiVersionStrategy versionStrategy) {
|
String value = strategy.resolveVersion(request);
|
||||||
|
|
||||||
String value = versionStrategy.resolveVersion(request);
|
|
||||||
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, request);
|
strategy.validateVersion(version, request);
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
|
@ -275,42 +273,44 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -343,6 +343,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,
|
||||||
|
@ -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 {
|
private static class AnnotationDescriptor {
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue