Optimal initialization of empty request mapping conditions
Closes gh-25143
This commit is contained in:
parent
3cbc297fc6
commit
e9a9883aa9
|
@ -29,6 +29,7 @@ import org.springframework.http.MediaType;
|
|||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.cors.reactive.CorsUtils;
|
||||
|
@ -75,39 +76,39 @@ public final class ConsumesRequestCondition extends AbstractRequestCondition<Con
|
|||
* @param headers as described in {@link RequestMapping#headers()}
|
||||
*/
|
||||
public ConsumesRequestCondition(String[] consumes, String[] headers) {
|
||||
this.expressions = new ArrayList<>(parseExpressions(consumes, headers));
|
||||
this.expressions = parseExpressions(consumes, headers);
|
||||
if (this.expressions.size() > 1) {
|
||||
Collections.sort(this.expressions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor for internal when creating matching conditions.
|
||||
* Note the expressions List is neither sorted nor deep copied.
|
||||
*/
|
||||
private ConsumesRequestCondition(List<ConsumeMediaTypeExpression> expressions) {
|
||||
this.expressions = expressions;
|
||||
}
|
||||
|
||||
|
||||
private static Set<ConsumeMediaTypeExpression> parseExpressions(String[] consumes, String[] headers) {
|
||||
Set<ConsumeMediaTypeExpression> result = new LinkedHashSet<>();
|
||||
if (headers != null) {
|
||||
private static List<ConsumeMediaTypeExpression> parseExpressions(String[] consumes, String[] headers) {
|
||||
Set<ConsumeMediaTypeExpression> result = null;
|
||||
if (!ObjectUtils.isEmpty(headers)) {
|
||||
for (String header : headers) {
|
||||
HeadersRequestCondition.HeaderExpression expr = new HeadersRequestCondition.HeaderExpression(header);
|
||||
if ("Content-Type".equalsIgnoreCase(expr.name)) {
|
||||
result = (result != null ? result : new LinkedHashSet<>());
|
||||
for (MediaType mediaType : MediaType.parseMediaTypes(expr.value)) {
|
||||
result.add(new ConsumeMediaTypeExpression(mediaType, expr.isNegated));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (consumes != null) {
|
||||
if (!ObjectUtils.isEmpty(consumes)) {
|
||||
result = (result != null ? result : new LinkedHashSet<>());
|
||||
for (String consume : consumes) {
|
||||
result.add(new ConsumeMediaTypeExpression(consume));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return (result != null ? new ArrayList<>(result) : Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor for internal when creating matching conditions.
|
||||
*/
|
||||
private ConsumesRequestCondition(List<ConsumeMediaTypeExpression> expressions) {
|
||||
this.expressions = expressions;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -17,10 +17,12 @@
|
|||
package org.springframework.web.reactive.result.condition;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.cors.reactive.CorsUtils;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
@ -52,7 +54,22 @@ public final class HeadersRequestCondition extends AbstractRequestCondition<Head
|
|||
* if 0, the condition will match to every request
|
||||
*/
|
||||
public HeadersRequestCondition(String... headers) {
|
||||
this(parseExpressions(headers));
|
||||
this.expressions = parseExpressions(headers);
|
||||
}
|
||||
|
||||
private static Set<HeaderExpression> parseExpressions(String... headers) {
|
||||
Set<HeaderExpression> result = null;
|
||||
if (!ObjectUtils.isEmpty(headers)) {
|
||||
for (String header : headers) {
|
||||
HeaderExpression expr = new HeaderExpression(header);
|
||||
if ("Accept".equalsIgnoreCase(expr.name) || "Content-Type".equalsIgnoreCase(expr.name)) {
|
||||
continue;
|
||||
}
|
||||
result = (result != null ? result : new LinkedHashSet<>(headers.length));
|
||||
result.add(expr);
|
||||
}
|
||||
}
|
||||
return (result != null ? result : Collections.emptySet());
|
||||
}
|
||||
|
||||
private HeadersRequestCondition(Set<HeaderExpression> conditions) {
|
||||
|
@ -60,20 +77,6 @@ public final class HeadersRequestCondition extends AbstractRequestCondition<Head
|
|||
}
|
||||
|
||||
|
||||
private static Set<HeaderExpression> parseExpressions(String... headers) {
|
||||
Set<HeaderExpression> expressions = new LinkedHashSet<>();
|
||||
if (headers != null) {
|
||||
for (String header : headers) {
|
||||
HeaderExpression expr = new HeaderExpression(header);
|
||||
if ("Accept".equalsIgnoreCase(expr.name) || "Content-Type".equalsIgnoreCase(expr.name)) {
|
||||
continue;
|
||||
}
|
||||
expressions.add(expr);
|
||||
}
|
||||
}
|
||||
return expressions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the contained request header expressions.
|
||||
*/
|
||||
|
@ -97,6 +100,15 @@ public final class HeadersRequestCondition extends AbstractRequestCondition<Head
|
|||
*/
|
||||
@Override
|
||||
public HeadersRequestCondition combine(HeadersRequestCondition other) {
|
||||
if (isEmpty() && other.isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
else if (other.isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
else if (isEmpty()) {
|
||||
return other;
|
||||
}
|
||||
Set<HeaderExpression> set = new LinkedHashSet<>(this.expressions);
|
||||
set.addAll(other.expressions);
|
||||
return new HeadersRequestCondition(set);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -21,6 +21,7 @@ import java.util.Collections;
|
|||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
|
@ -42,22 +43,22 @@ public final class ParamsRequestCondition extends AbstractRequestCondition<Param
|
|||
* if 0, the condition will match to every request.
|
||||
*/
|
||||
public ParamsRequestCondition(String... params) {
|
||||
this(parseExpressions(params));
|
||||
this.expressions = parseExpressions(params);
|
||||
}
|
||||
|
||||
private ParamsRequestCondition(Collection<ParamExpression> conditions) {
|
||||
this.expressions = Collections.unmodifiableSet(new LinkedHashSet<>(conditions));
|
||||
}
|
||||
|
||||
|
||||
private static Collection<ParamExpression> parseExpressions(String... params) {
|
||||
Set<ParamExpression> expressions = new LinkedHashSet<>();
|
||||
if (params != null) {
|
||||
for (String param : params) {
|
||||
expressions.add(new ParamExpression(param));
|
||||
}
|
||||
private static Set<ParamExpression> parseExpressions(String... params) {
|
||||
if (ObjectUtils.isEmpty(params)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
return expressions;
|
||||
Set<ParamExpression> result = new LinkedHashSet<>(params.length);
|
||||
for (String param : params) {
|
||||
result.add(new ParamExpression(param));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private ParamsRequestCondition(Set<ParamExpression> conditions) {
|
||||
this.expressions = conditions;
|
||||
}
|
||||
|
||||
|
||||
|
@ -84,6 +85,15 @@ public final class ParamsRequestCondition extends AbstractRequestCondition<Param
|
|||
*/
|
||||
@Override
|
||||
public ParamsRequestCondition combine(ParamsRequestCondition other) {
|
||||
if (isEmpty() && other.isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
else if (other.isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
else if (isEmpty()) {
|
||||
return other;
|
||||
}
|
||||
Set<ParamExpression> set = new LinkedHashSet<>(this.expressions);
|
||||
set.addAll(other.expressions);
|
||||
return new ParamsRequestCondition(set);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -27,6 +27,7 @@ import java.util.TreeSet;
|
|||
|
||||
import org.springframework.http.server.PathContainer;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.util.pattern.PathPattern;
|
||||
import org.springframework.web.util.pattern.PathPatternParser;
|
||||
|
@ -41,7 +42,7 @@ import org.springframework.web.util.pattern.PathPatternParser;
|
|||
*/
|
||||
public final class PatternsRequestCondition extends AbstractRequestCondition<PatternsRequestCondition> {
|
||||
|
||||
private static final SortedSet<PathPattern> EMPTY_PATTERNS =
|
||||
private static final SortedSet<PathPattern> EMPTY_PATH_PATTERN =
|
||||
new TreeSet<>(Collections.singleton(new PathPatternParser().parse("")));
|
||||
|
||||
|
||||
|
@ -53,21 +54,21 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
|
|||
* @param patterns 0 or more URL patterns; if 0 the condition will match to every request.
|
||||
*/
|
||||
public PatternsRequestCondition(PathPattern... patterns) {
|
||||
this(Arrays.asList(patterns));
|
||||
this(ObjectUtils.isEmpty(patterns) ? Collections.emptyList() : Arrays.asList(patterns));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance with the given URL patterns.
|
||||
*/
|
||||
public PatternsRequestCondition(List<PathPattern> patterns) {
|
||||
this(patterns.isEmpty() ? EMPTY_PATTERNS : new TreeSet<>(patterns));
|
||||
this.patterns = (patterns.isEmpty() ? EMPTY_PATH_PATTERN : new TreeSet<>(patterns));
|
||||
}
|
||||
|
||||
|
||||
private PatternsRequestCondition(SortedSet<PathPattern> patterns) {
|
||||
this.patterns = patterns;
|
||||
}
|
||||
|
||||
|
||||
public Set<PathPattern> getPatterns() {
|
||||
return this.patterns;
|
||||
}
|
||||
|
@ -94,25 +95,28 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
|
|||
*/
|
||||
@Override
|
||||
public PatternsRequestCondition combine(PatternsRequestCondition other) {
|
||||
SortedSet<PathPattern> combined;
|
||||
if (!this.patterns.isEmpty() && !other.patterns.isEmpty()) {
|
||||
combined = new TreeSet<>();
|
||||
if (isEmptyPathPattern() && other.isEmptyPathPattern()) {
|
||||
return this;
|
||||
}
|
||||
else if (other.isEmptyPathPattern()) {
|
||||
return this;
|
||||
}
|
||||
else if (isEmptyPathPattern()) {
|
||||
return other;
|
||||
}
|
||||
else {
|
||||
SortedSet<PathPattern> combined = new TreeSet<>();
|
||||
for (PathPattern pattern1 : this.patterns) {
|
||||
for (PathPattern pattern2 : other.patterns) {
|
||||
combined.add(pattern1.combine(pattern2));
|
||||
}
|
||||
}
|
||||
return new PatternsRequestCondition(combined);
|
||||
}
|
||||
else if (!this.patterns.isEmpty()) {
|
||||
combined = this.patterns;
|
||||
}
|
||||
else if (!other.patterns.isEmpty()) {
|
||||
combined = other.patterns;
|
||||
}
|
||||
else {
|
||||
combined = EMPTY_PATTERNS;
|
||||
}
|
||||
return new PatternsRequestCondition(combined);
|
||||
}
|
||||
|
||||
private boolean isEmptyPathPattern() {
|
||||
return this.patterns == EMPTY_PATH_PATTERN;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -126,31 +130,21 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
|
|||
@Override
|
||||
@Nullable
|
||||
public PatternsRequestCondition getMatchingCondition(ServerWebExchange exchange) {
|
||||
if (this.patterns.isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
SortedSet<PathPattern> matches = getMatchingPatterns(exchange);
|
||||
return (!matches.isEmpty() ? new PatternsRequestCondition(matches) : null);
|
||||
return (matches != null ? new PatternsRequestCondition(matches) : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the patterns matching the given lookup path. Invoking this method should
|
||||
* yield results equivalent to those of calling
|
||||
* {@link #getMatchingCondition(ServerWebExchange)}.
|
||||
* This method is provided as an alternative to be used if no request is available
|
||||
* (e.g. introspection, tooling, etc).
|
||||
* @param exchange the current exchange
|
||||
* @return a sorted set of matching patterns sorted with the closest match first
|
||||
*/
|
||||
@Nullable
|
||||
private SortedSet<PathPattern> getMatchingPatterns(ServerWebExchange exchange) {
|
||||
PathContainer lookupPath = exchange.getRequest().getPath().pathWithinApplication();
|
||||
TreeSet<PathPattern> pathPatterns = new TreeSet<>();
|
||||
TreeSet<PathPattern> result = null;
|
||||
for (PathPattern pattern : this.patterns) {
|
||||
if (pattern.matches(lookupPath)) {
|
||||
pathPatterns.add(pattern);
|
||||
result = (result != null ? result : new TreeSet<>());
|
||||
result.add(pattern);
|
||||
}
|
||||
}
|
||||
return pathPatterns;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,6 +25,7 @@ import java.util.Set;
|
|||
import org.springframework.http.MediaType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.accept.ContentNegotiationManager;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
@ -92,13 +93,35 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
|
|||
* @param resolver used to determine requested content type
|
||||
*/
|
||||
public ProducesRequestCondition(String[] produces, String[] headers, RequestedContentTypeResolver resolver) {
|
||||
this.expressions = new ArrayList<>(parseExpressions(produces, headers));
|
||||
this.expressions = parseExpressions(produces, headers);
|
||||
if (this.expressions.size() > 1) {
|
||||
Collections.sort(this.expressions);
|
||||
}
|
||||
this.contentTypeResolver = resolver != null ? resolver : DEFAULT_CONTENT_TYPE_RESOLVER;
|
||||
}
|
||||
|
||||
private List<ProduceMediaTypeExpression> parseExpressions(String[] produces, String[] headers) {
|
||||
Set<ProduceMediaTypeExpression> result = null;
|
||||
if (!ObjectUtils.isEmpty(headers)) {
|
||||
for (String header : headers) {
|
||||
HeadersRequestCondition.HeaderExpression expr = new HeadersRequestCondition.HeaderExpression(header);
|
||||
if ("Accept".equalsIgnoreCase(expr.name)) {
|
||||
for (MediaType mediaType : MediaType.parseMediaTypes(expr.value)) {
|
||||
result = (result != null ? result : new LinkedHashSet<>());
|
||||
result.add(new ProduceMediaTypeExpression(mediaType, expr.isNegated));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ObjectUtils.isEmpty(produces)) {
|
||||
for (String produce : produces) {
|
||||
result = (result != null ? result : new LinkedHashSet<>());
|
||||
result.add(new ProduceMediaTypeExpression(produce));
|
||||
}
|
||||
}
|
||||
return (result != null ? new ArrayList<>(result) : Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor for internal use to create matching conditions.
|
||||
* Note the expressions List is neither sorted, nor deep copied.
|
||||
|
@ -109,26 +132,6 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
|
|||
}
|
||||
|
||||
|
||||
private Set<ProduceMediaTypeExpression> parseExpressions(String[] produces, String[] headers) {
|
||||
Set<ProduceMediaTypeExpression> result = new LinkedHashSet<>();
|
||||
if (headers != null) {
|
||||
for (String header : headers) {
|
||||
HeadersRequestCondition.HeaderExpression expr = new HeadersRequestCondition.HeaderExpression(header);
|
||||
if ("Accept".equalsIgnoreCase(expr.name)) {
|
||||
for (MediaType mediaType : MediaType.parseMediaTypes(expr.value)) {
|
||||
result.add(new ProduceMediaTypeExpression(mediaType, expr.isNegated));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (produces != null) {
|
||||
for (String produce : produces) {
|
||||
result.add(new ProduceMediaTypeExpression(produce));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the contained "produces" expressions.
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -21,13 +21,13 @@ import java.util.Collection;
|
|||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.cors.reactive.CorsUtils;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
@ -62,16 +62,15 @@ public final class RequestMethodsRequestCondition extends AbstractRequestConditi
|
|||
* if, 0 the condition will match to every request
|
||||
*/
|
||||
public RequestMethodsRequestCondition(RequestMethod... requestMethods) {
|
||||
this(asList(requestMethods));
|
||||
this.methods = (ObjectUtils.isEmpty(requestMethods) ?
|
||||
Collections.emptySet() : new LinkedHashSet<>(Arrays.asList(requestMethods)));
|
||||
}
|
||||
|
||||
private RequestMethodsRequestCondition(Collection<RequestMethod> requestMethods) {
|
||||
this.methods = Collections.unmodifiableSet(new LinkedHashSet<>(requestMethods));
|
||||
}
|
||||
|
||||
|
||||
private static List<RequestMethod> asList(RequestMethod... requestMethods) {
|
||||
return (requestMethods != null ? Arrays.asList(requestMethods) : Collections.emptyList());
|
||||
/**
|
||||
* Private constructor for internal use when combining conditions.
|
||||
*/
|
||||
private RequestMethodsRequestCondition(Set<RequestMethod> requestMethods) {
|
||||
this.methods = requestMethods;
|
||||
}
|
||||
|
||||
|
||||
|
@ -98,6 +97,15 @@ public final class RequestMethodsRequestCondition extends AbstractRequestConditi
|
|||
*/
|
||||
@Override
|
||||
public RequestMethodsRequestCondition combine(RequestMethodsRequestCondition other) {
|
||||
if (isEmpty() && other.isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
else if (other.isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
else if (isEmpty()) {
|
||||
return other;
|
||||
}
|
||||
Set<RequestMethod> set = new LinkedHashSet<>(this.methods);
|
||||
set.addAll(other.methods);
|
||||
return new RequestMethodsRequestCondition(set);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,12 +16,13 @@
|
|||
|
||||
package org.springframework.web.reactive.result.method;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
|
||||
|
@ -54,6 +55,19 @@ import org.springframework.web.util.pattern.PathPatternParser;
|
|||
*/
|
||||
public final class RequestMappingInfo implements RequestCondition<RequestMappingInfo> {
|
||||
|
||||
private static final PatternsRequestCondition EMPTY_PATTERNS = new PatternsRequestCondition();
|
||||
|
||||
private static final RequestMethodsRequestCondition EMPTY_REQUEST_METHODS = new RequestMethodsRequestCondition();
|
||||
|
||||
private static final ParamsRequestCondition EMPTY_PARAMS = new ParamsRequestCondition();
|
||||
|
||||
private static final HeadersRequestCondition EMPTY_HEADERS = new HeadersRequestCondition();
|
||||
|
||||
private static final ConsumesRequestCondition EMPTY_CONSUMES = new ConsumesRequestCondition();
|
||||
|
||||
private static final ProducesRequestCondition EMPTY_PRODUCES = new ProducesRequestCondition();
|
||||
|
||||
|
||||
@Nullable
|
||||
private final String name;
|
||||
|
||||
|
@ -78,12 +92,12 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
|
|||
@Nullable ProducesRequestCondition produces, @Nullable RequestCondition<?> custom) {
|
||||
|
||||
this.name = (StringUtils.hasText(name) ? name : null);
|
||||
this.patternsCondition = (patterns != null ? patterns : new PatternsRequestCondition());
|
||||
this.methodsCondition = (methods != null ? methods : new RequestMethodsRequestCondition());
|
||||
this.paramsCondition = (params != null ? params : new ParamsRequestCondition());
|
||||
this.headersCondition = (headers != null ? headers : new HeadersRequestCondition());
|
||||
this.consumesCondition = (consumes != null ? consumes : new ConsumesRequestCondition());
|
||||
this.producesCondition = (produces != null ? produces : new ProducesRequestCondition());
|
||||
this.patternsCondition = (patterns != null ? patterns : EMPTY_PATTERNS);
|
||||
this.methodsCondition = (methods != null ? methods : EMPTY_REQUEST_METHODS);
|
||||
this.paramsCondition = (params != null ? params : EMPTY_PARAMS);
|
||||
this.headersCondition = (headers != null ? headers : EMPTY_HEADERS);
|
||||
this.consumesCondition = (consumes != null ? consumes : EMPTY_CONSUMES);
|
||||
this.producesCondition = (produces != null ? produces : EMPTY_PRODUCES);
|
||||
this.customConditionHolder = new RequestConditionHolder(custom);
|
||||
}
|
||||
|
||||
|
@ -430,6 +444,10 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
|
|||
@Nullable
|
||||
private String[] produces;
|
||||
|
||||
private boolean hasContentType;
|
||||
|
||||
private boolean hasAccept;
|
||||
|
||||
@Nullable
|
||||
private String mappingName;
|
||||
|
||||
|
@ -438,6 +456,7 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
|
|||
|
||||
private BuilderConfiguration options = new BuilderConfiguration();
|
||||
|
||||
|
||||
public DefaultBuilder(String... paths) {
|
||||
this.paths = paths;
|
||||
}
|
||||
|
@ -462,6 +481,12 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
|
|||
|
||||
@Override
|
||||
public DefaultBuilder headers(String... headers) {
|
||||
for (String header : headers) {
|
||||
this.hasContentType = this.hasContentType ||
|
||||
header.contains("Content-Type") || header.contains("content-type");
|
||||
this.hasAccept = this.hasAccept ||
|
||||
header.contains("Accept") || header.contains("accept");
|
||||
}
|
||||
this.headers = headers;
|
||||
return this;
|
||||
}
|
||||
|
@ -498,31 +523,50 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
|
|||
|
||||
@Override
|
||||
public RequestMappingInfo build() {
|
||||
RequestedContentTypeResolver contentTypeResolver = this.options.getContentTypeResolver();
|
||||
|
||||
PathPatternParser parser = (this.options.getPatternParser() != null ?
|
||||
this.options.getPatternParser() : new PathPatternParser());
|
||||
PatternsRequestCondition patternsCondition = new PatternsRequestCondition(parse(this.paths, parser));
|
||||
|
||||
return new RequestMappingInfo(this.mappingName, patternsCondition,
|
||||
new RequestMethodsRequestCondition(this.methods),
|
||||
new ParamsRequestCondition(this.params),
|
||||
new HeadersRequestCondition(this.headers),
|
||||
new ConsumesRequestCondition(this.consumes, this.headers),
|
||||
new ProducesRequestCondition(this.produces, this.headers, contentTypeResolver),
|
||||
RequestedContentTypeResolver contentTypeResolver = this.options.getContentTypeResolver();
|
||||
|
||||
return new RequestMappingInfo(this.mappingName,
|
||||
isEmpty(this.paths) ? null : new PatternsRequestCondition(parse(this.paths, parser)),
|
||||
ObjectUtils.isEmpty(this.methods) ?
|
||||
null : new RequestMethodsRequestCondition(this.methods),
|
||||
ObjectUtils.isEmpty(this.params) ?
|
||||
null : new ParamsRequestCondition(this.params),
|
||||
ObjectUtils.isEmpty(this.headers) ?
|
||||
null : new HeadersRequestCondition(this.headers),
|
||||
ObjectUtils.isEmpty(this.consumes) && !this.hasContentType ?
|
||||
null : new ConsumesRequestCondition(this.consumes, this.headers),
|
||||
ObjectUtils.isEmpty(this.produces) && !this.hasAccept ?
|
||||
null : new ProducesRequestCondition(this.produces, this.headers, contentTypeResolver),
|
||||
this.customCondition);
|
||||
}
|
||||
|
||||
private static List<PathPattern> parse(String[] paths, PathPatternParser parser) {
|
||||
return Arrays
|
||||
.stream(paths)
|
||||
.map(path -> {
|
||||
if (StringUtils.hasText(path) && !path.startsWith("/")) {
|
||||
path = "/" + path;
|
||||
}
|
||||
return parser.parse(path);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
private static List<PathPattern> parse(String[] patterns, PathPatternParser parser) {
|
||||
if (isEmpty(patterns)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<PathPattern> result = new ArrayList<>(patterns.length);
|
||||
for (String path : patterns) {
|
||||
if (StringUtils.hasText(path) && !path.startsWith("/")) {
|
||||
path = "/" + path;
|
||||
}
|
||||
result.add(parser.parse(path));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean isEmpty(String[] patterns) {
|
||||
if (!ObjectUtils.isEmpty(patterns)) {
|
||||
for (String pattern : patterns) {
|
||||
if (StringUtils.hasText(pattern)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -42,15 +42,19 @@ public class PatternsRequestConditionTests {
|
|||
@Test
|
||||
public void prependNonEmptyPatternsOnly() {
|
||||
PatternsRequestCondition c = createPatternsCondition("");
|
||||
assertThat(c.getPatterns().iterator().next().getPatternString()).as("Do not prepend empty patterns (SPR-8255)").isEqualTo("");
|
||||
assertThat(c.getPatterns().iterator().next().getPatternString())
|
||||
.as("Do not prepend empty patterns (SPR-8255)")
|
||||
.isEqualTo("");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void combineEmptySets() {
|
||||
PatternsRequestCondition c1 = new PatternsRequestCondition();
|
||||
PatternsRequestCondition c2 = new PatternsRequestCondition();
|
||||
PatternsRequestCondition c3 = c1.combine(c2);
|
||||
|
||||
assertThat(c1.combine(c2)).isEqualTo(createPatternsCondition());
|
||||
assertThat(c3).isSameAs(c1);
|
||||
assertThat(c1.getPatterns()).isSameAs(c2.getPatterns()).containsExactly(this.parser.parse(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -75,7 +79,7 @@ public class PatternsRequestConditionTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void matchDirectPath() throws Exception {
|
||||
public void matchDirectPath() {
|
||||
PatternsRequestCondition condition = createPatternsCondition("/foo");
|
||||
MockServerWebExchange exchange = MockServerWebExchange.from(get("/foo"));
|
||||
PatternsRequestCondition match = condition.getMatchingCondition(exchange);
|
||||
|
@ -84,7 +88,7 @@ public class PatternsRequestConditionTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void matchPattern() throws Exception {
|
||||
public void matchPattern() {
|
||||
PatternsRequestCondition condition = createPatternsCondition("/foo/*");
|
||||
MockServerWebExchange exchange = MockServerWebExchange.from(get("/foo/bar"));
|
||||
PatternsRequestCondition match = condition.getMatchingCondition(exchange);
|
||||
|
@ -93,7 +97,7 @@ public class PatternsRequestConditionTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void matchSortPatterns() throws Exception {
|
||||
public void matchSortPatterns() {
|
||||
PatternsRequestCondition condition = createPatternsCondition("/*/*", "/foo/bar", "/foo/*");
|
||||
MockServerWebExchange exchange = MockServerWebExchange.from(get("/foo/bar"));
|
||||
PatternsRequestCondition match = condition.getMatchingCondition(exchange);
|
||||
|
@ -103,20 +107,24 @@ public class PatternsRequestConditionTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void matchTrailingSlash() throws Exception {
|
||||
public void matchTrailingSlash() {
|
||||
MockServerWebExchange exchange = MockServerWebExchange.from(get("/foo/"));
|
||||
|
||||
PatternsRequestCondition condition = createPatternsCondition("/foo");
|
||||
PatternsRequestCondition match = condition.getMatchingCondition(exchange);
|
||||
|
||||
assertThat(match).isNotNull();
|
||||
assertThat(match.getPatterns().iterator().next().getPatternString()).as("Should match by default").isEqualTo("/foo");
|
||||
assertThat(match.getPatterns().iterator().next().getPatternString())
|
||||
.as("Should match by default")
|
||||
.isEqualTo("/foo");
|
||||
|
||||
condition = createPatternsCondition("/foo");
|
||||
match = condition.getMatchingCondition(exchange);
|
||||
|
||||
assertThat(match).isNotNull();
|
||||
assertThat(match.getPatterns().iterator().next().getPatternString()).as("Trailing slash should be insensitive to useSuffixPatternMatch settings (SPR-6164, SPR-5636)").isEqualTo("/foo");
|
||||
assertThat(match.getPatterns().iterator().next().getPatternString())
|
||||
.as("Trailing slash should be insensitive to useSuffixPatternMatch settings (SPR-6164, SPR-5636)")
|
||||
.isEqualTo("/foo");
|
||||
|
||||
PathPatternParser parser = new PathPatternParser();
|
||||
parser.setMatchOptionalTrailingSeparator(false);
|
||||
|
@ -127,7 +135,7 @@ public class PatternsRequestConditionTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void matchPatternContainsExtension() throws Exception {
|
||||
public void matchPatternContainsExtension() {
|
||||
PatternsRequestCondition condition = createPatternsCondition("/foo.jpg");
|
||||
MockServerWebExchange exchange = MockServerWebExchange.from(get("/foo.html"));
|
||||
PatternsRequestCondition match = condition.getMatchingCondition(exchange);
|
||||
|
@ -138,18 +146,16 @@ public class PatternsRequestConditionTests {
|
|||
@Test // gh-22543
|
||||
public void matchWithEmptyPatterns() {
|
||||
PatternsRequestCondition condition = new PatternsRequestCondition();
|
||||
assertThat(condition).isEqualTo(new PatternsRequestCondition(this.parser.parse("")));
|
||||
assertThat(condition.getMatchingCondition(MockServerWebExchange.from(get("")))).isNotNull();
|
||||
assertThat(condition.getMatchingCondition(MockServerWebExchange.from(get("/anything")))).isNull();
|
||||
|
||||
condition = condition.combine(new PatternsRequestCondition());
|
||||
assertThat(condition).isEqualTo(new PatternsRequestCondition(this.parser.parse("")));
|
||||
assertThat(condition.getMatchingCondition(MockServerWebExchange.from(get("")))).isNotNull();
|
||||
assertThat(condition.getMatchingCondition(MockServerWebExchange.from(get("/anything")))).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compareToConsistentWithEquals() throws Exception {
|
||||
public void compareToConsistentWithEquals() {
|
||||
PatternsRequestCondition c1 = createPatternsCondition("/foo*");
|
||||
PatternsRequestCondition c2 = createPatternsCondition("/foo*");
|
||||
|
||||
|
@ -157,7 +163,7 @@ public class PatternsRequestConditionTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void equallyMatchingPatternsAreBothPresent() throws Exception {
|
||||
public void equallyMatchingPatternsAreBothPresent() {
|
||||
PatternsRequestCondition c = createPatternsCondition("/a", "/b");
|
||||
assertThat(c.getPatterns().size()).isEqualTo(2);
|
||||
Iterator<PathPattern> itr = c.getPatterns().iterator();
|
||||
|
@ -166,7 +172,7 @@ public class PatternsRequestConditionTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void comparePatternSpecificity() throws Exception {
|
||||
public void comparePatternSpecificity() {
|
||||
ServerWebExchange exchange = MockServerWebExchange.from(get("/foo"));
|
||||
|
||||
PatternsRequestCondition c1 = createPatternsCondition("/fo*");
|
||||
|
@ -177,11 +183,13 @@ public class PatternsRequestConditionTests {
|
|||
c1 = createPatternsCondition("/fo*");
|
||||
c2 = createPatternsCondition("/*oo");
|
||||
|
||||
assertThat(c1.compareTo(c2, exchange)).as("Patterns are equally specific even if not the same").isEqualTo(0);
|
||||
assertThat(c1.compareTo(c2, exchange))
|
||||
.as("Patterns are equally specific even if not the same")
|
||||
.isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compareNumberOfMatchingPatterns() throws Exception {
|
||||
public void compareNumberOfMatchingPatterns() {
|
||||
ServerWebExchange exchange = MockServerWebExchange.from(get("/foo.html"));
|
||||
|
||||
PatternsRequestCondition c1 = createPatternsCondition("/foo.*", "/foo.jpeg");
|
||||
|
@ -197,7 +205,7 @@ public class PatternsRequestConditionTests {
|
|||
private PatternsRequestCondition createPatternsCondition(String... patterns) {
|
||||
return new PatternsRequestCondition(Arrays
|
||||
.stream(patterns)
|
||||
.map(rawPattern -> this.parser.parse(rawPattern))
|
||||
.map(this.parser::parse)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -49,7 +49,6 @@ public class RequestMappingInfoTests {
|
|||
|
||||
// TODO: CORS pre-flight (see @Disabled)
|
||||
|
||||
|
||||
@Test
|
||||
public void createEmpty() {
|
||||
RequestMappingInfo info = paths().build();
|
||||
|
@ -62,6 +61,22 @@ public class RequestMappingInfoTests {
|
|||
assertThat(info.getParamsCondition()).isNotNull();
|
||||
assertThat(info.getHeadersCondition()).isNotNull();
|
||||
assertThat(info.getCustomCondition()).isNull();
|
||||
|
||||
RequestMappingInfo anotherInfo = paths().build();
|
||||
assertThat(info.getPatternsCondition()).isSameAs(anotherInfo.getPatternsCondition());
|
||||
assertThat(info.getMethodsCondition()).isSameAs(anotherInfo.getMethodsCondition());
|
||||
assertThat(info.getParamsCondition()).isSameAs(anotherInfo.getParamsCondition());
|
||||
assertThat(info.getHeadersCondition()).isSameAs(anotherInfo.getHeadersCondition());
|
||||
assertThat(info.getConsumesCondition()).isSameAs(anotherInfo.getConsumesCondition());
|
||||
assertThat(info.getProducesCondition()).isSameAs(anotherInfo.getProducesCondition());
|
||||
|
||||
RequestMappingInfo result = info.combine(anotherInfo);
|
||||
assertThat(info.getPatternsCondition()).isSameAs(result.getPatternsCondition());
|
||||
assertThat(info.getMethodsCondition()).isSameAs(result.getMethodsCondition());
|
||||
assertThat(info.getParamsCondition()).isSameAs(result.getParamsCondition());
|
||||
assertThat(info.getHeadersCondition()).isSameAs(result.getHeadersCondition());
|
||||
assertThat(info.getConsumesCondition()).isSameAs(result.getConsumesCondition());
|
||||
assertThat(info.getProducesCondition()).isSameAs(result.getProducesCondition());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.springframework.http.InvalidMediaTypeException;
|
|||
import org.springframework.http.MediaType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.cors.CorsUtils;
|
||||
|
@ -76,12 +77,34 @@ public final class ConsumesRequestCondition extends AbstractRequestCondition<Con
|
|||
* @param headers as described in {@link RequestMapping#headers()}
|
||||
*/
|
||||
public ConsumesRequestCondition(String[] consumes, @Nullable String[] headers) {
|
||||
this.expressions = new ArrayList<>(parseExpressions(consumes, headers));
|
||||
this.expressions = parseExpressions(consumes, headers);
|
||||
if (this.expressions.size() > 1) {
|
||||
Collections.sort(this.expressions);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<ConsumeMediaTypeExpression> parseExpressions(String[] consumes, @Nullable String[] headers) {
|
||||
Set<ConsumeMediaTypeExpression> result = null;
|
||||
if (!ObjectUtils.isEmpty(headers)) {
|
||||
for (String header : headers) {
|
||||
HeaderExpression expr = new HeaderExpression(header);
|
||||
if ("Content-Type".equalsIgnoreCase(expr.name) && expr.value != null) {
|
||||
result = (result != null ? result : new LinkedHashSet<>());
|
||||
for (MediaType mediaType : MediaType.parseMediaTypes(expr.value)) {
|
||||
result.add(new ConsumeMediaTypeExpression(mediaType, expr.isNegated));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ObjectUtils.isEmpty(consumes)) {
|
||||
result = (result != null ? result : new LinkedHashSet<>());
|
||||
for (String consume : consumes) {
|
||||
result.add(new ConsumeMediaTypeExpression(consume));
|
||||
}
|
||||
}
|
||||
return (result != null ? new ArrayList<>(result) : Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor for internal when creating matching conditions.
|
||||
* Note the expressions List is neither sorted nor deep copied.
|
||||
|
@ -91,25 +114,6 @@ public final class ConsumesRequestCondition extends AbstractRequestCondition<Con
|
|||
}
|
||||
|
||||
|
||||
private static Set<ConsumeMediaTypeExpression> parseExpressions(String[] consumes, @Nullable String[] headers) {
|
||||
Set<ConsumeMediaTypeExpression> result = new LinkedHashSet<>();
|
||||
if (headers != null) {
|
||||
for (String header : headers) {
|
||||
HeaderExpression expr = new HeaderExpression(header);
|
||||
if ("Content-Type".equalsIgnoreCase(expr.name) && expr.value != null) {
|
||||
for (MediaType mediaType : MediaType.parseMediaTypes(expr.value)) {
|
||||
result.add(new ConsumeMediaTypeExpression(mediaType, expr.isNegated));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (String consume : consumes) {
|
||||
result.add(new ConsumeMediaTypeExpression(consume));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the contained MediaType expressions.
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.web.servlet.mvc.condition;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -55,7 +56,22 @@ public final class HeadersRequestCondition extends AbstractRequestCondition<Head
|
|||
* if 0, the condition will match to every request
|
||||
*/
|
||||
public HeadersRequestCondition(String... headers) {
|
||||
this(parseExpressions(headers));
|
||||
this.expressions = parseExpressions(headers);
|
||||
}
|
||||
|
||||
private static Set<HeaderExpression> parseExpressions(String... headers) {
|
||||
Set<HeaderExpression> result = null;
|
||||
if (!ObjectUtils.isEmpty(headers)) {
|
||||
for (String header : headers) {
|
||||
HeaderExpression expr = new HeaderExpression(header);
|
||||
if ("Accept".equalsIgnoreCase(expr.name) || "Content-Type".equalsIgnoreCase(expr.name)) {
|
||||
continue;
|
||||
}
|
||||
result = (result != null ? result : new LinkedHashSet<>(headers.length));
|
||||
result.add(expr);
|
||||
}
|
||||
}
|
||||
return (result != null ? result : Collections.emptySet());
|
||||
}
|
||||
|
||||
private HeadersRequestCondition(Set<HeaderExpression> conditions) {
|
||||
|
@ -63,18 +79,6 @@ public final class HeadersRequestCondition extends AbstractRequestCondition<Head
|
|||
}
|
||||
|
||||
|
||||
private static Set<HeaderExpression> parseExpressions(String... headers) {
|
||||
Set<HeaderExpression> expressions = new LinkedHashSet<>();
|
||||
for (String header : headers) {
|
||||
HeaderExpression expr = new HeaderExpression(header);
|
||||
if ("Accept".equalsIgnoreCase(expr.name) || "Content-Type".equalsIgnoreCase(expr.name)) {
|
||||
continue;
|
||||
}
|
||||
expressions.add(expr);
|
||||
}
|
||||
return expressions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the contained request header expressions.
|
||||
*/
|
||||
|
@ -98,6 +102,15 @@ public final class HeadersRequestCondition extends AbstractRequestCondition<Head
|
|||
*/
|
||||
@Override
|
||||
public HeadersRequestCondition combine(HeadersRequestCondition other) {
|
||||
if (isEmpty() && other.isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
else if (other.isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
else if (isEmpty()) {
|
||||
return other;
|
||||
}
|
||||
Set<HeaderExpression> set = new LinkedHashSet<>(this.expressions);
|
||||
set.addAll(other.expressions);
|
||||
return new HeadersRequestCondition(set);
|
||||
|
@ -157,7 +170,7 @@ public final class HeadersRequestCondition extends AbstractRequestCondition<Head
|
|||
*/
|
||||
static class HeaderExpression extends AbstractNameValueExpression<String> {
|
||||
|
||||
public HeaderExpression(String expression) {
|
||||
HeaderExpression(String expression) {
|
||||
super(expression);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -48,22 +48,24 @@ public final class ParamsRequestCondition extends AbstractRequestCondition<Param
|
|||
* if 0, the condition will match to every request.
|
||||
*/
|
||||
public ParamsRequestCondition(String... params) {
|
||||
this(parseExpressions(params));
|
||||
this.expressions = parseExpressions(params);
|
||||
}
|
||||
|
||||
private ParamsRequestCondition(Collection<ParamExpression> conditions) {
|
||||
this.expressions = Collections.unmodifiableSet(new LinkedHashSet<>(conditions));
|
||||
}
|
||||
|
||||
|
||||
private static Collection<ParamExpression> parseExpressions(String... params) {
|
||||
Set<ParamExpression> expressions = new LinkedHashSet<>();
|
||||
private static Set<ParamExpression> parseExpressions(String... params) {
|
||||
if (ObjectUtils.isEmpty(params)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
Set<ParamExpression> expressions = new LinkedHashSet<>(params.length);
|
||||
for (String param : params) {
|
||||
expressions.add(new ParamExpression(param));
|
||||
}
|
||||
return expressions;
|
||||
}
|
||||
|
||||
private ParamsRequestCondition(Set<ParamExpression> conditions) {
|
||||
this.expressions = conditions;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the contained request parameter expressions.
|
||||
|
@ -88,6 +90,15 @@ public final class ParamsRequestCondition extends AbstractRequestCondition<Param
|
|||
*/
|
||||
@Override
|
||||
public ParamsRequestCondition combine(ParamsRequestCondition other) {
|
||||
if (isEmpty() && other.isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
else if (other.isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
else if (isEmpty()) {
|
||||
return other;
|
||||
}
|
||||
Set<ParamExpression> set = new LinkedHashSet<>(this.expressions);
|
||||
set.addAll(other.expressions);
|
||||
return new ParamsRequestCondition(set);
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package org.springframework.web.servlet.mvc.condition;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
@ -30,6 +29,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
|
@ -42,7 +42,10 @@ import org.springframework.web.util.UrlPathHelper;
|
|||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public final class PatternsRequestCondition extends AbstractRequestCondition<PatternsRequestCondition> {
|
||||
public class PatternsRequestCondition extends AbstractRequestCondition<PatternsRequestCondition> {
|
||||
|
||||
private final static Set<String> EMPTY_PATH_PATTERN = Collections.singleton("");
|
||||
|
||||
|
||||
private final Set<String> patterns;
|
||||
|
||||
|
@ -64,7 +67,7 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
|
|||
* every request.
|
||||
*/
|
||||
public PatternsRequestCondition(String... patterns) {
|
||||
this(Arrays.asList(patterns), null, null, true, true, null);
|
||||
this(patterns, null, null, true, true, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -79,7 +82,7 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
|
|||
public PatternsRequestCondition(String[] patterns, @Nullable UrlPathHelper urlPathHelper,
|
||||
@Nullable PathMatcher pathMatcher, boolean useTrailingSlashMatch) {
|
||||
|
||||
this(Arrays.asList(patterns), urlPathHelper, pathMatcher, false, useTrailingSlashMatch, null);
|
||||
this(patterns, urlPathHelper, pathMatcher, false, useTrailingSlashMatch, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,7 +100,7 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
|
|||
public PatternsRequestCondition(String[] patterns, @Nullable UrlPathHelper urlPathHelper,
|
||||
@Nullable PathMatcher pathMatcher, boolean useSuffixPatternMatch, boolean useTrailingSlashMatch) {
|
||||
|
||||
this(Arrays.asList(patterns), urlPathHelper, pathMatcher, useSuffixPatternMatch, useTrailingSlashMatch, null);
|
||||
this(patterns, urlPathHelper, pathMatcher, useSuffixPatternMatch, useTrailingSlashMatch, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -117,18 +120,7 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
|
|||
@Nullable PathMatcher pathMatcher, boolean useSuffixPatternMatch,
|
||||
boolean useTrailingSlashMatch, @Nullable List<String> fileExtensions) {
|
||||
|
||||
this(Arrays.asList(patterns), urlPathHelper, pathMatcher, useSuffixPatternMatch,
|
||||
useTrailingSlashMatch, fileExtensions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor accepting a collection of patterns.
|
||||
*/
|
||||
private PatternsRequestCondition(Collection<String> patterns, @Nullable UrlPathHelper urlPathHelper,
|
||||
@Nullable PathMatcher pathMatcher, boolean useSuffixPatternMatch,
|
||||
boolean useTrailingSlashMatch, @Nullable List<String> fileExtensions) {
|
||||
|
||||
this.patterns = Collections.unmodifiableSet(prependLeadingSlash(patterns));
|
||||
this.patterns = initPatterns(patterns);
|
||||
this.pathHelper = urlPathHelper != null ? urlPathHelper : new UrlPathHelper();
|
||||
this.pathMatcher = pathMatcher != null ? pathMatcher : new AntPathMatcher();
|
||||
this.useSuffixPatternMatch = useSuffixPatternMatch;
|
||||
|
@ -144,6 +136,31 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
|
|||
}
|
||||
}
|
||||
|
||||
private static Set<String> initPatterns(String[] patterns) {
|
||||
if (!hasPattern(patterns)) {
|
||||
return EMPTY_PATH_PATTERN;
|
||||
}
|
||||
Set<String> result = new LinkedHashSet<>(patterns.length);
|
||||
for (String pattern : patterns) {
|
||||
if (StringUtils.hasLength(pattern) && !pattern.startsWith("/")) {
|
||||
pattern = "/" + pattern;
|
||||
}
|
||||
result.add(pattern);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean hasPattern(String[] patterns) {
|
||||
if (!ObjectUtils.isEmpty(patterns)) {
|
||||
for (String pattern : patterns) {
|
||||
if (StringUtils.hasText(pattern)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor for use when combining and matching.
|
||||
*/
|
||||
|
@ -157,20 +174,6 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
|
|||
}
|
||||
|
||||
|
||||
private static Set<String> prependLeadingSlash(Collection<String> patterns) {
|
||||
if (patterns.isEmpty()) {
|
||||
return Collections.singleton("");
|
||||
}
|
||||
Set<String> result = new LinkedHashSet<>(patterns.size());
|
||||
for (String pattern : patterns) {
|
||||
if (StringUtils.hasLength(pattern) && !pattern.startsWith("/")) {
|
||||
pattern = "/" + pattern;
|
||||
}
|
||||
result.add(pattern);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Set<String> getPatterns() {
|
||||
return this.patterns;
|
||||
}
|
||||
|
@ -197,6 +200,15 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
|
|||
*/
|
||||
@Override
|
||||
public PatternsRequestCondition combine(PatternsRequestCondition other) {
|
||||
if (isEmptyPathPattern() && other.isEmptyPathPattern()) {
|
||||
return this;
|
||||
}
|
||||
else if (other.isEmptyPathPattern()) {
|
||||
return this;
|
||||
}
|
||||
else if (isEmptyPathPattern()) {
|
||||
return other;
|
||||
}
|
||||
Set<String> result = new LinkedHashSet<>();
|
||||
if (!this.patterns.isEmpty() && !other.patterns.isEmpty()) {
|
||||
for (String pattern1 : this.patterns) {
|
||||
|
@ -205,18 +217,13 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (!this.patterns.isEmpty()) {
|
||||
result.addAll(this.patterns);
|
||||
}
|
||||
else if (!other.patterns.isEmpty()) {
|
||||
result.addAll(other.patterns);
|
||||
}
|
||||
else {
|
||||
result.add("");
|
||||
}
|
||||
return new PatternsRequestCondition(result, this);
|
||||
}
|
||||
|
||||
private boolean isEmptyPathPattern() {
|
||||
return this.patterns == EMPTY_PATH_PATTERN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if any of the patterns match the given request and returns an instance
|
||||
* that is guaranteed to contain matching patterns, sorted via
|
||||
|
@ -236,9 +243,6 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
|
|||
@Override
|
||||
@Nullable
|
||||
public PatternsRequestCondition getMatchingCondition(HttpServletRequest request) {
|
||||
if (this.patterns.isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
String lookupPath = this.pathHelper.getLookupPathForRequest(request, HandlerMapping.LOOKUP_PATH);
|
||||
List<String> matches = getMatchingPatterns(lookupPath);
|
||||
return !matches.isEmpty() ? new PatternsRequestCondition(new LinkedHashSet<>(matches), this) : null;
|
||||
|
@ -257,7 +261,7 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
|
|||
for (String pattern : this.patterns) {
|
||||
String match = getMatchingPattern(pattern, lookupPath);
|
||||
if (match != null) {
|
||||
matches = matches != null ? matches : new ArrayList<>();
|
||||
matches = (matches != null ? matches : new ArrayList<>());
|
||||
matches.add(match);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import org.springframework.http.MediaType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.HttpMediaTypeException;
|
||||
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||
|
@ -96,13 +97,35 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
|
|||
public ProducesRequestCondition(String[] produces, @Nullable String[] headers,
|
||||
@Nullable ContentNegotiationManager manager) {
|
||||
|
||||
this.expressions = new ArrayList<>(parseExpressions(produces, headers));
|
||||
this.expressions = parseExpressions(produces, headers);
|
||||
if (this.expressions.size() > 1) {
|
||||
Collections.sort(this.expressions);
|
||||
}
|
||||
this.contentNegotiationManager = manager != null ? manager : DEFAULT_CONTENT_NEGOTIATION_MANAGER;
|
||||
}
|
||||
|
||||
private List<ProduceMediaTypeExpression> parseExpressions(String[] produces, @Nullable String[] headers) {
|
||||
Set<ProduceMediaTypeExpression> result = null;
|
||||
if (!ObjectUtils.isEmpty(headers)) {
|
||||
for (String header : headers) {
|
||||
HeaderExpression expr = new HeaderExpression(header);
|
||||
if ("Accept".equalsIgnoreCase(expr.name) && expr.value != null) {
|
||||
for (MediaType mediaType : MediaType.parseMediaTypes(expr.value)) {
|
||||
result = (result != null ? result : new LinkedHashSet<>());
|
||||
result.add(new ProduceMediaTypeExpression(mediaType, expr.isNegated));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ObjectUtils.isEmpty(produces)) {
|
||||
for (String produce : produces) {
|
||||
result = (result != null ? result : new LinkedHashSet<>());
|
||||
result.add(new ProduceMediaTypeExpression(produce));
|
||||
}
|
||||
}
|
||||
return (result != null ? new ArrayList<>(result) : Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor for internal use to create matching conditions.
|
||||
* Note the expressions List is neither sorted nor deep copied.
|
||||
|
@ -113,24 +136,6 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
|
|||
}
|
||||
|
||||
|
||||
private Set<ProduceMediaTypeExpression> parseExpressions(String[] produces, @Nullable String[] headers) {
|
||||
Set<ProduceMediaTypeExpression> result = new LinkedHashSet<>();
|
||||
if (headers != null) {
|
||||
for (String header : headers) {
|
||||
HeaderExpression expr = new HeaderExpression(header);
|
||||
if ("Accept".equalsIgnoreCase(expr.name) && expr.value != null) {
|
||||
for (MediaType mediaType : MediaType.parseMediaTypes(expr.value)) {
|
||||
result.add(new ProduceMediaTypeExpression(mediaType, expr.isNegated));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (String produce : produces) {
|
||||
result.add(new ProduceMediaTypeExpression(produce));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the contained "produces" expressions.
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -30,6 +30,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.cors.CorsUtils;
|
||||
|
||||
|
@ -63,11 +64,15 @@ public final class RequestMethodsRequestCondition extends AbstractRequestConditi
|
|||
* if, 0 the condition will match to every request
|
||||
*/
|
||||
public RequestMethodsRequestCondition(RequestMethod... requestMethods) {
|
||||
this(Arrays.asList(requestMethods));
|
||||
this.methods = (ObjectUtils.isEmpty(requestMethods) ?
|
||||
Collections.emptySet() : new LinkedHashSet<>(Arrays.asList(requestMethods)));
|
||||
}
|
||||
|
||||
private RequestMethodsRequestCondition(Collection<RequestMethod> requestMethods) {
|
||||
this.methods = Collections.unmodifiableSet(new LinkedHashSet<>(requestMethods));
|
||||
/**
|
||||
* Private constructor for internal use when combining conditions.
|
||||
*/
|
||||
private RequestMethodsRequestCondition(Set<RequestMethod> methods) {
|
||||
this.methods = methods;
|
||||
}
|
||||
|
||||
|
||||
|
@ -94,6 +99,15 @@ public final class RequestMethodsRequestCondition extends AbstractRequestConditi
|
|||
*/
|
||||
@Override
|
||||
public RequestMethodsRequestCondition combine(RequestMethodsRequestCondition other) {
|
||||
if (isEmpty() && other.isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
else if (other.isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
else if (isEmpty()) {
|
||||
return other;
|
||||
}
|
||||
Set<RequestMethod> set = new LinkedHashSet<>(this.methods);
|
||||
set.addAll(other.methods);
|
||||
return new RequestMethodsRequestCondition(set);
|
||||
|
|
|
@ -23,6 +23,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.accept.ContentNegotiationManager;
|
||||
|
@ -56,6 +57,19 @@ import org.springframework.web.util.UrlPathHelper;
|
|||
*/
|
||||
public final class RequestMappingInfo implements RequestCondition<RequestMappingInfo> {
|
||||
|
||||
private static final PatternsRequestCondition EMPTY_PATTERNS = new PatternsRequestCondition();
|
||||
|
||||
private static final RequestMethodsRequestCondition EMPTY_REQUEST_METHODS = new RequestMethodsRequestCondition();
|
||||
|
||||
private static final ParamsRequestCondition EMPTY_PARAMS = new ParamsRequestCondition();
|
||||
|
||||
private static final HeadersRequestCondition EMPTY_HEADERS = new HeadersRequestCondition();
|
||||
|
||||
private static final ConsumesRequestCondition EMPTY_CONSUMES = new ConsumesRequestCondition();
|
||||
|
||||
private static final ProducesRequestCondition EMPTY_PRODUCES = new ProducesRequestCondition();
|
||||
|
||||
|
||||
@Nullable
|
||||
private final String name;
|
||||
|
||||
|
@ -80,12 +94,12 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
|
|||
@Nullable ProducesRequestCondition produces, @Nullable RequestCondition<?> custom) {
|
||||
|
||||
this.name = (StringUtils.hasText(name) ? name : null);
|
||||
this.patternsCondition = (patterns != null ? patterns : new PatternsRequestCondition());
|
||||
this.methodsCondition = (methods != null ? methods : new RequestMethodsRequestCondition());
|
||||
this.paramsCondition = (params != null ? params : new ParamsRequestCondition());
|
||||
this.headersCondition = (headers != null ? headers : new HeadersRequestCondition());
|
||||
this.consumesCondition = (consumes != null ? consumes : new ConsumesRequestCondition());
|
||||
this.producesCondition = (produces != null ? produces : new ProducesRequestCondition());
|
||||
this.patternsCondition = (patterns != null ? patterns : EMPTY_PATTERNS);
|
||||
this.methodsCondition = (methods != null ? methods : EMPTY_REQUEST_METHODS);
|
||||
this.paramsCondition = (params != null ? params : EMPTY_PARAMS);
|
||||
this.headersCondition = (headers != null ? headers : EMPTY_HEADERS);
|
||||
this.consumesCondition = (consumes != null ? consumes : EMPTY_CONSUMES);
|
||||
this.producesCondition = (produces != null ? produces : EMPTY_PRODUCES);
|
||||
this.customConditionHolder = new RequestConditionHolder(custom);
|
||||
}
|
||||
|
||||
|
@ -427,7 +441,7 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
|
|||
|
||||
private static class DefaultBuilder implements Builder {
|
||||
|
||||
private String[] paths = new String[0];
|
||||
private String[] paths;
|
||||
|
||||
private RequestMethod[] methods = new RequestMethod[0];
|
||||
|
||||
|
@ -439,6 +453,10 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
|
|||
|
||||
private String[] produces = new String[0];
|
||||
|
||||
private boolean hasContentType;
|
||||
|
||||
private boolean hasAccept;
|
||||
|
||||
@Nullable
|
||||
private String mappingName;
|
||||
|
||||
|
@ -471,6 +489,12 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
|
|||
|
||||
@Override
|
||||
public DefaultBuilder headers(String... headers) {
|
||||
for (String header : headers) {
|
||||
this.hasContentType = this.hasContentType ||
|
||||
header.contains("Content-Type") || header.contains("content-type");
|
||||
this.hasAccept = this.hasAccept ||
|
||||
header.contains("Accept") || header.contains("accept");
|
||||
}
|
||||
this.headers = headers;
|
||||
return this;
|
||||
}
|
||||
|
@ -508,19 +532,26 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
|
|||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public RequestMappingInfo build() {
|
||||
|
||||
PatternsRequestCondition patternsCondition = ObjectUtils.isEmpty(this.paths) ? null :
|
||||
new PatternsRequestCondition(
|
||||
this.paths, this.options.getUrlPathHelper(), this.options.getPathMatcher(),
|
||||
this.options.useSuffixPatternMatch(), this.options.useTrailingSlashMatch(),
|
||||
this.options.getFileExtensions());
|
||||
|
||||
ContentNegotiationManager manager = this.options.getContentNegotiationManager();
|
||||
|
||||
PatternsRequestCondition patternsCondition = new PatternsRequestCondition(
|
||||
this.paths, this.options.getUrlPathHelper(), this.options.getPathMatcher(),
|
||||
this.options.useSuffixPatternMatch(), this.options.useTrailingSlashMatch(),
|
||||
this.options.getFileExtensions());
|
||||
|
||||
return new RequestMappingInfo(this.mappingName, patternsCondition,
|
||||
new RequestMethodsRequestCondition(this.methods),
|
||||
new ParamsRequestCondition(this.params),
|
||||
new HeadersRequestCondition(this.headers),
|
||||
new ConsumesRequestCondition(this.consumes, this.headers),
|
||||
new ProducesRequestCondition(this.produces, this.headers, manager),
|
||||
ObjectUtils.isEmpty(this.methods) ?
|
||||
null : new RequestMethodsRequestCondition(this.methods),
|
||||
ObjectUtils.isEmpty(this.params) ?
|
||||
null : new ParamsRequestCondition(this.params),
|
||||
ObjectUtils.isEmpty(this.headers) ?
|
||||
null : new HeadersRequestCondition(this.headers),
|
||||
ObjectUtils.isEmpty(this.consumes) && !this.hasContentType ?
|
||||
null : new ConsumesRequestCondition(this.consumes, this.headers),
|
||||
ObjectUtils.isEmpty(this.produces) && !this.hasAccept ?
|
||||
null : new ProducesRequestCondition(this.produces, this.headers, manager),
|
||||
this.customCondition);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -17,7 +17,7 @@
|
|||
package org.springframework.web.servlet.mvc.condition;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
|
@ -48,8 +48,10 @@ public class PatternsRequestConditionTests {
|
|||
public void combineEmptySets() {
|
||||
PatternsRequestCondition c1 = new PatternsRequestCondition();
|
||||
PatternsRequestCondition c2 = new PatternsRequestCondition();
|
||||
PatternsRequestCondition c3 = c1.combine(c2);
|
||||
|
||||
assertThat(c1.combine(c2)).isEqualTo(new PatternsRequestCondition(""));
|
||||
assertThat(c3).isSameAs(c1);
|
||||
assertThat(c1.getPatterns()).isSameAs(c2.getPatterns()).containsExactly("");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -118,9 +120,8 @@ public class PatternsRequestConditionTests {
|
|||
|
||||
@Test // SPR-8410
|
||||
public void matchSuffixPatternUsingFileExtensions() {
|
||||
String[] patterns = new String[] {"/jobs/{jobName}"};
|
||||
List<String> extensions = Arrays.asList("json");
|
||||
PatternsRequestCondition condition = new PatternsRequestCondition(patterns, null, null, true, false, extensions);
|
||||
PatternsRequestCondition condition = new PatternsRequestCondition(
|
||||
new String[] {"/jobs/{jobName}"}, null, null, true, false, Collections.singletonList("json"));
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/jobs/my.job");
|
||||
PatternsRequestCondition match = condition.getMatchingCondition(request);
|
||||
|
@ -165,9 +166,11 @@ public class PatternsRequestConditionTests {
|
|||
match = condition.getMatchingCondition(request);
|
||||
|
||||
assertThat(match).isNotNull();
|
||||
assertThat(match.getPatterns().iterator().next()).as("Trailing slash should be insensitive to useSuffixPatternMatch settings (SPR-6164, SPR-5636)").isEqualTo("/foo/");
|
||||
assertThat(match.getPatterns().iterator().next())
|
||||
.as("Trailing slash should be insensitive to useSuffixPatternMatch settings (SPR-6164, SPR-5636)")
|
||||
.isEqualTo("/foo/");
|
||||
|
||||
condition = new PatternsRequestCondition(new String[] {"/foo"}, null, null, false, false);
|
||||
condition = new PatternsRequestCondition(new String[] {"/foo"}, null, null, false);
|
||||
match = condition.getMatchingCondition(request);
|
||||
|
||||
assertThat(match).isNull();
|
||||
|
@ -175,8 +178,8 @@ public class PatternsRequestConditionTests {
|
|||
|
||||
@Test
|
||||
public void matchPatternContainsExtension() {
|
||||
PatternsRequestCondition condition = new PatternsRequestCondition("/foo.jpg");
|
||||
PatternsRequestCondition match = condition.getMatchingCondition(new MockHttpServletRequest("GET", "/foo.html"));
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo.html");
|
||||
PatternsRequestCondition match = new PatternsRequestCondition("/foo.jpg").getMatchingCondition(request);
|
||||
|
||||
assertThat(match).isNull();
|
||||
}
|
||||
|
@ -184,12 +187,10 @@ public class PatternsRequestConditionTests {
|
|||
@Test // gh-22543
|
||||
public void matchWithEmptyPatterns() {
|
||||
PatternsRequestCondition condition = new PatternsRequestCondition();
|
||||
assertThat(condition).isEqualTo(new PatternsRequestCondition(""));
|
||||
assertThat(condition.getMatchingCondition(new MockHttpServletRequest("GET", ""))).isNotNull();
|
||||
assertThat(condition.getMatchingCondition(new MockHttpServletRequest("GET", "/anything"))).isNull();
|
||||
|
||||
condition = condition.combine(new PatternsRequestCondition());
|
||||
assertThat(condition).isEqualTo(new PatternsRequestCondition(""));
|
||||
assertThat(condition.getMatchingCondition(new MockHttpServletRequest("GET", ""))).isNotNull();
|
||||
assertThat(condition.getMatchingCondition(new MockHttpServletRequest("GET", "/anything"))).isNull();
|
||||
}
|
||||
|
@ -211,7 +212,7 @@ public class PatternsRequestConditionTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void compareNumberOfMatchingPatterns() throws Exception {
|
||||
public void compareNumberOfMatchingPatterns() {
|
||||
HttpServletRequest request = new MockHttpServletRequest("GET", "/foo.html");
|
||||
|
||||
PatternsRequestCondition c1 = new PatternsRequestCondition("/foo", "*.jpeg");
|
||||
|
|
|
@ -44,16 +44,33 @@ public class RequestMappingInfoTests {
|
|||
|
||||
@Test
|
||||
public void createEmpty() {
|
||||
|
||||
RequestMappingInfo info = paths().build();
|
||||
|
||||
// gh-22543
|
||||
assertThat(info.getPatternsCondition().getPatterns()).isEqualTo(Collections.singleton(""));
|
||||
assertThat(info.getMethodsCondition().getMethods().size()).isEqualTo(0);
|
||||
assertThat(info.getConsumesCondition().isEmpty()).isEqualTo(true);
|
||||
assertThat(info.getProducesCondition().isEmpty()).isEqualTo(true);
|
||||
assertThat(info.getParamsCondition()).isNotNull();
|
||||
assertThat(info.getHeadersCondition()).isNotNull();
|
||||
assertThat(info.getConsumesCondition().isEmpty()).isEqualTo(true);
|
||||
assertThat(info.getProducesCondition().isEmpty()).isEqualTo(true);
|
||||
assertThat(info.getCustomCondition()).isNull();
|
||||
|
||||
RequestMappingInfo anotherInfo = paths().build();
|
||||
assertThat(info.getPatternsCondition()).isSameAs(anotherInfo.getPatternsCondition());
|
||||
assertThat(info.getMethodsCondition()).isSameAs(anotherInfo.getMethodsCondition());
|
||||
assertThat(info.getParamsCondition()).isSameAs(anotherInfo.getParamsCondition());
|
||||
assertThat(info.getHeadersCondition()).isSameAs(anotherInfo.getHeadersCondition());
|
||||
assertThat(info.getConsumesCondition()).isSameAs(anotherInfo.getConsumesCondition());
|
||||
assertThat(info.getProducesCondition()).isSameAs(anotherInfo.getProducesCondition());
|
||||
|
||||
RequestMappingInfo result = info.combine(anotherInfo);
|
||||
assertThat(info.getPatternsCondition()).isSameAs(result.getPatternsCondition());
|
||||
assertThat(info.getMethodsCondition()).isSameAs(result.getMethodsCondition());
|
||||
assertThat(info.getParamsCondition()).isSameAs(result.getParamsCondition());
|
||||
assertThat(info.getHeadersCondition()).isSameAs(result.getHeadersCondition());
|
||||
assertThat(info.getConsumesCondition()).isSameAs(result.getConsumesCondition());
|
||||
assertThat(info.getProducesCondition()).isSameAs(result.getProducesCondition());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue