SPR-7354 - Added equivalent of JAX-RS @Consumes to Spring MVC

This commit is contained in:
Arjen Poutsma 2011-04-08 10:50:45 +00:00
parent bf6693dbc5
commit ff89c0e55a
8 changed files with 105 additions and 62 deletions

View File

@ -155,15 +155,19 @@ public final class RequestKey {
* Combines this {@code RequestKey} with another. The typical use case for this is combining type * Combines this {@code RequestKey} with another. The typical use case for this is combining type
* and method-level {@link RequestMapping @RequestMapping} annotations. * and method-level {@link RequestMapping @RequestMapping} annotations.
* *
* @param other the method-level RequestKey * @param methodKey the method-level RequestKey
* @param pathMatcher to {@linkplain PathMatcher#combine(String, String) combine} the patterns * @param pathMatcher to {@linkplain PathMatcher#combine(String, String) combine} the patterns
* @return the combined request key * @return the combined request key
*/ */
public RequestKey combine(RequestKey other, PathMatcher pathMatcher) { public RequestKey combine(RequestKey methodKey, PathMatcher pathMatcher) {
Set<String> patterns = combinePatterns(this.patterns, other.patterns, pathMatcher); Set<String> patterns = combinePatterns(this.patterns, methodKey.patterns, pathMatcher);
Set<RequestMethod> methods = union(this.methods, other.methods); Set<RequestMethod> methods = union(this.methods, methodKey.methods);
RequestCondition params = RequestConditionFactory.and(this.paramsCondition, other.paramsCondition); RequestCondition params = RequestConditionFactory.and(this.paramsCondition, methodKey.paramsCondition);
RequestCondition headers = RequestConditionFactory.and(this.headersCondition, other.headersCondition); RequestCondition headers = RequestConditionFactory.and(this.headersCondition, methodKey.headersCondition);
RequestCondition consumes;
// if (methodKey.consumesCondition.weight() > this.consumesCondition.weight()) {
//
// }
return new RequestKey(patterns, methods, params, headers, null); return new RequestKey(patterns, methods, params, headers, null);
} }
@ -278,15 +282,6 @@ public final class RequestKey {
return null; return null;
} }
private static boolean checkConditions(Set<RequestCondition> conditions, HttpServletRequest request) {
for (RequestCondition condition : conditions) {
if (!condition.match(request)) {
return false;
}
}
return true;
}
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) { if (this == obj) {

View File

@ -252,11 +252,11 @@ public class RequestMappingHandlerMethodMapping extends AbstractHandlerMethodMap
if (result != 0) { if (result != 0) {
return result; return result;
} }
result = otherKey.getParams().weight() - key.getParams().weight(); result = key.getParams().compareTo(otherKey.getParams());
if (result != 0) { if (result != 0) {
return result; return result;
} }
result = otherKey.getHeaders().weight() - key.getHeaders().weight(); result = key.getHeaders().compareTo(otherKey.getHeaders());
if (result != 0) { if (result != 0) {
return result; return result;
} }

View File

@ -26,7 +26,7 @@ import javax.servlet.http.HttpServletRequest;
* @author Arjen Poutsma * @author Arjen Poutsma
* @since 3.1 * @since 3.1
*/ */
abstract class AbstractNameValueCondition<T> implements RequestCondition { abstract class AbstractNameValueCondition<T> extends AbstractRequestCondition {
protected final String name; protected final String name;
@ -35,6 +35,7 @@ abstract class AbstractNameValueCondition<T> implements RequestCondition {
protected final boolean isNegated; protected final boolean isNegated;
AbstractNameValueCondition(String expression) { AbstractNameValueCondition(String expression) {
super(1);
int separator = expression.indexOf('='); int separator = expression.indexOf('=');
if (separator == -1) { if (separator == -1) {
this.isNegated = expression.startsWith("!"); this.isNegated = expression.startsWith("!");
@ -65,11 +66,6 @@ abstract class AbstractNameValueCondition<T> implements RequestCondition {
protected abstract boolean matchValue(HttpServletRequest request); protected abstract boolean matchValue(HttpServletRequest request);
public int weight() {
return 1;
}
@Override @Override
public int hashCode() { public int hashCode() {
int result = name.hashCode(); int result = name.hashCode();

View File

@ -0,0 +1,42 @@
/*
* 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;
/**
* Abstract base class for {@link RequestCondition} that provides a standard {@link Comparable} implementation.
*
* @author Arjen Poutsma
* @since 3.1
*/
public abstract class AbstractRequestCondition implements RequestCondition {
private final int weight;
protected AbstractRequestCondition(int weight) {
this.weight = weight;
}
public int getWeight() {
return weight;
}
public int compareTo(RequestCondition o) {
AbstractRequestCondition other = (AbstractRequestCondition) o;
return other.weight - this.weight;
}
}

View File

@ -24,11 +24,12 @@ import org.springframework.util.StringUtils;
/** /**
* @author Arjen Poutsma * @author Arjen Poutsma
*/ */
class ConsumesRequestCondition implements RequestCondition { class ConsumesRequestCondition extends AbstractRequestCondition {
private final MediaType mediaType; private final MediaType mediaType;
ConsumesRequestCondition(String mediaType) { ConsumesRequestCondition(String mediaType) {
super(1);
this.mediaType = MediaType.parseMediaType(mediaType); this.mediaType = MediaType.parseMediaType(mediaType);
} }
@ -41,7 +42,4 @@ class ConsumesRequestCondition implements RequestCondition {
return false; return false;
} }
public int weight() {
return 1;
}
} }

View File

@ -29,7 +29,7 @@ import javax.servlet.http.HttpServletRequest;
* @see RequestConditionFactory * @see RequestConditionFactory
* @since 3.1 * @since 3.1
*/ */
public interface RequestCondition { public interface RequestCondition extends Comparable<RequestCondition> {
/** /**
* Indicates whether this condition matches against the given servlet request. * Indicates whether this condition matches against the given servlet request.
@ -39,11 +39,4 @@ public interface RequestCondition {
*/ */
boolean match(HttpServletRequest request); boolean match(HttpServletRequest request);
/**
* Indicates the relative weight of this condition. More important conditions have a higher weight than ones that are
* less so.
*
* @return the weight of this condition
*/
int weight();
} }

View File

@ -16,6 +16,7 @@
package org.springframework.web.servlet.mvc.method.condition; package org.springframework.web.servlet.mvc.method.condition;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@ -25,20 +26,24 @@ import java.util.List;
* @author Arjen Poutsma * @author Arjen Poutsma
* @since 3.1 * @since 3.1
*/ */
abstract class RequestConditionComposite implements RequestCondition { abstract class RequestConditionComposite extends AbstractRequestCondition {
protected final List<RequestCondition> conditions; protected final List<RequestCondition> conditions;
public RequestConditionComposite(List<RequestCondition> conditions) { protected RequestConditionComposite(List<RequestCondition> conditions) {
this.conditions = conditions; super(getWeight(conditions));
this.conditions = Collections.unmodifiableList(conditions);
} }
public int weight() { private static int getWeight(List<RequestCondition> conditions) {
int size = 0; int weight = 0;
for (RequestCondition condition : conditions) { for (RequestCondition condition : conditions) {
size += condition.weight(); if (condition instanceof AbstractRequestCondition) {
AbstractRequestCondition abstractRequestCondition = (AbstractRequestCondition) condition;
weight += abstractRequestCondition.getWeight();
}
} }
return size; return weight;
} }
@Override @Override

View File

@ -33,41 +33,42 @@ import org.springframework.util.ObjectUtils;
*/ */
public abstract class RequestConditionFactory { public abstract class RequestConditionFactory {
private static final RequestCondition TRUE_CONDITION = new RequestCondition() { private static final RequestCondition TRUE_CONDITION = new AbstractRequestCondition(0) {
public boolean match(HttpServletRequest request) { public boolean match(HttpServletRequest request) {
return true; return true;
} }
public int weight() {
return 0;
}
@Override @Override
public String toString() { public String toString() {
return "TRUE"; return "TRUE";
} }
}; };
private static final RequestCondition FALSE_CONDITION = new RequestCondition() { private static final RequestCondition FALSE_CONDITION = new AbstractRequestCondition(0) {
public boolean match(HttpServletRequest request) { public boolean match(HttpServletRequest request) {
return false; return false;
} }
public int weight() {
return 0;
}
@Override @Override
public String toString() { public String toString() {
return "FALSE"; return "FALSE";
} }
}; };
/**
* Returns a condition that always returns {@code true} for {@link RequestCondition#match(HttpServletRequest)}.
*
* @return a condition that returns {@code true}
*/
public static RequestCondition trueCondition() { public static RequestCondition trueCondition() {
return TRUE_CONDITION; return TRUE_CONDITION;
} }
/**
* Returns a condition that always returns {@code false} for {@link RequestCondition#match(HttpServletRequest)}.
*
* @return a condition that returns {@code false}
*/
public static RequestCondition falseCondition() { public static RequestCondition falseCondition() {
return FALSE_CONDITION; return FALSE_CONDITION;
} }
@ -87,7 +88,12 @@ public abstract class RequestConditionFactory {
iterator.remove(); iterator.remove();
} }
} }
return new LogicalConjunctionRequestCondition(filteredConditions); if (filteredConditions.isEmpty()) {
return trueCondition();
}
else {
return new LogicalConjunctionRequestCondition(filteredConditions);
}
} }
/** /**
@ -108,7 +114,12 @@ public abstract class RequestConditionFactory {
iterator.remove(); iterator.remove();
} }
} }
return new LogicalDisjunctionRequestCondition(filteredConditions); if (filteredConditions.isEmpty()) {
return trueCondition();
}
else {
return new LogicalDisjunctionRequestCondition(filteredConditions);
}
} }
/** /**
@ -120,7 +131,7 @@ public abstract class RequestConditionFactory {
*/ */
public static RequestCondition parseParams(String... params) { public static RequestCondition parseParams(String... params) {
if (ObjectUtils.isEmpty(params)) { if (ObjectUtils.isEmpty(params)) {
return TRUE_CONDITION; return trueCondition();
} }
RequestCondition[] result = new RequestCondition[params.length]; RequestCondition[] result = new RequestCondition[params.length];
for (int i = 0; i < params.length; i++) { for (int i = 0; i < params.length; i++) {
@ -138,7 +149,7 @@ public abstract class RequestConditionFactory {
*/ */
public static RequestCondition parseHeaders(String... headers) { public static RequestCondition parseHeaders(String... headers) {
if (ObjectUtils.isEmpty(headers)) { if (ObjectUtils.isEmpty(headers)) {
return TRUE_CONDITION; return trueCondition();
} }
RequestCondition[] result = new RequestCondition[headers.length]; RequestCondition[] result = new RequestCondition[headers.length];
for (int i = 0; i < headers.length; i++) { for (int i = 0; i < headers.length; i++) {
@ -157,9 +168,16 @@ public abstract class RequestConditionFactory {
return "Accept".equalsIgnoreCase(name) || "Content-Type".equalsIgnoreCase(name); return "Accept".equalsIgnoreCase(name) || "Content-Type".equalsIgnoreCase(name);
} }
/**
* 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 RequestCondition parseConsumes(String... consumes) { public static RequestCondition parseConsumes(String... consumes) {
if (ObjectUtils.isEmpty(consumes)) { if (ObjectUtils.isEmpty(consumes)) {
return TRUE_CONDITION; return trueCondition();
} }
RequestCondition[] result = new RequestCondition[consumes.length]; RequestCondition[] result = new RequestCondition[consumes.length];
for (int i = 0; i < consumes.length; i++) { for (int i = 0; i < consumes.length; i++) {
@ -168,8 +186,4 @@ public abstract class RequestConditionFactory {
return or(result); return or(result);
} }
//
// Conditions
//
} }