SPR-7812 RequestCondition refactoring with the possibility for custom request conditions in mind.
git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@4566 50f2f4bb-b051-0410-bef5-90022cba6387
This commit is contained in:
parent
12faecff7b
commit
6f537ca74b
|
|
@ -16,31 +16,19 @@
|
|||
|
||||
package org.springframework.web.servlet.mvc.method;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.servlet.mvc.method.condition.ConsumesRequestCondition;
|
||||
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.RequestConditionFactory;
|
||||
import org.springframework.web.servlet.mvc.method.condition.RequestMethodsRequestCondition;
|
||||
|
||||
/**
|
||||
* Contains a set of conditions to match to a given request such as URL patterns, HTTP methods, request parameters
|
||||
* and headers.
|
||||
*
|
||||
* <p>Two {@link RequestMappingInfo}s can be combined resulting in a new {@link RequestMappingInfo} with conditions
|
||||
* from both. A {@link RequestMappingInfo} can also match itself to an HTTP request resulting in a new
|
||||
* {@link RequestMappingInfo} with the subset of conditions relevant to the request.
|
||||
* Contains request mapping conditions to be matched to a given request.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
|
|
@ -48,7 +36,7 @@ import org.springframework.web.servlet.mvc.method.condition.RequestMethodsReques
|
|||
*/
|
||||
public final class RequestMappingInfo {
|
||||
|
||||
private final Set<String> patterns;
|
||||
private final PatternsRequestCondition patternsCondition;
|
||||
|
||||
private final RequestMethodsRequestCondition methodsCondition;
|
||||
|
||||
|
|
@ -63,24 +51,15 @@ public final class RequestMappingInfo {
|
|||
private int hash;
|
||||
|
||||
/**
|
||||
* Creates a new {@code RequestMappingInfo} instance with the given URL patterns and HTTP methods.
|
||||
*
|
||||
* <p>Package protected for testing purposes.
|
||||
* Creates a new {@code RequestMappingInfo} instance.
|
||||
*/
|
||||
RequestMappingInfo(Collection<String> patterns, RequestMethod[] methods) {
|
||||
this(patterns, RequestConditionFactory.parseMethods(methods), null, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code RequestMappingInfo} instance with a full set of conditions.
|
||||
*/
|
||||
public RequestMappingInfo(Collection<String> patterns,
|
||||
RequestMethodsRequestCondition methodsCondition,
|
||||
ParamsRequestCondition paramsCondition,
|
||||
HeadersRequestCondition headersCondition,
|
||||
ConsumesRequestCondition consumesCondition,
|
||||
ProducesRequestCondition producesCondition) {
|
||||
this.patterns = asUnmodifiableSet(prependLeadingSlash(patterns));
|
||||
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();
|
||||
|
|
@ -88,67 +67,52 @@ public final class RequestMappingInfo {
|
|||
this.producesCondition = producesCondition != null ? producesCondition : new ProducesRequestCondition();
|
||||
}
|
||||
|
||||
private static Set<String> prependLeadingSlash(Collection<String> patterns) {
|
||||
if (patterns == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
Set<String> result = new LinkedHashSet<String>(patterns.size());
|
||||
for (String pattern : patterns) {
|
||||
if (StringUtils.hasLength(pattern) && !pattern.startsWith("/")) {
|
||||
pattern = "/" + pattern;
|
||||
}
|
||||
result.add(pattern);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static <T> Set<T> asUnmodifiableSet(Collection<T> collection) {
|
||||
if (collection == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
Set<T> result = new LinkedHashSet<T>(collection);
|
||||
return Collections.unmodifiableSet(result);
|
||||
/**
|
||||
* Package protected, used for testing.
|
||||
*/
|
||||
RequestMappingInfo(String[] patterns, RequestMethod... methods) {
|
||||
this(new PatternsRequestCondition(patterns), new RequestMethodsRequestCondition(methods), null, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the patterns of this request mapping info.
|
||||
*/
|
||||
public Set<String> getPatterns() {
|
||||
return patterns;
|
||||
public PatternsRequestCondition getPatternsCondition() {
|
||||
return patternsCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request method conditions of this request mapping info.
|
||||
* Returns the request method condition of this request mapping info.
|
||||
*/
|
||||
public RequestMethodsRequestCondition getMethods() {
|
||||
public RequestMethodsRequestCondition getMethodsCondition() {
|
||||
return methodsCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request parameters conditions of this request mapping info.
|
||||
* Returns the request parameters condition of this request mapping info.
|
||||
*/
|
||||
public ParamsRequestCondition getParams() {
|
||||
public ParamsRequestCondition getParamsCondition() {
|
||||
return paramsCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request headers conditions of this request mapping info.
|
||||
* Returns the request headers condition of this request mapping info.
|
||||
*/
|
||||
public HeadersRequestCondition getHeaders() {
|
||||
public HeadersRequestCondition getHeadersCondition() {
|
||||
return headersCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request consumes conditions of this request mapping info.
|
||||
* Returns the request consumes condition of this request mapping info.
|
||||
*/
|
||||
public ConsumesRequestCondition getConsumes() {
|
||||
public ConsumesRequestCondition getConsumesCondition() {
|
||||
return consumesCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request produces conditions of this request mapping info.
|
||||
* Returns the request produces condition of this request mapping info.
|
||||
*/
|
||||
public ProducesRequestCondition getProduces() {
|
||||
public ProducesRequestCondition getProducesCondition() {
|
||||
return producesCondition;
|
||||
}
|
||||
|
||||
|
|
@ -167,110 +131,44 @@ public final class RequestMappingInfo {
|
|||
* <li>Consumes are combined as per {@link ConsumesRequestCondition#combine(ConsumesRequestCondition)}.
|
||||
* </ul>
|
||||
* @param methodKey the key to combine with
|
||||
* @param pathMatcher to {@linkplain PathMatcher#combine(String, String) combine} the patterns
|
||||
* @return a new request mapping info containing conditions from both keys
|
||||
*/
|
||||
public RequestMappingInfo combine(RequestMappingInfo methodKey, PathMatcher pathMatcher) {
|
||||
Set<String> patterns = combinePatterns(this.patterns, methodKey.patterns, pathMatcher);
|
||||
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);
|
||||
}
|
||||
|
||||
private static Set<String> combinePatterns(Collection<String> typePatterns,
|
||||
Collection<String> methodPatterns,
|
||||
PathMatcher pathMatcher) {
|
||||
Set<String> result = new LinkedHashSet<String>();
|
||||
if (!typePatterns.isEmpty() && !methodPatterns.isEmpty()) {
|
||||
for (String pattern1 : typePatterns) {
|
||||
for (String pattern2 : methodPatterns) {
|
||||
result.add(pathMatcher.combine(pattern1, pattern2));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!typePatterns.isEmpty()) {
|
||||
result.addAll(typePatterns);
|
||||
}
|
||||
else if (!methodPatterns.isEmpty()) {
|
||||
result.addAll(methodPatterns);
|
||||
}
|
||||
else {
|
||||
result.add("");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@code RequestMappingInfo} that contains all conditions of this key that are relevant to the request.
|
||||
* <ul>
|
||||
* <li>The list of URL path patterns is trimmed to contain the patterns that match the URL with matching patterns
|
||||
* sorted via {@link PathMatcher#getPatternComparator(String)}.
|
||||
* <li>The list of HTTP methods is trimmed to contain only the method of the request.
|
||||
* <li>Request parameter and request header conditions are included in full.
|
||||
* <li>The list of consumes conditions is trimmed and sorted to match the request "Content-Type" header.
|
||||
* </ul>
|
||||
* @param lookupPath mapping lookup path within the current servlet mapping if applicable
|
||||
* 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
|
||||
* @param pathMatcher to check for matching patterns
|
||||
* @return a new request mapping info that contains all matching attributes, or {@code null} if not all conditions match
|
||||
*/
|
||||
public RequestMappingInfo getMatchingRequestMapping(String lookupPath, HttpServletRequest request, PathMatcher pathMatcher) {
|
||||
RequestMethodsRequestCondition matchingMethodCondition = methodsCondition.getMatchingCondition(request);
|
||||
ParamsRequestCondition matchingParamsCondition = paramsCondition.getMatchingCondition(request);
|
||||
HeadersRequestCondition matchingHeadersCondition = headersCondition.getMatchingCondition(request);
|
||||
ConsumesRequestCondition matchingConsumesCondition = consumesCondition.getMatchingCondition(request);
|
||||
ProducesRequestCondition matchingProducesCondition = producesCondition.getMatchingCondition(request);
|
||||
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);
|
||||
|
||||
if (matchingMethodCondition == null || matchingParamsCondition == null || matchingHeadersCondition == null ||
|
||||
matchingConsumesCondition == null || matchingProducesCondition == null) {
|
||||
if (matchingMethod == null || matchingParams == null || matchingHeaders == null ||
|
||||
matchingConsumes == null || matchingProduces == null) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
List<String> matchingPatterns = getMatchingPatterns(lookupPath, pathMatcher);
|
||||
if (!matchingPatterns.isEmpty()) {
|
||||
return new RequestMappingInfo(matchingPatterns, matchingMethodCondition, matchingParamsCondition,
|
||||
matchingHeadersCondition, matchingConsumesCondition, matchingProducesCondition);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> getMatchingPatterns(String lookupPath, PathMatcher pathMatcher) {
|
||||
|
||||
List<String> matchingPatterns = new ArrayList<String>();
|
||||
for (String pattern : this.patterns) {
|
||||
String matchingPattern = getMatchingPattern(pattern, lookupPath, pathMatcher);
|
||||
if (matchingPattern != null) {
|
||||
matchingPatterns.add(matchingPattern);
|
||||
}
|
||||
|
||||
PatternsRequestCondition matchingPatterns = patternsCondition.getMatchingCondition(request);
|
||||
if (matchingPatterns != null) {
|
||||
return new RequestMappingInfo(matchingPatterns, matchingMethod,
|
||||
matchingParams, matchingHeaders, matchingConsumes,
|
||||
matchingProduces);
|
||||
}
|
||||
|
||||
Collections.sort(matchingPatterns, pathMatcher.getPatternComparator(lookupPath));
|
||||
|
||||
return matchingPatterns;
|
||||
}
|
||||
|
||||
private String getMatchingPattern(String pattern, String lookupPath, PathMatcher pathMatcher) {
|
||||
if (pattern.equals(lookupPath)) {
|
||||
return pattern;
|
||||
}
|
||||
boolean hasSuffix = pattern.indexOf('.') != -1;
|
||||
if (!hasSuffix && pathMatcher.match(pattern + ".*", lookupPath)) {
|
||||
return pattern + ".*";
|
||||
}
|
||||
if (pathMatcher.match(pattern, lookupPath)) {
|
||||
return pattern;
|
||||
}
|
||||
boolean endsWithSlash = pattern.endsWith("/");
|
||||
if (!endsWithSlash && pathMatcher.match(pattern + "/", lookupPath)) {
|
||||
return pattern +"/";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -281,7 +179,7 @@ public final class RequestMappingInfo {
|
|||
}
|
||||
if (obj != null && obj instanceof RequestMappingInfo) {
|
||||
RequestMappingInfo other = (RequestMappingInfo) obj;
|
||||
return (this.patterns.equals(other.patterns) &&
|
||||
return (this.patternsCondition.equals(other.patternsCondition) &&
|
||||
this.methodsCondition.equals(other.methodsCondition) &&
|
||||
this.paramsCondition.equals(other.paramsCondition) &&
|
||||
this.headersCondition.equals(other.headersCondition) &&
|
||||
|
|
@ -295,7 +193,7 @@ public final class RequestMappingInfo {
|
|||
public int hashCode() {
|
||||
int result = hash;
|
||||
if (result == 0) {
|
||||
result = patterns.hashCode();
|
||||
result = patternsCondition.hashCode();
|
||||
result = 31 * result + methodsCondition.hashCode();
|
||||
result = 31 * result + paramsCondition.hashCode();
|
||||
result = 31 * result + headersCondition.hashCode();
|
||||
|
|
@ -309,7 +207,7 @@ public final class RequestMappingInfo {
|
|||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder("{");
|
||||
builder.append(patterns);
|
||||
builder.append(patternsCondition);
|
||||
builder.append(",methods=").append(methodsCondition);
|
||||
builder.append(",params=").append(paramsCondition);
|
||||
builder.append(",headers=").append(headersCondition);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ package org.springframework.web.servlet.mvc.method;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
|
@ -61,7 +60,7 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
|
|||
|
||||
@Override
|
||||
protected Set<String> getMappingPaths(RequestMappingInfo mapping) {
|
||||
return mapping.getPatterns();
|
||||
return mapping.getPatternsCondition().getPatterns();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -73,7 +72,7 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
|
|||
protected RequestMappingInfo getMatchingMapping(RequestMappingInfo mapping,
|
||||
String lookupPath,
|
||||
HttpServletRequest request) {
|
||||
return mapping.getMatchingRequestMapping(lookupPath, request, getPathMatcher());
|
||||
return mapping.getMatchingRequestMapping(request);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -81,7 +80,7 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
|
|||
*/
|
||||
@Override
|
||||
protected Comparator<RequestMappingInfo> getMappingComparator(String lookupPath, HttpServletRequest request) {
|
||||
return new RequestMappingInfoComparator(lookupPath, request);
|
||||
return new RequestMappingInfoComparator(request);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -94,12 +93,12 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
|
|||
protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) {
|
||||
super.handleMatch(info, lookupPath, request);
|
||||
|
||||
String pattern = info.getPatterns().iterator().next();
|
||||
String pattern = info.getPatternsCondition().getPatterns().iterator().next();
|
||||
Map<String, String> uriTemplateVariables = getPathMatcher().extractUriTemplateVariables(pattern, lookupPath);
|
||||
request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplateVariables);
|
||||
|
||||
if (!info.getProduces().isEmpty()) {
|
||||
Set<MediaType> mediaTypes = info.getProduces().getMediaTypes();
|
||||
if (!info.getProducesCondition().isEmpty()) {
|
||||
Set<MediaType> mediaTypes = info.getProducesCondition().getMediaTypes();
|
||||
request.setAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes);
|
||||
}
|
||||
}
|
||||
|
|
@ -117,18 +116,18 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
|
|||
Set<MediaType> consumableMediaTypes = new HashSet<MediaType>();
|
||||
Set<MediaType> producibleMediaTypes = new HashSet<MediaType>();
|
||||
for (RequestMappingInfo info : requestMappingInfos) {
|
||||
for (String pattern : info.getPatterns()) {
|
||||
for (String pattern : info.getPatternsCondition().getPatterns()) {
|
||||
if (getPathMatcher().match(pattern, lookupPath)) {
|
||||
if (!info.getMethods().match(request)) {
|
||||
for (RequestMethod method : info.getMethods().getMethods()) {
|
||||
if (info.getMethodsCondition().getMatchingCondition(request) == null) {
|
||||
for (RequestMethod method : info.getMethodsCondition().getMethods()) {
|
||||
allowedMethods.add(method.name());
|
||||
}
|
||||
}
|
||||
if (!info.getConsumes().match(request)) {
|
||||
consumableMediaTypes.addAll(info.getConsumes().getMediaTypes());
|
||||
if (info.getConsumesCondition().getMatchingCondition(request) == null) {
|
||||
consumableMediaTypes.addAll(info.getConsumesCondition().getMediaTypes());
|
||||
}
|
||||
if (!info.getProduces().match(request)) {
|
||||
producibleMediaTypes.addAll(info.getProduces().getMediaTypes());
|
||||
if (info.getProducesCondition().getMatchingCondition(request) == null) {
|
||||
producibleMediaTypes.addAll(info.getProducesCondition().getMediaTypes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -152,77 +151,44 @@ 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 not all {@link RequestMappingInfo} patterns may apply to the current request. Therefore an
|
||||
* HttpServletRequest is required as input.
|
||||
*
|
||||
* <p>Furthermore, the following assumptions are made about the input RequestMappings: <ul><li>Each RequestMappingInfo
|
||||
* has been fully matched to the request <li>The RequestMappingInfo contains matched patterns only <li>Patterns are
|
||||
* ordered with the best matching pattern at the top </ul>
|
||||
*
|
||||
* @see RequestMappingInfoHandlerMapping#getMatchingMapping(RequestMappingInfo, String, HttpServletRequest)
|
||||
* 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 Comparator<String> patternComparator;
|
||||
private final HttpServletRequest request;
|
||||
|
||||
private List<MediaType> requestAcceptHeader;
|
||||
|
||||
public RequestMappingInfoComparator(String lookupPath, HttpServletRequest request) {
|
||||
this.patternComparator = getPathMatcher().getPatternComparator(lookupPath);
|
||||
String acceptHeader = request.getHeader("Accept");
|
||||
this.requestAcceptHeader = MediaType.parseMediaTypes(acceptHeader);
|
||||
MediaType.sortByQualityValue(this.requestAcceptHeader);
|
||||
public RequestMappingInfoComparator(HttpServletRequest request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
public int compare(RequestMappingInfo mapping, RequestMappingInfo otherMapping) {
|
||||
int result = comparePatterns(mapping.getPatterns(), otherMapping.getPatterns());
|
||||
int result = mapping.getPatternsCondition().compareTo(otherMapping.getPatternsCondition(), request);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
result = mapping.getParams().compareTo(otherMapping.getParams());
|
||||
result = mapping.getParamsCondition().compareTo(otherMapping.getParamsCondition(), request);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
result = mapping.getHeaders().compareTo(otherMapping.getHeaders());
|
||||
result = mapping.getHeadersCondition().compareTo(otherMapping.getHeadersCondition(), request);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
result = mapping.getConsumes().compareTo(otherMapping.getConsumes());
|
||||
result = mapping.getConsumesCondition().compareTo(otherMapping.getConsumesCondition(), request);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
result = mapping.getProduces().compareTo(otherMapping.getProduces(), this.requestAcceptHeader);
|
||||
result = mapping.getProducesCondition().compareTo(otherMapping.getProducesCondition(), request);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
result = mapping.getMethods().compareTo(otherMapping.getMethods());
|
||||
result = mapping.getMethodsCondition().compareTo(otherMapping.getMethodsCondition(), request);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int comparePatterns(Set<String> patterns, Set<String> otherPatterns) {
|
||||
Iterator<String> iterator = patterns.iterator();
|
||||
Iterator<String> iteratorOther = otherPatterns.iterator();
|
||||
while (iterator.hasNext() && iteratorOther.hasNext()) {
|
||||
int result = patternComparator.compare(iterator.next(), iteratorOther.next());
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (iterator.hasNext()) {
|
||||
return -1;
|
||||
}
|
||||
else if (iteratorOther.hasNext()) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
package org.springframework.web.servlet.mvc.method.annotation;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.stereotype.Controller;
|
||||
|
|
@ -25,7 +24,12 @@ import org.springframework.util.PathMatcher;
|
|||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
|
||||
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
|
||||
import org.springframework.web.servlet.mvc.method.condition.RequestConditionFactory;
|
||||
import org.springframework.web.servlet.mvc.method.condition.ConsumesRequestCondition;
|
||||
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.RequestMethodsRequestCondition;
|
||||
|
||||
/**
|
||||
* A sub-class of {@link RequestMappingInfoHandlerMapping} that prepares {@link RequestMappingInfo}s
|
||||
|
|
@ -64,7 +68,7 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
|
|||
RequestMapping typeAnnot = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
|
||||
if (typeAnnot != null) {
|
||||
RequestMappingInfo typeMapping = createFromRequestMapping(typeAnnot);
|
||||
return typeMapping.combine(methodMapping, getPathMatcher());
|
||||
return typeMapping.combine(methodMapping);
|
||||
}
|
||||
else {
|
||||
return methodMapping;
|
||||
|
|
@ -75,13 +79,14 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
|
|||
}
|
||||
}
|
||||
|
||||
private static RequestMappingInfo createFromRequestMapping(RequestMapping annotation) {
|
||||
return new RequestMappingInfo(Arrays.asList(annotation.value()),
|
||||
RequestConditionFactory.parseMethods(annotation.method()),
|
||||
RequestConditionFactory.parseParams(annotation.params()),
|
||||
RequestConditionFactory.parseHeaders(annotation.headers()),
|
||||
RequestConditionFactory.parseConsumes(annotation.consumes(), annotation.headers()),
|
||||
RequestConditionFactory.parseProduces(annotation.produces(), annotation.headers()));
|
||||
private RequestMappingInfo createFromRequestMapping(RequestMapping annotation) {
|
||||
return new RequestMappingInfo(
|
||||
new PatternsRequestCondition(annotation.value(), getUrlPathHelper(), getPathMatcher()),
|
||||
new RequestMethodsRequestCondition(annotation.method()),
|
||||
new ParamsRequestCondition(annotation.params()),
|
||||
new HeadersRequestCondition(annotation.headers()),
|
||||
new ConsumesRequestCondition(annotation.consumes(), annotation.headers()),
|
||||
new ProducesRequestCondition(annotation.produces(), annotation.headers()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,14 +19,15 @@ package org.springframework.web.servlet.mvc.method.condition;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* A condition that supports simple "name=value" style expressions as documented in {@link
|
||||
* org.springframework.web.bind.annotation.RequestMapping#params()} and {@link org.springframework.web.bind.annotation.RequestMapping#headers()}.
|
||||
* Supports "name=value" style expressions as described in:
|
||||
* {@link org.springframework.web.bind.annotation.RequestMapping#params()} and
|
||||
* {@link org.springframework.web.bind.annotation.RequestMapping#headers()}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Arjen Poutsma
|
||||
* @since 3.1
|
||||
*/
|
||||
abstract class AbstractNameValueCondition<T> implements RequestCondition {
|
||||
abstract class AbstractNameValueExpression<T> {
|
||||
|
||||
protected final String name;
|
||||
|
||||
|
|
@ -34,7 +35,7 @@ abstract class AbstractNameValueCondition<T> implements RequestCondition {
|
|||
|
||||
protected final boolean isNegated;
|
||||
|
||||
AbstractNameValueCondition(String expression) {
|
||||
AbstractNameValueExpression(String expression) {
|
||||
int separator = expression.indexOf('=');
|
||||
if (separator == -1) {
|
||||
this.isNegated = expression.startsWith("!");
|
||||
|
|
@ -65,6 +66,20 @@ abstract class AbstractNameValueCondition<T> implements RequestCondition {
|
|||
|
||||
protected abstract boolean matchValue(HttpServletRequest request);
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj != null && obj instanceof AbstractNameValueExpression) {
|
||||
AbstractNameValueExpression<?> other = (AbstractNameValueExpression<?>) obj;
|
||||
return ((this.name.equalsIgnoreCase(other.name)) &&
|
||||
(this.value != null ? this.value.equals(other.value) : other.value == null) &&
|
||||
this.isNegated == other.isNegated);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = name.hashCode();
|
||||
|
|
@ -16,140 +16,194 @@
|
|||
|
||||
package org.springframework.web.servlet.mvc.method.condition;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.servlet.mvc.method.condition.HeadersRequestCondition.HeaderExpression;
|
||||
|
||||
/**
|
||||
* Represents a collection of consumes conditions, typically obtained from {@link org.springframework.web.bind.annotation.RequestMapping#consumes()
|
||||
* @RequestMapping.consumes()}.
|
||||
*
|
||||
* A logical disjunction (' || ') request condition to match requests against consumable media type expressions.
|
||||
*
|
||||
* <p>For details on the syntax of the expressions see {@link RequestMapping#consumes()}. If the condition is
|
||||
* created with 0 consumable media type expressions, it matches to every request.
|
||||
*
|
||||
* <p>This request condition is also capable of parsing header expressions specifically selecting 'Content-Type'
|
||||
* header expressions and converting them to consumable media type expressions.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see RequestConditionFactory#parseConsumes(String...)
|
||||
* @see RequestConditionFactory#parseConsumes(String[], String[])
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public class ConsumesRequestCondition
|
||||
extends MediaTypesRequestCondition<ConsumesRequestCondition.ConsumeRequestCondition>
|
||||
implements Comparable<ConsumesRequestCondition> {
|
||||
public class ConsumesRequestCondition extends RequestConditionSupport<ConsumesRequestCondition> {
|
||||
|
||||
ConsumesRequestCondition(Collection<ConsumeRequestCondition> conditions) {
|
||||
super(conditions);
|
||||
}
|
||||
|
||||
ConsumesRequestCondition(String... consumes) {
|
||||
this(parseConditions(Arrays.asList(consumes)));
|
||||
}
|
||||
|
||||
private static Set<ConsumeRequestCondition> parseConditions(List<String> consumes) {
|
||||
Set<ConsumeRequestCondition> conditions = new LinkedHashSet<ConsumeRequestCondition>(consumes.size());
|
||||
for (String consume : consumes) {
|
||||
conditions.add(new ConsumeRequestCondition(consume));
|
||||
}
|
||||
return conditions;
|
||||
}
|
||||
private final List<ConsumeMediaTypeExpression> expressions;
|
||||
|
||||
/**
|
||||
* Creates a default set of consumes request conditions.
|
||||
* 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
|
||||
*/
|
||||
public ConsumesRequestCondition() {
|
||||
this(Collections.<ConsumeRequestCondition>emptySet());
|
||||
public ConsumesRequestCondition(String... consumes) {
|
||||
this(consumes, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@code RequestCondition} that contains all conditions of this key that match the request.
|
||||
*
|
||||
* @param request the request
|
||||
* @return a new request condition that contains all matching attributes, or {@code null} if not all conditions match
|
||||
* 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
|
||||
*/
|
||||
public ConsumesRequestCondition(String[] consumes, String[] headers) {
|
||||
this(parseExpressions(consumes, headers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor.
|
||||
*/
|
||||
private ConsumesRequestCondition(Collection<ConsumeMediaTypeExpression> expressions) {
|
||||
this.expressions = new ArrayList<ConsumeMediaTypeExpression>(expressions);
|
||||
Collections.sort(this.expressions);
|
||||
}
|
||||
|
||||
private static Set<ConsumeMediaTypeExpression> parseExpressions(String[] consumes, String[] headers) {
|
||||
Set<ConsumeMediaTypeExpression> result = new LinkedHashSet<ConsumeMediaTypeExpression>();
|
||||
if (headers != null) {
|
||||
for (String header : headers) {
|
||||
HeaderExpression expr = new HeaderExpression(header);
|
||||
if ("Content-Type".equalsIgnoreCase(expr.name)) {
|
||||
for (MediaType mediaType : MediaType.parseMediaTypes(expr.value)) {
|
||||
result.add(new ConsumeMediaTypeExpression(mediaType, expr.isNegated));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (consumes != null) {
|
||||
for (String consume : consumes) {
|
||||
result.add(new ConsumeMediaTypeExpression(consume));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the consumable media types contained in all expressions of this condition.
|
||||
*/
|
||||
public Set<MediaType> getMediaTypes() {
|
||||
Set<MediaType> result = new LinkedHashSet<MediaType>();
|
||||
for (ConsumeMediaTypeExpression expression : expressions) {
|
||||
result.add(expression.getMediaType());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this condition contains 0 consumable media type expressions.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return expressions.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<ConsumeMediaTypeExpression> getContent() {
|
||||
return expressions;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isLogicalConjunction() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the "other" instance as long as it contains any expressions; or "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.
|
||||
*/
|
||||
public ConsumesRequestCondition combine(ConsumesRequestCondition other) {
|
||||
return !other.expressions.isEmpty() ? other : this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public ConsumesRequestCondition getMatchingCondition(HttpServletRequest request) {
|
||||
if (isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
Set<ConsumeRequestCondition> matchingConditions = new LinkedHashSet<ConsumeRequestCondition>(getConditions());
|
||||
for (Iterator<ConsumeRequestCondition> iterator = matchingConditions.iterator(); iterator.hasNext();) {
|
||||
ConsumeRequestCondition condition = iterator.next();
|
||||
if (!condition.match(request)) {
|
||||
Set<ConsumeMediaTypeExpression> result = new LinkedHashSet<ConsumeMediaTypeExpression>(expressions);
|
||||
for (Iterator<ConsumeMediaTypeExpression> iterator = result.iterator(); iterator.hasNext();) {
|
||||
ConsumeMediaTypeExpression expression = iterator.next();
|
||||
if (!expression.match(request)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
if (matchingConditions.isEmpty()) {
|
||||
return null;
|
||||
return (result.isEmpty()) ? null : new ConsumesRequestCondition(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns:
|
||||
* <ul>
|
||||
* <li>0 if the two conditions have the same number of expressions
|
||||
* <li>Less than 1 if "this" has more in number or more specific consumable media type expressions
|
||||
* <li>Greater than 1 if "other" has more in number or more specific consumable media type expressions
|
||||
* </ul>
|
||||
*
|
||||
* <p>It is assumed that both instances have been obtained via {@link #getMatchingCondition(HttpServletRequest)}
|
||||
* and each instance contains the matching consumable media type expression only or is otherwise empty.
|
||||
*/
|
||||
public int compareTo(ConsumesRequestCondition other, HttpServletRequest request) {
|
||||
if (expressions.isEmpty() && other.expressions.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
else if (expressions.isEmpty()) {
|
||||
return 1;
|
||||
}
|
||||
else if (other.expressions.isEmpty()) {
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
return new ConsumesRequestCondition(matchingConditions);
|
||||
return expressions.get(0).compareTo(other.expressions.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines this collection of request condition with another. Returns {@code other}, unless it is empty.
|
||||
*
|
||||
* @param other the condition to combine with
|
||||
* Parsing and request matching logic for consumable media type expressions.
|
||||
* @see RequestMapping#consumes()
|
||||
*/
|
||||
public ConsumesRequestCondition combine(ConsumesRequestCondition other) {
|
||||
return !other.isEmpty() ? other : this;
|
||||
}
|
||||
static class ConsumeMediaTypeExpression extends MediaTypeExpression {
|
||||
|
||||
|
||||
public int compareTo(ConsumesRequestCondition other) {
|
||||
MediaTypeRequestCondition thisMostSpecificCondition = this.getMostSpecificCondition();
|
||||
MediaTypeRequestCondition otherMostSpecificCondition = other.getMostSpecificCondition();
|
||||
if (thisMostSpecificCondition == null && otherMostSpecificCondition == null) {
|
||||
return 0;
|
||||
}
|
||||
else if (thisMostSpecificCondition == null) {
|
||||
return 1;
|
||||
}
|
||||
else if (otherMostSpecificCondition == null) {
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
return thisMostSpecificCondition.compareTo(otherMostSpecificCondition);
|
||||
}
|
||||
}
|
||||
|
||||
private MediaTypeRequestCondition getMostSpecificCondition() {
|
||||
if (!isEmpty()) {
|
||||
return getSortedConditions().get(0);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class ConsumeRequestCondition extends MediaTypesRequestCondition.MediaTypeRequestCondition {
|
||||
|
||||
ConsumeRequestCondition(String expression) {
|
||||
ConsumeMediaTypeExpression(String expression) {
|
||||
super(expression);
|
||||
}
|
||||
|
||||
ConsumeRequestCondition(MediaType mediaType, boolean negated) {
|
||||
ConsumeMediaTypeExpression(MediaType mediaType, boolean negated) {
|
||||
super(mediaType, negated);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean match(HttpServletRequest request, MediaType mediaType) {
|
||||
MediaType contentType = getContentType(request);
|
||||
|
||||
MediaType contentType = StringUtils.hasLength(request.getContentType()) ?
|
||||
MediaType.parseMediaType(request.getContentType()) :
|
||||
MediaType.APPLICATION_OCTET_STREAM ;
|
||||
|
||||
return mediaType.includes(contentType);
|
||||
}
|
||||
|
||||
private MediaType getContentType(HttpServletRequest request) {
|
||||
if (StringUtils.hasLength(request.getContentType())) {
|
||||
return MediaType.parseMediaType(request.getContentType());
|
||||
}
|
||||
else {
|
||||
return MediaType.APPLICATION_OCTET_STREAM;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,79 +16,117 @@
|
|||
|
||||
package org.springframework.web.servlet.mvc.method.condition;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
/**
|
||||
* Represents a collection of header request conditions, typically obtained from {@link
|
||||
* org.springframework.web.bind.annotation.RequestMapping#headers() @RequestMapping.headers()}.
|
||||
*
|
||||
* A logical conjunction (' && ') request condition that matches a request against a set of header expressions.
|
||||
*
|
||||
* <p>For details on the syntax of the expressions see {@link RequestMapping#headers()}. If the condition is
|
||||
* created with 0 header expressions, it will match to every request.
|
||||
*
|
||||
* <p>Note: when parsing header expressions, {@code "Accept"} and {@code "Content-Type"} header expressions
|
||||
* are filtered out. Those should be converted and used as "produces" and "consumes" conditions instead.
|
||||
* See the constructors for {@link ProducesRequestCondition} and {@link ConsumesRequestCondition}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see RequestConditionFactory#parseHeaders(String...)
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public class HeadersRequestCondition
|
||||
extends LogicalConjunctionRequestCondition<HeadersRequestCondition.HeaderRequestCondition>
|
||||
implements Comparable<HeadersRequestCondition> {
|
||||
public class HeadersRequestCondition extends RequestConditionSupport<HeadersRequestCondition> {
|
||||
|
||||
HeadersRequestCondition(Collection<HeaderRequestCondition> conditions) {
|
||||
super(conditions);
|
||||
private final Set<HeaderExpression> expressions;
|
||||
|
||||
/**
|
||||
* Create a {@link HeadersRequestCondition} with the given header expressions.
|
||||
*
|
||||
* <p>Note: {@code "Accept"} and {@code "Content-Type"} header expressions are filtered out.
|
||||
* 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.
|
||||
*/
|
||||
public HeadersRequestCondition(String... headers) {
|
||||
this(parseExpressions(headers));
|
||||
}
|
||||
|
||||
HeadersRequestCondition(String... headers) {
|
||||
this(parseConditions(Arrays.asList(headers)));
|
||||
|
||||
private HeadersRequestCondition(Collection<HeaderExpression> conditions) {
|
||||
this.expressions = Collections.unmodifiableSet(new LinkedHashSet<HeaderExpression>(conditions));
|
||||
}
|
||||
|
||||
private static Set<HeaderRequestCondition> parseConditions(Collection<String> params) {
|
||||
Set<HeaderRequestCondition> conditions = new LinkedHashSet<HeaderRequestCondition>(params.size());
|
||||
for (String param : params) {
|
||||
conditions.add(new HeaderRequestCondition(param));
|
||||
|
||||
private static Collection<HeaderExpression> parseExpressions(String... headers) {
|
||||
Set<HeaderExpression> expressions = new LinkedHashSet<HeaderExpression>();
|
||||
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 conditions;
|
||||
return expressions;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<HeaderExpression> getContent() {
|
||||
return expressions;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isLogicalConjunction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty set of header request conditions.
|
||||
*/
|
||||
public HeadersRequestCondition() {
|
||||
this(Collections.<HeaderRequestCondition>emptySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@code RequestCondition} that contains all conditions that match the request.
|
||||
*
|
||||
* @param request the request
|
||||
* @return a new request condition that contains all matching attributes, or {@code null} if not all conditions match
|
||||
*/
|
||||
public HeadersRequestCondition getMatchingCondition(HttpServletRequest request) {
|
||||
return match(request) ? this : null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Combines this collection of request condition with another by combining all header request conditions into a
|
||||
* logical AND.
|
||||
*
|
||||
* @param other the condition to combine with
|
||||
* Returns a new instance with the union of the header expressions from "this" and the "other" instance.
|
||||
*/
|
||||
public HeadersRequestCondition combine(HeadersRequestCondition other) {
|
||||
Set<HeaderRequestCondition> conditions = new LinkedHashSet<HeaderRequestCondition>(getConditions());
|
||||
conditions.addAll(other.getConditions());
|
||||
return new HeadersRequestCondition(conditions);
|
||||
Set<HeaderExpression> set = new LinkedHashSet<HeaderExpression>(this.expressions);
|
||||
set.addAll(other.expressions);
|
||||
return new HeadersRequestCondition(set);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns "this" instance if the request matches to all header expressions; or {@code null} otherwise.
|
||||
*/
|
||||
public HeadersRequestCondition getMatchingCondition(HttpServletRequest request) {
|
||||
for (HeaderExpression expression : expressions) {
|
||||
if (!expression.match(request)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public int compareTo(HeadersRequestCondition other) {
|
||||
return other.getConditions().size() - this.getConditions().size();
|
||||
/**
|
||||
* Returns:
|
||||
* <ul>
|
||||
* <li>0 if the two conditions have the same number of header expressions
|
||||
* <li>Less than 1 if "this" instance has more header expressions
|
||||
* <li>Greater than 1 if the "other" instance has more header expressions
|
||||
* </ul>
|
||||
*
|
||||
* <p>It is assumed that both instances have been obtained via {@link #getMatchingCondition(HttpServletRequest)}
|
||||
* and each instance contains the matching header expression only or is otherwise empty.
|
||||
*/
|
||||
public int compareTo(HeadersRequestCondition other, HttpServletRequest request) {
|
||||
return other.expressions.size() - this.expressions.size();
|
||||
}
|
||||
|
||||
static class HeaderRequestCondition extends AbstractNameValueCondition<String> {
|
||||
/**
|
||||
* Parsing and request matching logic for header expressions.
|
||||
* @see RequestMapping#headers()
|
||||
*/
|
||||
static class HeaderExpression extends AbstractNameValueExpression<String> {
|
||||
|
||||
public HeaderRequestCondition(String expression) {
|
||||
public HeaderExpression(String expression) {
|
||||
super(expression);
|
||||
}
|
||||
|
||||
|
|
@ -107,20 +145,6 @@ public class HeadersRequestCondition
|
|||
return value.equals(request.getHeader(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj != null && obj instanceof HeaderRequestCondition) {
|
||||
HeaderRequestCondition other = (HeaderRequestCondition) obj;
|
||||
return ((this.name.equalsIgnoreCase(other.name)) &&
|
||||
(this.value != null ? this.value.equals(other.value) : other.value == null) &&
|
||||
this.isNegated == other.isNegated);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = name.toLowerCase().hashCode();
|
||||
|
|
@ -128,7 +152,5 @@ public class HeadersRequestCondition
|
|||
result = 31 * result + (isNegated ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* 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.Set;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* {@link RequestCondition} implementation that represents a logical AND (i.e. &&).
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 3.1
|
||||
*/
|
||||
class LogicalConjunctionRequestCondition<T extends RequestCondition> extends RequestConditionComposite<T> {
|
||||
|
||||
LogicalConjunctionRequestCondition(Collection<T> conditions) {
|
||||
super(conditions);
|
||||
}
|
||||
|
||||
public boolean match(HttpServletRequest request) {
|
||||
Set<T> conditions = getConditions();
|
||||
if (isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
for (T condition : conditions) {
|
||||
if (!condition.match(request)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String getToStringInfix() {
|
||||
return " && ";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* 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 javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* {@link RequestCondition} implementation that represents a logical OR (i.e. ||).
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 3.1
|
||||
*/
|
||||
class LogicalDisjunctionRequestCondition<T extends RequestCondition> extends RequestConditionComposite<T> {
|
||||
|
||||
LogicalDisjunctionRequestCondition(Collection<T> conditions) {
|
||||
super(conditions);
|
||||
}
|
||||
|
||||
public boolean match(HttpServletRequest request) {
|
||||
if (isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
for (RequestCondition condition : getConditions()) {
|
||||
if (condition.match(request)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getToStringInfix() {
|
||||
return " || ";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* 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 javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
/**
|
||||
* Supports media type expressions as described in:
|
||||
* {@link RequestMapping#consumes()} and {@link RequestMapping#produces()}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
abstract class MediaTypeExpression implements Comparable<MediaTypeExpression> {
|
||||
|
||||
private final MediaType mediaType;
|
||||
|
||||
private final boolean isNegated;
|
||||
|
||||
MediaTypeExpression(String expression) {
|
||||
if (expression.startsWith("!")) {
|
||||
isNegated = true;
|
||||
expression = expression.substring(1);
|
||||
}
|
||||
else {
|
||||
isNegated = false;
|
||||
}
|
||||
this.mediaType = MediaType.parseMediaType(expression);
|
||||
}
|
||||
|
||||
MediaTypeExpression(MediaType mediaType, boolean negated) {
|
||||
this.mediaType = mediaType;
|
||||
isNegated = negated;
|
||||
}
|
||||
|
||||
public boolean match(HttpServletRequest request) {
|
||||
boolean match = match(request, this.mediaType);
|
||||
return !isNegated ? match : !match;
|
||||
}
|
||||
|
||||
protected abstract boolean match(HttpServletRequest request, MediaType mediaType);
|
||||
|
||||
MediaType getMediaType() {
|
||||
return mediaType;
|
||||
}
|
||||
|
||||
public int compareTo(MediaTypeExpression other) {
|
||||
return MediaType.SPECIFICITY_COMPARATOR.compare(this.getMediaType(), other.getMediaType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj != null && getClass().equals(obj.getClass())) {
|
||||
MediaTypeExpression other = (MediaTypeExpression) obj;
|
||||
return (this.mediaType.equals(other.mediaType)) && (this.isNegated == other.isNegated);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return mediaType.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (isNegated) {
|
||||
builder.append('!');
|
||||
}
|
||||
builder.append(mediaType.toString());
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,126 +0,0 @@
|
|||
/*
|
||||
* 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.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
class MediaTypesRequestCondition<T extends MediaTypesRequestCondition.MediaTypeRequestCondition>
|
||||
extends LogicalDisjunctionRequestCondition<T> {
|
||||
|
||||
private final List<T> sortedConditions;
|
||||
|
||||
public MediaTypesRequestCondition(Collection<T> conditions) {
|
||||
super(conditions);
|
||||
sortedConditions = new ArrayList<T>(conditions);
|
||||
Collections.sort(sortedConditions);
|
||||
}
|
||||
|
||||
protected List<T> getSortedConditions() {
|
||||
return sortedConditions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all {@link MediaType}s contained in this condition.
|
||||
*/
|
||||
public Set<MediaType> getMediaTypes() {
|
||||
Set<MediaType> result = new LinkedHashSet<MediaType>();
|
||||
for (MediaTypeRequestCondition condition : getConditions()) {
|
||||
result.add(condition.getMediaType());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
protected abstract static class MediaTypeRequestCondition
|
||||
implements RequestCondition, Comparable<MediaTypeRequestCondition> {
|
||||
|
||||
private final MediaType mediaType;
|
||||
|
||||
private final boolean isNegated;
|
||||
|
||||
MediaTypeRequestCondition(MediaType mediaType, boolean negated) {
|
||||
this.mediaType = mediaType;
|
||||
isNegated = negated;
|
||||
}
|
||||
|
||||
MediaTypeRequestCondition(String expression) {
|
||||
if (expression.startsWith("!")) {
|
||||
isNegated = true;
|
||||
expression = expression.substring(1);
|
||||
}
|
||||
else {
|
||||
isNegated = false;
|
||||
}
|
||||
this.mediaType = MediaType.parseMediaType(expression);
|
||||
}
|
||||
|
||||
public boolean match(HttpServletRequest request) {
|
||||
boolean match = match(request, this.mediaType);
|
||||
return !isNegated ? match : !match;
|
||||
}
|
||||
|
||||
protected abstract boolean match(HttpServletRequest request, MediaType mediaType);
|
||||
|
||||
MediaType getMediaType() {
|
||||
return mediaType;
|
||||
}
|
||||
|
||||
public int compareTo(MediaTypeRequestCondition other) {
|
||||
return MediaType.SPECIFICITY_COMPARATOR.compare(this.getMediaType(), other.getMediaType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj != null && getClass().equals(obj.getClass())) {
|
||||
MediaTypeRequestCondition other = (MediaTypeRequestCondition) obj;
|
||||
return (this.mediaType.equals(other.mediaType)) && (this.isNegated == other.isNegated);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return mediaType.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (isNegated) {
|
||||
builder.append('!');
|
||||
}
|
||||
builder.append(mediaType.toString());
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,80 +16,106 @@
|
|||
|
||||
package org.springframework.web.servlet.mvc.method.condition;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
|
||||
/**
|
||||
* Represents a collection of parameter request conditions, typically obtained from {@link
|
||||
* org.springframework.web.bind.annotation.RequestMapping#params() @RequestMapping.params()}.
|
||||
*
|
||||
* A logical conjunction (' && ') request condition that matches a request against a set parameter expressions.
|
||||
*
|
||||
* <p>For details on the syntax of the expressions see {@link RequestMapping#params()}. If the condition is
|
||||
* created with 0 parameter expressions, it will match to every request.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see RequestConditionFactory#parseParams(String...)
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public class ParamsRequestCondition
|
||||
extends LogicalConjunctionRequestCondition<ParamsRequestCondition.ParamRequestCondition>
|
||||
implements Comparable<ParamsRequestCondition> {
|
||||
public class ParamsRequestCondition extends RequestConditionSupport<ParamsRequestCondition> {
|
||||
|
||||
private ParamsRequestCondition(Collection<ParamRequestCondition> conditions) {
|
||||
super(conditions);
|
||||
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.
|
||||
*/
|
||||
public ParamsRequestCondition(String... params) {
|
||||
this(parseExpressions(params));
|
||||
}
|
||||
|
||||
private ParamsRequestCondition(Collection<ParamExpression> conditions) {
|
||||
this.expressions = Collections.unmodifiableSet(new LinkedHashSet<ParamExpression>(conditions));
|
||||
}
|
||||
|
||||
ParamsRequestCondition(String... params) {
|
||||
this(parseConditions(Arrays.asList(params)));
|
||||
}
|
||||
|
||||
private static Set<ParamRequestCondition> parseConditions(List<String> params) {
|
||||
Set<ParamRequestCondition> conditions = new LinkedHashSet<ParamRequestCondition>(params.size());
|
||||
for (String param : params) {
|
||||
conditions.add(new ParamRequestCondition(param));
|
||||
private static Collection<ParamExpression> parseExpressions(String... params) {
|
||||
Set<ParamExpression> expressions = new LinkedHashSet<ParamExpression>();
|
||||
if (params != null) {
|
||||
for (String header : params) {
|
||||
expressions.add(new ParamExpression(header));
|
||||
}
|
||||
}
|
||||
return conditions;
|
||||
return expressions;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<ParamExpression> getContent() {
|
||||
return expressions;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isLogicalConjunction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty set of parameter request conditions.
|
||||
*/
|
||||
public ParamsRequestCondition() {
|
||||
this(Collections.<ParamRequestCondition>emptySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@code RequestCondition} that contains all conditions that match the request.
|
||||
*
|
||||
* @param request the request
|
||||
* @return a new request condition that contains all matching attributes, or {@code null} if not all conditions match
|
||||
*/
|
||||
public ParamsRequestCondition getMatchingCondition(HttpServletRequest request) {
|
||||
return match(request) ? this : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines this collection of request condition with another by combining all parameter request conditions into a
|
||||
* logical AND.
|
||||
*
|
||||
* @param other the condition to combine with
|
||||
* Returns a new instance with the union of the param expressions from "this" and the "other" instance.
|
||||
*/
|
||||
public ParamsRequestCondition combine(ParamsRequestCondition other) {
|
||||
Set<ParamRequestCondition> conditions = new LinkedHashSet<ParamRequestCondition>(getConditions());
|
||||
conditions.addAll(other.getConditions());
|
||||
return new ParamsRequestCondition(conditions);
|
||||
Set<ParamExpression> set = new LinkedHashSet<ParamExpression>(this.expressions);
|
||||
set.addAll(other.expressions);
|
||||
return new ParamsRequestCondition(set);
|
||||
}
|
||||
|
||||
public int compareTo(ParamsRequestCondition other) {
|
||||
return other.getConditions().size() - this.getConditions().size();
|
||||
/**
|
||||
* Returns "this" instance if the request matches to all parameter expressions; or {@code null} otherwise.
|
||||
*/
|
||||
public ParamsRequestCondition getMatchingCondition(HttpServletRequest request) {
|
||||
for (ParamExpression expression : expressions) {
|
||||
if (!expression.match(request)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
static class ParamRequestCondition extends AbstractNameValueCondition<String> {
|
||||
/**
|
||||
* Returns:
|
||||
* <ul>
|
||||
* <li>0 if the two conditions have the same number of parameter expressions
|
||||
* <li>Less than 1 if "this" instance has more parameter expressions
|
||||
* <li>Greater than 1 if the "other" instance has more parameter expressions
|
||||
* </ul>
|
||||
*
|
||||
* <p>It is assumed that both instances have been obtained via {@link #getMatchingCondition(HttpServletRequest)}
|
||||
* and each instance contains the matching parameter expressions only or is otherwise empty.
|
||||
*/
|
||||
public int compareTo(ParamsRequestCondition other, HttpServletRequest request) {
|
||||
return other.expressions.size() - this.expressions.size();
|
||||
}
|
||||
|
||||
ParamRequestCondition(String expression) {
|
||||
/**
|
||||
* Parsing and request matching logic for parameter expressions.
|
||||
* @see RequestMapping#params()
|
||||
*/
|
||||
static class ParamExpression extends AbstractNameValueExpression<String> {
|
||||
|
||||
ParamExpression(String expression) {
|
||||
super(expression);
|
||||
}
|
||||
|
||||
|
|
@ -107,20 +133,6 @@ public class ParamsRequestCondition
|
|||
protected boolean matchValue(HttpServletRequest request) {
|
||||
return value.equals(request.getParameter(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj != null && obj instanceof ParamRequestCondition) {
|
||||
ParamRequestCondition other = (ParamRequestCondition) obj;
|
||||
return ((this.name.equals(other.name)) &&
|
||||
(this.value != null ? this.value.equals(other.value) : other.value == null) &&
|
||||
this.isNegated == other.isNegated);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* 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.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.util.UrlPathHelper;
|
||||
|
||||
/**
|
||||
* A logical disjunction (' || ') request condition that matches a request against a set of URL path patterns.
|
||||
*
|
||||
* <p>See Javadoc on individual methods for details on how URL patterns are matched, combined, and compared.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public class PatternsRequestCondition extends RequestConditionSupport<PatternsRequestCondition> {
|
||||
|
||||
private final Set<String> patterns;
|
||||
|
||||
private final UrlPathHelper urlPathHelper;
|
||||
|
||||
private final PathMatcher pathMatcher;
|
||||
|
||||
/**
|
||||
* 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 0 or more URL patterns; if 0 the condition will match to every request.
|
||||
*/
|
||||
public PatternsRequestCondition(String... patterns) {
|
||||
this(patterns, new UrlPathHelper(), new AntPathMatcher());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 urlPathHelper a {@link UrlPathHelper} for determining the lookup path for a request
|
||||
* @param pathMatcher a {@link PathMatcher} for pattern path matching
|
||||
*/
|
||||
public PatternsRequestCondition(String[] patterns, UrlPathHelper urlPathHelper, PathMatcher pathMatcher) {
|
||||
this(asList(patterns), urlPathHelper, pathMatcher);
|
||||
}
|
||||
|
||||
private static List<String> asList(String... patterns) {
|
||||
return patterns != null ? Arrays.asList(patterns) : Collections.<String>emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor.
|
||||
*/
|
||||
private PatternsRequestCondition(Collection<String> patterns, UrlPathHelper urlPathHelper, PathMatcher pathMatcher) {
|
||||
this.patterns = Collections.unmodifiableSet(prependLeadingSlash(patterns));
|
||||
this.urlPathHelper = urlPathHelper;
|
||||
this.pathMatcher = pathMatcher;
|
||||
}
|
||||
|
||||
private static Set<String> prependLeadingSlash(Collection<String> patterns) {
|
||||
if (patterns == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
Set<String> result = new LinkedHashSet<String>(patterns.size());
|
||||
for (String pattern : patterns) {
|
||||
if (StringUtils.hasLength(pattern) && !pattern.startsWith("/")) {
|
||||
pattern = "/" + pattern;
|
||||
}
|
||||
result.add(pattern);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Set<String> getPatterns() {
|
||||
return patterns;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<String> getContent() {
|
||||
return patterns;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isLogicalConjunction() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance with URL patterns from the current instance ("this") and
|
||||
* the "other" instance as follows:
|
||||
* <ul>
|
||||
* <li>If there are patterns in both instances, combine the patterns in "this" with
|
||||
* the patterns in "other" using {@link PathMatcher#combine(String, String)}.
|
||||
* <li>If only one instance has patterns, use them.
|
||||
* <li>If neither instance has patterns, use "".
|
||||
* </ul>
|
||||
*/
|
||||
public PatternsRequestCondition combine(PatternsRequestCondition other) {
|
||||
Set<String> result = new LinkedHashSet<String>();
|
||||
if (!this.patterns.isEmpty() && !other.patterns.isEmpty()) {
|
||||
for (String pattern1 : this.patterns) {
|
||||
for (String pattern2 : other.patterns) {
|
||||
result.add(pathMatcher.combine(pattern1, pattern2));
|
||||
}
|
||||
}
|
||||
}
|
||||
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, urlPathHelper, pathMatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if any of the patterns match the given request and returns an instance that is guaranteed
|
||||
* to contain matching patterns, sorted via {@link PathMatcher#getPatternComparator(String)}.
|
||||
*
|
||||
* <p>A matching pattern is obtained by making checks in the following order:
|
||||
* <ul>
|
||||
* <li>Direct match
|
||||
* <li>A pattern match with ".*" appended assuming the pattern already doesn't contain "."
|
||||
* <li>A pattern match
|
||||
* <li>A pattern match with "/" appended assuming the patterns already end with "/"
|
||||
* </ul>
|
||||
*
|
||||
* @param request the current request
|
||||
*
|
||||
* @return the same instance if the condition contains no patterns;
|
||||
* or a new condition with sorted matching patterns; or {@code null} if no patterns match.
|
||||
*/
|
||||
public PatternsRequestCondition getMatchingCondition(HttpServletRequest request) {
|
||||
if (patterns.isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
String lookupPath = urlPathHelper.getLookupPathForRequest(request);
|
||||
List<String> matches = new ArrayList<String>();
|
||||
for (String pattern : patterns) {
|
||||
String match = getMatchingPattern(pattern, lookupPath);
|
||||
if (match != null) {
|
||||
matches.add(match);
|
||||
}
|
||||
}
|
||||
Collections.sort(matches, pathMatcher.getPatternComparator(lookupPath));
|
||||
return matches.isEmpty() ? null : new PatternsRequestCondition(matches, urlPathHelper, pathMatcher);
|
||||
}
|
||||
|
||||
private String getMatchingPattern(String pattern, String lookupPath) {
|
||||
if (pattern.equals(lookupPath)) {
|
||||
return pattern;
|
||||
}
|
||||
boolean hasSuffix = pattern.indexOf('.') != -1;
|
||||
if (!hasSuffix && pathMatcher.match(pattern + ".*", lookupPath)) {
|
||||
return pattern + ".*";
|
||||
}
|
||||
if (pathMatcher.match(pattern, lookupPath)) {
|
||||
return pattern;
|
||||
}
|
||||
boolean endsWithSlash = pattern.endsWith("/");
|
||||
if (!endsWithSlash && pathMatcher.match(pattern + "/", lookupPath)) {
|
||||
return pattern +"/";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the two conditions and return 0 if they match equally to the request, less than one if "this"
|
||||
* matches the request more, and greater than one if "other" matches the request more. Patterns are
|
||||
* compared one at a time, from top to bottom via {@link PathMatcher#getPatternComparator(String)}.
|
||||
* If all compared patterns match equally, but one instance has more patterns, it is a closer match.
|
||||
*
|
||||
* <p>It is assumed that both instances have been obtained via {@link #getMatchingCondition(HttpServletRequest)}
|
||||
* to ensure they contain only patterns that match the request and are sorted with the best matches on top.
|
||||
*/
|
||||
public int compareTo(PatternsRequestCondition other, HttpServletRequest request) {
|
||||
String lookupPath = urlPathHelper.getLookupPathForRequest(request);
|
||||
Comparator<String> patternComparator = pathMatcher.getPatternComparator(lookupPath);
|
||||
|
||||
Iterator<String> iterator = patterns.iterator();
|
||||
Iterator<String> iteratorOther = other.patterns.iterator();
|
||||
while (iterator.hasNext() && iteratorOther.hasNext()) {
|
||||
int result = patternComparator.compare(iterator.next(), iteratorOther.next());
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (iterator.hasNext()) {
|
||||
return -1;
|
||||
}
|
||||
else if (iteratorOther.hasNext()) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -16,99 +16,170 @@
|
|||
|
||||
package org.springframework.web.servlet.mvc.method.condition;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.servlet.mvc.method.condition.HeadersRequestCondition.HeaderExpression;
|
||||
|
||||
/**
|
||||
* Represents a collection of produces conditions, typically obtained from {@link
|
||||
* org.springframework.web.bind.annotation.RequestMapping#produces() @RequestMapping.produces()}.
|
||||
*
|
||||
* A logical disjunction (' || ') request condition to match requests against producible media type expressions.
|
||||
*
|
||||
* <p>For details on the syntax of the expressions see {@link RequestMapping#consumes()}. If the condition is
|
||||
* created with 0 producible media type expressions, it matches to every request.
|
||||
*
|
||||
* <p>This request condition is also capable of parsing header expressions specifically selecting 'Accept' header
|
||||
* expressions and converting them to prodicuble media type expressions.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see RequestConditionFactory#parseProduces(String...)
|
||||
* @see RequestConditionFactory#parseProduces(String[], String[])
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public class ProducesRequestCondition
|
||||
extends MediaTypesRequestCondition<ProducesRequestCondition.ProduceRequestCondition> {
|
||||
public class ProducesRequestCondition extends RequestConditionSupport<ProducesRequestCondition> {
|
||||
|
||||
ProducesRequestCondition(Collection<ProduceRequestCondition> conditions) {
|
||||
super(conditions);
|
||||
}
|
||||
|
||||
|
||||
ProducesRequestCondition(String... consumes) {
|
||||
this(parseConditions(Arrays.asList(consumes)));
|
||||
}
|
||||
|
||||
private static Set<ProduceRequestCondition> parseConditions(List<String> consumes) {
|
||||
Set<ProduceRequestCondition> conditions = new LinkedHashSet<ProduceRequestCondition>(consumes.size());
|
||||
for (String consume : consumes) {
|
||||
conditions.add(new ProduceRequestCondition(consume));
|
||||
}
|
||||
return conditions;
|
||||
}
|
||||
private final List<ProduceMediaTypeExpression> expressions;
|
||||
|
||||
/**
|
||||
* Creates an empty set of consumes request conditions.
|
||||
* Creates a {@link ProducesRequestCondition} with the given producible media type expressions.
|
||||
* @param produces the expressions to parse; if 0 the condition matches to every request
|
||||
*/
|
||||
public ProducesRequestCondition() {
|
||||
this(Collections.<ProduceRequestCondition>emptySet());
|
||||
public ProducesRequestCondition(String... produces) {
|
||||
this(produces, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public ProducesRequestCondition(String[] produces, String[] headers) {
|
||||
this(parseExpressions(produces, headers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@code RequestCondition} that contains all conditions of this key that match the request.
|
||||
*
|
||||
* @param request the request
|
||||
* @return a new request condition that contains all matching attributes, or {@code null} if not all conditions match
|
||||
* A private constructor.
|
||||
*/
|
||||
private ProducesRequestCondition(Collection<ProduceMediaTypeExpression> expressions) {
|
||||
this.expressions = new ArrayList<ProduceMediaTypeExpression>(expressions);
|
||||
Collections.sort(this.expressions);
|
||||
}
|
||||
|
||||
private static Set<ProduceMediaTypeExpression> parseExpressions(String[] produces, String[] headers) {
|
||||
Set<ProduceMediaTypeExpression> result = new LinkedHashSet<ProduceMediaTypeExpression>();
|
||||
if (headers != null) {
|
||||
for (String header : headers) {
|
||||
HeaderExpression expr = new 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the producible media types contained in all expressions of this condition.
|
||||
*/
|
||||
public Set<MediaType> getMediaTypes() {
|
||||
Set<MediaType> result = new LinkedHashSet<MediaType>();
|
||||
for (ProduceMediaTypeExpression expression : expressions) {
|
||||
result.add(expression.getMediaType());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this condition contains no producible media type expressions.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return expressions.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<ProduceMediaTypeExpression> getContent() {
|
||||
return expressions;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isLogicalConjunction() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the "other" instance if "other" as long as it contains any expressions; or "this" instance otherwise.
|
||||
* In other words "other" takes precedence over "this" as long as it contains any expressions.
|
||||
* <p>Example: method-level "produces" overrides type-level "produces" condition.
|
||||
*/
|
||||
public ProducesRequestCondition combine(ProducesRequestCondition other) {
|
||||
return !other.expressions.isEmpty() ? other : this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if any of the producible 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.
|
||||
*/
|
||||
public ProducesRequestCondition getMatchingCondition(HttpServletRequest request) {
|
||||
if (isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
Set<ProduceRequestCondition> matchingConditions = new LinkedHashSet<ProduceRequestCondition>(getConditions());
|
||||
for (Iterator<ProduceRequestCondition> iterator = matchingConditions.iterator(); iterator.hasNext();) {
|
||||
ProduceRequestCondition condition = iterator.next();
|
||||
if (!condition.match(request)) {
|
||||
Set<ProduceMediaTypeExpression> result = new LinkedHashSet<ProduceMediaTypeExpression>(expressions);
|
||||
for (Iterator<ProduceMediaTypeExpression> iterator = result.iterator(); iterator.hasNext();) {
|
||||
ProduceMediaTypeExpression expression = iterator.next();
|
||||
if (!expression.match(request)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
if (matchingConditions.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return new ProducesRequestCondition(matchingConditions);
|
||||
}
|
||||
return (result.isEmpty()) ? null : new ProducesRequestCondition(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines this collection of request condition with another. Returns {@code other}, unless it has the default
|
||||
* value (i.e. {@code */*}).
|
||||
*
|
||||
* @param other the condition to combine with
|
||||
* Returns:
|
||||
* <ul>
|
||||
* <li>0 if the two conditions have the same number of expressions
|
||||
* <li>Less than 1 if "this" has more in number or more specific producible media type expressions
|
||||
* <li>Greater than 1 if "other" has more in number or more specific producible media type expressions
|
||||
* </ul>
|
||||
*
|
||||
* <p>It is assumed that both instances have been obtained via {@link #getMatchingCondition(HttpServletRequest)}
|
||||
* and each instance contains the matching producible media type expression only or is otherwise empty.
|
||||
*/
|
||||
public ProducesRequestCondition combine(ProducesRequestCondition other) {
|
||||
return !other.isEmpty() ? other : this;
|
||||
}
|
||||
|
||||
public int compareTo(ProducesRequestCondition other, List<MediaType> acceptedMediaTypes) {
|
||||
public int compareTo(ProducesRequestCondition other, HttpServletRequest request) {
|
||||
String acceptHeader = request.getHeader("Accept");
|
||||
List<MediaType> acceptedMediaTypes = MediaType.parseMediaTypes(acceptHeader);
|
||||
MediaType.sortByQualityValue(acceptedMediaTypes);
|
||||
|
||||
for (MediaType acceptedMediaType : acceptedMediaTypes) {
|
||||
int thisIndex = this.indexOfMediaType(acceptedMediaType);
|
||||
int otherIndex = other.indexOfMediaType(acceptedMediaType);
|
||||
if (thisIndex != otherIndex) {
|
||||
return otherIndex - thisIndex;
|
||||
} else if (thisIndex != -1 && otherIndex != -1) {
|
||||
ProduceRequestCondition thisCondition = this.getSortedConditions().get(thisIndex);
|
||||
ProduceRequestCondition otherCondition = other.getSortedConditions().get(otherIndex);
|
||||
int result = thisCondition.compareTo(otherCondition);
|
||||
ProduceMediaTypeExpression thisExpr = this.expressions.get(thisIndex);
|
||||
ProduceMediaTypeExpression otherExpr = other.expressions.get(otherIndex);
|
||||
int result = thisExpr.compareTo(otherExpr);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
|
@ -118,29 +189,31 @@ public class ProducesRequestCondition
|
|||
}
|
||||
|
||||
private int indexOfMediaType(MediaType mediaType) {
|
||||
List<ProduceRequestCondition> sortedConditions = getSortedConditions();
|
||||
for (int i = 0; i < sortedConditions.size(); i++) {
|
||||
ProduceRequestCondition condition = sortedConditions.get(i);
|
||||
if (mediaType.includes(condition.getMediaType())) {
|
||||
for (int i = 0; i < expressions.size(); i++) {
|
||||
if (mediaType.includes(expressions.get(i).getMediaType())) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static class ProduceRequestCondition extends MediaTypesRequestCondition.MediaTypeRequestCondition {
|
||||
/**
|
||||
* Parsing and request matching logic for producible media type expressions.
|
||||
* @see RequestMapping#produces()
|
||||
*/
|
||||
static class ProduceMediaTypeExpression extends MediaTypeExpression {
|
||||
|
||||
ProduceRequestCondition(MediaType mediaType, boolean negated) {
|
||||
ProduceMediaTypeExpression(MediaType mediaType, boolean negated) {
|
||||
super(mediaType, negated);
|
||||
}
|
||||
|
||||
ProduceRequestCondition(String expression) {
|
||||
ProduceMediaTypeExpression(String expression) {
|
||||
super(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean match(HttpServletRequest request, MediaType mediaType) {
|
||||
List<MediaType> acceptedMediaTypes = getAccept(request);
|
||||
List<MediaType> acceptedMediaTypes = getAcceptedMediaTypes(request);
|
||||
for (MediaType acceptedMediaType : acceptedMediaTypes) {
|
||||
if (mediaType.isCompatibleWith(acceptedMediaType)) {
|
||||
return true;
|
||||
|
|
@ -149,7 +222,7 @@ public class ProducesRequestCondition
|
|||
return false;
|
||||
}
|
||||
|
||||
private List<MediaType> getAccept(HttpServletRequest request) {
|
||||
private List<MediaType> getAcceptedMediaTypes(HttpServletRequest request) {
|
||||
String acceptHeader = request.getHeader("Accept");
|
||||
if (StringUtils.hasLength(acceptHeader)) {
|
||||
return MediaType.parseMediaTypes(acceptHeader);
|
||||
|
|
@ -159,4 +232,5 @@ public class ProducesRequestCondition
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,23 +19,39 @@ package org.springframework.web.servlet.mvc.method.condition;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* Defines the contract for conditions that must be met given an incoming request.
|
||||
*
|
||||
* <p>Implementations of this interface are created by the {@link RequestConditionFactory}.
|
||||
*
|
||||
* The contract for request conditions.
|
||||
*
|
||||
* <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.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Arjen Poutsma
|
||||
* @see RequestConditionFactory
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface RequestCondition {
|
||||
public interface RequestCondition<This extends RequestCondition<This>> {
|
||||
|
||||
/**
|
||||
* Indicates whether this condition matches against the given servlet request.
|
||||
*
|
||||
* @param request the request
|
||||
* @return {@code true} if this condition matches the request; {@code false} otherwise
|
||||
* Defines the rules for combining "this" condition (i.e. the current instance) with another condition.
|
||||
* <p>Example: combine type- and method-level request mapping conditions.
|
||||
*
|
||||
* @returns a request condition instance that is the result of combining the two condition instances.
|
||||
*/
|
||||
boolean match(HttpServletRequest request);
|
||||
This combine(This other);
|
||||
|
||||
/**
|
||||
* Checks if this condition matches the provided request and returns a potentially new request condition
|
||||
* with content tailored to the current request. For example a condition with URL patterns might return
|
||||
* a new condition that contains matching patterns sorted with best matching patterns on top.
|
||||
*
|
||||
* @return a condition instance in case of a match; or {@code null} if there is no match.
|
||||
*/
|
||||
This 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)}
|
||||
* to ensure they have content relevant to current request only.
|
||||
*/
|
||||
int compareTo(This other, HttpServletRequest request);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,194 +0,0 @@
|
|||
/*
|
||||
* 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.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
/**
|
||||
* Factory for {@link RequestCondition} objects.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract class RequestConditionFactory {
|
||||
|
||||
private static final String CONTENT_TYPE_HEADER = "Content-Type";
|
||||
|
||||
private static final String ACCEPT_HEADER = "Accept";
|
||||
|
||||
/**
|
||||
* Parses the given request methods, and returns them as a single request condition.
|
||||
*
|
||||
* @param methods the methods
|
||||
* @return the request condition
|
||||
* @see org.springframework.web.bind.annotation.RequestMapping#method()
|
||||
*/
|
||||
public static RequestMethodsRequestCondition parseMethods(RequestMethod... methods) {
|
||||
return methods != null ? new RequestMethodsRequestCondition(methods) : new RequestMethodsRequestCondition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given parameters, and returns them as a single request condition.
|
||||
*
|
||||
* @param params the parameters
|
||||
* @return the request condition
|
||||
* @see org.springframework.web.bind.annotation.RequestMapping#params()
|
||||
*/
|
||||
public static ParamsRequestCondition parseParams(String... params) {
|
||||
return params != null ? new ParamsRequestCondition(params) : new ParamsRequestCondition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given headers, and returns them as a single request condition.
|
||||
*
|
||||
* @param headers the headers
|
||||
* @return the request condition
|
||||
* @see org.springframework.web.bind.annotation.RequestMapping#headers()
|
||||
*/
|
||||
public static HeadersRequestCondition parseHeaders(String... headers) {
|
||||
if (headers == null) {
|
||||
return new HeadersRequestCondition();
|
||||
}
|
||||
HeadersRequestCondition headersCondition = new HeadersRequestCondition(headers);
|
||||
|
||||
// filter out Accept and Content-Type headers, they are dealt with by produces and consumes respectively
|
||||
Set<HeadersRequestCondition.HeaderRequestCondition> filteredConditions =
|
||||
new LinkedHashSet<HeadersRequestCondition.HeaderRequestCondition>(headersCondition.getConditions());
|
||||
|
||||
for (Iterator<HeadersRequestCondition.HeaderRequestCondition> iterator = filteredConditions.iterator();
|
||||
iterator.hasNext();) {
|
||||
HeadersRequestCondition.HeaderRequestCondition headerCondition = iterator.next();
|
||||
if (ACCEPT_HEADER.equalsIgnoreCase(headerCondition.name) ||
|
||||
CONTENT_TYPE_HEADER.equalsIgnoreCase(headerCondition.name)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
return new HeadersRequestCondition(filteredConditions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given consumes, and returns them as a single request condition.
|
||||
*
|
||||
* @param consumes the consumes
|
||||
* @return the request condition
|
||||
* @see org.springframework.web.bind.annotation.RequestMapping#consumes()
|
||||
*/
|
||||
public static ConsumesRequestCondition parseConsumes(String... consumes) {
|
||||
return new ConsumesRequestCondition(consumes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given consumes and {@code Content-Type} headers, and returns them as a single request condition. <p>Only
|
||||
* {@code Content-Type} headers will be used, all other headers will be ignored.
|
||||
*
|
||||
* @param consumes the consumes
|
||||
* @param headers the headers
|
||||
* @return the request condition
|
||||
* @see org.springframework.web.bind.annotation.RequestMapping#consumes()
|
||||
*/
|
||||
public static ConsumesRequestCondition parseConsumes(String[] consumes, String[] headers) {
|
||||
|
||||
List<ConsumesRequestCondition.ConsumeRequestCondition> allConditions = parseContentTypeHeaders(headers);
|
||||
|
||||
// ignore the default consumes() value if any content-type headers have been set
|
||||
boolean headersHasContentType = !allConditions.isEmpty();
|
||||
boolean consumesHasDefaultValue = consumes.length == 1 && consumes[0].equals("*/*");
|
||||
if (!headersHasContentType || !consumesHasDefaultValue) {
|
||||
for (String consume : consumes) {
|
||||
allConditions.add(new ConsumesRequestCondition.ConsumeRequestCondition(consume));
|
||||
}
|
||||
}
|
||||
return new ConsumesRequestCondition(allConditions);
|
||||
}
|
||||
|
||||
private static List<ConsumesRequestCondition.ConsumeRequestCondition> parseContentTypeHeaders(String[] headers) {
|
||||
List<ConsumesRequestCondition.ConsumeRequestCondition> conditions =
|
||||
new ArrayList<ConsumesRequestCondition.ConsumeRequestCondition>();
|
||||
HeadersRequestCondition headersCondition = new HeadersRequestCondition(headers);
|
||||
for (HeadersRequestCondition.HeaderRequestCondition headerCondition : headersCondition.getConditions()) {
|
||||
if (CONTENT_TYPE_HEADER.equalsIgnoreCase(headerCondition.name)) {
|
||||
List<MediaType> mediaTypes = MediaType.parseMediaTypes(headerCondition.value);
|
||||
for (MediaType mediaType : mediaTypes) {
|
||||
conditions.add(new ConsumesRequestCondition.ConsumeRequestCondition(mediaType,
|
||||
headerCondition.isNegated));
|
||||
}
|
||||
}
|
||||
}
|
||||
return conditions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given produces, and returns them as a single request condition.
|
||||
*
|
||||
* @param produces the produces
|
||||
* @return the request condition
|
||||
* @see org.springframework.web.bind.annotation.RequestMapping#produces()
|
||||
*/
|
||||
public static ProducesRequestCondition parseProduces(String... produces) {
|
||||
return new ProducesRequestCondition(produces);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given produces and {@code Accept} headers, and returns them as a single request condition. <p>Only {@code
|
||||
* Accept} headers will be used, all other headers will be ignored.
|
||||
*
|
||||
* @param produces the consumes
|
||||
* @param headers the headers
|
||||
* @return the request condition
|
||||
* @see org.springframework.web.bind.annotation.RequestMapping#produces()
|
||||
*/
|
||||
public static ProducesRequestCondition parseProduces(String[] produces, String[] headers) {
|
||||
|
||||
List<ProducesRequestCondition.ProduceRequestCondition> allConditions = parseAcceptHeaders(headers);
|
||||
|
||||
// ignore the default consumes() value if any accept headers have been set
|
||||
boolean headersHasAccept = !allConditions.isEmpty();
|
||||
boolean producesHasDefaultValue = produces.length == 1 && produces[0].equals("*/*");
|
||||
if (!headersHasAccept || !producesHasDefaultValue) {
|
||||
for (String produce : produces) {
|
||||
allConditions.add(new ProducesRequestCondition.ProduceRequestCondition(produce));
|
||||
}
|
||||
}
|
||||
return new ProducesRequestCondition(allConditions);
|
||||
}
|
||||
|
||||
private static List<ProducesRequestCondition.ProduceRequestCondition> parseAcceptHeaders(String[] headers) {
|
||||
List<ProducesRequestCondition.ProduceRequestCondition> allConditions =
|
||||
new ArrayList<ProducesRequestCondition.ProduceRequestCondition>();
|
||||
HeadersRequestCondition headersCondition = new HeadersRequestCondition(headers);
|
||||
for (HeadersRequestCondition.HeaderRequestCondition headerCondition : headersCondition.getConditions()) {
|
||||
if (ACCEPT_HEADER.equalsIgnoreCase(headerCondition.name)) {
|
||||
List<MediaType> mediaTypes = MediaType.parseMediaTypes(headerCondition.value);
|
||||
for (MediaType mediaType : mediaTypes) {
|
||||
allConditions.add(new ProducesRequestCondition.ProduceRequestCondition(mediaType,
|
||||
headerCondition.isNegated));
|
||||
}
|
||||
}
|
||||
}
|
||||
return allConditions;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -17,64 +17,62 @@
|
|||
package org.springframework.web.servlet.mvc.method.condition;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Abstract base class for {@link RequestCondition} implementations that wrap other request conditions.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* Base class for {@link RequestCondition}s.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
abstract class RequestConditionComposite<T extends RequestCondition> implements RequestCondition {
|
||||
|
||||
private final Set<T> conditions;
|
||||
|
||||
protected RequestConditionComposite(Collection<T> conditions) {
|
||||
this.conditions = Collections.unmodifiableSet(new LinkedHashSet<T>(conditions));
|
||||
}
|
||||
|
||||
protected Set<T> getConditions() {
|
||||
return conditions;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return conditions.isEmpty();
|
||||
}
|
||||
|
||||
abstract class RequestConditionSupport<This extends RequestConditionSupport<This>> implements RequestCondition<This> {
|
||||
|
||||
/**
|
||||
* Returns the individual expressions a request condition is composed of such as
|
||||
* URL patterns, HTTP request methods, parameter expressions, etc.
|
||||
*/
|
||||
protected abstract Collection<?> getContent();
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o != null && getClass().equals(o.getClass())) {
|
||||
RequestConditionComposite other = (RequestConditionComposite) o;
|
||||
return this.conditions.equals(other.conditions);
|
||||
RequestConditionSupport<?> other = (RequestConditionSupport<?>) o;
|
||||
return getContent().equals(other.getContent());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return conditions.hashCode();
|
||||
return getContent().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder("[");
|
||||
String infix = getToStringInfix();
|
||||
for (Iterator<T> iterator = conditions.iterator(); iterator.hasNext();) {
|
||||
RequestCondition condition = iterator.next();
|
||||
builder.append(condition.toString());
|
||||
for (Iterator<?> iterator = getContent().iterator(); iterator.hasNext();) {
|
||||
Object expression = iterator.next();
|
||||
builder.append(expression.toString());
|
||||
if (iterator.hasNext()) {
|
||||
builder.append(infix);
|
||||
if (isLogicalConjunction()) {
|
||||
builder.append(" && ");
|
||||
}
|
||||
else {
|
||||
builder.append(" || ");
|
||||
}
|
||||
}
|
||||
}
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
protected abstract String getToStringInfix();
|
||||
/**
|
||||
* Returns {@code true} if the individual expressions of the condition are combined via logical
|
||||
* conjunction (" && "); or {@code false} otherwise.
|
||||
*/
|
||||
protected abstract boolean isLogicalConjunction();
|
||||
|
||||
}
|
||||
|
|
@ -22,132 +22,102 @@ import java.util.Collections;
|
|||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
/**
|
||||
* Represents a collection of {@link RequestMethod} conditions, typically obtained from {@link
|
||||
* org.springframework.web.bind.annotation.RequestMapping#method() @RequestMapping.methods()}.
|
||||
*
|
||||
* A logical disjunction (' || ') request condition that matches a request against a set of {@link RequestMethod}s.
|
||||
*
|
||||
* <p>If the condition is created with 0 HTTP request methods, it matches to every request.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see RequestConditionFactory#parseMethods(RequestMethod...)
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public class RequestMethodsRequestCondition
|
||||
extends LogicalDisjunctionRequestCondition<RequestMethodsRequestCondition.RequestMethodRequestCondition>
|
||||
implements Comparable<RequestMethodsRequestCondition> {
|
||||
|
||||
private RequestMethodsRequestCondition(Collection<RequestMethodRequestCondition> conditions) {
|
||||
super(conditions);
|
||||
}
|
||||
|
||||
RequestMethodsRequestCondition(RequestMethod... methods) {
|
||||
this(parseConditions(Arrays.asList(methods)));
|
||||
}
|
||||
|
||||
private static Set<RequestMethodRequestCondition> parseConditions(List<RequestMethod> methods) {
|
||||
Set<RequestMethodRequestCondition> conditions =
|
||||
new LinkedHashSet<RequestMethodRequestCondition>(methods.size());
|
||||
for (RequestMethod method : methods) {
|
||||
conditions.add(new RequestMethodRequestCondition(method));
|
||||
}
|
||||
return conditions;
|
||||
}
|
||||
public class RequestMethodsRequestCondition extends RequestConditionSupport<RequestMethodsRequestCondition> {
|
||||
|
||||
private final Set<RequestMethod> methods;
|
||||
|
||||
/**
|
||||
* Creates an empty set of method request conditions.
|
||||
* 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.
|
||||
*/
|
||||
public RequestMethodsRequestCondition() {
|
||||
this(Collections.<RequestMethodRequestCondition>emptySet());
|
||||
public RequestMethodsRequestCondition(RequestMethod... requestMethods) {
|
||||
this(asList(requestMethods));
|
||||
}
|
||||
|
||||
private static List<RequestMethod> asList(RequestMethod... requestMethods) {
|
||||
return requestMethods != null ? Arrays.asList(requestMethods) : Collections.<RequestMethod>emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor.
|
||||
*/
|
||||
private RequestMethodsRequestCondition(Collection<RequestMethod> requestMethods) {
|
||||
this.methods = Collections.unmodifiableSet(new LinkedHashSet<RequestMethod>(requestMethods));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all {@link RequestMethod}s contained in this condition.
|
||||
*/
|
||||
public Set<RequestMethod> getMethods() {
|
||||
Set<RequestMethod> result = new LinkedHashSet<RequestMethod>();
|
||||
for (RequestMethodRequestCondition condition : getConditions()) {
|
||||
result.add(condition.getMethod());
|
||||
}
|
||||
return result;
|
||||
return methods;
|
||||
}
|
||||
|
||||
public int compareTo(RequestMethodsRequestCondition other) {
|
||||
return other.getConditions().size() - this.getConditions().size();
|
||||
@Override
|
||||
protected Collection<RequestMethod> getContent() {
|
||||
return methods;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isLogicalConjunction() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@code RequestMethodsRequestCondition} that contains all conditions that match the request.
|
||||
*
|
||||
* @param request the request
|
||||
* @return a new request condition that contains all matching attributes, or {@code null} if not all conditions match
|
||||
*/
|
||||
public RequestMethodsRequestCondition getMatchingCondition(HttpServletRequest request) {
|
||||
if (isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
else {
|
||||
if (match(request)) {
|
||||
return new RequestMethodsRequestCondition(RequestMethod.valueOf(request.getMethod()));
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines this collection of request method conditions with another by combining all methods into a logical OR.
|
||||
*
|
||||
* @param other the condition to combine with
|
||||
* Returns a new instance with a union of the HTTP request methods from "this" and the "other" instance.
|
||||
*/
|
||||
public RequestMethodsRequestCondition combine(RequestMethodsRequestCondition other) {
|
||||
Set<RequestMethodRequestCondition> conditions =
|
||||
new LinkedHashSet<RequestMethodRequestCondition>(getConditions());
|
||||
conditions.addAll(other.getConditions());
|
||||
return new RequestMethodsRequestCondition(conditions);
|
||||
Set<RequestMethod> set = new LinkedHashSet<RequestMethod>(this.methods);
|
||||
set.addAll(other.methods);
|
||||
return new RequestMethodsRequestCondition(set);
|
||||
}
|
||||
|
||||
static class RequestMethodRequestCondition implements RequestCondition {
|
||||
|
||||
private final RequestMethod method;
|
||||
|
||||
RequestMethodRequestCondition(RequestMethod method) {
|
||||
this.method = method;
|
||||
/**
|
||||
* Checks if any of the HTTP request methods match the given request and returns an instance that
|
||||
* contain the matching request method.
|
||||
* @param request the current request
|
||||
* @return the same instance if the condition contains no request method;
|
||||
* or a new condition with the matching request method; or {@code null} if no request methods match.
|
||||
*/
|
||||
public RequestMethodsRequestCondition getMatchingCondition(HttpServletRequest request) {
|
||||
if (methods.isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
|
||||
RequestMethod getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public boolean match(HttpServletRequest request) {
|
||||
RequestMethod method = RequestMethod.valueOf(request.getMethod());
|
||||
return this.method.equals(method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
RequestMethod incomingRequestMethod = RequestMethod.valueOf(request.getMethod());
|
||||
for (RequestMethod method : methods) {
|
||||
if (method.equals(incomingRequestMethod)) {
|
||||
return new RequestMethodsRequestCondition(method);
|
||||
}
|
||||
if (obj != null && obj instanceof RequestMethodRequestCondition) {
|
||||
RequestMethodRequestCondition other = (RequestMethodRequestCondition) obj;
|
||||
return this.method.equals(other.method);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return method.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return method.toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns:
|
||||
* <ul>
|
||||
* <li>0 if the two conditions contain the same number of HTTP request methods.
|
||||
* <li>Less than 1 if "this" instance has an HTTP request method but "other" doesn't.
|
||||
* <li>Greater than 1 "other" has an HTTP request method but "this" doesn't.
|
||||
* </ul>
|
||||
*
|
||||
* <p>It is assumed that both instances have been obtained via {@link #getMatchingCondition(HttpServletRequest)}
|
||||
* and therefore each instance contains the matching HTTP request method only or is otherwise empty.
|
||||
*/
|
||||
public int compareTo(RequestMethodsRequestCondition other, HttpServletRequest request) {
|
||||
return other.methods.size() - this.methods.size();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,11 @@
|
|||
|
||||
package org.springframework.web.servlet.mvc.method;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
|
@ -23,17 +28,14 @@ import java.util.List;
|
|||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||
import org.springframework.web.servlet.mvc.method.condition.RequestConditionFactory;
|
||||
import org.springframework.web.servlet.mvc.method.condition.ParamsRequestCondition;
|
||||
import org.springframework.web.servlet.mvc.method.condition.ProducesRequestCondition;
|
||||
import org.springframework.web.servlet.mvc.method.condition.RequestMethodsRequestCondition;
|
||||
import org.springframework.web.util.UrlPathHelper;
|
||||
|
||||
import static java.util.Arrays.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Test fixture with {@link RequestMappingHandlerMapping} testing its {@link RequestMappingInfo} comparator.
|
||||
*
|
||||
|
|
@ -57,8 +59,8 @@ public class RequestMappingInfoComparatorTests {
|
|||
request.setRequestURI("/foo");
|
||||
String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
|
||||
Comparator<RequestMappingInfo> comparator = handlerMapping.getMappingComparator(lookupPath, request);
|
||||
RequestMappingInfo key1 = new RequestMappingInfo(asList("/fo*"), null);
|
||||
RequestMappingInfo key2 = new RequestMappingInfo(asList("/foo"), null);
|
||||
RequestMappingInfo key1 = new RequestMappingInfo(new String[]{"/fo*"});
|
||||
RequestMappingInfo key2 = new RequestMappingInfo(new String[]{"/foo"});
|
||||
|
||||
assertEquals(1, comparator.compare(key1, key2));
|
||||
}
|
||||
|
|
@ -68,8 +70,8 @@ public class RequestMappingInfoComparatorTests {
|
|||
request.setRequestURI("/foo");
|
||||
String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
|
||||
Comparator<RequestMappingInfo> comparator = handlerMapping.getMappingComparator(lookupPath, request);
|
||||
RequestMappingInfo key1 = new RequestMappingInfo(asList("/foo*"), null);
|
||||
RequestMappingInfo key2 = new RequestMappingInfo(asList("/foo*"), null);
|
||||
RequestMappingInfo key1 = new RequestMappingInfo(new String[]{"/foo*"});
|
||||
RequestMappingInfo key2 = new RequestMappingInfo(new String[]{"/foo*"});
|
||||
|
||||
assertEquals(0, comparator.compare(key1, key2));
|
||||
}
|
||||
|
|
@ -78,20 +80,20 @@ public class RequestMappingInfoComparatorTests {
|
|||
public void greaterNumberOfMatchingPatternsWins() throws Exception {
|
||||
request.setRequestURI("/foo.html");
|
||||
String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
|
||||
RequestMappingInfo key1 = new RequestMappingInfo(asList("/foo", "*.jpeg"), null);
|
||||
RequestMappingInfo key2 = new RequestMappingInfo(asList("/foo", "*.html"), null);
|
||||
RequestMappingInfo key1 = new RequestMappingInfo(new String[]{"/foo", "*.jpeg"});
|
||||
RequestMappingInfo key2 = new RequestMappingInfo(new String[]{"/foo", "*.html"});
|
||||
RequestMappingInfo match1 = handlerMapping.getMatchingMapping(key1, lookupPath, request);
|
||||
RequestMappingInfo match2 = handlerMapping.getMatchingMapping(key2, lookupPath, request);
|
||||
List<RequestMappingInfo> matches = asList(match1, match2);
|
||||
Collections.sort(matches, handlerMapping.getMappingComparator(lookupPath, request));
|
||||
|
||||
assertSame(match2.getPatterns(), matches.get(0).getPatterns());
|
||||
assertSame(match2.getPatternsCondition(), matches.get(0).getPatternsCondition());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void oneMethodWinsOverNone() {
|
||||
Comparator<RequestMappingInfo> comparator = handlerMapping.getMappingComparator("", request);
|
||||
RequestMappingInfo key1 = new RequestMappingInfo(null, null);
|
||||
RequestMappingInfo key1 = new RequestMappingInfo(null);
|
||||
RequestMappingInfo key2 = new RequestMappingInfo(null, new RequestMethod[] {RequestMethod.GET});
|
||||
|
||||
assertEquals(1, comparator.compare(key1, key2));
|
||||
|
|
@ -99,10 +101,11 @@ public class RequestMappingInfoComparatorTests {
|
|||
|
||||
@Test
|
||||
public void methodsAndParams() {
|
||||
RequestMappingInfo empty = new RequestMappingInfo(null, null);
|
||||
RequestMappingInfo empty = new RequestMappingInfo(null);
|
||||
RequestMappingInfo oneMethod = new RequestMappingInfo(null, new RequestMethod[] {RequestMethod.GET});
|
||||
RequestMappingInfo oneMethodOneParam =
|
||||
new RequestMappingInfo(null, RequestConditionFactory.parseMethods(RequestMethod.GET), RequestConditionFactory.parseParams("foo"), null, null, null);
|
||||
new RequestMappingInfo(null, new RequestMethodsRequestCondition(RequestMethod.GET),
|
||||
new ParamsRequestCondition("foo"), null, null, null);
|
||||
List<RequestMappingInfo> list = asList(empty, oneMethod, oneMethodOneParam);
|
||||
Collections.shuffle(list);
|
||||
Collections.sort(list, handlerMapping.getMappingComparator("", request));
|
||||
|
|
@ -114,9 +117,9 @@ public class RequestMappingInfoComparatorTests {
|
|||
|
||||
@Test
|
||||
public void produces() {
|
||||
RequestMappingInfo html = new RequestMappingInfo(null, null, null, null, null, RequestConditionFactory.parseProduces("text/html"));
|
||||
RequestMappingInfo xml = new RequestMappingInfo(null, null, null, null, null, RequestConditionFactory.parseProduces("application/xml"));
|
||||
RequestMappingInfo none = new RequestMappingInfo(null, null);
|
||||
RequestMappingInfo html = new RequestMappingInfo(null, null, null, null, null, new ProducesRequestCondition("text/html"));
|
||||
RequestMappingInfo xml = new RequestMappingInfo(null, null, null, null, null, new ProducesRequestCondition("application/xml"));
|
||||
RequestMappingInfo none = new RequestMappingInfo(null);
|
||||
|
||||
request.addHeader("Accept", "application/xml, text/html");
|
||||
Comparator<RequestMappingInfo> comparator = handlerMapping.getMappingComparator("", request);
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ import static org.junit.Assert.assertSame;
|
|||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
|
|
@ -42,9 +41,13 @@ import org.springframework.web.servlet.HandlerInterceptor;
|
|||
import org.springframework.web.servlet.HandlerMapping;
|
||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
||||
import org.springframework.web.servlet.handler.MappedInterceptor;
|
||||
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||
import org.springframework.web.servlet.mvc.method.condition.RequestConditionFactory;
|
||||
import org.springframework.web.servlet.mvc.method.condition.ConsumesRequestCondition;
|
||||
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.RequestMethodsRequestCondition;
|
||||
import org.springframework.web.util.UrlPathHelper;
|
||||
|
||||
/**
|
||||
|
|
@ -129,7 +132,7 @@ public class RequestMappingInfoHandlerMappingTests {
|
|||
|
||||
@Test
|
||||
public void uriTemplateVariables() {
|
||||
RequestMappingInfo key = new RequestMappingInfo(Arrays.asList("/{path1}/{path2}"), null);
|
||||
RequestMappingInfo key = new RequestMappingInfo(new String[] {"/{path1}/{path2}"});
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/1/2");
|
||||
String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
|
||||
|
||||
|
|
@ -197,12 +200,13 @@ public class RequestMappingInfoHandlerMappingTests {
|
|||
@Override
|
||||
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
|
||||
RequestMapping annotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
|
||||
return new RequestMappingInfo(Arrays.asList(annotation.value()),
|
||||
RequestConditionFactory.parseMethods(annotation.method()),
|
||||
RequestConditionFactory.parseParams(annotation.params()),
|
||||
RequestConditionFactory.parseHeaders(annotation.headers()),
|
||||
RequestConditionFactory.parseConsumes(annotation.consumes(), annotation.headers()),
|
||||
RequestConditionFactory.parseProduces(annotation.produces(), annotation.headers()));
|
||||
return new RequestMappingInfo(
|
||||
new PatternsRequestCondition(annotation.value(), getUrlPathHelper(), getPathMatcher()),
|
||||
new RequestMethodsRequestCondition(annotation.method()),
|
||||
new ParamsRequestCondition(annotation.params()),
|
||||
new HeadersRequestCondition(annotation.headers()),
|
||||
new ConsumesRequestCondition(annotation.consumes(), annotation.headers()),
|
||||
new ProducesRequestCondition(annotation.produces(), annotation.headers()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,20 +16,19 @@
|
|||
|
||||
package org.springframework.web.servlet.mvc.method;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.GET;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.POST;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
|
||||
import org.springframework.web.servlet.mvc.method.condition.RequestConditionFactory;
|
||||
import org.springframework.web.util.UrlPathHelper;
|
||||
|
||||
import static java.util.Arrays.*;
|
||||
import static java.util.Collections.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.*;
|
||||
import org.springframework.web.servlet.mvc.method.condition.ConsumesRequestCondition;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Test fixture for {@link RequestMappingInfo} tests.
|
||||
|
|
@ -41,8 +40,8 @@ public class RequestMappingInfoTests {
|
|||
|
||||
@Test
|
||||
public void equals() {
|
||||
RequestMappingInfo key1 = new RequestMappingInfo(singleton("/foo"), methods(GET));
|
||||
RequestMappingInfo key2 = new RequestMappingInfo(singleton("/foo"), methods(GET));
|
||||
RequestMappingInfo key1 = new RequestMappingInfo(new String[] {"/foo"}, GET);
|
||||
RequestMappingInfo key2 = new RequestMappingInfo(new String[] {"/foo"}, GET);
|
||||
|
||||
assertEquals(key1, key2);
|
||||
assertEquals(key1.hashCode(), key2.hashCode());
|
||||
|
|
@ -50,8 +49,8 @@ public class RequestMappingInfoTests {
|
|||
|
||||
@Test
|
||||
public void equalsPrependSlash() {
|
||||
RequestMappingInfo key1 = new RequestMappingInfo(singleton("/foo"), methods(GET));
|
||||
RequestMappingInfo key2 = new RequestMappingInfo(singleton("foo"), methods(GET));
|
||||
RequestMappingInfo key1 = new RequestMappingInfo(new String[] {"/foo"}, GET);
|
||||
RequestMappingInfo key2 = new RequestMappingInfo(new String[] {"foo"}, GET);
|
||||
|
||||
assertEquals(key1, key2);
|
||||
assertEquals(key1.hashCode(), key2.hashCode());
|
||||
|
|
@ -59,213 +58,190 @@ public class RequestMappingInfoTests {
|
|||
|
||||
@Test
|
||||
public void combinePatterns() {
|
||||
AntPathMatcher pathMatcher = new AntPathMatcher();
|
||||
RequestMappingInfo key1 = createFromPatterns("/t1", "/t2");
|
||||
RequestMappingInfo key2 = createFromPatterns("/m1", "/m2");
|
||||
RequestMappingInfo key3 = createFromPatterns("/t1/m1", "/t1/m2", "/t2/m1", "/t2/m2");
|
||||
assertEquals(key3.getPatternsCondition(), key1.combine(key2).getPatternsCondition());
|
||||
|
||||
RequestMappingInfo key1 = createKeyFromPatterns("/t1", "/t2");
|
||||
RequestMappingInfo key2 = createKeyFromPatterns("/m1", "/m2");
|
||||
RequestMappingInfo key3 = createKeyFromPatterns("/t1/m1", "/t1/m2", "/t2/m1", "/t2/m2");
|
||||
assertEquals(key3.getPatterns(), key1.combine(key2, pathMatcher).getPatterns());
|
||||
key1 = createFromPatterns("/t1");
|
||||
key2 = createFromPatterns();
|
||||
key3 = createFromPatterns("/t1");
|
||||
assertEquals(key3.getPatternsCondition(), key1.combine(key2).getPatternsCondition());
|
||||
|
||||
key1 = createKeyFromPatterns("/t1");
|
||||
key2 = createKeyFromPatterns();
|
||||
key3 = createKeyFromPatterns("/t1");
|
||||
assertEquals(key3.getPatterns(), key1.combine(key2, pathMatcher).getPatterns());
|
||||
key1 = createFromPatterns();
|
||||
key2 = createFromPatterns("/m1");
|
||||
key3 = createFromPatterns("/m1");
|
||||
assertEquals(key3.getPatternsCondition(), key1.combine(key2).getPatternsCondition());
|
||||
|
||||
key1 = createKeyFromPatterns();
|
||||
key2 = createKeyFromPatterns("/m1");
|
||||
key3 = createKeyFromPatterns("/m1");
|
||||
assertEquals(key3.getPatterns(), key1.combine(key2, pathMatcher).getPatterns());
|
||||
key1 = createFromPatterns();
|
||||
key2 = createFromPatterns();
|
||||
key3 = createFromPatterns("");
|
||||
assertEquals(key3.getPatternsCondition(), key1.combine(key2).getPatternsCondition());
|
||||
|
||||
key1 = createKeyFromPatterns();
|
||||
key2 = createKeyFromPatterns();
|
||||
key3 = createKeyFromPatterns("");
|
||||
assertEquals(key3.getPatterns(), key1.combine(key2, pathMatcher).getPatterns());
|
||||
|
||||
key1 = createKeyFromPatterns("/t1");
|
||||
key2 = createKeyFromPatterns("");
|
||||
key3 = createKeyFromPatterns("/t1");
|
||||
assertEquals(key3.getPatterns(), key1.combine(key2, pathMatcher).getPatterns());
|
||||
key1 = createFromPatterns("/t1");
|
||||
key2 = createFromPatterns("");
|
||||
key3 = createFromPatterns("/t1");
|
||||
assertEquals(key3.getPatternsCondition(), key1.combine(key2).getPatternsCondition());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchPatternsToRequest() {
|
||||
UrlPathHelper pathHelper = new UrlPathHelper();
|
||||
PathMatcher pathMatcher = new AntPathMatcher();
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
RequestMappingInfo key = new RequestMappingInfo(singleton("/foo"), null);
|
||||
RequestMappingInfo match =
|
||||
key.getMatchingRequestMapping(pathHelper.getLookupPathForRequest(request), request, pathMatcher);
|
||||
RequestMappingInfo match = createFromPatterns("/foo").getMatchingRequestMapping(request);
|
||||
|
||||
assertNotNull(match);
|
||||
|
||||
request = new MockHttpServletRequest("GET", "/foo/bar");
|
||||
key = new RequestMappingInfo(singleton("/foo/*"), null);
|
||||
match = key.getMatchingRequestMapping(pathHelper.getLookupPathForRequest(request), request, pathMatcher);
|
||||
match = createFromPatterns("/foo/*").getMatchingRequestMapping(request);
|
||||
|
||||
assertNotNull("Pattern match", match);
|
||||
|
||||
request = new MockHttpServletRequest("GET", "/foo.html");
|
||||
key = new RequestMappingInfo(singleton("/foo"), null);
|
||||
match = key.getMatchingRequestMapping(pathHelper.getLookupPathForRequest(request), request, pathMatcher);
|
||||
match = createFromPatterns("/foo").getMatchingRequestMapping(request);
|
||||
|
||||
assertNotNull("Implicit match by extension", match);
|
||||
assertEquals("Contains matched pattern", "/foo.*", match.getPatterns().iterator().next());
|
||||
assertEquals("Contains matched pattern", "/foo.*", match.getPatternsCondition().getPatterns().iterator().next());
|
||||
|
||||
request = new MockHttpServletRequest("GET", "/foo/");
|
||||
key = new RequestMappingInfo(singleton("/foo"), null);
|
||||
match = key.getMatchingRequestMapping(pathHelper.getLookupPathForRequest(request), request, pathMatcher);
|
||||
match = createFromPatterns("/foo").getMatchingRequestMapping(request);
|
||||
|
||||
assertNotNull("Implicit match by trailing slash", match);
|
||||
assertEquals("Contains matched pattern", "/foo/", match.getPatterns().iterator().next());
|
||||
assertEquals("Contains matched pattern", "/foo/", match.getPatternsCondition().getPatterns().iterator().next());
|
||||
|
||||
request = new MockHttpServletRequest("GET", "/foo.html");
|
||||
key = new RequestMappingInfo(singleton("/foo.jpg"), null);
|
||||
match = key.getMatchingRequestMapping(pathHelper.getLookupPathForRequest(request), request, pathMatcher);
|
||||
match = createFromPatterns("/foo.jpg").getMatchingRequestMapping(request);
|
||||
|
||||
assertNull("Implicit match ignored if pattern has extension", match);
|
||||
|
||||
request = new MockHttpServletRequest("GET", "/foo.html");
|
||||
key = new RequestMappingInfo(singleton("/foo.jpg"), null);
|
||||
match = key.getMatchingRequestMapping(pathHelper.getLookupPathForRequest(request), request, pathMatcher);
|
||||
match = createFromPatterns("/foo.jpg").getMatchingRequestMapping(request);
|
||||
|
||||
assertNull("Implicit match ignored on pattern with trailing slash", match);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchRequestMethods() {
|
||||
PathMatcher pathMatcher = new AntPathMatcher();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
|
||||
|
||||
RequestMappingInfo key = new RequestMappingInfo(singleton("/foo"), null);
|
||||
RequestMappingInfo match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
|
||||
RequestMappingInfo key = createFromPatterns("/foo");
|
||||
RequestMappingInfo match = createFromPatterns("/foo").getMatchingRequestMapping(request);
|
||||
|
||||
assertNotNull("No method matches any method", match);
|
||||
|
||||
key = new RequestMappingInfo(singleton("/foo"), methods(GET));
|
||||
match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
|
||||
key = new RequestMappingInfo(new String[]{"/foo"}, GET);
|
||||
match = key.getMatchingRequestMapping(request);
|
||||
|
||||
assertNotNull("Exact match", match);
|
||||
|
||||
key = new RequestMappingInfo(singleton("/foo"), methods(POST));
|
||||
match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
|
||||
key = new RequestMappingInfo(new String[]{"/foo"}, POST);
|
||||
match = key.getMatchingRequestMapping(request);
|
||||
|
||||
assertNull("No match", match);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchingKeyContent() {
|
||||
PathMatcher pathMatcher = new AntPathMatcher();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
|
||||
|
||||
RequestMappingInfo key = new RequestMappingInfo(asList("/foo*", "/bar"), methods(GET, POST));
|
||||
RequestMappingInfo match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
|
||||
RequestMappingInfo expected = new RequestMappingInfo(singleton("/foo*"), methods(GET));
|
||||
RequestMappingInfo key = new RequestMappingInfo(new String[] {"/foo*", "/bar"}, GET, POST);
|
||||
RequestMappingInfo match = key.getMatchingRequestMapping(request);
|
||||
RequestMappingInfo expected = new RequestMappingInfo(new String[] {"/foo*"}, GET);
|
||||
|
||||
assertEquals("Matching RequestKey contains matched patterns and methods only", expected, match);
|
||||
|
||||
key = new RequestMappingInfo(asList("/**", "/foo*", "/foo"), null);
|
||||
match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
|
||||
expected = new RequestMappingInfo(asList("/foo", "/foo*", "/**"), null);
|
||||
key = createFromPatterns("/**", "/foo*", "/foo");
|
||||
match = key.getMatchingRequestMapping(request);
|
||||
expected = createFromPatterns("/foo", "/foo*", "/**");
|
||||
|
||||
assertEquals("Matched patterns are sorted with best match at the top", expected, match);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void paramsCondition() {
|
||||
PathMatcher pathMatcher = new AntPathMatcher();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
request.setParameter("foo", "bar");
|
||||
String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
|
||||
|
||||
RequestMappingInfo key =
|
||||
new RequestMappingInfo(asList("/foo"), null, RequestConditionFactory.parseParams("foo=bar"), null,
|
||||
null, null);
|
||||
RequestMappingInfo match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
|
||||
new RequestMappingInfo(
|
||||
new PatternsRequestCondition("/foo"), null,
|
||||
new ParamsRequestCondition("foo=bar"), null, null, null);
|
||||
RequestMappingInfo match = key.getMatchingRequestMapping(request);
|
||||
|
||||
assertNotNull(match);
|
||||
|
||||
key = new RequestMappingInfo(singleton("/foo"), null, RequestConditionFactory.parseParams("foo!=bar"), null,
|
||||
null, null);
|
||||
match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
|
||||
key = new RequestMappingInfo(
|
||||
new PatternsRequestCondition("/foo"), null,
|
||||
new ParamsRequestCondition("foo!=bar"), null, null, null);
|
||||
match = key.getMatchingRequestMapping(request);
|
||||
|
||||
assertNull(match);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headersCondition() {
|
||||
PathMatcher pathMatcher = new AntPathMatcher();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
request.addHeader("foo", "bar");
|
||||
String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
|
||||
|
||||
RequestMappingInfo key =
|
||||
new RequestMappingInfo(singleton("/foo"), null, null, RequestConditionFactory.parseHeaders("foo=bar"),
|
||||
null, null);
|
||||
RequestMappingInfo match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
|
||||
new RequestMappingInfo(
|
||||
new PatternsRequestCondition("/foo"), null, null,
|
||||
new HeadersRequestCondition("foo=bar"), null, null);
|
||||
RequestMappingInfo match = key.getMatchingRequestMapping(request);
|
||||
|
||||
assertNotNull(match);
|
||||
|
||||
key = new RequestMappingInfo(singleton("/foo"), null, null, RequestConditionFactory.parseHeaders("foo!=bar"),
|
||||
null, null);
|
||||
match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
|
||||
key = new RequestMappingInfo(
|
||||
new PatternsRequestCondition("/foo"), null, null,
|
||||
new HeadersRequestCondition("foo!=bar"), null, null);
|
||||
match = key.getMatchingRequestMapping(request);
|
||||
|
||||
assertNull(match);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void consumesCondition() {
|
||||
PathMatcher pathMatcher = new AntPathMatcher();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
request.setContentType("text/plain");
|
||||
String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
|
||||
|
||||
RequestMappingInfo key = new RequestMappingInfo(singleton("/foo"), null, null, null,
|
||||
RequestConditionFactory.parseConsumes("text/plain"), null);
|
||||
RequestMappingInfo match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
|
||||
RequestMappingInfo key =
|
||||
new RequestMappingInfo(
|
||||
new PatternsRequestCondition("/foo"), null, null, null,
|
||||
new ConsumesRequestCondition("text/plain"), null);
|
||||
RequestMappingInfo match = key.getMatchingRequestMapping(request);
|
||||
|
||||
assertNotNull(match);
|
||||
|
||||
key = new RequestMappingInfo(singleton("/foo"), null, null, null,
|
||||
RequestConditionFactory.parseConsumes("application/xml"), null);
|
||||
match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
|
||||
key = new RequestMappingInfo(
|
||||
new PatternsRequestCondition("/foo"), null, null, null,
|
||||
new ConsumesRequestCondition("application/xml"), null);
|
||||
match = key.getMatchingRequestMapping(request);
|
||||
|
||||
assertNull(match);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void producesCondition() {
|
||||
PathMatcher pathMatcher = new AntPathMatcher();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
request.addHeader("Accept", "text/plain");
|
||||
String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
|
||||
|
||||
RequestMappingInfo key = new RequestMappingInfo(singleton("/foo"), null, null, null,
|
||||
null, RequestConditionFactory.parseProduces("text/plain"));
|
||||
RequestMappingInfo match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
|
||||
RequestMappingInfo key =
|
||||
new RequestMappingInfo(
|
||||
new PatternsRequestCondition("/foo"), null, null, null, null,
|
||||
new ProducesRequestCondition("text/plain"));
|
||||
RequestMappingInfo match = key.getMatchingRequestMapping(request);
|
||||
|
||||
assertNotNull(match);
|
||||
|
||||
key = new RequestMappingInfo(singleton("/foo"), null, null, null, null,
|
||||
RequestConditionFactory.parseProduces("application/xml"));
|
||||
match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
|
||||
key = new RequestMappingInfo(
|
||||
new PatternsRequestCondition("/foo"), null, null, null, null,
|
||||
new ProducesRequestCondition("application/xml"));
|
||||
match = key.getMatchingRequestMapping(request);
|
||||
|
||||
assertNull(match);
|
||||
}
|
||||
|
||||
private RequestMappingInfo createKeyFromPatterns(String... patterns) {
|
||||
return new RequestMappingInfo(asList(patterns), null);
|
||||
}
|
||||
|
||||
private RequestMethod[] methods(RequestMethod... methods) {
|
||||
if (methods != null) {
|
||||
return methods;
|
||||
}
|
||||
else {
|
||||
return new RequestMethod[0];
|
||||
}
|
||||
private RequestMappingInfo createFromPatterns(String... patterns) {
|
||||
return new RequestMappingInfo(patterns);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -16,13 +16,17 @@
|
|||
|
||||
package org.springframework.web.servlet.mvc.method.condition;
|
||||
|
||||
import java.util.Set;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.springframework.web.servlet.mvc.method.condition.ConsumesRequestCondition.ConsumeMediaTypeExpression;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
|
|
@ -31,75 +35,79 @@ public class ConsumesRequestConditionTests {
|
|||
|
||||
@Test
|
||||
public void consumesMatch() {
|
||||
RequestCondition condition = new ConsumesRequestCondition("text/plain");
|
||||
ConsumesRequestCondition condition = new ConsumesRequestCondition("text/plain");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setContentType("text/plain");
|
||||
|
||||
assertTrue(condition.match(request));
|
||||
assertNotNull(condition.getMatchingCondition(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void negatedConsumesMatch() {
|
||||
RequestCondition condition = new ConsumesRequestCondition("!text/plain");
|
||||
ConsumesRequestCondition condition = new ConsumesRequestCondition("!text/plain");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setContentType("text/plain");
|
||||
|
||||
assertFalse(condition.match(request));
|
||||
assertNull(condition.getMatchingCondition(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void consumesWildcardMatch() {
|
||||
RequestCondition condition = new ConsumesRequestCondition("text/*");
|
||||
ConsumesRequestCondition condition = new ConsumesRequestCondition("text/*");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setContentType("text/plain");
|
||||
|
||||
assertTrue(condition.match(request));
|
||||
assertNotNull(condition.getMatchingCondition(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void consumesMultipleMatch() {
|
||||
RequestCondition condition = new ConsumesRequestCondition("text/plain", "application/xml");
|
||||
ConsumesRequestCondition condition = new ConsumesRequestCondition("text/plain", "application/xml");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setContentType("text/plain");
|
||||
|
||||
assertTrue(condition.match(request));
|
||||
assertNotNull(condition.getMatchingCondition(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void consumesSingleNoMatch() {
|
||||
RequestCondition condition = new ConsumesRequestCondition("text/plain");
|
||||
ConsumesRequestCondition condition = new ConsumesRequestCondition("text/plain");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setContentType("application/xml");
|
||||
|
||||
assertFalse(condition.match(request));
|
||||
assertNull(condition.getMatchingCondition(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compareToSingle() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
||||
ConsumesRequestCondition condition1 = new ConsumesRequestCondition("text/plain");
|
||||
ConsumesRequestCondition condition2 = new ConsumesRequestCondition("text/*");
|
||||
|
||||
int result = condition1.compareTo(condition2);
|
||||
int result = condition1.compareTo(condition2, request);
|
||||
assertTrue("Invalid comparison result: " + result, result < 0);
|
||||
|
||||
result = condition2.compareTo(condition1);
|
||||
result = condition2.compareTo(condition1, request);
|
||||
assertTrue("Invalid comparison result: " + result, result > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compareToMultiple() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
||||
ConsumesRequestCondition condition1 = new ConsumesRequestCondition("*/*", "text/plain");
|
||||
ConsumesRequestCondition condition2 = new ConsumesRequestCondition("text/*", "text/plain;q=0.7");
|
||||
|
||||
int result = condition1.compareTo(condition2);
|
||||
int result = condition1.compareTo(condition2, request);
|
||||
assertTrue("Invalid comparison result: " + result, result < 0);
|
||||
|
||||
result = condition2.compareTo(condition1);
|
||||
result = condition2.compareTo(condition1, request);
|
||||
assertTrue("Invalid comparison result: " + result, result > 0);
|
||||
}
|
||||
|
||||
|
|
@ -126,28 +134,11 @@ public class ConsumesRequestConditionTests {
|
|||
public void parseConsumesAndHeaders() {
|
||||
String[] consumes = new String[] {"text/plain"};
|
||||
String[] headers = new String[]{"foo=bar", "content-type=application/xml,application/pdf"};
|
||||
ConsumesRequestCondition condition = RequestConditionFactory.parseConsumes(consumes, headers);
|
||||
ConsumesRequestCondition condition = new ConsumesRequestCondition(consumes, headers);
|
||||
|
||||
assertConditions(condition, "text/plain", "application/xml", "application/pdf");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseConsumesDefault() {
|
||||
String[] consumes = new String[] {"*/*"};
|
||||
String[] headers = new String[0];
|
||||
ConsumesRequestCondition condition = RequestConditionFactory.parseConsumes(consumes, headers);
|
||||
|
||||
assertConditions(condition, "*/*");
|
||||
}
|
||||
@Test
|
||||
public void parseConsumesDefaultAndHeaders() {
|
||||
String[] consumes = new String[] {"*/*"};
|
||||
String[] headers = new String[]{"foo=bar", "content-type=text/plain"};
|
||||
ConsumesRequestCondition condition = RequestConditionFactory.parseConsumes(consumes, headers);
|
||||
|
||||
assertConditions(condition, "text/plain");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMatchingCondition() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
|
@ -165,12 +156,12 @@ public class ConsumesRequestConditionTests {
|
|||
}
|
||||
|
||||
private void assertConditions(ConsumesRequestCondition condition, String... expected) {
|
||||
Set<ConsumesRequestCondition.ConsumeRequestCondition> conditions = condition.getConditions();
|
||||
assertEquals("Invalid amount of conditions", conditions.size(), expected.length);
|
||||
Collection<ConsumeMediaTypeExpression> expressions = condition.getContent();
|
||||
assertEquals("Invalid amount of conditions", expressions.size(), expected.length);
|
||||
for (String s : expected) {
|
||||
boolean found = false;
|
||||
for (ConsumesRequestCondition.ConsumeRequestCondition requestCondition : conditions) {
|
||||
String conditionMediaType = requestCondition.getMediaType().toString();
|
||||
for (ConsumeMediaTypeExpression expr : expressions) {
|
||||
String conditionMediaType = expr.getMediaType().toString();
|
||||
if (conditionMediaType.equals(s)) {
|
||||
found = true;
|
||||
break;
|
||||
|
|
@ -181,12 +172,6 @@ public class ConsumesRequestConditionTests {
|
|||
fail("Condition [" + s + "] not found");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,13 +16,17 @@
|
|||
|
||||
package org.springframework.web.servlet.mvc.method.condition;
|
||||
|
||||
import java.util.Set;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.springframework.web.servlet.mvc.method.condition.HeadersRequestCondition.HeaderExpression;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
|
|
@ -40,81 +44,83 @@ public class HeadersRequestConditionTests {
|
|||
|
||||
@Test
|
||||
public void headerPresent() {
|
||||
RequestCondition condition = new HeadersRequestCondition("accept");
|
||||
HeadersRequestCondition condition = new HeadersRequestCondition("accept");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader("Accept", "");
|
||||
|
||||
assertTrue(condition.match(request));
|
||||
assertNotNull(condition.getMatchingCondition(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headerPresentNoMatch() {
|
||||
RequestCondition condition = new HeadersRequestCondition("foo");
|
||||
HeadersRequestCondition condition = new HeadersRequestCondition("foo");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader("bar", "");
|
||||
|
||||
assertFalse(condition.match(request));
|
||||
assertNull(condition.getMatchingCondition(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headerNotPresent() {
|
||||
RequestCondition condition = new HeadersRequestCondition("!accept");
|
||||
HeadersRequestCondition condition = new HeadersRequestCondition("!accept");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
||||
assertTrue(condition.match(request));
|
||||
assertNotNull(condition.getMatchingCondition(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headerValueMatch() {
|
||||
RequestCondition condition = new HeadersRequestCondition("foo=bar");
|
||||
HeadersRequestCondition condition = new HeadersRequestCondition("foo=bar");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader("foo", "bar");
|
||||
|
||||
assertTrue(condition.match(request));
|
||||
assertNotNull(condition.getMatchingCondition(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headerValueNoMatch() {
|
||||
RequestCondition condition = new HeadersRequestCondition("foo=bar");
|
||||
HeadersRequestCondition condition = new HeadersRequestCondition("foo=bar");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader("foo", "bazz");
|
||||
|
||||
assertFalse(condition.match(request));
|
||||
assertNull(condition.getMatchingCondition(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headerCaseSensitiveValueMatch() {
|
||||
RequestCondition condition = new HeadersRequestCondition("foo=Bar");
|
||||
HeadersRequestCondition condition = new HeadersRequestCondition("foo=Bar");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader("foo", "bar");
|
||||
|
||||
assertFalse(condition.match(request));
|
||||
assertNull(condition.getMatchingCondition(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headerValueMatchNegated() {
|
||||
RequestCondition condition = new HeadersRequestCondition("foo!=bar");
|
||||
HeadersRequestCondition condition = new HeadersRequestCondition("foo!=bar");
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader("foo", "baz");
|
||||
|
||||
assertTrue(condition.match(request));
|
||||
assertNotNull(condition.getMatchingCondition(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compareTo() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
||||
HeadersRequestCondition condition1 = new HeadersRequestCondition("foo", "bar", "baz");
|
||||
HeadersRequestCondition condition2 = new HeadersRequestCondition("foo", "bar");
|
||||
|
||||
int result = condition1.compareTo(condition2);
|
||||
int result = condition1.compareTo(condition2, request);
|
||||
assertTrue("Invalid comparison result: " + result, result < 0);
|
||||
|
||||
result = condition2.compareTo(condition1);
|
||||
result = condition2.compareTo(condition1, request);
|
||||
assertTrue("Invalid comparison result: " + result, result > 0);
|
||||
}
|
||||
|
||||
|
|
@ -125,7 +131,7 @@ public class HeadersRequestConditionTests {
|
|||
HeadersRequestCondition condition2 = new HeadersRequestCondition("foo=baz");
|
||||
|
||||
HeadersRequestCondition result = condition1.combine(condition2);
|
||||
Set<HeadersRequestCondition.HeaderRequestCondition> conditions = result.getConditions();
|
||||
Collection<HeaderExpression> conditions = result.getContent();
|
||||
assertEquals(2, conditions.size());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,13 +16,17 @@
|
|||
|
||||
package org.springframework.web.servlet.mvc.method.condition;
|
||||
|
||||
import java.util.Set;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.springframework.web.servlet.mvc.method.condition.ParamsRequestCondition.ParamExpression;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
|
|
@ -41,62 +45,64 @@ public class ParamsRequestConditionTests {
|
|||
|
||||
@Test
|
||||
public void paramPresent() {
|
||||
RequestCondition condition = new ParamsRequestCondition("foo");
|
||||
ParamsRequestCondition condition = new ParamsRequestCondition("foo");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addParameter("foo", "");
|
||||
|
||||
assertTrue(condition.match(request));
|
||||
assertNotNull(condition.getMatchingCondition(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void paramPresentNoMatch() {
|
||||
RequestCondition condition = new ParamsRequestCondition("foo");
|
||||
ParamsRequestCondition condition = new ParamsRequestCondition("foo");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader("bar", "");
|
||||
|
||||
assertFalse(condition.match(request));
|
||||
assertNull(condition.getMatchingCondition(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void paramNotPresent() {
|
||||
RequestCondition condition = new ParamsRequestCondition("!foo");
|
||||
ParamsRequestCondition condition = new ParamsRequestCondition("!foo");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
||||
assertTrue(condition.match(request));
|
||||
assertNotNull(condition.getMatchingCondition(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void paramValueMatch() {
|
||||
RequestCondition condition = new ParamsRequestCondition("foo=bar");
|
||||
ParamsRequestCondition condition = new ParamsRequestCondition("foo=bar");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addParameter("foo", "bar");
|
||||
|
||||
assertTrue(condition.match(request));
|
||||
assertNotNull(condition.getMatchingCondition(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void paramValueNoMatch() {
|
||||
RequestCondition condition = new ParamsRequestCondition("foo=bar");
|
||||
ParamsRequestCondition condition = new ParamsRequestCondition("foo=bar");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addParameter("foo", "bazz");
|
||||
|
||||
assertFalse(condition.match(request));
|
||||
assertNull(condition.getMatchingCondition(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compareTo() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
||||
ParamsRequestCondition condition1 = new ParamsRequestCondition("foo", "bar", "baz");
|
||||
ParamsRequestCondition condition2 = new ParamsRequestCondition("foo", "bar");
|
||||
|
||||
int result = condition1.compareTo(condition2);
|
||||
int result = condition1.compareTo(condition2, request);
|
||||
assertTrue("Invalid comparison result: " + result, result < 0);
|
||||
|
||||
result = condition2.compareTo(condition1);
|
||||
result = condition2.compareTo(condition1, request);
|
||||
assertTrue("Invalid comparison result: " + result, result > 0);
|
||||
}
|
||||
|
||||
|
|
@ -106,7 +112,7 @@ public class ParamsRequestConditionTests {
|
|||
ParamsRequestCondition condition2 = new ParamsRequestCondition("foo=baz");
|
||||
|
||||
ParamsRequestCondition result = condition1.combine(condition2);
|
||||
Set<ParamsRequestCondition.ParamRequestCondition> conditions = result.getConditions();
|
||||
Collection<ParamExpression> conditions = result.getContent();
|
||||
assertEquals(2, conditions.size());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,17 +16,17 @@
|
|||
|
||||
package org.springframework.web.servlet.mvc.method.condition;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.springframework.web.servlet.mvc.method.condition.ProducesRequestCondition.ProduceMediaTypeExpression;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
|
|
@ -35,65 +35,66 @@ public class ProducesRequestConditionTests {
|
|||
|
||||
@Test
|
||||
public void consumesMatch() {
|
||||
RequestCondition condition = new ProducesRequestCondition("text/plain");
|
||||
ProducesRequestCondition condition = new ProducesRequestCondition("text/plain");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader("Accept", "text/plain");
|
||||
|
||||
assertTrue(condition.match(request));
|
||||
assertNotNull(condition.getMatchingCondition(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void negatedConsumesMatch() {
|
||||
RequestCondition condition = new ProducesRequestCondition("!text/plain");
|
||||
ProducesRequestCondition condition = new ProducesRequestCondition("!text/plain");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader("Accept", "text/plain");
|
||||
|
||||
assertFalse(condition.match(request));
|
||||
assertNull(condition.getMatchingCondition(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void consumesWildcardMatch() {
|
||||
RequestCondition condition = new ProducesRequestCondition("text/*");
|
||||
ProducesRequestCondition condition = new ProducesRequestCondition("text/*");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader("Accept", "text/plain");
|
||||
|
||||
assertTrue(condition.match(request));
|
||||
assertNotNull(condition.getMatchingCondition(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void consumesMultipleMatch() {
|
||||
RequestCondition condition = new ProducesRequestCondition("text/plain", "application/xml");
|
||||
ProducesRequestCondition condition = new ProducesRequestCondition("text/plain", "application/xml");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader("Accept", "text/plain");
|
||||
|
||||
assertTrue(condition.match(request));
|
||||
assertNotNull(condition.getMatchingCondition(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void consumesSingleNoMatch() {
|
||||
RequestCondition condition = new ProducesRequestCondition("text/plain");
|
||||
ProducesRequestCondition condition = new ProducesRequestCondition("text/plain");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader("Accept", "application/xml");
|
||||
|
||||
assertFalse(condition.match(request));
|
||||
assertNull(condition.getMatchingCondition(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compareToSingle() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader("Accept", "text/plain");
|
||||
|
||||
ProducesRequestCondition condition1 = new ProducesRequestCondition("text/plain");
|
||||
ProducesRequestCondition condition2 = new ProducesRequestCondition("text/*");
|
||||
|
||||
List<MediaType> accept = Collections.singletonList(MediaType.TEXT_PLAIN);
|
||||
|
||||
int result = condition1.compareTo(condition2, accept);
|
||||
int result = condition1.compareTo(condition2, request);
|
||||
assertTrue("Invalid comparison result: " + result, result < 0);
|
||||
|
||||
result = condition2.compareTo(condition1, accept);
|
||||
result = condition2.compareTo(condition1, request);
|
||||
assertTrue("Invalid comparison result: " + result, result > 0);
|
||||
}
|
||||
|
||||
|
|
@ -102,23 +103,25 @@ public class ProducesRequestConditionTests {
|
|||
ProducesRequestCondition condition1 = new ProducesRequestCondition("*/*", "text/plain");
|
||||
ProducesRequestCondition condition2 = new ProducesRequestCondition("text/*", "text/plain;q=0.7");
|
||||
|
||||
List<MediaType> accept = Collections.singletonList(MediaType.TEXT_PLAIN);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader("Accept", "text/plain");
|
||||
|
||||
int result = condition1.compareTo(condition2, accept);
|
||||
int result = condition1.compareTo(condition2, request);
|
||||
assertTrue("Invalid comparison result: " + result, result < 0);
|
||||
|
||||
result = condition2.compareTo(condition1, accept);
|
||||
result = condition2.compareTo(condition1, request);
|
||||
assertTrue("Invalid comparison result: " + result, result > 0);
|
||||
|
||||
condition1 = new ProducesRequestCondition("*/*");
|
||||
condition2 = new ProducesRequestCondition("text/*");
|
||||
|
||||
accept = Collections.singletonList(new MediaType("text", "*"));
|
||||
request = new MockHttpServletRequest();
|
||||
request.addHeader("Accept", "text/*");
|
||||
|
||||
result = condition1.compareTo(condition2, accept);
|
||||
result = condition1.compareTo(condition2, request);
|
||||
assertTrue("Invalid comparison result: " + result, result > 0);
|
||||
|
||||
result = condition2.compareTo(condition1, accept);
|
||||
result = condition2.compareTo(condition1, request);
|
||||
assertTrue("Invalid comparison result: " + result, result < 0);
|
||||
}
|
||||
|
||||
|
|
@ -127,20 +130,24 @@ public class ProducesRequestConditionTests {
|
|||
ProducesRequestCondition condition1 = new ProducesRequestCondition("text/*", "text/plain");
|
||||
ProducesRequestCondition condition2 = new ProducesRequestCondition("application/*", "application/xml");
|
||||
|
||||
List<MediaType> accept = Arrays.asList(MediaType.TEXT_PLAIN, MediaType.APPLICATION_XML);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader("Accept", "text/plain");
|
||||
request.addHeader("Accept", "application/xml");
|
||||
|
||||
int result = condition1.compareTo(condition2, accept);
|
||||
int result = condition1.compareTo(condition2, request);
|
||||
assertTrue("Invalid comparison result: " + result, result < 0);
|
||||
|
||||
result = condition2.compareTo(condition1, accept);
|
||||
result = condition2.compareTo(condition1, request);
|
||||
assertTrue("Invalid comparison result: " + result, result > 0);
|
||||
|
||||
accept = Arrays.asList(MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN);
|
||||
request = new MockHttpServletRequest();
|
||||
request.addHeader("Accept", "application/xml");
|
||||
request.addHeader("Accept", "text/plain");
|
||||
|
||||
result = condition1.compareTo(condition2, accept);
|
||||
result = condition1.compareTo(condition2, request);
|
||||
assertTrue("Invalid comparison result: " + result, result > 0);
|
||||
|
||||
result = condition2.compareTo(condition1, accept);
|
||||
result = condition2.compareTo(condition1, request);
|
||||
assertTrue("Invalid comparison result: " + result, result < 0);
|
||||
}
|
||||
|
||||
|
|
@ -166,28 +173,11 @@ public class ProducesRequestConditionTests {
|
|||
public void parseConsumesAndHeaders() {
|
||||
String[] consumes = new String[] {"text/plain"};
|
||||
String[] headers = new String[]{"foo=bar", "accept=application/xml,application/pdf"};
|
||||
ProducesRequestCondition condition = RequestConditionFactory.parseProduces(consumes, headers);
|
||||
ProducesRequestCondition condition = new ProducesRequestCondition(consumes, headers);
|
||||
|
||||
assertConditions(condition, "text/plain", "application/xml", "application/pdf");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseConsumesDefault() {
|
||||
String[] consumes = new String[] {"*/*"};
|
||||
String[] headers = new String[0];
|
||||
ProducesRequestCondition condition = RequestConditionFactory.parseProduces(consumes, headers);
|
||||
|
||||
assertConditions(condition, "*/*");
|
||||
}
|
||||
@Test
|
||||
public void parseConsumesDefaultAndHeaders() {
|
||||
String[] consumes = new String[] {"*/*"};
|
||||
String[] headers = new String[]{"foo=bar", "accept=text/plain"};
|
||||
ProducesRequestCondition condition = RequestConditionFactory.parseProduces(consumes, headers);
|
||||
|
||||
assertConditions(condition, "text/plain");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMatchingCondition() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
|
@ -205,12 +195,12 @@ public class ProducesRequestConditionTests {
|
|||
}
|
||||
|
||||
private void assertConditions(ProducesRequestCondition condition, String... expected) {
|
||||
Set<ProducesRequestCondition.ProduceRequestCondition> conditions = condition.getConditions();
|
||||
assertEquals("Invalid amount of conditions", conditions.size(), expected.length);
|
||||
Collection<ProduceMediaTypeExpression> expressions = condition.getContent();
|
||||
assertEquals("Invalid amount of conditions", expressions.size(), expected.length);
|
||||
for (String s : expected) {
|
||||
boolean found = false;
|
||||
for (ProducesRequestCondition.ProduceRequestCondition requestCondition : conditions) {
|
||||
String conditionMediaType = requestCondition.getMediaType().toString();
|
||||
for (ProduceMediaTypeExpression expr : expressions) {
|
||||
String conditionMediaType = expr.getMediaType().toString();
|
||||
if (conditionMediaType.equals(s)) {
|
||||
found = true;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -30,29 +30,29 @@ public class RequestMethodsRequestConditionTests {
|
|||
|
||||
@Test
|
||||
public void methodMatch() {
|
||||
RequestCondition condition = new RequestMethodsRequestCondition(RequestMethod.GET);
|
||||
RequestMethodsRequestCondition condition = new RequestMethodsRequestCondition(RequestMethod.GET);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
|
||||
assertTrue(condition.match(request));
|
||||
assertNotNull(condition.getMatchingCondition(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodNoMatch() {
|
||||
RequestCondition condition = new RequestMethodsRequestCondition(RequestMethod.GET);
|
||||
RequestMethodsRequestCondition condition = new RequestMethodsRequestCondition(RequestMethod.GET);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/foo");
|
||||
|
||||
assertFalse(condition.match(request));
|
||||
assertNull(condition.getMatchingCondition(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleMethodsMatch() {
|
||||
RequestCondition condition = new RequestMethodsRequestCondition(RequestMethod.GET, RequestMethod.POST);
|
||||
RequestMethodsRequestCondition condition = new RequestMethodsRequestCondition(RequestMethod.GET, RequestMethod.POST);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
|
||||
assertTrue(condition.match(request));
|
||||
assertNotNull(condition.getMatchingCondition(request));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -62,16 +62,18 @@ public class RequestMethodsRequestConditionTests {
|
|||
RequestMethodsRequestCondition condition2 = new RequestMethodsRequestCondition(RequestMethod.POST);
|
||||
RequestMethodsRequestCondition condition3 = new RequestMethodsRequestCondition();
|
||||
|
||||
int result = condition1.compareTo(condition2);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
||||
int result = condition1.compareTo(condition2, request);
|
||||
assertTrue("Invalid comparison result: " + result, result < 0);
|
||||
|
||||
result = condition2.compareTo(condition1);
|
||||
result = condition2.compareTo(condition1, request);
|
||||
assertTrue("Invalid comparison result: " + result, result > 0);
|
||||
|
||||
result = condition2.compareTo(condition3);
|
||||
result = condition2.compareTo(condition3, request);
|
||||
assertTrue("Invalid comparison result: " + result, result < 0);
|
||||
|
||||
result = condition1.compareTo(condition1);
|
||||
result = condition1.compareTo(condition1, request);
|
||||
assertEquals("Invalid comparison result ", 0, result);
|
||||
}
|
||||
|
||||
|
|
@ -81,7 +83,7 @@ public class RequestMethodsRequestConditionTests {
|
|||
RequestMethodsRequestCondition condition2 = new RequestMethodsRequestCondition(RequestMethod.POST);
|
||||
|
||||
RequestMethodsRequestCondition result = condition1.combine(condition2);
|
||||
assertEquals(2, result.getConditions().size());
|
||||
assertEquals(2, result.getContent().size());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue