Skip to content

Commit 71aae40

Browse files
committed
SPR-7354 - Added equivalent of JAX-RS @consumes to Spring MVC
1 parent 7f247a6 commit 71aae40

21 files changed

+1030
-791
lines changed

org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import java.util.List;
2525
import java.util.Map;
2626
import java.util.Set;
27-
2827
import javax.servlet.http.HttpServletRequest;
2928

3029
import org.springframework.core.annotation.AnnotationUtils;
@@ -128,7 +127,7 @@ private static RequestMappingInfo createFromRequestMapping(RequestMapping annota
128127
return new RequestMappingInfo(Arrays.asList(annotation.value()), Arrays.asList(annotation.method()),
129128
RequestConditionFactory.parseParams(annotation.params()),
130129
RequestConditionFactory.parseHeaders(annotation.headers()),
131-
RequestConditionFactory.parseConsumes());
130+
RequestConditionFactory.parseConsumes(annotation.consumes(), annotation.headers()));
132131
}
133132

134133
@Override
@@ -240,6 +239,10 @@ public int compare(RequestMappingInfo mapping, RequestMappingInfo otherMapping)
240239
if (result != 0) {
241240
return result;
242241
}
242+
result = mapping.getConsumes().compareTo(otherMapping.getConsumes());
243+
if (result != 0) {
244+
return result;
245+
}
243246
/*
244247
TODO: fix
245248
result = compareAcceptHeaders(mapping.getAcceptHeaderMediaTypes(), otherMapping.getAcceptHeaderMediaTypes());

org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingInfo.java

Lines changed: 44 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@
2222
import java.util.LinkedHashSet;
2323
import java.util.List;
2424
import java.util.Set;
25-
2625
import javax.servlet.http.HttpServletRequest;
2726

2827
import org.springframework.util.PathMatcher;
2928
import org.springframework.util.StringUtils;
3029
import org.springframework.web.bind.annotation.RequestMethod;
31-
import org.springframework.web.servlet.mvc.method.condition.RequestCondition;
32-
import org.springframework.web.servlet.mvc.method.condition.RequestConditionFactory;
30+
import org.springframework.web.servlet.mvc.method.condition.ConsumesRequestCondition;
31+
import org.springframework.web.servlet.mvc.method.condition.HeadersRequestCondition;
32+
import org.springframework.web.servlet.mvc.method.condition.ParamsRequestCondition;
3333

3434
/**
3535
* Contains a set of conditions to match to a given request such as URL patterns, HTTP methods, request parameters
@@ -49,16 +49,16 @@ public final class RequestMappingInfo {
4949

5050
private final Set<RequestMethod> methods;
5151

52-
private final RequestCondition paramsCondition;
52+
private final ParamsRequestCondition paramsCondition;
5353

54-
private final RequestCondition headersCondition;
54+
private final HeadersRequestCondition headersCondition;
5555

56-
private final RequestCondition consumesCondition;
56+
private final ConsumesRequestCondition consumesCondition;
5757

5858
private int hash;
5959

6060
/**
61-
* Creates a new {@code RequestKey} instance with the given URL patterns and HTTP methods.
61+
* Creates a new {@code RequestMappingInfo} instance with the given URL patterns and HTTP methods.
6262
*
6363
* <p>Package protected for testing purposes.
6464
*/
@@ -67,18 +67,18 @@ public final class RequestMappingInfo {
6767
}
6868

6969
/**
70-
* Creates a new {@code RequestKey} instance with a full set of conditions.
70+
* Creates a new {@code RequestMappingInfo} instance with a full set of conditions.
7171
*/
7272
public RequestMappingInfo(Collection<String> patterns,
7373
Collection<RequestMethod> methods,
74-
RequestCondition paramsCondition,
75-
RequestCondition headersCondition,
76-
RequestCondition consumesCondition) {
74+
ParamsRequestCondition paramsCondition,
75+
HeadersRequestCondition headersCondition,
76+
ConsumesRequestCondition consumesCondition) {
7777
this.patterns = asUnmodifiableSet(prependLeadingSlash(patterns));
7878
this.methods = asUnmodifiableSet(methods);
79-
this.paramsCondition = paramsCondition != null ? paramsCondition : RequestConditionFactory.trueCondition();
80-
this.headersCondition = headersCondition != null ? headersCondition : RequestConditionFactory.trueCondition();
81-
this.consumesCondition = consumesCondition != null ? consumesCondition : RequestConditionFactory.trueCondition();
79+
this.paramsCondition = paramsCondition != null ? paramsCondition : new ParamsRequestCondition();
80+
this.headersCondition = headersCondition != null ? headersCondition : new HeadersRequestCondition();
81+
this.consumesCondition = consumesCondition != null ? consumesCondition : new ConsumesRequestCondition();
8282
}
8383

8484
private static Set<String> prependLeadingSlash(Collection<String> patterns) {
@@ -118,21 +118,28 @@ public Set<RequestMethod> getMethods() {
118118
}
119119

120120
/**
121-
* Returns the request parameters of this request key.
121+
* Returns the request parameters conditions of this request key.
122122
*/
123-
public RequestCondition getParams() {
123+
public ParamsRequestCondition getParams() {
124124
return paramsCondition;
125125
}
126126

127127
/**
128-
* Returns the request headers of this request key.
128+
* Returns the request headers conditions of this request key.
129129
*/
130-
public RequestCondition getHeaders() {
130+
public HeadersRequestCondition getHeaders() {
131131
return headersCondition;
132132
}
133133

134134
/**
135-
* Combines this {@code RequestKey} with another as follows:
135+
* Returns the request consumes conditions of this request key.
136+
*/
137+
public ConsumesRequestCondition getConsumes() {
138+
return consumesCondition;
139+
}
140+
141+
/**
142+
* Combines this {@code RequestMappingInfo} with another as follows:
136143
* <ul>
137144
* <li>URL patterns:
138145
* <ul>
@@ -141,9 +148,9 @@ public RequestCondition getHeaders() {
141148
* <li>If neither contains patterns use ""
142149
* </ul>
143150
* <li>HTTP methods are combined as union of all HTTP methods listed in both keys.
144-
* <li>Request parameter are combined into a logical AND.
145-
* <li>Request header are combined into a logical AND.
146-
* <li>Consumes .. TODO
151+
* <li>Request parameters are combined as per {@link ParamsRequestCondition#combine(ParamsRequestCondition)}.
152+
* <li>Request headers are combined as per {@link HeadersRequestCondition#combine(HeadersRequestCondition)}.
153+
* <li>Consumes are combined as per {@link ConsumesRequestCondition#combine(ConsumesRequestCondition)}.
147154
* </ul>
148155
* @param methodKey the key to combine with
149156
* @param pathMatcher to {@linkplain PathMatcher#combine(String, String) combine} the patterns
@@ -152,9 +159,9 @@ public RequestCondition getHeaders() {
152159
public RequestMappingInfo combine(RequestMappingInfo methodKey, PathMatcher pathMatcher) {
153160
Set<String> patterns = combinePatterns(this.patterns, methodKey.patterns, pathMatcher);
154161
Set<RequestMethod> methods = union(this.methods, methodKey.methods);
155-
RequestCondition params = RequestConditionFactory.and(this.paramsCondition, methodKey.paramsCondition);
156-
RequestCondition headers = RequestConditionFactory.and(this.headersCondition, methodKey.headersCondition);
157-
RequestCondition consumes = RequestConditionFactory.mostSpecific(methodKey.consumesCondition, this.consumesCondition);
162+
ParamsRequestCondition params = this.paramsCondition.combine(methodKey.paramsCondition);
163+
HeadersRequestCondition headers = this.headersCondition.combine(methodKey.headersCondition);
164+
ConsumesRequestCondition consumes = this.consumesCondition.combine(methodKey.consumesCondition);
158165

159166
return new RequestMappingInfo(patterns, methods, params, headers, consumes);
160167
}
@@ -189,7 +196,7 @@ private static <T> Set<T> union(Collection<T> s1, Collection<T> s2) {
189196
}
190197

191198
/**
192-
* Returns a new {@code RequestKey} that contains all conditions of this key that are relevant to the request.
199+
* Returns a new {@code RequestMappingInfo} that contains all conditions of this key that are relevant to the request.
193200
* <ul>
194201
* <li>The list of URL path patterns is trimmed to contain the patterns that match the URL with matching patterns
195202
* sorted via {@link PathMatcher#getPatternComparator(String)}.
@@ -203,16 +210,20 @@ private static <T> Set<T> union(Collection<T> s1, Collection<T> s2) {
203210
* @return a new request key that contains all matching attributes, or {@code null} if not all conditions match
204211
*/
205212
public RequestMappingInfo getMatchingRequestMapping(String lookupPath, HttpServletRequest request, PathMatcher pathMatcher) {
206-
if (!checkMethod(request) || !paramsCondition.match(request) || !headersCondition.match(request) ||
207-
!consumesCondition.match(request)) {
213+
ParamsRequestCondition matchingParamsCondition = paramsCondition.getMatchingCondition(request);
214+
HeadersRequestCondition matchingHeadersCondition = headersCondition.getMatchingCondition(request);
215+
ConsumesRequestCondition matchingConsumesCondition = consumesCondition.getMatchingCondition(request);
216+
217+
if (!checkMethod(request) || matchingParamsCondition == null || matchingHeadersCondition == null ||
218+
matchingConsumesCondition == null) {
208219
return null;
209220
}
210221
else {
211222
List<String> matchingPatterns = getMatchingPatterns(lookupPath, request, pathMatcher);
212223
if (!matchingPatterns.isEmpty()) {
213224
Set<RequestMethod> matchingMethods = getMatchingMethod(request);
214-
return new RequestMappingInfo(matchingPatterns, matchingMethods, this.paramsCondition, this.headersCondition,
215-
this.consumesCondition);
225+
return new RequestMappingInfo(matchingPatterns, matchingMethods, matchingParamsCondition,
226+
matchingHeadersCondition, matchingConsumesCondition);
216227
}
217228
else {
218229
return null;
@@ -277,7 +288,8 @@ public boolean equals(Object obj) {
277288
RequestMappingInfo other = (RequestMappingInfo) obj;
278289
return (this.patterns.equals(other.patterns) && this.methods.equals(other.methods) &&
279290
this.paramsCondition.equals(other.paramsCondition) &&
280-
this.headersCondition.equals(other.headersCondition));
291+
this.headersCondition.equals(other.headersCondition) &&
292+
this.consumesCondition.equals(other.consumesCondition));
281293
}
282294
return false;
283295
}
@@ -290,6 +302,7 @@ public int hashCode() {
290302
result = 31 * result + methods.hashCode();
291303
result = 31 * result + paramsCondition.hashCode();
292304
result = 31 * result + headersCondition.hashCode();
305+
result = 31 * result + consumesCondition.hashCode();
293306
hash = result;
294307
}
295308
return result;

org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/condition/AbstractNameValueCondition.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
* @author Arjen Poutsma
2727
* @since 3.1
2828
*/
29-
abstract class AbstractNameValueCondition<T> extends AbstractRequestCondition {
29+
abstract class AbstractNameValueCondition<T> implements RequestCondition {
3030

3131
protected final String name;
3232

@@ -65,11 +65,6 @@ public final boolean match(HttpServletRequest request) {
6565

6666
protected abstract boolean matchValue(HttpServletRequest request);
6767

68-
@Override
69-
public int getSpecificity() {
70-
return 1;
71-
}
72-
7368
@Override
7469
public int hashCode() {
7570
int result = name.hashCode();

org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/condition/AbstractRequestCondition.java

Lines changed: 0 additions & 41 deletions
This file was deleted.

0 commit comments

Comments
 (0)