From 5da79ebca61f049a5dc8c3be07c2676f20f12947 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 14 Feb 2014 21:38:44 +0100 Subject: [PATCH] Related polishing Issue. SPR-11428 (cherry picked from commit 9c6df76) --- .../web/method/HandlerMethodSelector.java | 7 +- .../ExceptionHandlerMethodResolver.java | 49 +++++++----- .../condition/AbstractRequestCondition.java | 25 ++++--- .../condition/CompositeRequestCondition.java | 18 +++-- .../condition/ConsumesRequestCondition.java | 22 +++--- .../condition/HeadersRequestCondition.java | 16 ++-- .../mvc/condition/ParamsRequestCondition.java | 18 +++-- .../condition/PatternsRequestCondition.java | 19 +++-- .../condition/ProducesRequestCondition.java | 74 +++++++++---------- .../mvc/condition/RequestCondition.java | 13 ++-- .../mvc/condition/RequestConditionHolder.java | 10 +-- .../RequestMethodsRequestCondition.java | 35 ++++----- .../RequestMappingInfoHandlerMapping.java | 16 ++-- .../RequestMappingHandlerMapping.java | 55 ++++++-------- .../RequestMappingHandlerMappingTests.java | 18 ++--- 15 files changed, 198 insertions(+), 197 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/web/method/HandlerMethodSelector.java b/spring-web/src/main/java/org/springframework/web/method/HandlerMethodSelector.java index fc43fc5f8b5..671f35a3ac1 100644 --- a/spring-web/src/main/java/org/springframework/web/method/HandlerMethodSelector.java +++ b/spring-web/src/main/java/org/springframework/web/method/HandlerMethodSelector.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -37,9 +37,8 @@ import org.springframework.util.ReflectionUtils.MethodFilter; public abstract class HandlerMethodSelector { /** - * Selects handler methods for the given handler type. Callers of this method define handler methods - * of interest through the {@link MethodFilter} parameter. - * + * Select handler methods for the given handler type. + *

Callers define handler methods of interest through the {@link MethodFilter} parameter. * @param handlerType the handler type to search handler methods on * @param handlerMethodFilter a {@link MethodFilter} to help recognize handler methods of interest * @return the selected methods, or an empty set diff --git a/spring-web/src/main/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolver.java b/spring-web/src/main/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolver.java index 626b0fe2189..d55c191ae21 100644 --- a/spring-web/src/main/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolver.java +++ b/spring-web/src/main/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -43,14 +43,25 @@ import org.springframework.web.method.HandlerMethodSelector; */ public class ExceptionHandlerMethodResolver { + /** + * A filter for selecting {@code @ExceptionHandler} methods. + */ + public final static MethodFilter EXCEPTION_HANDLER_METHODS = new MethodFilter() { + public boolean matches(Method method) { + return (AnnotationUtils.findAnnotation(method, ExceptionHandler.class) != null); + } + }; + private static final Method NO_METHOD_FOUND = ClassUtils.getMethodIfAvailable(System.class, "currentTimeMillis"); + private final Map, Method> mappedMethods = new ConcurrentHashMap, Method>(16); private final Map, Method> exceptionLookupCache = new ConcurrentHashMap, Method>(16); + /** * A constructor that finds {@link ExceptionHandler} methods in the given type. * @param handlerType the type to introspect @@ -63,6 +74,7 @@ public class ExceptionHandlerMethodResolver { } } + /** * Extract exception mappings from the {@code @ExceptionHandler} annotation * first and as a fall-back from the method signature. @@ -70,10 +82,7 @@ public class ExceptionHandlerMethodResolver { @SuppressWarnings("unchecked") private List> detectExceptionMappings(Method method) { List> result = new ArrayList>(); - - ExceptionHandler annotation = AnnotationUtils.findAnnotation(method, ExceptionHandler.class); - result.addAll(Arrays.asList(annotation.value())); - + detectAnnotationExceptionMappings(method, result); if (result.isEmpty()) { for (Class paramType : method.getParameterTypes()) { if (Throwable.class.isAssignableFrom(paramType)) { @@ -81,12 +90,15 @@ public class ExceptionHandlerMethodResolver { } } } - Assert.notEmpty(result, "No exception types mapped to {" + method + "}"); - return result; } + protected void detectAnnotationExceptionMappings(Method method, List> result) { + ExceptionHandler annot = AnnotationUtils.findAnnotation(method, ExceptionHandler.class); + result.addAll(Arrays.asList(annot.value())); + } + private void addExceptionMapping(Class exceptionType, Method method) { Method oldMethod = this.mappedMethods.put(exceptionType, method); if (oldMethod != null && !oldMethod.equals(method)) { @@ -110,7 +122,16 @@ public class ExceptionHandlerMethodResolver { * @return a method to handle the exception or {@code null} */ public Method resolveMethod(Exception exception) { - Class exceptionType = exception.getClass(); + return resolveMethodByExceptionType(exception.getClass()); + } + + /** + * Find a method to handle the given exception type. This can be useful if + * an Exception instance is not available (example for tools). + * @param exceptionType the exception type + * @return a method to handle the exception or {@code null} + */ + public Method resolveMethodByExceptionType(Class exceptionType) { Method method = this.exceptionLookupCache.get(exceptionType); if (method == null) { method = getMappedMethod(exceptionType); @@ -131,21 +152,11 @@ public class ExceptionHandlerMethodResolver { } if (!matches.isEmpty()) { Collections.sort(matches, new ExceptionDepthComparator(exceptionType)); - return mappedMethods.get(matches.get(0)); + return this.mappedMethods.get(matches.get(0)); } else { return null; } } - /** - * A filter for selecting {@code @ExceptionHandler} methods. - */ - public final static MethodFilter EXCEPTION_HANDLER_METHODS = new MethodFilter() { - - public boolean matches(Method method) { - return AnnotationUtils.findAnnotation(method, ExceptionHandler.class) != null; - } - }; - } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/AbstractRequestCondition.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/AbstractRequestCondition.java index 921ecb249a0..f67b1d20d45 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/AbstractRequestCondition.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/AbstractRequestCondition.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -28,20 +28,13 @@ import java.util.Iterator; */ public abstract class AbstractRequestCondition> implements RequestCondition { - /** - * Return the discrete items a request condition is composed of. - * For example URL patterns, HTTP request methods, param expressions, etc. - * @return a collection of objects, never {@code null} - */ - protected abstract Collection getContent(); - @Override - public boolean equals(Object o) { - if (this == o) { + public boolean equals(Object obj) { + if (this == obj) { return true; } - if (o != null && getClass().equals(o.getClass())) { - AbstractRequestCondition other = (AbstractRequestCondition) o; + if (obj != null && getClass().equals(obj.getClass())) { + AbstractRequestCondition other = (AbstractRequestCondition) obj; return getContent().equals(other.getContent()); } return false; @@ -66,6 +59,14 @@ public abstract class AbstractRequestCondition getContent(); + /** * The notation to use when printing discrete items of content. * For example " || " for URL patterns or " && " for param expressions. diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/CompositeRequestCondition.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/CompositeRequestCondition.java index b7c8e0442a6..14d51450ed9 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/CompositeRequestCondition.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/CompositeRequestCondition.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -20,7 +20,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; - import javax.servlet.http.HttpServletRequest; import org.springframework.util.Assert; @@ -43,6 +42,7 @@ public class CompositeRequestCondition extends AbstractRequestCondition... rawConditions) { RequestConditionHolder[] wrappedConditions = new RequestConditionHolder[rawConditions.length]; for (int i = 0; i < rawConditions.length; i++) { @@ -61,10 +66,6 @@ public class CompositeRequestCondition extends AbstractRequestCondition expressions; + /** * Creates a new instance from 0 or more "consumes" expressions. * @param consumes expressions with the syntax described in * {@link RequestMapping#consumes()}; if 0 expressions are provided, - * the condition will match to every request. + * the condition will match to every request */ public ConsumesRequestCondition(String... consumes) { this(consumes, null); @@ -78,6 +78,7 @@ public final class ConsumesRequestCondition extends AbstractRequestCondition parseExpressions(String[] consumes, String[] headers) { Set result = new LinkedHashSet(); if (headers != null) { @@ -98,6 +99,7 @@ public final class ConsumesRequestCondition extends AbstractRequestCondition - *

  • 0 if the two conditions have the same number of expressions - *
  • Less than 0 if "this" has more or more specific media type expressions - *
  • Greater than 0 if "other" has more or more specific media type expressions + *
  • 0 if the two conditions have the same number of expressions + *
  • Less than 0 if "this" has more or more specific media type expressions + *
  • Greater than 0 if "other" has more or more specific media type expressions * - * *

    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. @@ -197,6 +196,7 @@ public final class ConsumesRequestCondition extends AbstractRequestCondition expressions; + /** * Create a new instance from the given header expressions. Expressions with * header names 'Accept' or 'Content-Type' are ignored. See {@link ConsumesRequestCondition} * and {@link ProducesRequestCondition} for those. * @param headers media type expressions with syntax defined in {@link RequestMapping#headers()}; - * if 0, the condition will match to every request. + * if 0, the condition will match to every request */ public HeadersRequestCondition(String... headers) { this(parseExpressions(headers)); @@ -56,6 +56,7 @@ public final class HeadersRequestCondition extends AbstractRequestCondition(conditions)); } + private static Collection parseExpressions(String... headers) { Set expressions = new LinkedHashSet(); if (headers != null) { @@ -113,11 +114,10 @@ public final class HeadersRequestCondition extends AbstractRequestCondition - *

  • 0 if the two conditions have the same number of header expressions - *
  • Less than 0 if "this" instance has more header expressions - *
  • Greater than 0 if the "other" instance has more header expressions + *
  • 0 if the two conditions have the same number of header expressions + *
  • Less than 0 if "this" instance has more header expressions + *
  • Greater than 0 if the "other" instance has more header expressions * - * *

    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. @@ -126,6 +126,7 @@ public final class HeadersRequestCondition extends AbstractRequestCondition expressions; + /** * Create a new instance from the given param expressions. * @param params expressions with syntax defined in {@link RequestMapping#params()}; @@ -51,6 +51,7 @@ public final class ParamsRequestCondition extends AbstractRequestCondition(conditions)); } + private static Collection parseExpressions(String... params) { Set expressions = new LinkedHashSet(); if (params != null) { @@ -61,6 +62,7 @@ public final class ParamsRequestCondition extends AbstractRequestCondition getContent() { - return expressions; + return this.expressions; } @Override @@ -104,19 +106,19 @@ public final class ParamsRequestCondition extends AbstractRequestCondition - *

  • 0 if the two conditions have the same number of parameter expressions - *
  • Less than 0 if "this" instance has more parameter expressions - *
  • Greater than 0 if the "other" instance has more parameter expressions + *
  • 0 if the two conditions have the same number of parameter expressions + *
  • Less than 0 if "this" instance has more parameter expressions + *
  • Greater than 0 if the "other" instance has more parameter expressions * - * *

    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(); + return (other.expressions.size() - this.expressions.size()); } + /** * Parses and matches a single param expression to a request. */ diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/PatternsRequestCondition.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/PatternsRequestCondition.java index d68b231ba56..69f10ad3bce 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/PatternsRequestCondition.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/PatternsRequestCondition.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -154,10 +154,10 @@ public final class PatternsRequestCondition extends AbstractRequestCondition - *

  • If there are patterns in both instances, combine the patterns in "this" with - * the patterns in "other" using {@link PathMatcher#combine(String, String)}. - *
  • If only one instance has patterns, use them. - *
  • If neither instance has patterns, use an empty String (i.e. ""). + *
  • If there are patterns in both instances, combine the patterns in "this" with + * the patterns in "other" using {@link PathMatcher#combine(String, String)}. + *
  • If only one instance has patterns, use them. + *
  • If neither instance has patterns, use an empty String (i.e. ""). * */ @Override @@ -189,10 +189,10 @@ public final class PatternsRequestCondition extends AbstractRequestConditionA matching pattern is obtained by making checks in the following order: *
      - *
    • Direct match - *
    • Pattern match with ".*" appended if the pattern doesn't already contain a "." - *
    • Pattern match - *
    • Pattern match with "/" appended if the pattern doesn't already end in "/" + *
    • Direct match + *
    • Pattern match with ".*" appended if the pattern doesn't already contain a "." + *
    • Pattern match + *
    • Pattern match with "/" appended if the pattern doesn't already end in "/" *
    * @param request the current request * @return the same instance if the condition contains no patterns; @@ -264,7 +264,6 @@ public final class PatternsRequestCondition extends AbstractRequestCondition patternComparator = this.pathMatcher.getPatternComparator(lookupPath); - Iterator iterator = this.patterns.iterator(); Iterator iteratorOther = other.patterns.iterator(); while (iterator.hasNext() && iteratorOther.hasNext()) { diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/ProducesRequestCondition.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/ProducesRequestCondition.java index 13292f1a766..24b71952e83 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/ProducesRequestCondition.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/ProducesRequestCondition.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -23,7 +23,6 @@ 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; @@ -46,10 +45,14 @@ import org.springframework.web.servlet.mvc.condition.HeadersRequestCondition.Hea */ public final class ProducesRequestCondition extends AbstractRequestCondition { + private final List MEDIA_TYPE_ALL_LIST = + Collections.singletonList(new ProduceMediaTypeExpression("*/*")); + private final List expressions; private final ContentNegotiationManager contentNegotiationManager; + /** * Creates a new instance from "produces" expressions. If 0 expressions * are provided in total, this condition will match to any request. @@ -78,14 +81,22 @@ public final class ProducesRequestCondition extends AbstractRequestCondition(parseExpressions(produces, headers)); Collections.sort(this.expressions); - this.contentNegotiationManager = (manager != null) ? manager : new ContentNegotiationManager(); + this.contentNegotiationManager = (manager != null ? manager : new ContentNegotiationManager()); + } + + /** + * Private constructor with already parsed media type expressions. + */ + private ProducesRequestCondition(Collection expressions, ContentNegotiationManager manager) { + this.expressions = new ArrayList(expressions); + Collections.sort(this.expressions); + this.contentNegotiationManager = (manager != null ? manager : new ContentNegotiationManager()); } + private Set parseExpressions(String[] produces, String[] headers) { Set result = new LinkedHashSet(); if (headers != null) { @@ -106,17 +117,6 @@ public final class ProducesRequestCondition extends AbstractRequestCondition expressions, - ContentNegotiationManager manager) { - - this.expressions = new ArrayList(expressions); - Collections.sort(this.expressions); - this.contentNegotiationManager = (manager != null) ? manager : new ContentNegotiationManager(); - } - /** * Return the contained "produces" expressions. */ @@ -168,12 +168,10 @@ public final class ProducesRequestCondition extends AbstractRequestCondition - *
  • Sort 'Accept' header media types by quality value via - * {@link MediaType#sortByQualityValue(List)} and iterate the list. - *
  • Get the first index of matching media types in each "produces" - * condition first matching with {@link MediaType#equals(Object)} and - * then with {@link MediaType#includes(MediaType)}. - *
  • If a lower index is found, the condition at that index wins. - *
  • If both indexes are equal, the media types at the index are - * compared further with {@link MediaType#SPECIFICITY_COMPARATOR}. + *
  • Sort 'Accept' header media types by quality value via + * {@link MediaType#sortByQualityValue(List)} and iterate the list. + *
  • Get the first index of matching media types in each "produces" + * condition first matching with {@link MediaType#equals(Object)} and + * then with {@link MediaType#includes(MediaType)}. + *
  • If a lower index is found, the condition at that index wins. + *
  • If both indexes are equal, the media types at the index are + * compared further with {@link MediaType#SPECIFICITY_COMPARATOR}. * - * *

    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 @@ -211,7 +207,6 @@ public final class ProducesRequestCondition extends AbstractRequestCondition acceptedMediaTypes = getAcceptedMediaTypes(request); - for (MediaType acceptedMediaType : acceptedMediaTypes) { int thisIndex = this.indexOfEqualMediaType(acceptedMediaType); int otherIndex = other.indexOfEqualMediaType(acceptedMediaType); @@ -228,9 +223,9 @@ public final class ProducesRequestCondition extends AbstractRequestCondition getExpressionsToCompare() { - return this.expressions.isEmpty() ? MEDIA_TYPE_ALL_LIST : this.expressions; + return (this.expressions.isEmpty() ? MEDIA_TYPE_ALL_LIST : this.expressions); } - private final List MEDIA_TYPE_ALL_LIST = - Collections.singletonList(new ProduceMediaTypeExpression("*/*")); - /** * Parses and matches a single media type expression to a request's 'Accept' header. diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/RequestCondition.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/RequestCondition.java index d4c69a9360d..0fad8079dac 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/RequestCondition.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/RequestCondition.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -21,15 +21,14 @@ import javax.servlet.http.HttpServletRequest; import org.springframework.web.bind.annotation.RequestMapping; /** - * The contract for request conditions. + * The contract for request conditions in Spring MVC's mapping infrastructure. * *

    Request conditions can be combined via {@link #combine(Object)}, matched to * a request via {@link #getMatchingCondition(HttpServletRequest)}, and compared * to each other via {@link #compareTo(Object, HttpServletRequest)} to determine * which matches a request more closely. * - * @param The type of objects that this RequestCondition can be combined - * with compared to. + * @param the type of objects that this RequestCondition can be combined with and compared to * * @author Rossen Stoyanchev * @author Arjen Poutsma @@ -41,10 +40,9 @@ public interface RequestCondition { * Defines the rules for combining this condition (i.e. the current instance) * with another condition. For example combining type- and method-level * {@link RequestMapping} conditions. - * * @param other the condition to combine with. * @return a request condition instance that is the result of combining - * the two condition instances. + * the two condition instances. */ T combine(T other); @@ -54,9 +52,8 @@ public interface RequestCondition { * 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. + * or {@code null} if there is no match */ T getMatchingCondition(HttpServletRequest request); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/RequestConditionHolder.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/RequestConditionHolder.java index 8779839fbbd..75ca99a5774 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/RequestConditionHolder.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/RequestConditionHolder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -18,10 +18,8 @@ package org.springframework.web.servlet.mvc.condition; import java.util.Collection; import java.util.Collections; - import javax.servlet.http.HttpServletRequest; - /** * A holder for a {@link RequestCondition} useful when the type of the request * condition is not known ahead of time, e.g. custom condition. Since this @@ -40,6 +38,7 @@ public final class RequestConditionHolder extends AbstractRequestCondition condition; + /** * Create a new holder to wrap the given request condition. * @param requestCondition the condition to hold, may be {@code null} @@ -49,6 +48,7 @@ public final class RequestConditionHolder extends AbstractRequestCondition) requestCondition; } + /** * Return the held request condition, or {@code null} if not holding one. */ @@ -58,7 +58,7 @@ public final class RequestConditionHolder extends AbstractRequestCondition getContent() { - return this.condition != null ? Collections.singleton(this.condition) : Collections.emptyList(); + return (this.condition != null ? Collections.singleton(this.condition) : Collections.emptyList()); } @Override @@ -109,7 +109,7 @@ public final class RequestConditionHolder extends AbstractRequestCondition match = (RequestCondition) this.condition.getMatchingCondition(request); - return (match != null) ? new RequestConditionHolder(match) : null; + return (match != null ? new RequestConditionHolder(match) : null); } /** diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/RequestMethodsRequestCondition.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/RequestMethodsRequestCondition.java index 22d5e3b8b5a..9d89b7bc1b6 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/RequestMethodsRequestCondition.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/RequestMethodsRequestCondition.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2014 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. @@ -22,7 +22,6 @@ 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; @@ -39,36 +38,36 @@ public final class RequestMethodsRequestCondition extends AbstractRequestConditi private final Set methods; + /** * Create a new instance with the given request methods. * @param requestMethods 0 or more HTTP request methods; - * if, 0 the condition will match to every request. + * if, 0 the condition will match to every request */ public RequestMethodsRequestCondition(RequestMethod... requestMethods) { this(asList(requestMethods)); } - private static List asList(RequestMethod... requestMethods) { - return requestMethods != null ? Arrays.asList(requestMethods) : Collections.emptyList(); - } - - /** - * Private constructor. - */ private RequestMethodsRequestCondition(Collection requestMethods) { this.methods = Collections.unmodifiableSet(new LinkedHashSet(requestMethods)); } + + private static List asList(RequestMethod... requestMethods) { + return (requestMethods != null ? Arrays.asList(requestMethods) : Collections.emptyList()); + } + + /** * Returns all {@link RequestMethod}s contained in this condition. */ public Set getMethods() { - return methods; + return this.methods; } @Override protected Collection getContent() { - return methods; + return this.methods; } @Override @@ -89,7 +88,6 @@ public final class RequestMethodsRequestCondition extends AbstractRequestConditi /** * Check if any of the HTTP request methods match the given request and * return an instance that contains the matching HTTP request method only. - * * @param request the current request * @return the same instance if the condition is empty, a new condition with * the matched request method, or {@code null} if no request methods match @@ -113,7 +111,7 @@ public final class RequestMethodsRequestCondition extends AbstractRequestConditi try { return RequestMethod.valueOf(request.getMethod()); } - catch (IllegalArgumentException e) { + catch (IllegalArgumentException ex) { return null; } } @@ -121,17 +119,16 @@ public final class RequestMethodsRequestCondition extends AbstractRequestConditi /** * Returns: *

    - * *

    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(); + return (other.methods.size() - this.methods.size()); } } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMapping.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMapping.java index 62fdd9d95f6..4e58fa9b38b 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMapping.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMapping.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -16,9 +16,15 @@ package org.springframework.web.servlet.mvc.method; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; import java.util.Map.Entry; - +import java.util.Set; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -44,7 +50,7 @@ import org.springframework.web.util.WebUtils; * * @author Arjen Poutsma * @author Rossen Stoyanchev - * @since 3.1.0 + * @since 3.1 */ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMethodMapping { @@ -254,7 +260,7 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe ParamsRequestCondition condition = partialMatch.getParamsCondition(); if (!CollectionUtils.isEmpty(condition.getExpressions()) && (condition.getMatchingCondition(request) == null)) { Set expressions = new HashSet(); - for (NameValueExpression expr : condition.getExpressions()) { + for (NameValueExpression expr : condition.getExpressions()) { expressions.add(expr.toString()); } return expressions; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java index 53335e5d543..b4a4a0fcbe7 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -78,7 +78,6 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi /** * Whether to use suffix pattern match for registered file extensions only * when matching patterns to requests. - * *

    If enabled, a controller method mapped to "/users" also matches to * "/users.json" assuming ".json" is a file extension registered with the * provided {@link #setContentNegotiationManager(ContentNegotiationManager) @@ -87,14 +86,13 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi * can lead to ambiguous interpretation of path variable content, (e.g. given * "/users/{user}" and incoming URLs such as "/users/john.j.joe" and * "/users/john.j.joe.json"). - * *

    If enabled, this flag also enables * {@link #setUseSuffixPatternMatch(boolean) useSuffixPatternMatch}. The * default value is {@code false}. */ - public void setUseRegisteredSuffixPatternMatch(boolean useRegsiteredSuffixPatternMatch) { - this.useRegisteredSuffixPatternMatch = useRegsiteredSuffixPatternMatch; - this.useSuffixPatternMatch = useRegsiteredSuffixPatternMatch ? true : this.useSuffixPatternMatch; + public void setUseRegisteredSuffixPatternMatch(boolean useRegisteredSuffixPatternMatch) { + this.useRegisteredSuffixPatternMatch = useRegisteredSuffixPatternMatch; + this.useSuffixPatternMatch = (useRegisteredSuffixPatternMatch || this.useSuffixPatternMatch); } /** @@ -106,20 +104,30 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi this.useTrailingSlashMatch = useTrailingSlashMatch; } - @Override - public void setEmbeddedValueResolver(StringValueResolver resolver) { - this.embeddedValueResolver = resolver; - } - /** * Set the {@link ContentNegotiationManager} to use to determine requested media types. * If not set, the default constructor is used. */ public void setContentNegotiationManager(ContentNegotiationManager contentNegotiationManager) { - Assert.notNull(contentNegotiationManager); + Assert.notNull(contentNegotiationManager, "ContentNegotiationManager must not be null"); this.contentNegotiationManager = contentNegotiationManager; } + @Override + public void setEmbeddedValueResolver(StringValueResolver resolver) { + this.embeddedValueResolver = resolver; + } + + @Override + public void afterPropertiesSet() { + if (this.useRegisteredSuffixPatternMatch) { + this.fileExtensions.addAll(this.contentNegotiationManager.getAllFileExtensions()); + } + super.afterPropertiesSet(); + } + + + /** * Whether to use suffix pattern matching. */ @@ -131,11 +139,11 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi * Whether to use registered suffixes for pattern matching. */ public boolean useRegisteredSuffixPatternMatch() { - return useRegisteredSuffixPatternMatch; + return this.useRegisteredSuffixPatternMatch; } /** - * Whether to match to URLs irrespective of the presence of a trailing slash. + * Whether to match to URLs irrespective of the presence of a trailing slash. */ public boolean useTrailingSlashMatch() { return this.useTrailingSlashMatch; @@ -155,13 +163,6 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi return this.fileExtensions; } - @Override - public void afterPropertiesSet() { - if (this.useRegisteredSuffixPatternMatch) { - this.fileExtensions.addAll(contentNegotiationManager.getAllFileExtensions()); - } - super.afterPropertiesSet(); - } /** * {@inheritDoc} @@ -176,10 +177,8 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi /** * Uses method and type-level @{@link RequestMapping} annotations to create * the RequestMappingInfo. - * * @return the created RequestMappingInfo, or {@code null} if the method * does not have a {@code @RequestMapping} annotation. - * * @see #getCustomMethodCondition(Method) * @see #getCustomTypeCondition(Class) */ @@ -204,11 +203,9 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi * The custom {@link RequestCondition} can be of any type so long as the * same condition type is returned from all calls to this method in order * to ensure custom request conditions can be combined and compared. - * *

    Consider extending {@link AbstractRequestCondition} for custom * condition types and using {@link CompositeRequestCondition} to provide * multiple custom conditions. - * * @param handlerType the handler type for which to create the condition * @return the condition, or {@code null} */ @@ -221,11 +218,9 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi * The custom {@link RequestCondition} can be of any type so long as the * same condition type is returned from all calls to this method in order * to ensure custom request conditions can be combined and compared. - * *

    Consider extending {@link AbstractRequestCondition} for custom * condition types and using {@link CompositeRequestCondition} to provide * multiple custom conditions. - * * @param method the handler method for which to create the condition * @return the condition, or {@code null} */ @@ -236,9 +231,7 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi /** * Created a RequestMappingInfo from a RequestMapping annotation. */ - protected RequestMappingInfo createRequestMappingInfo(RequestMapping annotation, - RequestCondition customCondition) { - + protected RequestMappingInfo createRequestMappingInfo(RequestMapping annotation, RequestCondition customCondition) { String[] patterns = resolveEmbeddedValuesInPatterns(annotation.value()); return new RequestMappingInfo( new PatternsRequestCondition(patterns, getUrlPathHelper(), getPathMatcher(), @@ -261,7 +254,7 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi } else { String[] resolvedPatterns = new String[patterns.length]; - for (int i=0; i < patterns.length; i++) { + for (int i = 0; i < patterns.length; i++) { resolvedPatterns[i] = this.embeddedValueResolver.resolveStringValue(patterns[i]); } return resolvedPatterns; diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMappingTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMappingTests.java index 63fce21fa7d..c56d7632d0a 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMappingTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMappingTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -13,12 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.web.servlet.mvc.method.annotation; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +package org.springframework.web.servlet.mvc.method.annotation; import java.lang.reflect.Method; import java.util.Arrays; @@ -29,6 +25,7 @@ import java.util.Set; import org.junit.Before; import org.junit.Test; + import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; import org.springframework.util.StringValueResolver; @@ -38,6 +35,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.context.support.StaticWebApplicationContext; import org.springframework.web.servlet.mvc.method.RequestMappingInfo; +import static org.junit.Assert.*; + /** * Tests for {@link RequestMappingHandlerMapping}. * @@ -47,14 +46,16 @@ public class RequestMappingHandlerMappingTests { private RequestMappingHandlerMapping handlerMapping; + @Before public void setup() { this.handlerMapping = new RequestMappingHandlerMapping(); this.handlerMapping.setApplicationContext(new StaticWebApplicationContext()); } + @Test - public void useRegsiteredSuffixPatternMatch() { + public void useRegisteredSuffixPatternMatch() { assertTrue(this.handlerMapping.useSuffixPatternMatch()); assertFalse(this.handlerMapping.useRegisteredSuffixPatternMatch()); @@ -72,8 +73,7 @@ public class RequestMappingHandlerMappingTests { } @Test - public void useRegsiteredSuffixPatternMatchInitialization() { - + public void useRegisteredSuffixPatternMatchInitialization() { Map fileExtensions = Collections.singletonMap("json", MediaType.APPLICATION_JSON); PathExtensionContentNegotiationStrategy strategy = new PathExtensionContentNegotiationStrategy(fileExtensions); ContentNegotiationManager manager = new ContentNegotiationManager(strategy);