@@ -82,7 +82,7 @@ public class HandlerMappingIntrospector
82
82
@ Nullable
83
83
private List <HandlerMapping > handlerMappings ;
84
84
85
- private Map <HandlerMapping , PathPatternMatchableHandlerMapping > pathPatternHandlerMappings = Collections .emptyMap ();
85
+ private Map <HandlerMapping , PathPatternMatchableHandlerMapping > pathPatternMappings = Collections .emptyMap ();
86
86
87
87
88
88
@ Override
@@ -95,10 +95,55 @@ public void afterPropertiesSet() {
95
95
if (this .handlerMappings == null ) {
96
96
Assert .notNull (this .applicationContext , "No ApplicationContext" );
97
97
this .handlerMappings = initHandlerMappings (this .applicationContext );
98
- this .pathPatternHandlerMappings = initPathPatternMatchableHandlerMappings (this .handlerMappings );
98
+
99
+ this .pathPatternMappings = this .handlerMappings .stream ()
100
+ .filter (m -> m instanceof MatchableHandlerMapping hm && hm .getPatternParser () != null )
101
+ .map (mapping -> (MatchableHandlerMapping ) mapping )
102
+ .collect (Collectors .toMap (mapping -> mapping , PathPatternMatchableHandlerMapping ::new ));
99
103
}
100
104
}
101
105
106
+ private static List <HandlerMapping > initHandlerMappings (ApplicationContext context ) {
107
+
108
+ Map <String , HandlerMapping > beans =
109
+ BeanFactoryUtils .beansOfTypeIncludingAncestors (context , HandlerMapping .class , true , false );
110
+
111
+ if (!beans .isEmpty ()) {
112
+ List <HandlerMapping > mappings = new ArrayList <>(beans .values ());
113
+ AnnotationAwareOrderComparator .sort (mappings );
114
+ return Collections .unmodifiableList (mappings );
115
+ }
116
+
117
+ return Collections .unmodifiableList (initFallback (context ));
118
+ }
119
+
120
+ private static List <HandlerMapping > initFallback (ApplicationContext applicationContext ) {
121
+ Properties properties ;
122
+ try {
123
+ Resource resource = new ClassPathResource ("DispatcherServlet.properties" , DispatcherServlet .class );
124
+ properties = PropertiesLoaderUtils .loadProperties (resource );
125
+ }
126
+ catch (IOException ex ) {
127
+ throw new IllegalStateException ("Could not load DispatcherServlet.properties: " + ex .getMessage ());
128
+ }
129
+
130
+ String value = properties .getProperty (HandlerMapping .class .getName ());
131
+ String [] names = StringUtils .commaDelimitedListToStringArray (value );
132
+ List <HandlerMapping > result = new ArrayList <>(names .length );
133
+ for (String name : names ) {
134
+ try {
135
+ Class <?> clazz = ClassUtils .forName (name , DispatcherServlet .class .getClassLoader ());
136
+ Object mapping = applicationContext .getAutowireCapableBeanFactory ().createBean (clazz );
137
+ result .add ((HandlerMapping ) mapping );
138
+ }
139
+ catch (ClassNotFoundException ex ) {
140
+ throw new IllegalStateException ("Could not find default HandlerMapping [" + name + "]" );
141
+ }
142
+ }
143
+ return result ;
144
+ }
145
+
146
+
102
147
/**
103
148
* Return the configured or detected {@code HandlerMapping}s.
104
149
*/
@@ -109,27 +154,27 @@ public List<HandlerMapping> getHandlerMappings() {
109
154
110
155
/**
111
156
* Find the {@link HandlerMapping} that would handle the given request and
112
- * return it as a {@link MatchableHandlerMapping} that can be used to test
113
- * request-matching criteria.
114
- * <p>If the matching HandlerMapping is not an instance of
115
- * {@link MatchableHandlerMapping}, an IllegalStateException is raised.
157
+ * return a {@link MatchableHandlerMapping} to use for path matching.
116
158
* @param request the current request
117
- * @return the resolved matcher, or {@code null}
159
+ * @return the resolved {@code MatchableHandlerMapping}, or {@code null}
160
+ * @throws IllegalStateException if the matching HandlerMapping is not an
161
+ * instance of {@link MatchableHandlerMapping}
118
162
* @throws Exception if any of the HandlerMapping's raise an exception
119
163
*/
120
164
@ Nullable
121
165
public MatchableHandlerMapping getMatchableHandlerMapping (HttpServletRequest request ) throws Exception {
122
166
HttpServletRequest wrappedRequest = new AttributesPreservingRequest (request );
123
- return doWithMatchingMapping (wrappedRequest , false , (matchedMapping , executionChain ) -> {
124
- if (matchedMapping instanceof MatchableHandlerMapping matchableHandlerMapping ) {
125
- PathPatternMatchableHandlerMapping mapping = this .pathPatternHandlerMappings .get (matchedMapping );
126
- if (mapping != null ) {
167
+
168
+ return doWithHandlerMapping (wrappedRequest , false , (mapping , executionChain ) -> {
169
+ if (mapping instanceof MatchableHandlerMapping ) {
170
+ PathPatternMatchableHandlerMapping pathPatternMapping = this .pathPatternMappings .get (mapping );
171
+ if (pathPatternMapping != null ) {
127
172
RequestPath requestPath = ServletRequestPathUtils .getParsedRequestPath (wrappedRequest );
128
- return new PathSettingHandlerMapping ( mapping , requestPath );
173
+ return new LookupPathMatchableHandlerMapping ( pathPatternMapping , requestPath );
129
174
}
130
175
else {
131
176
String lookupPath = (String ) wrappedRequest .getAttribute (UrlPathHelper .PATH_ATTRIBUTE );
132
- return new PathSettingHandlerMapping ( matchableHandlerMapping , lookupPath );
177
+ return new LookupPathMatchableHandlerMapping (( MatchableHandlerMapping ) mapping , lookupPath );
133
178
}
134
179
}
135
180
throw new IllegalStateException ("HandlerMapping is not a MatchableHandlerMapping" );
@@ -140,7 +185,7 @@ public MatchableHandlerMapping getMatchableHandlerMapping(HttpServletRequest req
140
185
@ Nullable
141
186
public CorsConfiguration getCorsConfiguration (HttpServletRequest request ) {
142
187
AttributesPreservingRequest wrappedRequest = new AttributesPreservingRequest (request );
143
- return doWithMatchingMappingIgnoringException (wrappedRequest , (handlerMapping , executionChain ) -> {
188
+ return doWithHandlerMappingIgnoringException (wrappedRequest , (handlerMapping , executionChain ) -> {
144
189
for (HandlerInterceptor interceptor : executionChain .getInterceptorList ()) {
145
190
if (interceptor instanceof CorsConfigurationSource ccs ) {
146
191
return ccs .getCorsConfiguration (wrappedRequest );
@@ -154,15 +199,15 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
154
199
}
155
200
156
201
@ Nullable
157
- private <T > T doWithMatchingMapping (
202
+ private <T > T doWithHandlerMapping (
158
203
HttpServletRequest request , boolean ignoreException ,
159
- BiFunction <HandlerMapping , HandlerExecutionChain , T > matchHandler ) throws Exception {
204
+ BiFunction <HandlerMapping , HandlerExecutionChain , T > extractor ) throws Exception {
160
205
161
- Assert .state (this .handlerMappings != null , "Handler mappings not initialized" );
206
+ Assert .state (this .handlerMappings != null , "HandlerMapping's not initialized" );
162
207
163
- boolean parseRequestPath = !this .pathPatternHandlerMappings .isEmpty ();
208
+ boolean parsePath = !this .pathPatternMappings .isEmpty ();
164
209
RequestPath previousPath = null ;
165
- if (parseRequestPath ) {
210
+ if (parsePath ) {
166
211
previousPath = (RequestPath ) request .getAttribute (ServletRequestPathUtils .PATH_ATTRIBUTE );
167
212
ServletRequestPathUtils .parseAndCache (request );
168
213
}
@@ -180,79 +225,30 @@ private <T> T doWithMatchingMapping(
180
225
if (chain == null ) {
181
226
continue ;
182
227
}
183
- return matchHandler .apply (handlerMapping , chain );
228
+ return extractor .apply (handlerMapping , chain );
184
229
}
185
230
}
186
231
finally {
187
- if (parseRequestPath ) {
232
+ if (parsePath ) {
188
233
ServletRequestPathUtils .setParsedRequestPath (previousPath , request );
189
234
}
190
235
}
191
236
return null ;
192
237
}
193
238
194
239
@ Nullable
195
- private <T > T doWithMatchingMappingIgnoringException (
240
+ private <T > T doWithHandlerMappingIgnoringException (
196
241
HttpServletRequest request , BiFunction <HandlerMapping , HandlerExecutionChain , T > matchHandler ) {
197
242
198
243
try {
199
- return doWithMatchingMapping (request , true , matchHandler );
244
+ return doWithHandlerMapping (request , true , matchHandler );
200
245
}
201
246
catch (Exception ex ) {
202
247
throw new IllegalStateException ("HandlerMapping exception not suppressed" , ex );
203
248
}
204
249
}
205
250
206
251
207
- private static List <HandlerMapping > initHandlerMappings (ApplicationContext applicationContext ) {
208
- Map <String , HandlerMapping > beans = BeanFactoryUtils .beansOfTypeIncludingAncestors (
209
- applicationContext , HandlerMapping .class , true , false );
210
- if (!beans .isEmpty ()) {
211
- List <HandlerMapping > mappings = new ArrayList <>(beans .values ());
212
- AnnotationAwareOrderComparator .sort (mappings );
213
- return Collections .unmodifiableList (mappings );
214
- }
215
- return Collections .unmodifiableList (initFallback (applicationContext ));
216
- }
217
-
218
- private static List <HandlerMapping > initFallback (ApplicationContext applicationContext ) {
219
- Properties props ;
220
- String path = "DispatcherServlet.properties" ;
221
- try {
222
- Resource resource = new ClassPathResource (path , DispatcherServlet .class );
223
- props = PropertiesLoaderUtils .loadProperties (resource );
224
- }
225
- catch (IOException ex ) {
226
- throw new IllegalStateException ("Could not load '" + path + "': " + ex .getMessage ());
227
- }
228
-
229
- String value = props .getProperty (HandlerMapping .class .getName ());
230
- String [] names = StringUtils .commaDelimitedListToStringArray (value );
231
- List <HandlerMapping > result = new ArrayList <>(names .length );
232
- for (String name : names ) {
233
- try {
234
- Class <?> clazz = ClassUtils .forName (name , DispatcherServlet .class .getClassLoader ());
235
- Object mapping = applicationContext .getAutowireCapableBeanFactory ().createBean (clazz );
236
- result .add ((HandlerMapping ) mapping );
237
- }
238
- catch (ClassNotFoundException ex ) {
239
- throw new IllegalStateException ("Could not find default HandlerMapping [" + name + "]" );
240
- }
241
- }
242
- return result ;
243
- }
244
-
245
- private static Map <HandlerMapping , PathPatternMatchableHandlerMapping > initPathPatternMatchableHandlerMappings (
246
- List <HandlerMapping > mappings ) {
247
-
248
- return mappings .stream ()
249
- .filter (MatchableHandlerMapping .class ::isInstance )
250
- .map (MatchableHandlerMapping .class ::cast )
251
- .filter (mapping -> mapping .getPatternParser () != null )
252
- .collect (Collectors .toMap (mapping -> mapping , PathPatternMatchableHandlerMapping ::new ));
253
- }
254
-
255
-
256
252
/**
257
253
* Request wrapper that buffers request attributes in order protect the
258
254
* underlying request from attribute changes.
@@ -298,26 +294,27 @@ public void removeAttribute(String name) {
298
294
}
299
295
300
296
301
- private static class PathSettingHandlerMapping implements MatchableHandlerMapping {
297
+ private static class LookupPathMatchableHandlerMapping implements MatchableHandlerMapping {
302
298
303
299
private final MatchableHandlerMapping delegate ;
304
300
305
- private final Object path ;
301
+ private final Object lookupPath ;
306
302
307
303
private final String pathAttributeName ;
308
304
309
- PathSettingHandlerMapping (MatchableHandlerMapping delegate , Object path ) {
305
+ LookupPathMatchableHandlerMapping (MatchableHandlerMapping delegate , Object lookupPath ) {
310
306
this .delegate = delegate ;
311
- this .path = path ;
312
- this .pathAttributeName = (path instanceof RequestPath ?
307
+ this .lookupPath = lookupPath ;
308
+ this .pathAttributeName = (lookupPath instanceof RequestPath ?
313
309
ServletRequestPathUtils .PATH_ATTRIBUTE : UrlPathHelper .PATH_ATTRIBUTE );
314
310
}
315
311
316
312
@ Nullable
317
313
@ Override
318
314
public RequestMatchResult match (HttpServletRequest request , String pattern ) {
315
+ pattern = (StringUtils .hasLength (pattern ) && !pattern .startsWith ("/" ) ? "/" + pattern : pattern );
319
316
Object previousPath = request .getAttribute (this .pathAttributeName );
320
- request .setAttribute (this .pathAttributeName , this .path );
317
+ request .setAttribute (this .pathAttributeName , this .lookupPath );
321
318
try {
322
319
return this .delegate .match (request , pattern );
323
320
}
0 commit comments