@ -507,41 +507,30 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
@@ -507,41 +507,30 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
Set < String > allowedMethods = new LinkedHashSet < String > ( 7 ) ;
String resolvedMethodName = null ;
for ( Method handlerMethod : getHandlerMethods ( ) ) {
RequestMappingInfo mappingInfo = new RequestMappingInfo ( ) ;
RequestMapping mapping = AnnotationUtils . findAnnotation ( handlerMethod , RequestMapping . class ) ;
mappingInfo . paths = mapping . value ( ) ;
if ( ! hasTypeLevelMapping ( ) | | ! Arrays . equals ( mapping . method ( ) , getTypeLevelMapping ( ) . method ( ) ) ) {
mappingInfo . methods = mapping . method ( ) ;
}
if ( ! hasTypeLevelMapping ( ) | | ! Arrays . equals ( mapping . params ( ) , getTypeLevelMapping ( ) . params ( ) ) ) {
mappingInfo . params = mapping . params ( ) ;
}
if ( ! hasTypeLevelMapping ( ) | | ! Arrays . equals ( mapping . headers ( ) , getTypeLevelMapping ( ) . headers ( ) ) ) {
mappingInfo . headers = mapping . headers ( ) ;
}
RequestMappingInfo mappingInfo = createRequestMappingInfo ( handlerMethod ) ;
boolean match = false ;
if ( mappingInfo . paths . length > 0 ) {
List < String > matchedPath s = new ArrayList < String > ( mappingInfo . path s . length ) ;
for ( String ma ppedP attern : mappingInfo . path s ) {
if ( ! hasTypeLevelMapping ( ) & & ! ma ppedP attern. startsWith ( "/" ) ) {
ma ppedP attern = "/" + ma ppedP attern;
if ( mappingInfo . hasPatterns ( ) ) {
List < String > matchingPatterns = new ArrayList < String > ( mappingInfo . patterns . length ) ;
for ( String pattern : mappingInfo . patterns ) {
if ( ! hasTypeLevelMapping ( ) & & ! pattern . startsWith ( "/" ) ) {
pattern = "/" + pattern ;
}
String matchedPattern = getMatch edPattern( ma ppedP attern, lookupPath , request ) ;
if ( match edPattern ! = null ) {
String combinedPattern = getCombinedPattern ( pattern , lookupPath , request ) ;
if ( combinedPattern ! = null ) {
if ( mappingInfo . matches ( request ) ) {
match = true ;
matchedPaths . add ( match edPattern ) ;
matchingPatterns . add ( combin edPattern ) ;
}
else {
for ( RequestMethod requestMethod : mappingInfo . methods ) {
allowedMethods . add ( requestMethod . toString ( ) ) ;
if ( ! mappingInfo . matchesRequestMethod ( request ) ) {
allowedMethods . addAll ( mappingInfo . methodNames ( ) ) ;
}
break ;
}
}
}
Collections . sort ( matchedPath s , pathComparator ) ;
mappingInfo . matchedPaths = matchedPath s ;
Collections . sort ( matchingPattern s , pathComparator ) ;
mappingInfo . matchedPatterns = matchingPattern s ;
}
else {
// No paths specified: parameter match sufficient.
@ -551,15 +540,15 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
@@ -551,15 +540,15 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
match = false ;
}
else {
for ( RequestMethod requestMethod : mappingInfo . methods ) {
allowedMethods . add ( requestMethod . toString ( ) ) ;
if ( ! mappingInfo . matchesRequestMethod ( request ) ) {
allowedMethods . addAll ( mappingInfo . methodNames ( ) ) ;
}
}
}
if ( match ) {
Method oldMappedMethod = targetHandlerMethods . put ( mappingInfo , handlerMethod ) ;
if ( oldMappedMethod ! = null & & oldMappedMethod ! = handlerMethod ) {
if ( methodNameResolver ! = null & & mappingInfo . path s . length = = 0 ) {
if ( methodNameResolver ! = null & & mappingInfo . pattern s . length = = 0 ) {
if ( ! oldMappedMethod . getName ( ) . equals ( handlerMethod . getName ( ) ) ) {
if ( resolvedMethodName = = null ) {
resolvedMethodName = methodNameResolver . getHandlerMethodName ( request ) ;
@ -594,7 +583,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
@@ -594,7 +583,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
new RequestMappingInfoComparator ( pathComparator , request ) ;
Collections . sort ( matches , requestMappingInfoComparator ) ;
RequestMappingInfo bestMappingMatch = matches . get ( 0 ) ;
String bestMatchedPath = bestMappingMatch . bestMatchedPath ( ) ;
String bestMatchedPath = bestMappingMatch . bestMatchedPattern ( ) ;
if ( bestMatchedPath ! = null ) {
extractHandlerMethodUriTemplates ( bestMatchedPath , lookupPath , request ) ;
}
@ -605,21 +594,38 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
@@ -605,21 +594,38 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
throw new HttpRequestMethodNotSupportedException ( request . getMethod ( ) ,
StringUtils . toStringArray ( allowedMethods ) ) ;
}
else {
throw new NoSuchRequestHandlingMethodException ( lookupPath , request . getMethod ( ) ,
request . getParameterMap ( ) ) ;
}
throw new NoSuchRequestHandlingMethodException ( lookupPath , request . getMethod ( ) ,
request . getParameterMap ( ) ) ;
}
}
private RequestMappingInfo createRequestMappingInfo ( Method handlerMethod ) {
RequestMappingInfo mappingInfo = new RequestMappingInfo ( ) ;
RequestMapping mapping = AnnotationUtils . findAnnotation ( handlerMethod , RequestMapping . class ) ;
mappingInfo . patterns = mapping . value ( ) ;
if ( ! hasTypeLevelMapping ( ) | | ! Arrays . equals ( mapping . method ( ) , getTypeLevelMapping ( ) . method ( ) ) ) {
mappingInfo . methods = mapping . method ( ) ;
}
if ( ! hasTypeLevelMapping ( ) | | ! Arrays . equals ( mapping . params ( ) , getTypeLevelMapping ( ) . params ( ) ) ) {
mappingInfo . params = mapping . params ( ) ;
}
if ( ! hasTypeLevelMapping ( ) | | ! Arrays . equals ( mapping . headers ( ) , getTypeLevelMapping ( ) . headers ( ) ) ) {
mappingInfo . headers = mapping . headers ( ) ;
}
return mappingInfo ;
}
/ * *
* Determines the matched pattern for the given methodLevelPattern and path .
* < p > Uses the following algorithm : < ol > < li > If there is a type - level mapping with path information , it is { @linkplain
* PathMatcher # combine ( String , String ) combined } with the method - level pattern . < li > If there is a { @linkplain
* HandlerMapping # BEST_MATCHING_PATTERN_ATTRIBUTE best matching pattern } in the request , it is combined with the
* method - level pattern . < li > Otherwise ,
* Determines the combined pattern for the given methodLevelPattern and path .
* < p > Uses the following algorithm : < ol >
* < li > If there is a type - level mapping with path information , it is { @linkplain
* PathMatcher # combine ( String , String ) combined } with the method - level pattern . < / li >
* < li > If there is a { @linkplain HandlerMapping # BEST_MATCHING_PATTERN_ATTRIBUTE best matching pattern } in the
* request , it is combined with the method - level pattern . < / li >
* < li > Otherwise , the method - level pattern is returned . < / li >
* < / ol >
* /
private String getMatchedPattern ( String methodLevelPattern , String lookupPath , HttpServletRequest request ) {
private String getCombin edPattern ( String methodLevelPattern , String lookupPath , HttpServletRequest request ) {
if ( hasTypeLevelMapping ( ) & & ( ! ObjectUtils . isEmpty ( getTypeLevelMapping ( ) . value ( ) ) ) ) {
String [ ] typeLevelPatterns = getTypeLevelMapping ( ) . value ( ) ;
for ( String typeLevelPattern : typeLevelPatterns ) {
@ -978,9 +984,9 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
@@ -978,9 +984,9 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
* /
static class RequestMappingInfo {
String [ ] path s = new String [ 0 ] ;
String [ ] pattern s = new String [ 0 ] ;
List < String > matchedPath s = Collections . emptyList ( ) ;
List < String > matchedPattern s = Collections . emptyList ( ) ;
RequestMethod [ ] methods = new RequestMethod [ 0 ] ;
@ -988,28 +994,69 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
@@ -988,28 +994,69 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
String [ ] headers = new String [ 0 ] ;
public String bestMatchedPath ( ) {
return ( ! this . matchedPaths . isEmpty ( ) ? this . matchedPaths . get ( 0 ) : null ) ;
public boolean hasPatterns ( ) {
return patterns . length > 0 ;
}
public String bestMatchedPattern ( ) {
return ( ! this . matchedPatterns . isEmpty ( ) ? this . matchedPatterns . get ( 0 ) : null ) ;
}
public boolean matches ( HttpServletRequest request ) {
return ServletAnnotationMappingUtils . checkRequestMethod ( this . methods , request ) & &
ServletAnnotationMappingUtils . checkParameters ( this . params , request ) & &
ServletAnnotationMappingUtils . checkHeaders ( this . headers , request ) ;
return matchesRequestMethod ( request ) & & matchesParameters ( request ) & & matchesHeaders ( request ) ;
}
public boolean matchesHeaders ( HttpServletRequest request ) {
return ServletAnnotationMappingUtils . checkHeaders ( this . headers , request ) ;
}
public boolean matchesParameters ( HttpServletRequest request ) {
return ServletAnnotationMappingUtils . checkParameters ( this . params , request ) ;
}
public boolean matchesRequestMethod ( HttpServletRequest request ) {
return ServletAnnotationMappingUtils . checkRequestMethod ( this . methods , request ) ;
}
public Set < String > methodNames ( ) {
Set < String > methodNames = new LinkedHashSet < String > ( methods . length ) ;
for ( RequestMethod method : methods ) {
methodNames . add ( method . name ( ) ) ;
}
return methodNames ;
}
@Override
public boolean equals ( Object obj ) {
RequestMappingInfo other = ( RequestMappingInfo ) obj ;
return ( Arrays . equals ( this . paths , other . paths ) & & Arrays . equals ( this . methods , other . methods ) & &
return ( Arrays . equals ( this . pattern s , other . pattern s ) & & Arrays . equals ( this . methods , other . methods ) & &
Arrays . equals ( this . params , other . params ) & & Arrays . equals ( this . headers , other . headers ) ) ;
}
@Override
public int hashCode ( ) {
return ( Arrays . hashCode ( this . paths ) * 23 + Arrays . hashCode ( this . methods ) * 29 +
return ( Arrays . hashCode ( this . pattern s ) * 23 + Arrays . hashCode ( this . methods ) * 29 +
Arrays . hashCode ( this . params ) * 31 + Arrays . hashCode ( this . headers ) ) ;
}
@Override
public String toString ( ) {
StringBuilder builder = new StringBuilder ( ) ;
builder . append ( Arrays . asList ( patterns ) ) ;
if ( methods . length > 0 ) {
builder . append ( ',' ) ;
builder . append ( Arrays . asList ( methods ) ) ;
}
if ( headers . length > 0 ) {
builder . append ( ',' ) ;
builder . append ( Arrays . asList ( headers ) ) ;
}
if ( params . length > 0 ) {
builder . append ( ',' ) ;
builder . append ( Arrays . asList ( params ) ) ;
}
return builder . toString ( ) ;
}
}
@ -1017,7 +1064,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
@@ -1017,7 +1064,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
* Comparator capable of sorting { @link RequestMappingInfo } s ( RHIs ) so that sorting a list with this comparator will
* result in :
* < ul >
* < li > RHIs with { @linkplain RequestMappingInfo # matchedPath s better matched paths } take prescedence
* < li > RHIs with { @linkplain RequestMappingInfo # matchedPattern s better matched paths } take prescedence
* over those with a weaker match ( as expressed by the { @linkplain PathMatcher # getPatternComparator ( String ) path
* pattern comparator } . ) Typically , this means that patterns without wild cards and uri templates will be ordered
* before those without . < / li >
@ -1039,7 +1086,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
@@ -1039,7 +1086,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
}
public int compare ( RequestMappingInfo info1 , RequestMappingInfo info2 ) {
int pathComparison = pathComparator . compare ( info1 . bestMatchedPath ( ) , info2 . bestMatchedPath ( ) ) ;
int pathComparison = pathComparator . compare ( info1 . bestMatchedPattern ( ) , info2 . bestMatchedPattern ( ) ) ;
if ( pathComparison ! = 0 ) {
return pathComparison ;
}