1
1
/*
2
- * Copyright 2002-2012 the original author or authors.
2
+ * Copyright 2002-2014 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
21
21
import java .util .Collection ;
22
22
import java .util .Collections ;
23
23
import java .util .Comparator ;
24
+ import java .util .IdentityHashMap ;
24
25
import java .util .LinkedHashMap ;
25
26
import java .util .List ;
26
27
import java .util .Map ;
27
28
import java .util .Set ;
28
-
29
29
import javax .servlet .ServletException ;
30
30
import javax .servlet .http .HttpServletRequest ;
31
31
@@ -118,32 +118,33 @@ protected void initHandlerMethods() {
118
118
*/
119
119
protected abstract boolean isHandler (Class <?> beanType );
120
120
121
- /**
122
- * Invoked after all handler methods have been detected.
123
- * @param handlerMethods a read-only map with handler methods and mappings.
124
- */
125
- protected void handlerMethodsInitialized (Map <T , HandlerMethod > handlerMethods ) {
126
- }
127
-
128
121
/**
129
122
* Look for handler methods in a handler.
130
123
* @param handler the bean name of a handler or a handler instance
131
124
*/
132
125
protected void detectHandlerMethods (final Object handler ) {
133
- Class <?> handlerType = ( handler instanceof String ) ?
134
- getApplicationContext ().getType ((String ) handler ) : handler .getClass ();
126
+ Class <?> handlerType =
127
+ ( handler instanceof String ? getApplicationContext ().getType ((String ) handler ) : handler .getClass () );
135
128
129
+ // Avoid repeated calls to getMappingForMethod which would rebuild RequestMatchingInfo instances
130
+ final Map <Method , T > mappings = new IdentityHashMap <Method , T >();
136
131
final Class <?> userType = ClassUtils .getUserClass (handlerType );
137
132
138
133
Set <Method > methods = HandlerMethodSelector .selectMethods (userType , new MethodFilter () {
139
134
public boolean matches (Method method ) {
140
- return getMappingForMethod (method , userType ) != null ;
135
+ T mapping = getMappingForMethod (method , userType );
136
+ if (mapping != null ) {
137
+ mappings .put (method , mapping );
138
+ return true ;
139
+ }
140
+ else {
141
+ return false ;
142
+ }
141
143
}
142
144
});
143
145
144
146
for (Method method : methods ) {
145
- T mapping = getMappingForMethod (method , userType );
146
- registerHandlerMethod (handler , method , mapping );
147
+ registerHandlerMethod (handler , method , mappings .get (method ));
147
148
}
148
149
}
149
150
@@ -167,11 +168,11 @@ public boolean matches(Method method) {
167
168
*/
168
169
protected void registerHandlerMethod (Object handler , Method method , T mapping ) {
169
170
HandlerMethod newHandlerMethod = createHandlerMethod (handler , method );
170
- HandlerMethod oldHandlerMethod = handlerMethods .get (mapping );
171
+ HandlerMethod oldHandlerMethod = this . handlerMethods .get (mapping );
171
172
if (oldHandlerMethod != null && !oldHandlerMethod .equals (newHandlerMethod )) {
172
- throw new IllegalStateException ("Ambiguous mapping found. Cannot map '" + newHandlerMethod .getBean ()
173
- + "' bean method \n " + newHandlerMethod + "\n to " + mapping + ": There is already '"
174
- + oldHandlerMethod .getBean () + "' bean method\n " + oldHandlerMethod + " mapped." );
173
+ throw new IllegalStateException ("Ambiguous mapping found. Cannot map '" + newHandlerMethod .getBean () +
174
+ "' bean method \n " + newHandlerMethod + "\n to " + mapping + ": There is already '" +
175
+ oldHandlerMethod .getBean () + "' bean method\n " + oldHandlerMethod + " mapped." );
175
176
}
176
177
177
178
this .handlerMethods .put (mapping , newHandlerMethod );
@@ -210,6 +211,14 @@ protected HandlerMethod createHandlerMethod(Object handler, Method method) {
210
211
*/
211
212
protected abstract Set <String > getMappingPathPatterns (T mapping );
212
213
214
+ /**
215
+ * Invoked after all handler methods have been detected.
216
+ * @param handlerMethods a read-only map with handler methods and mappings.
217
+ */
218
+ protected void handlerMethodsInitialized (Map <T , HandlerMethod > handlerMethods ) {
219
+ }
220
+
221
+
213
222
/**
214
223
* Look up a handler method for the given request.
215
224
*/
@@ -219,9 +228,7 @@ protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Ex
219
228
if (logger .isDebugEnabled ()) {
220
229
logger .debug ("Looking up handler method for path " + lookupPath );
221
230
}
222
-
223
231
HandlerMethod handlerMethod = lookupHandlerMethod (lookupPath , request );
224
-
225
232
if (logger .isDebugEnabled ()) {
226
233
if (handlerMethod != null ) {
227
234
logger .debug ("Returning handler method [" + handlerMethod + "]" );
@@ -230,8 +237,7 @@ protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Ex
230
237
logger .debug ("Did not find handler method for [" + lookupPath + "]" );
231
238
}
232
239
}
233
-
234
- return (handlerMethod != null ) ? handlerMethod .createWithResolvedBean () : null ;
240
+ return (handlerMethod != null ? handlerMethod .createWithResolvedBean () : null );
235
241
}
236
242
237
243
/**
@@ -245,25 +251,21 @@ protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Ex
245
251
*/
246
252
protected HandlerMethod lookupHandlerMethod (String lookupPath , HttpServletRequest request ) throws Exception {
247
253
List <Match > matches = new ArrayList <Match >();
248
-
249
254
List <T > directPathMatches = this .urlMap .get (lookupPath );
250
255
if (directPathMatches != null ) {
251
256
addMatchingMappings (directPathMatches , matches , request );
252
257
}
253
-
254
258
if (matches .isEmpty ()) {
255
- // No choice but to go through all mappings
259
+ // No choice but to go through all mappings...
256
260
addMatchingMappings (this .handlerMethods .keySet (), matches , request );
257
261
}
258
262
259
263
if (!matches .isEmpty ()) {
260
264
Comparator <Match > comparator = new MatchComparator (getMappingComparator (request ));
261
265
Collections .sort (matches , comparator );
262
-
263
266
if (logger .isTraceEnabled ()) {
264
267
logger .trace ("Found " + matches .size () + " matching mapping(s) for [" + lookupPath + "] : " + matches );
265
268
}
266
-
267
269
Match bestMatch = matches .get (0 );
268
270
if (matches .size () > 1 ) {
269
271
Match secondBestMatch = matches .get (1 );
@@ -275,7 +277,6 @@ protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletReques
275
277
m1 + ", " + m2 + "}" );
276
278
}
277
279
}
278
-
279
280
handleMatch (bestMatch .mapping , lookupPath , request );
280
281
return bestMatch .handlerMethod ;
281
282
}
@@ -288,7 +289,7 @@ private void addMatchingMappings(Collection<T> mappings, List<Match> matches, Ht
288
289
for (T mapping : mappings ) {
289
290
T match = getMatchingMapping (mapping , request );
290
291
if (match != null ) {
291
- matches .add (new Match (match , handlerMethods .get (mapping )));
292
+ matches .add (new Match (match , this . handlerMethods .get (mapping )));
292
293
}
293
294
}
294
295
}
@@ -335,15 +336,16 @@ protected HandlerMethod handleNoMatch(Set<T> mappings, String lookupPath, HttpSe
335
336
336
337
337
338
/**
338
- * A temporary container for a mapping matched to a request.
339
+ * A thin wrapper around a matched HandlerMethod and its mapping, for the purpose of
340
+ * comparing the best match with a comparator in the context of the current request.
339
341
*/
340
342
private class Match {
341
343
342
344
private final T mapping ;
343
345
344
346
private final HandlerMethod handlerMethod ;
345
347
346
- private Match (T mapping , HandlerMethod handlerMethod ) {
348
+ public Match (T mapping , HandlerMethod handlerMethod ) {
347
349
this .mapping = mapping ;
348
350
this .handlerMethod = handlerMethod ;
349
351
}
0 commit comments