SPR-7812 Add CustomRequestCondition
This commit is contained in:
@@ -257,14 +257,14 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||
List<Match> matches = new ArrayList<Match>();
|
||||
|
||||
for (T mapping : mappings) {
|
||||
T match = getMatchingMapping(mapping, lookupPath, request);
|
||||
T match = getMatchingMapping(mapping, request);
|
||||
if (match != null) {
|
||||
matches.add(new Match(match, handlerMethods.get(mapping)));
|
||||
}
|
||||
}
|
||||
|
||||
if (!matches.isEmpty()) {
|
||||
Comparator<Match> comparator = new MatchComparator(getMappingComparator(lookupPath, request));
|
||||
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
|
||||
Collections.sort(matches, comparator);
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
@@ -309,20 +309,18 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||
* will contain only 1).
|
||||
*
|
||||
* @param mapping the mapping to get a match for
|
||||
* @param lookupPath mapping lookup path within the current servlet mapping if applicable
|
||||
* @param request the current HTTP servlet request
|
||||
* @return a matching mapping, or {@code null} if the given mapping does not match the request
|
||||
*/
|
||||
protected abstract T getMatchingMapping(T mapping, String lookupPath, HttpServletRequest request);
|
||||
protected abstract T getMatchingMapping(T mapping, HttpServletRequest request);
|
||||
|
||||
/**
|
||||
* Returns a comparator to sort request mappings with. The returned comparator should sort 'better' matches higher.
|
||||
*
|
||||
* @param lookupPath mapping lookup path within the current servlet mapping if applicable
|
||||
* @param request the current HTTP servlet request
|
||||
* @return the comparator
|
||||
*/
|
||||
protected abstract Comparator<T> getMappingComparator(String lookupPath, HttpServletRequest request);
|
||||
protected abstract Comparator<T> getMappingComparator(HttpServletRequest request);
|
||||
|
||||
/**
|
||||
* Invoked when no match was found. Default implementation returns {@code null}.
|
||||
|
||||
@@ -18,17 +18,29 @@ package org.springframework.web.servlet.mvc.method;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.servlet.mvc.method.condition.ConsumesRequestCondition;
|
||||
import org.springframework.web.servlet.mvc.method.condition.CustomRequestCondition;
|
||||
import org.springframework.web.servlet.mvc.method.condition.HeadersRequestCondition;
|
||||
import org.springframework.web.servlet.mvc.method.condition.ParamsRequestCondition;
|
||||
import org.springframework.web.servlet.mvc.method.condition.PatternsRequestCondition;
|
||||
import org.springframework.web.servlet.mvc.method.condition.ProducesRequestCondition;
|
||||
import org.springframework.web.servlet.mvc.method.condition.RequestCondition;
|
||||
import org.springframework.web.servlet.mvc.method.condition.RequestMethodsRequestCondition;
|
||||
|
||||
/**
|
||||
* Contains request mapping conditions to be matched to a given request.
|
||||
* A RequestMapingInfo encapsulates and operates on the following request mapping conditions:
|
||||
* <ul>
|
||||
* <li>{@link PatternsRequestCondition}</li>
|
||||
* <li>{@link RequestMethodsRequestCondition}</li>
|
||||
* <li>{@link ParamsRequestCondition}</li>
|
||||
* <li>{@link HeadersRequestCondition}</li>
|
||||
* <li>{@link ConsumesRequestCondition}</li>
|
||||
* <li>{@link ProducesRequestCondition}</li>
|
||||
* </ul>
|
||||
*
|
||||
* Optionally a custom request condition may also be provided by wrapping it in an instance
|
||||
* of {@link CustomRequestCondition}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
@@ -47,129 +59,182 @@ public final class RequestMappingInfo {
|
||||
private final ConsumesRequestCondition consumesCondition;
|
||||
|
||||
private final ProducesRequestCondition producesCondition;
|
||||
|
||||
private CustomRequestCondition customCondition = new CustomRequestCondition();
|
||||
|
||||
private int hash;
|
||||
|
||||
/**
|
||||
* Creates a new {@code RequestMappingInfo} instance.
|
||||
*/
|
||||
public RequestMappingInfo(PatternsRequestCondition patternsCondition,
|
||||
RequestMethodsRequestCondition methodsCondition,
|
||||
ParamsRequestCondition paramsCondition,
|
||||
HeadersRequestCondition headersCondition,
|
||||
ConsumesRequestCondition consumesCondition,
|
||||
ProducesRequestCondition producesCondition) {
|
||||
this.patternsCondition = patternsCondition != null ? patternsCondition : new PatternsRequestCondition();
|
||||
this.methodsCondition = methodsCondition != null ? methodsCondition : new RequestMethodsRequestCondition();
|
||||
this.paramsCondition = paramsCondition != null ? paramsCondition : new ParamsRequestCondition();
|
||||
this.headersCondition = headersCondition != null ? headersCondition : new HeadersRequestCondition();
|
||||
this.consumesCondition = consumesCondition != null ? consumesCondition : new ConsumesRequestCondition();
|
||||
this.producesCondition = producesCondition != null ? producesCondition : new ProducesRequestCondition();
|
||||
public RequestMappingInfo(PatternsRequestCondition patterns,
|
||||
RequestMethodsRequestCondition methods,
|
||||
ParamsRequestCondition params,
|
||||
HeadersRequestCondition headers,
|
||||
ConsumesRequestCondition consumes,
|
||||
ProducesRequestCondition produces) {
|
||||
this(patterns, methods, params, headers, consumes, produces, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Package protected, used for testing.
|
||||
* Creates a new {@code RequestMappingInfo} instance also providing a custom {@link RequestCondition}.
|
||||
*/
|
||||
public RequestMappingInfo(PatternsRequestCondition patterns,
|
||||
RequestMethodsRequestCondition methods,
|
||||
ParamsRequestCondition params,
|
||||
HeadersRequestCondition headers,
|
||||
ConsumesRequestCondition consumes,
|
||||
ProducesRequestCondition produces,
|
||||
CustomRequestCondition custom) {
|
||||
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.customCondition = custom != null ? custom : new CustomRequestCondition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Package protected constructor for tests.
|
||||
*/
|
||||
RequestMappingInfo(String[] patterns, RequestMethod... methods) {
|
||||
this(new PatternsRequestCondition(patterns), new RequestMethodsRequestCondition(methods), null, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the patterns of this request mapping info.
|
||||
* Returns the URL patterns of this request mapping info.
|
||||
*/
|
||||
public PatternsRequestCondition getPatternsCondition() {
|
||||
return patternsCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request method condition of this request mapping info.
|
||||
* Returns the HTTP request methods of this {@link RequestMappingInfo}.
|
||||
*/
|
||||
public RequestMethodsRequestCondition getMethodsCondition() {
|
||||
return methodsCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request parameters condition of this request mapping info.
|
||||
* Returns the "parameters" condition of this {@link RequestMappingInfo}.
|
||||
*/
|
||||
public ParamsRequestCondition getParamsCondition() {
|
||||
return paramsCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request headers condition of this request mapping info.
|
||||
* Returns the "headers" condition of this {@link RequestMappingInfo}.
|
||||
*/
|
||||
public HeadersRequestCondition getHeadersCondition() {
|
||||
return headersCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request consumes condition of this request mapping info.
|
||||
* Returns the "consumes" condition of this {@link RequestMappingInfo}.
|
||||
*/
|
||||
public ConsumesRequestCondition getConsumesCondition() {
|
||||
return consumesCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request produces condition of this request mapping info.
|
||||
* Returns the "produces" condition of this {@link RequestMappingInfo}.
|
||||
*/
|
||||
public ProducesRequestCondition getProducesCondition() {
|
||||
return producesCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines this {@code RequestMappingInfo} with another as follows:
|
||||
* <ul>
|
||||
* <li>URL patterns:
|
||||
* <ul>
|
||||
* <li>If both have patterns combine them according to the rules of the given {@link PathMatcher}
|
||||
* <li>If either contains patterns, but not both, use the available pattern
|
||||
* <li>If neither contains patterns use ""
|
||||
* </ul>
|
||||
* <li>HTTP methods are combined as union of all HTTP methods listed in both keys.
|
||||
* <li>Request parameters are combined as per {@link ParamsRequestCondition#combine(ParamsRequestCondition)}.
|
||||
* <li>Request headers are combined as per {@link HeadersRequestCondition#combine(HeadersRequestCondition)}.
|
||||
* <li>Consumes are combined as per {@link ConsumesRequestCondition#combine(ConsumesRequestCondition)}.
|
||||
* </ul>
|
||||
* @param methodKey the key to combine with
|
||||
* @return a new request mapping info containing conditions from both keys
|
||||
* Sets a custom request condition.
|
||||
*/
|
||||
public RequestMappingInfo combine(RequestMappingInfo methodKey) {
|
||||
PatternsRequestCondition patterns = this.patternsCondition.combine(methodKey.patternsCondition);
|
||||
RequestMethodsRequestCondition methods = this.methodsCondition.combine(methodKey.methodsCondition);
|
||||
ParamsRequestCondition params = this.paramsCondition.combine(methodKey.paramsCondition);
|
||||
HeadersRequestCondition headers = this.headersCondition.combine(methodKey.headersCondition);
|
||||
ConsumesRequestCondition consumes = this.consumesCondition.combine(methodKey.consumesCondition);
|
||||
ProducesRequestCondition produces = this.producesCondition.combine(methodKey.producesCondition);
|
||||
|
||||
return new RequestMappingInfo(patterns, methods, params, headers, consumes, produces);
|
||||
public void setCustomCondition(CustomRequestCondition customCondition) {
|
||||
this.customCondition = customCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@code RequestMappingInfo} with conditions relevant to the current request.
|
||||
* For example the list of URL path patterns is trimmed to contain the patterns that match the URL.
|
||||
* @param request the current request
|
||||
* @return a new request mapping info that contains all matching attributes, or {@code null} if not all conditions match
|
||||
* Combines "this" request mapping info (i.e. the current instance) with another request mapping info instance.
|
||||
* <p>Example: combine type- and method-level request mappings.
|
||||
* @return a new request mapping info instance; never {@code null}
|
||||
*/
|
||||
public RequestMappingInfo getMatchingRequestMapping(HttpServletRequest request) {
|
||||
RequestMethodsRequestCondition matchingMethod = methodsCondition.getMatchingCondition(request);
|
||||
ParamsRequestCondition matchingParams = paramsCondition.getMatchingCondition(request);
|
||||
HeadersRequestCondition matchingHeaders = headersCondition.getMatchingCondition(request);
|
||||
ConsumesRequestCondition matchingConsumes = consumesCondition.getMatchingCondition(request);
|
||||
ProducesRequestCondition matchingProduces = producesCondition.getMatchingCondition(request);
|
||||
public RequestMappingInfo combine(RequestMappingInfo other) {
|
||||
PatternsRequestCondition patterns = this.patternsCondition.combine(other.patternsCondition);
|
||||
RequestMethodsRequestCondition methods = this.methodsCondition.combine(other.methodsCondition);
|
||||
ParamsRequestCondition params = this.paramsCondition.combine(other.paramsCondition);
|
||||
HeadersRequestCondition headers = this.headersCondition.combine(other.headersCondition);
|
||||
ConsumesRequestCondition consumes = this.consumesCondition.combine(other.consumesCondition);
|
||||
ProducesRequestCondition produces = this.producesCondition.combine(other.producesCondition);
|
||||
CustomRequestCondition custom = this.customCondition.combine(other.customCondition);
|
||||
|
||||
if (matchingMethod == null || matchingParams == null || matchingHeaders == null ||
|
||||
matchingConsumes == null || matchingProduces == null) {
|
||||
return new RequestMappingInfo(patterns, methods, params, headers, consumes, produces, custom);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if all conditions in this request mapping info match the provided request and returns
|
||||
* a potentially new request mapping info with conditions tailored to the current request.
|
||||
* <p>For example the returned instance may contain the subset of URL patterns that match to
|
||||
* the current request, sorted with best matching patterns on top.
|
||||
* @return a new instance in case all conditions match; or {@code null} otherwise
|
||||
*/
|
||||
public RequestMappingInfo getMatchingRequestMappingInfo(HttpServletRequest request) {
|
||||
RequestMethodsRequestCondition methods = methodsCondition.getMatchingCondition(request);
|
||||
ParamsRequestCondition params = paramsCondition.getMatchingCondition(request);
|
||||
HeadersRequestCondition headers = headersCondition.getMatchingCondition(request);
|
||||
ConsumesRequestCondition consumes = consumesCondition.getMatchingCondition(request);
|
||||
ProducesRequestCondition produces = producesCondition.getMatchingCondition(request);
|
||||
|
||||
if (methods == null || params == null || headers == null || consumes == null || produces == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PatternsRequestCondition matchingPatterns = patternsCondition.getMatchingCondition(request);
|
||||
if (matchingPatterns != null) {
|
||||
return new RequestMappingInfo(matchingPatterns, matchingMethod,
|
||||
matchingParams, matchingHeaders, matchingConsumes,
|
||||
matchingProduces);
|
||||
PatternsRequestCondition patterns = patternsCondition.getMatchingCondition(request);
|
||||
if (patterns == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
CustomRequestCondition custom = customCondition.getMatchingCondition(request);
|
||||
if (custom == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new RequestMappingInfo(patterns, methods, params, headers, consumes, produces, custom);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares "this" info (i.e. the current instance) with another info in the context of a request.
|
||||
* <p>Note: it is assumed both instances have been obtained via
|
||||
* {@link #getMatchingRequestMappingInfo(HttpServletRequest)} to ensure they have conditions with
|
||||
* content relevant to current request.
|
||||
*/
|
||||
public int compareTo(RequestMappingInfo other, HttpServletRequest request) {
|
||||
int result = patternsCondition.compareTo(other.getPatternsCondition(), request);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
result = paramsCondition.compareTo(other.getParamsCondition(), request);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
result = headersCondition.compareTo(other.getHeadersCondition(), request);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
result = consumesCondition.compareTo(other.getConsumesCondition(), request);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
result = producesCondition.compareTo(other.getProducesCondition(), request);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
result = methodsCondition.compareTo(other.getMethodsCondition(), request);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
result = customCondition.compareTo(other.customCondition, request);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -184,7 +249,8 @@ public final class RequestMappingInfo {
|
||||
this.paramsCondition.equals(other.paramsCondition) &&
|
||||
this.headersCondition.equals(other.headersCondition) &&
|
||||
this.consumesCondition.equals(other.consumesCondition) &&
|
||||
this.producesCondition.equals(other.producesCondition));
|
||||
this.producesCondition.equals(other.producesCondition) &&
|
||||
this.customCondition.equals(other.customCondition));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -199,6 +265,7 @@ public final class RequestMappingInfo {
|
||||
result = 31 * result + headersCondition.hashCode();
|
||||
result = 31 * result + consumesCondition.hashCode();
|
||||
result = 31 * result + producesCondition.hashCode();
|
||||
result = 31 * result + customCondition.hashCode();
|
||||
hash = result;
|
||||
}
|
||||
return result;
|
||||
@@ -213,6 +280,7 @@ public final class RequestMappingInfo {
|
||||
builder.append(",headers=").append(headersCondition);
|
||||
builder.append(",consumes=").append(consumesCondition);
|
||||
builder.append(",produces=").append(producesCondition);
|
||||
builder.append(",custom=").append(customCondition);
|
||||
builder.append('}');
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||
import org.springframework.web.HttpMediaTypeNotSupportedException;
|
||||
@@ -53,34 +52,47 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
|
||||
while (mappings.size() > 1) {
|
||||
RequestMappingInfo mapping = mappings.remove(0);
|
||||
for (RequestMappingInfo otherMapping : mappings) {
|
||||
// further validate mapping conditions
|
||||
// TODO: further validate mapping conditions
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL paths associated with this {@link RequestMappingInfo}.
|
||||
*/
|
||||
@Override
|
||||
protected Set<String> getMappingPaths(RequestMappingInfo mapping) {
|
||||
return mapping.getPatternsCondition().getPatterns();
|
||||
Set<String> paths = new HashSet<String>();
|
||||
for (String pattern : mapping.getPatternsCondition().getPatterns()) {
|
||||
if (!getPathMatcher().isPattern(pattern)) {
|
||||
paths.add(pattern);
|
||||
}
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link RequestMappingInfo} with attributes matching to the current request or {@code null}.
|
||||
*
|
||||
* @see RequestMappingInfo#getMatchingRequestMapping(String, HttpServletRequest, PathMatcher)
|
||||
* Checks if the given RequestMappingInfo matches the current request and returns a potentially new
|
||||
* RequestMappingInfo instances tailored to the current request, for example containing the subset
|
||||
* of URL patterns or media types that match the request.
|
||||
*
|
||||
* @returns a RequestMappingInfo instance in case of a match; or {@code null} in case of no match.
|
||||
*/
|
||||
@Override
|
||||
protected RequestMappingInfo getMatchingMapping(RequestMappingInfo mapping,
|
||||
String lookupPath,
|
||||
HttpServletRequest request) {
|
||||
return mapping.getMatchingRequestMapping(request);
|
||||
protected RequestMappingInfo getMatchingMapping(RequestMappingInfo mapping, HttpServletRequest request) {
|
||||
return mapping.getMatchingRequestMappingInfo(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Comparator} that can be used to sort and select the best matching {@link RequestMappingInfo}.
|
||||
* Returns a {@link Comparator} for sorting {@link RequestMappingInfo} in the context of the given request.
|
||||
*/
|
||||
@Override
|
||||
protected Comparator<RequestMappingInfo> getMappingComparator(String lookupPath, HttpServletRequest request) {
|
||||
return new RequestMappingInfoComparator(request);
|
||||
protected Comparator<RequestMappingInfo> getMappingComparator(final HttpServletRequest request) {
|
||||
return new Comparator<RequestMappingInfo>() {
|
||||
public int compare(RequestMappingInfo info, RequestMappingInfo otherInfo) {
|
||||
return info.compareTo(otherInfo, request);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,30 +118,33 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
|
||||
/**
|
||||
* Iterates all {@link RequestMappingInfo}s looking for mappings that match by URL but not by HTTP method.
|
||||
*
|
||||
* @throws HttpRequestMethodNotSupportedException if there are matches by URL but not by HTTP method
|
||||
* @throws HttpRequestMethodNotSupportedException
|
||||
* if there are matches by URL but not by HTTP method
|
||||
* @throws HttpMediaTypeNotAcceptableException
|
||||
* if there are matches by URL but the consumable media types don't match the 'Content-Type' header
|
||||
* @throws HttpMediaTypeNotAcceptableException
|
||||
* if there are matches by URL but the producible media types don't match the 'Accept' header
|
||||
*/
|
||||
@Override
|
||||
protected HandlerMethod handleNoMatch(Set<RequestMappingInfo> requestMappingInfos,
|
||||
String lookupPath,
|
||||
protected HandlerMethod handleNoMatch(Set<RequestMappingInfo> requestMappingInfos,
|
||||
String lookupPath,
|
||||
HttpServletRequest request) throws ServletException {
|
||||
Set<String> allowedMethods = new HashSet<String>(6);
|
||||
Set<MediaType> consumableMediaTypes = new HashSet<MediaType>();
|
||||
Set<MediaType> producibleMediaTypes = new HashSet<MediaType>();
|
||||
for (RequestMappingInfo info : requestMappingInfos) {
|
||||
for (String pattern : info.getPatternsCondition().getPatterns()) {
|
||||
if (getPathMatcher().match(pattern, lookupPath)) {
|
||||
if (info.getMethodsCondition().getMatchingCondition(request) == null) {
|
||||
for (RequestMethod method : info.getMethodsCondition().getMethods()) {
|
||||
allowedMethods.add(method.name());
|
||||
}
|
||||
}
|
||||
if (info.getConsumesCondition().getMatchingCondition(request) == null) {
|
||||
consumableMediaTypes.addAll(info.getConsumesCondition().getMediaTypes());
|
||||
}
|
||||
if (info.getProducesCondition().getMatchingCondition(request) == null) {
|
||||
producibleMediaTypes.addAll(info.getProducesCondition().getMediaTypes());
|
||||
if (info.getPatternsCondition().getMatchingCondition(request) != null) {
|
||||
if (info.getMethodsCondition().getMatchingCondition(request) == null) {
|
||||
for (RequestMethod method : info.getMethodsCondition().getMethods()) {
|
||||
allowedMethods.add(method.name());
|
||||
}
|
||||
}
|
||||
if (info.getConsumesCondition().getMatchingCondition(request) == null) {
|
||||
consumableMediaTypes.addAll(info.getConsumesCondition().getMediaTypes());
|
||||
}
|
||||
if (info.getProducesCondition().getMatchingCondition(request) == null) {
|
||||
producibleMediaTypes.addAll(info.getProducesCondition().getMediaTypes());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!allowedMethods.isEmpty()) {
|
||||
@@ -150,45 +165,4 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A comparator for {@link RequestMappingInfo}s. Effective comparison can only be done in the context
|
||||
* of a specific request. For example only a subset of URL patterns may apply to the current request.
|
||||
*/
|
||||
private class RequestMappingInfoComparator implements Comparator<RequestMappingInfo> {
|
||||
|
||||
private final HttpServletRequest request;
|
||||
|
||||
public RequestMappingInfoComparator(HttpServletRequest request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
public int compare(RequestMappingInfo mapping, RequestMappingInfo otherMapping) {
|
||||
int result = mapping.getPatternsCondition().compareTo(otherMapping.getPatternsCondition(), request);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
result = mapping.getParamsCondition().compareTo(otherMapping.getParamsCondition(), request);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
result = mapping.getHeadersCondition().compareTo(otherMapping.getHeadersCondition(), request);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
result = mapping.getConsumesCondition().compareTo(otherMapping.getConsumesCondition(), request);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
result = mapping.getProducesCondition().compareTo(otherMapping.getProducesCondition(), request);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
result = mapping.getMethodsCondition().compareTo(otherMapping.getMethodsCondition(), request);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ import org.springframework.web.servlet.mvc.method.condition.RequestMethodsReques
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1.0
|
||||
* @since 3.1
|
||||
*/
|
||||
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping {
|
||||
|
||||
@@ -62,20 +62,18 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
|
||||
*/
|
||||
@Override
|
||||
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
|
||||
RequestMapping annotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
|
||||
if (annotation != null) {
|
||||
RequestMappingInfo methodMapping = createFromRequestMapping(annotation);
|
||||
RequestMapping typeAnnot = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
|
||||
if (typeAnnot != null) {
|
||||
RequestMappingInfo typeMapping = createFromRequestMapping(typeAnnot);
|
||||
return typeMapping.combine(methodMapping);
|
||||
}
|
||||
else {
|
||||
return methodMapping;
|
||||
}
|
||||
RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
|
||||
if (methodAnnotation == null) {
|
||||
return null;
|
||||
}
|
||||
RequestMappingInfo methodInfo = createFromRequestMapping(methodAnnotation);
|
||||
RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
|
||||
if (typeAnnotation != null) {
|
||||
RequestMappingInfo typeInfo = createFromRequestMapping(typeAnnotation);
|
||||
return typeInfo.combine(methodInfo);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
return methodInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,5 +86,5 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
|
||||
new ConsumesRequestCondition(annotation.consumes(), annotation.headers()),
|
||||
new ProducesRequestCondition(annotation.produces(), annotation.headers()));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -25,11 +25,11 @@ import java.util.Iterator;
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
abstract class RequestConditionSupport<This extends RequestConditionSupport<This>> implements RequestCondition<This> {
|
||||
abstract class AbstractRequestCondition<T extends AbstractRequestCondition<T>> implements RequestCondition<T> {
|
||||
|
||||
/**
|
||||
* Returns the individual expressions a request condition is composed of such as
|
||||
* URL patterns, HTTP request methods, parameter expressions, etc.
|
||||
* Returns the discrete expressions a request condition is composed of such as URL patterns,
|
||||
* HTTP request methods, parameter expressions, etc.
|
||||
*/
|
||||
protected abstract Collection<?> getContent();
|
||||
|
||||
@@ -39,7 +39,7 @@ abstract class RequestConditionSupport<This extends RequestConditionSupport<This
|
||||
return true;
|
||||
}
|
||||
if (o != null && getClass().equals(o.getClass())) {
|
||||
RequestConditionSupport<?> other = (RequestConditionSupport<?>) o;
|
||||
AbstractRequestCondition<?> other = (AbstractRequestCondition<?>) o;
|
||||
return getContent().equals(other.getContent());
|
||||
}
|
||||
return false;
|
||||
@@ -57,12 +57,7 @@ abstract class RequestConditionSupport<This extends RequestConditionSupport<This
|
||||
Object expression = iterator.next();
|
||||
builder.append(expression.toString());
|
||||
if (iterator.hasNext()) {
|
||||
if (isLogicalConjunction()) {
|
||||
builder.append(" && ");
|
||||
}
|
||||
else {
|
||||
builder.append(" || ");
|
||||
}
|
||||
builder.append(getToStringInfix());
|
||||
}
|
||||
}
|
||||
builder.append("]");
|
||||
@@ -73,6 +68,6 @@ abstract class RequestConditionSupport<This extends RequestConditionSupport<This
|
||||
* Returns {@code true} if the individual expressions of the condition are combined via logical
|
||||
* conjunction (" && "); or {@code false} otherwise.
|
||||
*/
|
||||
protected abstract boolean isLogicalConjunction();
|
||||
protected abstract String getToStringInfix();
|
||||
|
||||
}
|
||||
@@ -44,13 +44,13 @@ import org.springframework.web.servlet.mvc.method.condition.HeadersRequestCondit
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public class ConsumesRequestCondition extends RequestConditionSupport<ConsumesRequestCondition> {
|
||||
public class ConsumesRequestCondition extends AbstractRequestCondition<ConsumesRequestCondition> {
|
||||
|
||||
private final List<ConsumeMediaTypeExpression> expressions;
|
||||
|
||||
/**
|
||||
* Creates a {@link ConsumesRequestCondition} with the given consumable media type expressions.
|
||||
* @param consumes the expressions to parse; if 0 the condition matches to every request
|
||||
* @param consumes the expressions to parse; if 0, the condition matches to every request
|
||||
*/
|
||||
public ConsumesRequestCondition(String... consumes) {
|
||||
this(consumes, null);
|
||||
@@ -60,8 +60,8 @@ public class ConsumesRequestCondition extends RequestConditionSupport<ConsumesRe
|
||||
* Creates a {@link ConsumesRequestCondition} with the given header and consumes expressions.
|
||||
* In addition to consume expressions, {@code "Content-Type"} header expressions are extracted
|
||||
* and treated as consumable media type expressions.
|
||||
* @param consumes the consumes expressions to parse; 0 matches to all requests
|
||||
* @param headers the header expression to parse; 0 matches to all requests
|
||||
* @param consumes the consumes expressions to parse; if 0, the condition matches to all requests
|
||||
* @param headers the header expression to parse; if 0, the condition matches to all requests
|
||||
*/
|
||||
public ConsumesRequestCondition(String[] consumes, String[] headers) {
|
||||
this(parseExpressions(consumes, headers));
|
||||
@@ -119,12 +119,12 @@ public class ConsumesRequestCondition extends RequestConditionSupport<ConsumesRe
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isLogicalConjunction() {
|
||||
return false;
|
||||
protected String getToStringInfix() {
|
||||
return " || ";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the "other" instance as long as it contains any expressions; or "this" instance otherwise.
|
||||
* Returns the "other" instance provided it contains expressions; returns "this" instance otherwise.
|
||||
* In other words "other" takes precedence over "this" as long as it has expressions.
|
||||
* <p>Example: method-level "consumes" overrides type-level "consumes" condition.
|
||||
*/
|
||||
@@ -133,13 +133,13 @@ public class ConsumesRequestCondition extends RequestConditionSupport<ConsumesRe
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if any of the consumable media type expressions match the given request and returns an instance that
|
||||
* is guaranteed to contain matching media type expressions only.
|
||||
* Checks if any of the consumable media type expressions match the given request and returns an
|
||||
* instance that is guaranteed to contain matching media type expressions only.
|
||||
*
|
||||
* @param request the current request
|
||||
*
|
||||
* @return the same instance if the condition contains no expressions;
|
||||
* or a new condition with matching expressions; or {@code null} if no expressions match.
|
||||
* or a new condition with matching expressions only; or {@code null} if no expressions match.
|
||||
*/
|
||||
public ConsumesRequestCondition getMatchingCondition(HttpServletRequest request) {
|
||||
if (isEmpty()) {
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.servlet.mvc.method.condition;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* Wraps and delegates operations to a custom {@link RequestCondition} whose type is not known and even its
|
||||
* presence is not guaranteed ahead of time. The main purpose of this class is to ensure a type-safe and
|
||||
* null-safe way of combining and comparing custom request conditions.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public final class CustomRequestCondition extends AbstractRequestCondition<CustomRequestCondition> {
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private final RequestCondition customCondition;
|
||||
|
||||
/**
|
||||
* Creates a {@link CustomRequestCondition} that wraps the given {@link RequestCondition} instance.
|
||||
* @param requestCondition the custom request condition to wrap
|
||||
*/
|
||||
public CustomRequestCondition(RequestCondition<?> requestCondition) {
|
||||
this.customCondition = requestCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty {@link CustomRequestCondition}.
|
||||
*/
|
||||
public CustomRequestCondition() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public RequestCondition<?> getRequestCondition() {
|
||||
return customCondition;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<?> getContent() {
|
||||
return customCondition != null ? Collections.singleton(customCondition) : Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getToStringInfix() {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates the operation to the wrapped custom request conditions. May also return "this" instance
|
||||
* if the "other" does not contain a custom request condition and vice versa.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public CustomRequestCondition combine(CustomRequestCondition other) {
|
||||
if (customCondition == null && other.customCondition == null) {
|
||||
return this;
|
||||
}
|
||||
else if (customCondition == null) {
|
||||
return other;
|
||||
}
|
||||
else if (other.customCondition == null) {
|
||||
return this;
|
||||
}
|
||||
else {
|
||||
assertCompatible(other);
|
||||
RequestCondition<?> combined = (RequestCondition<?>) customCondition.combine(other.customCondition);
|
||||
return new CustomRequestCondition(combined);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertCompatible(CustomRequestCondition other) {
|
||||
if (customCondition != null && other.customCondition != null) {
|
||||
Class<?> clazz = customCondition.getClass();
|
||||
Class<?> otherClazz = other.customCondition.getClass();
|
||||
if (!clazz.equals(otherClazz)) {
|
||||
throw new ClassCastException("Incompatible custom request conditions: " + clazz + ", " + otherClazz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates the operation to the wrapped custom request condition; or otherwise returns the same
|
||||
* instance if there is no custom request condition.
|
||||
*/
|
||||
public CustomRequestCondition getMatchingCondition(HttpServletRequest request) {
|
||||
if (customCondition == null) {
|
||||
return this;
|
||||
}
|
||||
RequestCondition<?> match = (RequestCondition<?>) customCondition.getMatchingCondition(request);
|
||||
return new CustomRequestCondition(match);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates the operation to the wrapped custom request conditions after checking for the presence
|
||||
* custom request conditions and asserting type safety. The presence of a custom request condition
|
||||
* in one instance but not the other will cause it to be selected, and vice versa.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public int compareTo(CustomRequestCondition other, HttpServletRequest request) {
|
||||
if (customCondition == null && other.customCondition == null) {
|
||||
return 0;
|
||||
}
|
||||
else if (customCondition == null) {
|
||||
return 1;
|
||||
}
|
||||
else if (other.customCondition == null) {
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
assertCompatible(other);
|
||||
return customCondition.compareTo(other.customCondition, request);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -39,7 +39,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public class HeadersRequestCondition extends RequestConditionSupport<HeadersRequestCondition> {
|
||||
public class HeadersRequestCondition extends AbstractRequestCondition<HeadersRequestCondition> {
|
||||
|
||||
private final Set<HeaderExpression> expressions;
|
||||
|
||||
@@ -50,7 +50,7 @@ public class HeadersRequestCondition extends RequestConditionSupport<HeadersRequ
|
||||
* Those should be converted and used as "produces" and "consumes" conditions instead.
|
||||
* See the constructors for {@link ProducesRequestCondition} and {@link ConsumesRequestCondition}.
|
||||
*
|
||||
* @param headers 0 or more header expressions; if 0 the condition will match to every request.
|
||||
* @param headers 0 or more header expressions; if 0, the condition will match to every request.
|
||||
*/
|
||||
public HeadersRequestCondition(String... headers) {
|
||||
this(parseExpressions(headers));
|
||||
@@ -80,8 +80,8 @@ public class HeadersRequestCondition extends RequestConditionSupport<HeadersRequ
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isLogicalConjunction() {
|
||||
return true;
|
||||
protected String getToStringInfix() {
|
||||
return " && ";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,14 +36,14 @@ import org.springframework.web.util.WebUtils;
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public class ParamsRequestCondition extends RequestConditionSupport<ParamsRequestCondition> {
|
||||
public class ParamsRequestCondition extends AbstractRequestCondition<ParamsRequestCondition> {
|
||||
|
||||
private final Set<ParamExpression> expressions;
|
||||
|
||||
/**
|
||||
* Create a {@link ParamsRequestCondition} with the given param expressions.
|
||||
*
|
||||
* @param params 0 or more param expressions; if 0 the condition will match to every request.
|
||||
* @param params 0 or more param expressions; if 0, the condition will match to every request.
|
||||
*/
|
||||
public ParamsRequestCondition(String... params) {
|
||||
this(parseExpressions(params));
|
||||
@@ -69,8 +69,8 @@ public class ParamsRequestCondition extends RequestConditionSupport<ParamsReques
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isLogicalConjunction() {
|
||||
return true;
|
||||
protected String getToStringInfix() {
|
||||
return " && ";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,7 +41,7 @@ import org.springframework.web.util.UrlPathHelper;
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public class PatternsRequestCondition extends RequestConditionSupport<PatternsRequestCondition> {
|
||||
public class PatternsRequestCondition extends AbstractRequestCondition<PatternsRequestCondition> {
|
||||
|
||||
private final Set<String> patterns;
|
||||
|
||||
@@ -62,7 +62,7 @@ public class PatternsRequestCondition extends RequestConditionSupport<PatternsRe
|
||||
* Creates a new {@link PatternsRequestCondition} with the given URL patterns.
|
||||
* Each pattern that is not empty and does not start with "/" is prepended with "/".
|
||||
*
|
||||
* @param patterns the URL patterns to use; if 0 the condition will match to every request.
|
||||
* @param patterns the URL patterns to use; if 0, the condition will match to every request.
|
||||
* @param urlPathHelper a {@link UrlPathHelper} for determining the lookup path for a request
|
||||
* @param pathMatcher a {@link PathMatcher} for pattern path matching
|
||||
*/
|
||||
@@ -96,7 +96,7 @@ public class PatternsRequestCondition extends RequestConditionSupport<PatternsRe
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public Set<String> getPatterns() {
|
||||
return patterns;
|
||||
}
|
||||
@@ -107,8 +107,8 @@ public class PatternsRequestCondition extends RequestConditionSupport<PatternsRe
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isLogicalConjunction() {
|
||||
return false;
|
||||
protected String getToStringInfix() {
|
||||
return " || ";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -44,7 +44,7 @@ import org.springframework.web.servlet.mvc.method.condition.HeadersRequestCondit
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public class ProducesRequestCondition extends RequestConditionSupport<ProducesRequestCondition> {
|
||||
public class ProducesRequestCondition extends AbstractRequestCondition<ProducesRequestCondition> {
|
||||
|
||||
private final List<ProduceMediaTypeExpression> expressions;
|
||||
|
||||
@@ -60,8 +60,8 @@ public class ProducesRequestCondition extends RequestConditionSupport<ProducesRe
|
||||
* Creates a {@link ProducesRequestCondition} with the given header and produces expressions.
|
||||
* In addition to produces expressions, {@code "Accept"} header expressions are extracted and treated as
|
||||
* producible media type expressions.
|
||||
* @param produces the produces expressions to parse
|
||||
* @param headers the header expression to parse
|
||||
* @param produces the produces expressions to parse; if 0, the condition matches to all requests
|
||||
* @param headers the header expression to parse; if 0, the condition matches to all requests
|
||||
*/
|
||||
public ProducesRequestCondition(String[] produces, String[] headers) {
|
||||
this(parseExpressions(produces, headers));
|
||||
@@ -119,8 +119,8 @@ public class ProducesRequestCondition extends RequestConditionSupport<ProducesRe
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isLogicalConjunction() {
|
||||
return false;
|
||||
protected String getToStringInfix() {
|
||||
return " || ";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,11 +24,13 @@ import javax.servlet.http.HttpServletRequest;
|
||||
* <p>Request conditions can be combined (e.g. type + method-level conditions), matched to a request,
|
||||
* or compared to each other to determine if one matches the request better.
|
||||
*
|
||||
* @param <T> The type of objects that this RequestCondition can be compared to and combined with.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Arjen Poutsma
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface RequestCondition<This extends RequestCondition<This>> {
|
||||
public interface RequestCondition<T> {
|
||||
|
||||
/**
|
||||
* Defines the rules for combining "this" condition (i.e. the current instance) with another condition.
|
||||
@@ -36,7 +38,7 @@ public interface RequestCondition<This extends RequestCondition<This>> {
|
||||
*
|
||||
* @returns a request condition instance that is the result of combining the two condition instances.
|
||||
*/
|
||||
This combine(This other);
|
||||
T combine(T other);
|
||||
|
||||
/**
|
||||
* Checks if this condition matches the provided request and returns a potentially new request condition
|
||||
@@ -45,13 +47,13 @@ public interface RequestCondition<This extends RequestCondition<This>> {
|
||||
*
|
||||
* @return a condition instance in case of a match; or {@code null} if there is no match.
|
||||
*/
|
||||
This getMatchingCondition(HttpServletRequest request);
|
||||
T getMatchingCondition(HttpServletRequest request);
|
||||
|
||||
/**
|
||||
* Compares "this" condition (i.e. the current instance) with another condition in the context of a request.
|
||||
* <p>Note: it is assumed instances have been obtained via {@link #getMatchingCondition(HttpServletRequest)}
|
||||
* <p>Note: it is assumed both instances have been obtained via {@link #getMatchingCondition(HttpServletRequest)}
|
||||
* to ensure they have content relevant to current request only.
|
||||
*/
|
||||
int compareTo(This other, HttpServletRequest request);
|
||||
int compareTo(T other, HttpServletRequest request);
|
||||
|
||||
}
|
||||
|
||||
@@ -36,13 +36,13 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public class RequestMethodsRequestCondition extends RequestConditionSupport<RequestMethodsRequestCondition> {
|
||||
public class RequestMethodsRequestCondition extends AbstractRequestCondition<RequestMethodsRequestCondition> {
|
||||
|
||||
private final Set<RequestMethod> methods;
|
||||
|
||||
/**
|
||||
* Create a {@link RequestMethodsRequestCondition} with the given {@link RequestMethod}s.
|
||||
* @param requestMethods 0 or more HTTP request methods; if 0 the condition will match to every request.
|
||||
* Create a {@link RequestMethodsRequestCondition} with the given request methods.
|
||||
* @param requestMethods 0 or more HTTP request methods; if, 0 the condition will match to every request.
|
||||
*/
|
||||
public RequestMethodsRequestCondition(RequestMethod... requestMethods) {
|
||||
this(asList(requestMethods));
|
||||
@@ -72,8 +72,8 @@ public class RequestMethodsRequestCondition extends RequestConditionSupport<Requ
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isLogicalConjunction() {
|
||||
return false;
|
||||
protected String getToStringInfix() {
|
||||
return " || ";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user