SPR-7353 - Added equivalent of JAX-RS @Produces to Spring MVC
This commit is contained in:
parent
a557878a6f
commit
bb2cc8457f
|
|
@ -25,7 +25,6 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
|
|
@ -141,7 +140,9 @@ public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<R
|
|||
RequestConditionFactory.parseMethods(annotation.method()),
|
||||
RequestConditionFactory.parseParams(annotation.params()),
|
||||
RequestConditionFactory.parseHeaders(annotation.headers()),
|
||||
RequestConditionFactory.parseConsumes(annotation.consumes(), annotation.headers()));
|
||||
RequestConditionFactory.parseConsumes(annotation.consumes(), annotation.headers()),
|
||||
RequestConditionFactory.parseProduces(annotation.produces(), annotation.headers())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -257,13 +258,10 @@ public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<R
|
|||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
/*
|
||||
TODO: fix
|
||||
result = compareAcceptHeaders(mapping.getAcceptHeaderMediaTypes(), otherMapping.getAcceptHeaderMediaTypes());
|
||||
result = mapping.getProduces().compareTo(otherMapping.getProduces(), this.requestAcceptHeader);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
*/
|
||||
result = mapping.getMethods().compareTo(otherMapping.getMethods());
|
||||
if (result != 0) {
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ 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.ProducesRequestCondition;
|
||||
import org.springframework.web.servlet.mvc.method.condition.RequestConditionFactory;
|
||||
import org.springframework.web.servlet.mvc.method.condition.RequestMethodsRequestCondition;
|
||||
|
||||
|
|
@ -57,6 +58,8 @@ public final class RequestMappingInfo {
|
|||
|
||||
private final ConsumesRequestCondition consumesCondition;
|
||||
|
||||
private final ProducesRequestCondition producesCondition;
|
||||
|
||||
private int hash;
|
||||
|
||||
/**
|
||||
|
|
@ -65,7 +68,7 @@ public final class RequestMappingInfo {
|
|||
* <p>Package protected for testing purposes.
|
||||
*/
|
||||
RequestMappingInfo(Collection<String> patterns, RequestMethod[] methods) {
|
||||
this(patterns, RequestConditionFactory.parseMethods(methods), null, null, null);
|
||||
this(patterns, RequestConditionFactory.parseMethods(methods), null, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -75,12 +78,14 @@ public final class RequestMappingInfo {
|
|||
RequestMethodsRequestCondition methodsCondition,
|
||||
ParamsRequestCondition paramsCondition,
|
||||
HeadersRequestCondition headersCondition,
|
||||
ConsumesRequestCondition consumesCondition) {
|
||||
ConsumesRequestCondition consumesCondition,
|
||||
ProducesRequestCondition producesCondition) {
|
||||
this.patterns = asUnmodifiableSet(prependLeadingSlash(patterns));
|
||||
this.methodsCondition = methodsCondition != null ? methodsCondition : new RequestMethodsRequestCondition();
|
||||
this.paramsCondition = paramsCondition != null ? paramsCondition : new ParamsRequestCondition();
|
||||
this.headersCondition = headersCondition != null ? headersCondition : new HeadersRequestCondition();
|
||||
this.consumesCondition = consumesCondition != null ? consumesCondition : new ConsumesRequestCondition();
|
||||
this.producesCondition = producesCondition != null ? producesCondition : new ProducesRequestCondition();
|
||||
}
|
||||
|
||||
private static Set<String> prependLeadingSlash(Collection<String> patterns) {
|
||||
|
|
@ -106,40 +111,47 @@ public final class RequestMappingInfo {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the patterns of this request key.
|
||||
* Returns the patterns of this request mapping info.
|
||||
*/
|
||||
public Set<String> getPatterns() {
|
||||
return patterns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request method conditions of this request key.
|
||||
* Returns the request method conditions of this request mapping info.
|
||||
*/
|
||||
public RequestMethodsRequestCondition getMethods() {
|
||||
return methodsCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request parameters conditions of this request key.
|
||||
* Returns the request parameters conditions of this request mapping info.
|
||||
*/
|
||||
public ParamsRequestCondition getParams() {
|
||||
return paramsCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request headers conditions of this request key.
|
||||
* Returns the request headers conditions of this request mapping info.
|
||||
*/
|
||||
public HeadersRequestCondition getHeaders() {
|
||||
return headersCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request consumes conditions of this request key.
|
||||
* Returns the request consumes conditions of this request mapping info.
|
||||
*/
|
||||
public ConsumesRequestCondition getConsumes() {
|
||||
return consumesCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request produces conditions of this request mapping info.
|
||||
*/
|
||||
public ProducesRequestCondition getProduces() {
|
||||
return producesCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines this {@code RequestMappingInfo} with another as follows:
|
||||
* <ul>
|
||||
|
|
@ -156,7 +168,7 @@ public final class RequestMappingInfo {
|
|||
* </ul>
|
||||
* @param methodKey the key to combine with
|
||||
* @param pathMatcher to {@linkplain PathMatcher#combine(String, String) combine} the patterns
|
||||
* @return a new request key containing conditions from both keys
|
||||
* @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);
|
||||
|
|
@ -164,8 +176,9 @@ public final class RequestMappingInfo {
|
|||
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);
|
||||
return new RequestMappingInfo(patterns, methods, params, headers, consumes, produces);
|
||||
}
|
||||
|
||||
private static Set<String> combinePatterns(Collection<String> typePatterns,
|
||||
|
|
@ -203,23 +216,24 @@ public final class RequestMappingInfo {
|
|||
* @param lookupPath mapping lookup path within the current servlet mapping if applicable
|
||||
* @param request the current request
|
||||
* @param pathMatcher to check for matching patterns
|
||||
* @return a new request key that contains all matching attributes, or {@code null} if not all conditions match
|
||||
* @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);
|
||||
|
||||
if (matchingMethodCondition == null || matchingParamsCondition == null || matchingHeadersCondition == null ||
|
||||
matchingConsumesCondition == null) {
|
||||
matchingConsumesCondition == null || matchingProducesCondition == null) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
List<String> matchingPatterns = getMatchingPatterns(lookupPath, pathMatcher);
|
||||
if (!matchingPatterns.isEmpty()) {
|
||||
return new RequestMappingInfo(matchingPatterns, matchingMethodCondition, matchingParamsCondition,
|
||||
matchingHeadersCondition, matchingConsumesCondition);
|
||||
matchingHeadersCondition, matchingConsumesCondition, matchingProducesCondition);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
|
|
@ -271,7 +285,8 @@ public final class RequestMappingInfo {
|
|||
this.methodsCondition.equals(other.methodsCondition) &&
|
||||
this.paramsCondition.equals(other.paramsCondition) &&
|
||||
this.headersCondition.equals(other.headersCondition) &&
|
||||
this.consumesCondition.equals(other.consumesCondition));
|
||||
this.consumesCondition.equals(other.consumesCondition) &&
|
||||
this.producesCondition.equals(other.producesCondition));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -285,6 +300,7 @@ public final class RequestMappingInfo {
|
|||
result = 31 * result + paramsCondition.hashCode();
|
||||
result = 31 * result + headersCondition.hashCode();
|
||||
result = 31 * result + consumesCondition.hashCode();
|
||||
result = 31 * result + producesCondition.hashCode();
|
||||
hash = result;
|
||||
}
|
||||
return result;
|
||||
|
|
@ -298,6 +314,7 @@ public final class RequestMappingInfo {
|
|||
builder.append(",params=").append(paramsCondition);
|
||||
builder.append(",headers=").append(headersCondition);
|
||||
builder.append(",consumes=").append(consumesCondition);
|
||||
builder.append(",produces=").append(producesCondition);
|
||||
builder.append('}');
|
||||
return builder.toString();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package org.springframework.web.servlet.mvc.method.condition;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
|
@ -27,33 +26,23 @@ import java.util.Set;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Represents a collection of consumes conditions, typically obtained from {@link
|
||||
* org.springframework.web.bind.annotation.RequestMapping#consumes() @RequestMapping.consumes()}.
|
||||
* Represents a collection of consumes conditions, typically obtained from {@link org.springframework.web.bind.annotation.RequestMapping#consumes()
|
||||
* @RequestMapping.consumes()}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see RequestConditionFactory#parseHeaders(String...)
|
||||
* @see RequestConditionFactory#parseConsumes(String...)
|
||||
* @see RequestConditionFactory#parseConsumes(String[], String[])
|
||||
* @since 3.1
|
||||
*/
|
||||
public class ConsumesRequestCondition
|
||||
extends LogicalDisjunctionRequestCondition<ConsumesRequestCondition.ConsumeRequestCondition>
|
||||
extends MediaTypesRequestCondition<ConsumesRequestCondition.ConsumeRequestCondition>
|
||||
implements Comparable<ConsumesRequestCondition> {
|
||||
|
||||
private final ConsumeRequestCondition mostSpecificCondition;
|
||||
|
||||
ConsumesRequestCondition(Collection<ConsumeRequestCondition> conditions) {
|
||||
super(conditions);
|
||||
Assert.notEmpty(conditions, "'conditions' must not be empty");
|
||||
mostSpecificCondition = getMostSpecificCondition();
|
||||
}
|
||||
|
||||
private ConsumeRequestCondition getMostSpecificCondition() {
|
||||
List<ConsumeRequestCondition> conditions = new ArrayList<ConsumeRequestCondition>(getConditions());
|
||||
Collections.sort(conditions);
|
||||
return conditions.get(0);
|
||||
}
|
||||
|
||||
ConsumesRequestCondition(String... consumes) {
|
||||
|
|
@ -72,7 +61,7 @@ public class ConsumesRequestCondition
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates an default set of consumes request conditions.
|
||||
* Creates a default set of consumes request conditions.
|
||||
*/
|
||||
public ConsumesRequestCondition() {
|
||||
this(Collections.singleton(new ConsumeRequestCondition(MediaType.ALL, false)));
|
||||
|
|
@ -101,8 +90,8 @@ public class ConsumesRequestCondition
|
|||
}
|
||||
|
||||
/**
|
||||
* Combines this collection of request condition with another. Returns {@code other}, unless it has the default
|
||||
* value (i.e. <code>*/*</code>).
|
||||
* Combines this collection of request condition with another. Returns {@code other}, unless it has the default value
|
||||
* (i.e. <code>*/*</code>).
|
||||
*
|
||||
* @param other the condition to combine with
|
||||
*/
|
||||
|
|
@ -122,79 +111,32 @@ public class ConsumesRequestCondition
|
|||
}
|
||||
|
||||
public int compareTo(ConsumesRequestCondition other) {
|
||||
return this.mostSpecificCondition.compareTo(other.mostSpecificCondition);
|
||||
return this.getMostSpecificCondition().compareTo(other.getMostSpecificCondition());
|
||||
}
|
||||
|
||||
private static MediaType getContentType(HttpServletRequest request) {
|
||||
if (StringUtils.hasLength(request.getContentType())) {
|
||||
return MediaType.parseMediaType(request.getContentType());
|
||||
}
|
||||
else {
|
||||
return MediaType.APPLICATION_OCTET_STREAM;
|
||||
}
|
||||
}
|
||||
|
||||
static class ConsumeRequestCondition implements RequestCondition, Comparable<ConsumeRequestCondition> {
|
||||
|
||||
private final MediaType mediaType;
|
||||
|
||||
private final boolean isNegated;
|
||||
static class ConsumeRequestCondition extends MediaTypesRequestCondition.MediaTypeRequestCondition {
|
||||
|
||||
ConsumeRequestCondition(String expression) {
|
||||
if (expression.startsWith("!")) {
|
||||
isNegated = true;
|
||||
expression = expression.substring(1);
|
||||
super(expression);
|
||||
}
|
||||
|
||||
ConsumeRequestCondition(MediaType mediaType, boolean negated) {
|
||||
super(mediaType, negated);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean match(HttpServletRequest request, MediaType mediaType) {
|
||||
MediaType contentType = getContentType(request);
|
||||
return mediaType.includes(contentType);
|
||||
}
|
||||
|
||||
private MediaType getContentType(HttpServletRequest request) {
|
||||
if (StringUtils.hasLength(request.getContentType())) {
|
||||
return MediaType.parseMediaType(request.getContentType());
|
||||
}
|
||||
else {
|
||||
isNegated = false;
|
||||
return MediaType.APPLICATION_OCTET_STREAM;
|
||||
}
|
||||
this.mediaType = MediaType.parseMediaType(expression);
|
||||
}
|
||||
|
||||
ConsumeRequestCondition(MediaType mediaType, boolean isNegated) {
|
||||
this.mediaType = mediaType;
|
||||
this.isNegated = isNegated;
|
||||
}
|
||||
|
||||
public boolean match(HttpServletRequest request) {
|
||||
MediaType contentType = getContentType(request);
|
||||
boolean match = this.mediaType.includes(contentType);
|
||||
return !isNegated ? match : !match;
|
||||
}
|
||||
|
||||
public int compareTo(ConsumeRequestCondition other) {
|
||||
return MediaType.SPECIFICITY_COMPARATOR.compare(this.mediaType, other.mediaType);
|
||||
}
|
||||
|
||||
MediaType getMediaType() {
|
||||
return mediaType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj != null && obj instanceof ConsumeRequestCondition) {
|
||||
ConsumeRequestCondition other = (ConsumeRequestCondition) 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* 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.List;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
class MediaTypesRequestCondition<T extends MediaTypesRequestCondition.MediaTypeRequestCondition>
|
||||
extends LogicalDisjunctionRequestCondition<T> {
|
||||
|
||||
private final List<T> sortedConditions;
|
||||
|
||||
public MediaTypesRequestCondition(Collection<T> conditions) {
|
||||
super(conditions);
|
||||
Assert.notEmpty(conditions, "'conditions' must not be empty");
|
||||
sortedConditions = new ArrayList<T>(conditions);
|
||||
Collections.sort(sortedConditions);
|
||||
}
|
||||
|
||||
private MediaTypeRequestCondition getMostSpecificCondition(Collection<T> conditions) {
|
||||
List<MediaTypeRequestCondition> conditionList = new ArrayList<MediaTypeRequestCondition>(conditions);
|
||||
Collections.sort(conditionList);
|
||||
return conditionList.get(0);
|
||||
}
|
||||
|
||||
protected MediaTypeRequestCondition getMostSpecificCondition() {
|
||||
return sortedConditions.get(0);
|
||||
}
|
||||
|
||||
protected List<T> getSortedConditions() {
|
||||
return sortedConditions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* 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.Arrays;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Represents a collection of produces conditions, typically obtained from {@link
|
||||
* org.springframework.web.bind.annotation.RequestMapping#produces() @RequestMapping.produces()}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see RequestConditionFactory#parseProduces(String...)
|
||||
* @see RequestConditionFactory#parseProduces(String[], String[])
|
||||
* @since 3.1
|
||||
*/
|
||||
public class ProducesRequestCondition
|
||||
extends MediaTypesRequestCondition<ProducesRequestCondition.ProduceRequestCondition> {
|
||||
|
||||
ProducesRequestCondition(Collection<ProduceRequestCondition> conditions) {
|
||||
super(conditions);
|
||||
}
|
||||
|
||||
|
||||
ProducesRequestCondition(String... consumes) {
|
||||
this(parseConditions(Arrays.asList(consumes)));
|
||||
}
|
||||
|
||||
private static Set<ProduceRequestCondition> parseConditions(List<String> consumes) {
|
||||
if (consumes.isEmpty()) {
|
||||
consumes = Collections.singletonList("*/*");
|
||||
}
|
||||
Set<ProduceRequestCondition> conditions = new LinkedHashSet<ProduceRequestCondition>(consumes.size());
|
||||
for (String consume : consumes) {
|
||||
conditions.add(new ProduceRequestCondition(consume));
|
||||
}
|
||||
return conditions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an default set of consumes request conditions.
|
||||
*/
|
||||
public ProducesRequestCondition() {
|
||||
this(Collections.singleton(new ProduceRequestCondition(MediaType.ALL, false)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public ProducesRequestCondition getMatchingCondition(HttpServletRequest request) {
|
||||
Set<ProduceRequestCondition> matchingConditions = new LinkedHashSet<ProduceRequestCondition>(getConditions());
|
||||
for (Iterator<ProduceRequestCondition> iterator = matchingConditions.iterator(); iterator.hasNext();) {
|
||||
ProduceRequestCondition condition = iterator.next();
|
||||
if (!condition.match(request)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
if (matchingConditions.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return new ProducesRequestCondition(matchingConditions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public ProducesRequestCondition combine(ProducesRequestCondition other) {
|
||||
return !other.hasDefaultValue() ? other : this;
|
||||
}
|
||||
|
||||
private boolean hasDefaultValue() {
|
||||
Set<ProduceRequestCondition> conditions = getConditions();
|
||||
if (conditions.size() == 1) {
|
||||
ProduceRequestCondition condition = conditions.iterator().next();
|
||||
return condition.getMediaType().equals(MediaType.ALL);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public int compareTo(ProducesRequestCondition other, List<MediaType> 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);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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())) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static class ProduceRequestCondition extends MediaTypesRequestCondition.MediaTypeRequestCondition {
|
||||
|
||||
ProduceRequestCondition(MediaType mediaType, boolean negated) {
|
||||
super(mediaType, negated);
|
||||
}
|
||||
|
||||
ProduceRequestCondition(String expression) {
|
||||
super(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean match(HttpServletRequest request, MediaType mediaType) {
|
||||
List<MediaType> acceptedMediaTypes = getAccept(request);
|
||||
for (MediaType acceptedMediaType : acceptedMediaTypes) {
|
||||
if (mediaType.isCompatibleWith(acceptedMediaType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private List<MediaType> getAccept(HttpServletRequest request) {
|
||||
String acceptHeader = request.getHeader("Accept");
|
||||
if (StringUtils.hasLength(acceptHeader)) {
|
||||
return MediaType.parseMediaTypes(acceptHeader);
|
||||
}
|
||||
else {
|
||||
return Collections.singletonList(MediaType.ALL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -99,6 +99,15 @@ public abstract class RequestConditionFactory {
|
|||
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);
|
||||
|
|
@ -115,14 +124,65 @@ public abstract class RequestConditionFactory {
|
|||
}
|
||||
|
||||
private static List<ConsumesRequestCondition.ConsumeRequestCondition> parseContentTypeHeaders(String[] headers) {
|
||||
List<ConsumesRequestCondition.ConsumeRequestCondition> allConditions =
|
||||
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) {
|
||||
allConditions.add(new ConsumesRequestCondition.ConsumeRequestCondition(mediaType,
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
|
@ -130,4 +190,5 @@ public abstract class RequestConditionFactory {
|
|||
return allConditions;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import java.util.Comparator;
|
|||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
|
|
@ -100,7 +99,7 @@ public class RequestMappingInfoComparatorTests {
|
|||
RequestMappingInfo empty = new RequestMappingInfo(null, null);
|
||||
RequestMappingInfo oneMethod = new RequestMappingInfo(null, new RequestMethod[] {RequestMethod.GET});
|
||||
RequestMappingInfo oneMethodOneParam =
|
||||
new RequestMappingInfo(null, RequestConditionFactory.parseMethods(RequestMethod.GET), RequestConditionFactory.parseParams("foo"), null, null);
|
||||
new RequestMappingInfo(null, RequestConditionFactory.parseMethods(RequestMethod.GET), RequestConditionFactory.parseParams("foo"), null, null, null);
|
||||
List<RequestMappingInfo> list = asList(empty, oneMethod, oneMethodOneParam);
|
||||
Collections.shuffle(list);
|
||||
Collections.sort(list, handlerMapping.getMappingComparator("", request));
|
||||
|
|
@ -111,16 +110,16 @@ public class RequestMappingInfoComparatorTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore // TODO : remove ignore
|
||||
public void acceptHeaders() {
|
||||
RequestMappingInfo html = new RequestMappingInfo(null, null, null, RequestConditionFactory.parseHeaders("accept=text/html"), null);
|
||||
RequestMappingInfo xml = new RequestMappingInfo(null, null, null, RequestConditionFactory.parseHeaders("accept=application/xml"), null);
|
||||
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);
|
||||
|
||||
request.addHeader("Accept", "application/xml, text/html");
|
||||
Comparator<RequestMappingInfo> comparator = handlerMapping.getMappingComparator("", request);
|
||||
|
||||
assertTrue(comparator.compare(html, xml) > 0);
|
||||
int result = comparator.compare(html, xml);
|
||||
assertTrue("Invalid comparison result: " + result, result > 0);
|
||||
assertTrue(comparator.compare(xml, html) < 0);
|
||||
assertTrue(comparator.compare(xml, none) < 0);
|
||||
assertTrue(comparator.compare(none, xml) > 0);
|
||||
|
|
|
|||
|
|
@ -181,13 +181,13 @@ public class RequestMappingInfoTests {
|
|||
|
||||
RequestMappingInfo key =
|
||||
new RequestMappingInfo(asList("/foo"), null, RequestConditionFactory.parseParams("foo=bar"), null,
|
||||
null);
|
||||
null, null);
|
||||
RequestMappingInfo match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
|
||||
|
||||
assertNotNull(match);
|
||||
|
||||
key = new RequestMappingInfo(singleton("/foo"), null, RequestConditionFactory.parseParams("foo!=bar"), null,
|
||||
null);
|
||||
null, null);
|
||||
match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
|
||||
|
||||
assertNull(match);
|
||||
|
|
@ -202,13 +202,13 @@ public class RequestMappingInfoTests {
|
|||
|
||||
RequestMappingInfo key =
|
||||
new RequestMappingInfo(singleton("/foo"), null, null, RequestConditionFactory.parseHeaders("foo=bar"),
|
||||
null);
|
||||
null, null);
|
||||
RequestMappingInfo match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
|
||||
|
||||
assertNotNull(match);
|
||||
|
||||
key = new RequestMappingInfo(singleton("/foo"), null, null, RequestConditionFactory.parseHeaders("foo!=bar"),
|
||||
null);
|
||||
null, null);
|
||||
match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
|
||||
|
||||
assertNull(match);
|
||||
|
|
@ -222,13 +222,33 @@ public class RequestMappingInfoTests {
|
|||
String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
|
||||
|
||||
RequestMappingInfo key = new RequestMappingInfo(singleton("/foo"), null, null, null,
|
||||
RequestConditionFactory.parseConsumes("text/plain"));
|
||||
RequestConditionFactory.parseConsumes("text/plain"), null);
|
||||
RequestMappingInfo match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
|
||||
|
||||
assertNotNull(match);
|
||||
|
||||
key = new RequestMappingInfo(singleton("/foo"), null, null, null,
|
||||
RequestConditionFactory.parseConsumes("application/xml"));
|
||||
RequestConditionFactory.parseConsumes("application/xml"), null);
|
||||
match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
|
||||
|
||||
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);
|
||||
|
||||
assertNotNull(match);
|
||||
|
||||
key = new RequestMappingInfo(singleton("/foo"), null, null, null, null,
|
||||
RequestConditionFactory.parseProduces("application/xml"));
|
||||
match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
|
||||
|
||||
assertNull(match);
|
||||
|
|
|
|||
|
|
@ -16,14 +16,6 @@
|
|||
|
||||
package org.springframework.web.servlet.mvc.method.annotation;
|
||||
|
||||
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.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.beans.PropertyEditorSupport;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
|
|
@ -48,7 +40,6 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
|
|
@ -60,8 +51,8 @@ import javax.validation.Valid;
|
|||
import javax.validation.constraints.NotNull;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
|
||||
import org.springframework.aop.interceptor.SimpleTraceInterceptor;
|
||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||
|
|
@ -142,6 +133,8 @@ import org.springframework.web.servlet.mvc.method.annotation.support.ServletWebA
|
|||
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
|
||||
import org.springframework.web.servlet.view.InternalResourceViewResolver;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* The origin of this test fixture is {@link ServletHandlerMethodTests} with tests in this class adapted to run
|
||||
* against the HandlerMethod infrastructure rather than against the DefaultAnnotationHandlerMapping, the
|
||||
|
|
@ -1033,8 +1026,6 @@ public class ServletHandlerMethodTests {
|
|||
assertEquals("non-pdf", response.getContentAsString());
|
||||
}
|
||||
|
||||
// TODO: uncomment ignore
|
||||
@Ignore
|
||||
@Test
|
||||
public void acceptHeaders() throws ServletException, IOException {
|
||||
initDispatcherServlet(AcceptHeadersController.class, null);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
* 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.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public class ProducesRequestConditionTests {
|
||||
|
||||
@Test
|
||||
public void consumesMatch() {
|
||||
RequestCondition condition = new ProducesRequestCondition("text/plain");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader("Accept", "text/plain");
|
||||
|
||||
assertTrue(condition.match(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void negatedConsumesMatch() {
|
||||
RequestCondition condition = new ProducesRequestCondition("!text/plain");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader("Accept", "text/plain");
|
||||
|
||||
assertFalse(condition.match(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void consumesWildcardMatch() {
|
||||
RequestCondition condition = new ProducesRequestCondition("text/*");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader("Accept", "text/plain");
|
||||
|
||||
assertTrue(condition.match(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void consumesMultipleMatch() {
|
||||
RequestCondition condition = new ProducesRequestCondition("text/plain", "application/xml");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader("Accept", "text/plain");
|
||||
|
||||
assertTrue(condition.match(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void consumesSingleNoMatch() {
|
||||
RequestCondition condition = new ProducesRequestCondition("text/plain");
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader("Accept", "application/xml");
|
||||
|
||||
assertFalse(condition.match(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compareToSingle() {
|
||||
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);
|
||||
assertTrue("Invalid comparison result: " + result, result < 0);
|
||||
|
||||
result = condition2.compareTo(condition1, accept);
|
||||
assertTrue("Invalid comparison result: " + result, result > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compareToMultiple() {
|
||||
ProducesRequestCondition condition1 = new ProducesRequestCondition("*/*", "text/plain");
|
||||
ProducesRequestCondition condition2 = new ProducesRequestCondition("text/*", "text/plain;q=0.7");
|
||||
|
||||
List<MediaType> accept = Collections.singletonList(MediaType.TEXT_PLAIN);
|
||||
|
||||
int result = condition1.compareTo(condition2, accept);
|
||||
assertTrue("Invalid comparison result: " + result, result < 0);
|
||||
|
||||
result = condition2.compareTo(condition1, accept);
|
||||
assertTrue("Invalid comparison result: " + result, result > 0);
|
||||
|
||||
condition1 = new ProducesRequestCondition("*/*");
|
||||
condition2 = new ProducesRequestCondition("text/*");
|
||||
|
||||
accept = Collections.singletonList(new MediaType("text", "*"));
|
||||
|
||||
result = condition1.compareTo(condition2, accept);
|
||||
assertTrue("Invalid comparison result: " + result, result > 0);
|
||||
|
||||
result = condition2.compareTo(condition1, accept);
|
||||
assertTrue("Invalid comparison result: " + result, result < 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compareToMultipleAccept() {
|
||||
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);
|
||||
|
||||
int result = condition1.compareTo(condition2, accept);
|
||||
assertTrue("Invalid comparison result: " + result, result < 0);
|
||||
|
||||
result = condition2.compareTo(condition1, accept);
|
||||
assertTrue("Invalid comparison result: " + result, result > 0);
|
||||
|
||||
accept = Arrays.asList(MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN);
|
||||
|
||||
result = condition1.compareTo(condition2, accept);
|
||||
assertTrue("Invalid comparison result: " + result, result > 0);
|
||||
|
||||
result = condition2.compareTo(condition1, accept);
|
||||
assertTrue("Invalid comparison result: " + result, result < 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void combine() {
|
||||
ProducesRequestCondition condition1 = new ProducesRequestCondition("text/plain");
|
||||
ProducesRequestCondition condition2 = new ProducesRequestCondition("application/xml");
|
||||
|
||||
ProducesRequestCondition result = condition1.combine(condition2);
|
||||
assertEquals(condition2, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void combineWithDefault() {
|
||||
ProducesRequestCondition condition1 = new ProducesRequestCondition("text/plain");
|
||||
ProducesRequestCondition condition2 = new ProducesRequestCondition("*/*");
|
||||
|
||||
ProducesRequestCondition result = condition1.combine(condition2);
|
||||
assertEquals(condition1, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
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);
|
||||
|
||||
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();
|
||||
request.addHeader("Accept", "text/plain");
|
||||
|
||||
ProducesRequestCondition condition = new ProducesRequestCondition("text/plain", "application/xml");
|
||||
|
||||
ProducesRequestCondition result = condition.getMatchingCondition(request);
|
||||
assertConditions(result, "text/plain");
|
||||
|
||||
condition = new ProducesRequestCondition("application/xml");
|
||||
|
||||
result = condition.getMatchingCondition(request);
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
private void assertConditions(ProducesRequestCondition condition, String... expected) {
|
||||
Set<ProducesRequestCondition.ProduceRequestCondition> conditions = condition.getConditions();
|
||||
assertEquals("Invalid amount of conditions", conditions.size(), expected.length);
|
||||
for (String s : expected) {
|
||||
boolean found = false;
|
||||
for (ProducesRequestCondition.ProduceRequestCondition requestCondition : conditions) {
|
||||
String conditionMediaType = requestCondition.getMediaType().toString();
|
||||
if (conditionMediaType.equals(s)) {
|
||||
found = true;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
fail("Condition [" + s + "] not found");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -311,4 +311,17 @@ public @interface RequestMapping {
|
|||
*/
|
||||
String[] consumes() default "*/*";
|
||||
|
||||
/**
|
||||
* The producible media types of the mapped request, narrowing the primary mapping.
|
||||
* <p>The format is a sequence of media types ("text/plain", "application/*),
|
||||
* with a request only mapped if the {@code Accept} matches one of these media types.
|
||||
* Expressions can be negated by using the "!" operator, as in "!text/plain", which matches
|
||||
* all requests with a {@code Accept} other than "text/plain".
|
||||
* <p><b>Supported at the type level as well as at the method level!</b>
|
||||
* When used at the type level, all method-level mappings override
|
||||
* this consumes restriction.
|
||||
* @see org.springframework.http.MediaType
|
||||
*/
|
||||
String[] produces() default "*/*";
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue