RequestCondition implementations minor refactoring
Reduce object creation by pre-computing instances that can be re-used, and eliminating collection copying and sorting where not needed. See gh-22644
This commit is contained in:
parent
8f967129b9
commit
bb9fcad58a
|
|
@ -25,6 +25,8 @@ import java.util.Set;
|
|||
|
||||
import org.springframework.http.InvalidMediaTypeException;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.cors.reactive.CorsUtils;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
|
@ -68,15 +70,16 @@ public final class ConsumesRequestCondition extends AbstractRequestCondition<Con
|
|||
* @param headers as described in {@link RequestMapping#headers()}
|
||||
*/
|
||||
public ConsumesRequestCondition(String[] consumes, String[] headers) {
|
||||
this(parseExpressions(consumes, headers));
|
||||
this.expressions = new ArrayList<>(parseExpressions(consumes, headers));
|
||||
Collections.sort(this.expressions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor accepting parsed media type expressions.
|
||||
* Private constructor for internal when creating matching conditions.
|
||||
* Note the expressions List is neither sorted nor deep copied.
|
||||
*/
|
||||
private ConsumesRequestCondition(Collection<ConsumeMediaTypeExpression> expressions) {
|
||||
this.expressions = new ArrayList<>(expressions);
|
||||
Collections.sort(this.expressions);
|
||||
private ConsumesRequestCondition(List<ConsumeMediaTypeExpression> expressions) {
|
||||
this.expressions = expressions;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -166,9 +169,20 @@ public final class ConsumesRequestCondition extends AbstractRequestCondition<Con
|
|||
if (isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
Set<ConsumeMediaTypeExpression> result = new LinkedHashSet<>(this.expressions);
|
||||
result.removeIf(expression -> !expression.match(exchange));
|
||||
return (!result.isEmpty() ? new ConsumesRequestCondition(result) : null);
|
||||
List<ConsumeMediaTypeExpression> result = getMatchingExpressions(exchange);
|
||||
return !CollectionUtils.isEmpty(result) ? new ConsumesRequestCondition(result) : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private List<ConsumeMediaTypeExpression> getMatchingExpressions(ServerWebExchange exchange) {
|
||||
List<ConsumeMediaTypeExpression> result = null;
|
||||
for (ConsumeMediaTypeExpression expression : this.expressions) {
|
||||
if (expression.match(exchange)) {
|
||||
result = result != null ? result : new ArrayList<>();
|
||||
result.add(expression);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 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,6 @@
|
|||
package org.springframework.web.reactive.result.condition;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
|
|
@ -56,12 +55,12 @@ public final class HeadersRequestCondition extends AbstractRequestCondition<Head
|
|||
this(parseExpressions(headers));
|
||||
}
|
||||
|
||||
private HeadersRequestCondition(Collection<HeaderExpression> conditions) {
|
||||
this.expressions = Collections.unmodifiableSet(new LinkedHashSet<>(conditions));
|
||||
private HeadersRequestCondition(Set<HeaderExpression> conditions) {
|
||||
this.expressions = conditions;
|
||||
}
|
||||
|
||||
|
||||
private static Collection<HeaderExpression> parseExpressions(String... headers) {
|
||||
private static Set<HeaderExpression> parseExpressions(String... headers) {
|
||||
Set<HeaderExpression> expressions = new LinkedHashSet<>();
|
||||
if (headers != null) {
|
||||
for (String header : headers) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 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,6 @@
|
|||
package org.springframework.web.reactive.result.condition;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
|
|
@ -25,11 +24,11 @@ import java.util.Set;
|
|||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.accept.ContentNegotiationManager;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.cors.reactive.CorsUtils;
|
||||
import org.springframework.web.reactive.accept.HeaderContentTypeResolver;
|
||||
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
|
||||
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
|
||||
import org.springframework.web.server.NotAcceptableStatusException;
|
||||
|
|
@ -48,6 +47,9 @@ import org.springframework.web.server.UnsupportedMediaTypeStatusException;
|
|||
*/
|
||||
public final class ProducesRequestCondition extends AbstractRequestCondition<ProducesRequestCondition> {
|
||||
|
||||
private static final RequestedContentTypeResolver DEFAULT_CONTENT_TYPE_RESOLVER =
|
||||
new RequestedContentTypeResolverBuilder().build();
|
||||
|
||||
private static final ProducesRequestCondition EMPTY_CONDITION = new ProducesRequestCondition();
|
||||
|
||||
|
||||
|
|
@ -90,18 +92,16 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
|
|||
public ProducesRequestCondition(String[] produces, String[] headers, RequestedContentTypeResolver resolver) {
|
||||
this.expressions = new ArrayList<>(parseExpressions(produces, headers));
|
||||
Collections.sort(this.expressions);
|
||||
this.contentTypeResolver = (resolver != null ? resolver : new HeaderContentTypeResolver());
|
||||
this.contentTypeResolver = resolver != null ? resolver : DEFAULT_CONTENT_TYPE_RESOLVER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor with already parsed media type expressions.
|
||||
* Private constructor for internal use to create matching conditions.
|
||||
* Note the expressions List is neither sorted, nor deep copied.
|
||||
*/
|
||||
private ProducesRequestCondition(Collection<ProduceMediaTypeExpression> expressions,
|
||||
RequestedContentTypeResolver resolver) {
|
||||
|
||||
this.expressions = new ArrayList<>(expressions);
|
||||
Collections.sort(this.expressions);
|
||||
this.contentTypeResolver = (resolver != null ? resolver : new RequestedContentTypeResolverBuilder().build());
|
||||
private ProducesRequestCondition(List<ProduceMediaTypeExpression> expressions, ProducesRequestCondition other) {
|
||||
this.expressions = expressions;
|
||||
this.contentTypeResolver = other.contentTypeResolver;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -189,10 +189,9 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
|
|||
if (isEmpty() || CorsUtils.isPreFlightRequest(exchange.getRequest())) {
|
||||
return EMPTY_CONDITION;
|
||||
}
|
||||
Set<ProduceMediaTypeExpression> result = new LinkedHashSet<>(this.expressions);
|
||||
result.removeIf(expression -> !expression.match(exchange));
|
||||
if (!result.isEmpty()) {
|
||||
return new ProducesRequestCondition(result, this.contentTypeResolver);
|
||||
List<ProduceMediaTypeExpression> result = getMatchingExpressions(exchange);
|
||||
if (!CollectionUtils.isEmpty(result)) {
|
||||
return new ProducesRequestCondition(result, this);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
|
|
@ -207,6 +206,18 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
|
|||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private List<ProduceMediaTypeExpression> getMatchingExpressions(ServerWebExchange exchange) {
|
||||
List<ProduceMediaTypeExpression> result = null;
|
||||
for (ProduceMediaTypeExpression expression : this.expressions) {
|
||||
if (expression.match(exchange)) {
|
||||
result = result != null ? result : new ArrayList<>();
|
||||
result.add(expression);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this and another "produces" condition as follows:
|
||||
* <ol>
|
||||
|
|
|
|||
|
|
@ -19,8 +19,10 @@ package org.springframework.web.reactive.result.condition;
|
|||
import java.util.Arrays;
|
||||
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;
|
||||
|
|
@ -39,8 +41,15 @@ import org.springframework.web.server.ServerWebExchange;
|
|||
*/
|
||||
public final class RequestMethodsRequestCondition extends AbstractRequestCondition<RequestMethodsRequestCondition> {
|
||||
|
||||
private static final RequestMethodsRequestCondition GET_CONDITION =
|
||||
new RequestMethodsRequestCondition(RequestMethod.GET);
|
||||
/** Per HTTP method cache to return ready instances from getMatchingCondition. */
|
||||
private static final Map<String, RequestMethodsRequestCondition> requestMethodConditionCache;
|
||||
|
||||
static {
|
||||
requestMethodConditionCache = new HashMap<>(RequestMethod.values().length);
|
||||
for (RequestMethod method : RequestMethod.values()) {
|
||||
requestMethodConditionCache.put(method.name(), new RequestMethodsRequestCondition(method));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final Set<RequestMethod> methods;
|
||||
|
|
@ -110,11 +119,11 @@ public final class RequestMethodsRequestCondition extends AbstractRequestConditi
|
|||
}
|
||||
if (getMethods().isEmpty()) {
|
||||
if (RequestMethod.OPTIONS.name().equals(exchange.getRequest().getMethodValue())) {
|
||||
return null; // No implicit match for OPTIONS (we handle it)
|
||||
return null; // We handle OPTIONS transparently, so don't match if no explicit declarations
|
||||
}
|
||||
return this;
|
||||
}
|
||||
return matchRequestMethod(exchange.getRequest().getMethod());
|
||||
return matchRequestMethod(exchange.getRequest().getMethodValue());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -122,24 +131,25 @@ public final class RequestMethodsRequestCondition extends AbstractRequestConditi
|
|||
* Hence empty conditions is a match, otherwise try to match to the HTTP
|
||||
* method in the "Access-Control-Request-Method" header.
|
||||
*/
|
||||
@Nullable
|
||||
private RequestMethodsRequestCondition matchPreFlight(ServerHttpRequest request) {
|
||||
if (getMethods().isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
HttpMethod expectedMethod = request.getHeaders().getAccessControlRequestMethod();
|
||||
return matchRequestMethod(expectedMethod);
|
||||
return expectedMethod != null ? matchRequestMethod(expectedMethod.name()) : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private RequestMethodsRequestCondition matchRequestMethod(@Nullable HttpMethod httpMethod) {
|
||||
private RequestMethodsRequestCondition matchRequestMethod(@Nullable String httpMethod) {
|
||||
if (httpMethod != null) {
|
||||
for (RequestMethod method : getMethods()) {
|
||||
if (httpMethod.matches(method.name())) {
|
||||
return new RequestMethodsRequestCondition(method);
|
||||
return requestMethodConditionCache.get(method.name());
|
||||
}
|
||||
}
|
||||
if (httpMethod == HttpMethod.HEAD && getMethods().contains(RequestMethod.GET)) {
|
||||
return GET_CONDITION;
|
||||
if (HttpMethod.HEAD.matches(httpMethod) && getMethods().contains(RequestMethod.GET)) {
|
||||
return requestMethodConditionCache.get(HttpMethod.GET.name());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ abstract class AbstractNameValueExpression<T> implements NameValueExpression<T>
|
|||
else {
|
||||
isMatch = matchName(request);
|
||||
}
|
||||
return (this.isNegated ? !isMatch : isMatch);
|
||||
return this.isNegated != isMatch;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import org.springframework.http.InvalidMediaTypeException;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.cors.CorsUtils;
|
||||
|
|
@ -70,15 +71,16 @@ public final class ConsumesRequestCondition extends AbstractRequestCondition<Con
|
|||
* @param headers as described in {@link RequestMapping#headers()}
|
||||
*/
|
||||
public ConsumesRequestCondition(String[] consumes, @Nullable String[] headers) {
|
||||
this(parseExpressions(consumes, headers));
|
||||
this.expressions = new ArrayList<>(parseExpressions(consumes, headers));
|
||||
Collections.sort(this.expressions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor accepting parsed media type expressions.
|
||||
* Private constructor for internal when creating matching conditions.
|
||||
* Note the expressions List is neither sorted nor deep copied.
|
||||
*/
|
||||
private ConsumesRequestCondition(Collection<ConsumeMediaTypeExpression> expressions) {
|
||||
this.expressions = new ArrayList<>(expressions);
|
||||
Collections.sort(this.expressions);
|
||||
private ConsumesRequestCondition(List<ConsumeMediaTypeExpression> expressions) {
|
||||
this.expressions = expressions;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -179,9 +181,20 @@ public final class ConsumesRequestCondition extends AbstractRequestCondition<Con
|
|||
return null;
|
||||
}
|
||||
|
||||
Set<ConsumeMediaTypeExpression> result = new LinkedHashSet<>(this.expressions);
|
||||
result.removeIf(expression -> !expression.match(contentType));
|
||||
return (!result.isEmpty() ? new ConsumesRequestCondition(result) : null);
|
||||
List<ConsumeMediaTypeExpression> result = getMatchingExpressions(contentType);
|
||||
return !CollectionUtils.isEmpty(result) ? new ConsumesRequestCondition(result) : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private List<ConsumeMediaTypeExpression> getMatchingExpressions(MediaType contentType) {
|
||||
List<ConsumeMediaTypeExpression> result = null;
|
||||
for (ConsumeMediaTypeExpression expression : this.expressions) {
|
||||
if (expression.match(contentType)) {
|
||||
result = result != null ? result : new ArrayList<>();
|
||||
result.add(expression);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 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,6 @@
|
|||
package org.springframework.web.servlet.mvc.condition;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
|
@ -58,12 +57,12 @@ public final class HeadersRequestCondition extends AbstractRequestCondition<Head
|
|||
this(parseExpressions(headers));
|
||||
}
|
||||
|
||||
private HeadersRequestCondition(Collection<HeaderExpression> conditions) {
|
||||
this.expressions = Collections.unmodifiableSet(new LinkedHashSet<>(conditions));
|
||||
private HeadersRequestCondition(Set<HeaderExpression> conditions) {
|
||||
this.expressions = conditions;
|
||||
}
|
||||
|
||||
|
||||
private static Collection<HeaderExpression> parseExpressions(String... headers) {
|
||||
private static Set<HeaderExpression> parseExpressions(String... headers) {
|
||||
Set<HeaderExpression> expressions = new LinkedHashSet<>();
|
||||
for (String header : headers) {
|
||||
HeaderExpression expr = new HeaderExpression(header);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 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.
|
||||
|
|
@ -18,6 +18,7 @@ package org.springframework.web.servlet.mvc.condition;
|
|||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
|
@ -142,8 +143,15 @@ public final class ParamsRequestCondition extends AbstractRequestCondition<Param
|
|||
*/
|
||||
static class ParamExpression extends AbstractNameValueExpression<String> {
|
||||
|
||||
private final Set<String> namesToMatch = new HashSet<>(WebUtils.SUBMIT_IMAGE_SUFFIXES.length + 1);
|
||||
|
||||
|
||||
ParamExpression(String expression) {
|
||||
super(expression);
|
||||
this.namesToMatch.add(getName());
|
||||
for (String suffix : WebUtils.SUBMIT_IMAGE_SUFFIXES) {
|
||||
this.namesToMatch.add(getName() + suffix);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -158,8 +166,12 @@ public final class ParamsRequestCondition extends AbstractRequestCondition<Param
|
|||
|
||||
@Override
|
||||
protected boolean matchName(HttpServletRequest request) {
|
||||
return (WebUtils.hasSubmitParameter(request, this.name) ||
|
||||
request.getParameterMap().containsKey(this.name));
|
||||
for (String current : this.namesToMatch) {
|
||||
if (request.getParameterMap().get(current) != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return request.getParameterMap().containsKey(this.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -105,8 +105,8 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
|
|||
boolean useTrailingSlashMatch, @Nullable List<String> fileExtensions) {
|
||||
|
||||
this.patterns = Collections.unmodifiableSet(prependLeadingSlash(patterns));
|
||||
this.pathHelper = (urlPathHelper != null ? urlPathHelper : new UrlPathHelper());
|
||||
this.pathMatcher = (pathMatcher != null ? pathMatcher : new AntPathMatcher());
|
||||
this.pathHelper = urlPathHelper != null ? urlPathHelper : new UrlPathHelper();
|
||||
this.pathMatcher = pathMatcher != null ? pathMatcher : new AntPathMatcher();
|
||||
this.useSuffixPatternMatch = useSuffixPatternMatch;
|
||||
this.useTrailingSlashMatch = useTrailingSlashMatch;
|
||||
|
||||
|
|
@ -120,6 +120,18 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor for use when combining and matching.
|
||||
*/
|
||||
private PatternsRequestCondition(Set<String> patterns, PatternsRequestCondition other) {
|
||||
this.patterns = patterns;
|
||||
this.pathHelper = other.pathHelper;
|
||||
this.pathMatcher = other.pathMatcher;
|
||||
this.useSuffixPatternMatch = other.useSuffixPatternMatch;
|
||||
this.useTrailingSlashMatch = other.useTrailingSlashMatch;
|
||||
this.fileExtensions.addAll(other.fileExtensions);
|
||||
}
|
||||
|
||||
|
||||
private static Set<String> prependLeadingSlash(Collection<String> patterns) {
|
||||
Set<String> result = new LinkedHashSet<>(patterns.size());
|
||||
|
|
@ -175,8 +187,7 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
|
|||
else {
|
||||
result.add("");
|
||||
}
|
||||
return new PatternsRequestCondition(result, this.pathHelper, this.pathMatcher,
|
||||
this.useSuffixPatternMatch, this.useTrailingSlashMatch, this.fileExtensions);
|
||||
return new PatternsRequestCondition(result, this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -203,28 +214,29 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
|
|||
}
|
||||
String lookupPath = this.pathHelper.getLookupPathForRequest(request);
|
||||
List<String> matches = getMatchingPatterns(lookupPath);
|
||||
return (!matches.isEmpty() ?
|
||||
new PatternsRequestCondition(matches, this.pathHelper, this.pathMatcher,
|
||||
this.useSuffixPatternMatch, this.useTrailingSlashMatch, this.fileExtensions) : null);
|
||||
return !matches.isEmpty() ? new PatternsRequestCondition(new LinkedHashSet<>(matches), this) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the patterns matching the given lookup path. Invoking this method should
|
||||
* yield results equivalent to those of calling
|
||||
* {@link #getMatchingCondition(javax.servlet.http.HttpServletRequest)}.
|
||||
* yield results equivalent to those of calling {@link #getMatchingCondition}.
|
||||
* This method is provided as an alternative to be used if no request is available
|
||||
* (e.g. introspection, tooling, etc).
|
||||
* @param lookupPath the lookup path to match to existing patterns
|
||||
* @return a collection of matching patterns sorted with the closest match at the top
|
||||
*/
|
||||
public List<String> getMatchingPatterns(String lookupPath) {
|
||||
List<String> matches = new ArrayList<>();
|
||||
List<String> matches = null;
|
||||
for (String pattern : this.patterns) {
|
||||
String match = getMatchingPattern(pattern, lookupPath);
|
||||
if (match != null) {
|
||||
matches = matches != null ? matches : new ArrayList<>();
|
||||
matches.add(match);
|
||||
}
|
||||
}
|
||||
if (matches == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if (matches.size() > 1) {
|
||||
matches.sort(this.pathMatcher.getPatternComparator(lookupPath));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
package org.springframework.web.servlet.mvc.condition;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
|
|
@ -26,6 +25,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.StringUtils;
|
||||
import org.springframework.web.HttpMediaTypeException;
|
||||
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||
|
|
@ -48,6 +48,9 @@ import org.springframework.web.servlet.mvc.condition.HeadersRequestCondition.Hea
|
|||
*/
|
||||
public final class ProducesRequestCondition extends AbstractRequestCondition<ProducesRequestCondition> {
|
||||
|
||||
private static final ContentNegotiationManager DEFAULT_CONTENT_NEGOTIATION_MANAGER =
|
||||
new ContentNegotiationManager();
|
||||
|
||||
private static final ProducesRequestCondition EMPTY_CONDITION = new ProducesRequestCondition();
|
||||
|
||||
private static final List<ProduceMediaTypeExpression> MEDIA_TYPE_ALL_LIST =
|
||||
|
|
@ -92,18 +95,16 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
|
|||
|
||||
this.expressions = new ArrayList<>(parseExpressions(produces, headers));
|
||||
Collections.sort(this.expressions);
|
||||
this.contentNegotiationManager = (manager != null ? manager : new ContentNegotiationManager());
|
||||
this.contentNegotiationManager = manager != null ? manager : DEFAULT_CONTENT_NEGOTIATION_MANAGER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor with already parsed media type expressions.
|
||||
* Private constructor for internal use to create matching conditions.
|
||||
* Note the expressions List is neither sorted nor deep copied.
|
||||
*/
|
||||
private ProducesRequestCondition(Collection<ProduceMediaTypeExpression> expressions,
|
||||
@Nullable ContentNegotiationManager manager) {
|
||||
|
||||
this.expressions = new ArrayList<>(expressions);
|
||||
Collections.sort(this.expressions);
|
||||
this.contentNegotiationManager = (manager != null ? manager : new ContentNegotiationManager());
|
||||
private ProducesRequestCondition(List<ProduceMediaTypeExpression> expressions, ProducesRequestCondition other) {
|
||||
this.expressions = expressions;
|
||||
this.contentNegotiationManager = other.contentNegotiationManager;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -198,10 +199,9 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
|
|||
return null;
|
||||
}
|
||||
|
||||
Set<ProduceMediaTypeExpression> result = new LinkedHashSet<>(this.expressions);
|
||||
result.removeIf(expression -> !expression.match(acceptedMediaTypes));
|
||||
if (!result.isEmpty()) {
|
||||
return new ProducesRequestCondition(result, this.contentNegotiationManager);
|
||||
List<ProduceMediaTypeExpression> result = getMatchingExpressions(acceptedMediaTypes);
|
||||
if (!CollectionUtils.isEmpty(result)) {
|
||||
return new ProducesRequestCondition(result, this);
|
||||
}
|
||||
else if (MediaType.ALL.isPresentIn(acceptedMediaTypes)) {
|
||||
return EMPTY_CONDITION;
|
||||
|
|
@ -211,6 +211,18 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
|
|||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private List<ProduceMediaTypeExpression> getMatchingExpressions(List<MediaType> acceptedMediaTypes) {
|
||||
List<ProduceMediaTypeExpression> result = null;
|
||||
for (ProduceMediaTypeExpression expression : this.expressions) {
|
||||
if (expression.match(acceptedMediaTypes)) {
|
||||
result = result != null ? result : new ArrayList<>();
|
||||
result.add(expression);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this and another "produces" condition as follows:
|
||||
* <ol>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 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.
|
||||
|
|
@ -19,7 +19,9 @@ package org.springframework.web.servlet.mvc.condition;
|
|||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
|
@ -40,8 +42,16 @@ import org.springframework.web.cors.CorsUtils;
|
|||
*/
|
||||
public final class RequestMethodsRequestCondition extends AbstractRequestCondition<RequestMethodsRequestCondition> {
|
||||
|
||||
private static final RequestMethodsRequestCondition GET_CONDITION =
|
||||
new RequestMethodsRequestCondition(RequestMethod.GET);
|
||||
/** Per HTTP method cache to return ready instances from getMatchingCondition. */
|
||||
private static final Map<String, RequestMethodsRequestCondition> requestMethodConditionCache;
|
||||
|
||||
static {
|
||||
requestMethodConditionCache = new HashMap<>(RequestMethod.values().length);
|
||||
for (RequestMethod method : RequestMethod.values()) {
|
||||
requestMethodConditionCache.put(method.name(), new RequestMethodsRequestCondition(method));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final Set<RequestMethod> methods;
|
||||
|
||||
|
|
@ -108,7 +118,7 @@ public final class RequestMethodsRequestCondition extends AbstractRequestConditi
|
|||
if (RequestMethod.OPTIONS.name().equals(request.getMethod()) &&
|
||||
!DispatcherType.ERROR.equals(request.getDispatcherType())) {
|
||||
|
||||
return null; // No implicit match for OPTIONS (we handle it)
|
||||
return null; // We handle OPTIONS transparently, so don't match if no explicit declarations
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
|
@ -136,11 +146,11 @@ public final class RequestMethodsRequestCondition extends AbstractRequestConditi
|
|||
if (httpMethod != null) {
|
||||
for (RequestMethod method : getMethods()) {
|
||||
if (httpMethod.matches(method.name())) {
|
||||
return new RequestMethodsRequestCondition(method);
|
||||
return requestMethodConditionCache.get(method.name());
|
||||
}
|
||||
}
|
||||
if (httpMethod == HttpMethod.HEAD && getMethods().contains(RequestMethod.GET)) {
|
||||
return GET_CONDITION;
|
||||
return requestMethodConditionCache.get(HttpMethod.GET.name());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
|
|
|||
Loading…
Reference in New Issue