1
1
/*
2
- * Copyright 2002-2021 the original author or authors.
2
+ * Copyright 2002-2023 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.
@@ -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
/**
@@ -113,10 +113,55 @@ public void afterPropertiesSet() {
113
113
if (this .handlerMappings == null ) {
114
114
Assert .notNull (this .applicationContext , "No ApplicationContext" );
115
115
this .handlerMappings = initHandlerMappings (this .applicationContext );
116
- this .pathPatternHandlerMappings = initPathPatternMatchableHandlerMappings (this .handlerMappings );
116
+
117
+ this .pathPatternMappings = this .handlerMappings .stream ()
118
+ .filter (m -> m instanceof MatchableHandlerMapping && ((MatchableHandlerMapping ) m ).getPatternParser () != null )
119
+ .map (mapping -> (MatchableHandlerMapping ) mapping )
120
+ .collect (Collectors .toMap (mapping -> mapping , PathPatternMatchableHandlerMapping ::new ));
117
121
}
118
122
}
119
123
124
+ private static List <HandlerMapping > initHandlerMappings (ApplicationContext context ) {
125
+
126
+ Map <String , HandlerMapping > beans =
127
+ BeanFactoryUtils .beansOfTypeIncludingAncestors (context , HandlerMapping .class , true , false );
128
+
129
+ if (!beans .isEmpty ()) {
130
+ List <HandlerMapping > mappings = new ArrayList <>(beans .values ());
131
+ AnnotationAwareOrderComparator .sort (mappings );
132
+ return Collections .unmodifiableList (mappings );
133
+ }
134
+
135
+ return Collections .unmodifiableList (initFallback (context ));
136
+ }
137
+
138
+ private static List <HandlerMapping > initFallback (ApplicationContext applicationContext ) {
139
+ Properties properties ;
140
+ try {
141
+ Resource resource = new ClassPathResource ("DispatcherServlet.properties" , DispatcherServlet .class );
142
+ properties = PropertiesLoaderUtils .loadProperties (resource );
143
+ }
144
+ catch (IOException ex ) {
145
+ throw new IllegalStateException ("Could not load DispatcherServlet.properties: " + ex .getMessage ());
146
+ }
147
+
148
+ String value = properties .getProperty (HandlerMapping .class .getName ());
149
+ String [] names = StringUtils .commaDelimitedListToStringArray (value );
150
+ List <HandlerMapping > result = new ArrayList <>(names .length );
151
+ for (String name : names ) {
152
+ try {
153
+ Class <?> clazz = ClassUtils .forName (name , DispatcherServlet .class .getClassLoader ());
154
+ Object mapping = applicationContext .getAutowireCapableBeanFactory ().createBean (clazz );
155
+ result .add ((HandlerMapping ) mapping );
156
+ }
157
+ catch (ClassNotFoundException ex ) {
158
+ throw new IllegalStateException ("Could not find default HandlerMapping [" + name + "]" );
159
+ }
160
+ }
161
+ return result ;
162
+ }
163
+
164
+
120
165
/**
121
166
* Return the configured or detected {@code HandlerMapping}s.
122
167
*/
@@ -127,27 +172,27 @@ public List<HandlerMapping> getHandlerMappings() {
127
172
128
173
/**
129
174
* Find the {@link HandlerMapping} that would handle the given request and
130
- * return it as a {@link MatchableHandlerMapping} that can be used to test
131
- * request-matching criteria.
132
- * <p>If the matching HandlerMapping is not an instance of
133
- * {@link MatchableHandlerMapping}, an IllegalStateException is raised.
175
+ * return a {@link MatchableHandlerMapping} to use for path matching.
134
176
* @param request the current request
135
- * @return the resolved matcher, or {@code null}
177
+ * @return the resolved {@code MatchableHandlerMapping}, or {@code null}
178
+ * @throws IllegalStateException if the matching HandlerMapping is not an
179
+ * instance of {@link MatchableHandlerMapping}
136
180
* @throws Exception if any of the HandlerMapping's raise an exception
137
181
*/
138
182
@ Nullable
139
183
public MatchableHandlerMapping getMatchableHandlerMapping (HttpServletRequest request ) throws Exception {
140
184
HttpServletRequest wrappedRequest = new AttributesPreservingRequest (request );
141
- return doWithMatchingMapping (wrappedRequest , false , (matchedMapping , executionChain ) -> {
142
- if (matchedMapping instanceof MatchableHandlerMapping ) {
143
- PathPatternMatchableHandlerMapping mapping = this .pathPatternHandlerMappings .get (matchedMapping );
144
- if (mapping != null ) {
185
+
186
+ return doWithHandlerMapping (wrappedRequest , false , (mapping , executionChain ) -> {
187
+ if (mapping instanceof MatchableHandlerMapping ) {
188
+ PathPatternMatchableHandlerMapping pathPatternMapping = this .pathPatternMappings .get (mapping );
189
+ if (pathPatternMapping != null ) {
145
190
RequestPath requestPath = ServletRequestPathUtils .getParsedRequestPath (wrappedRequest );
146
- return new PathSettingHandlerMapping ( mapping , requestPath );
191
+ return new LookupPathMatchableHandlerMapping ( pathPatternMapping , requestPath );
147
192
}
148
193
else {
149
194
String lookupPath = (String ) wrappedRequest .getAttribute (UrlPathHelper .PATH_ATTRIBUTE );
150
- return new PathSettingHandlerMapping ((MatchableHandlerMapping ) matchedMapping , lookupPath );
195
+ return new LookupPathMatchableHandlerMapping ((MatchableHandlerMapping ) mapping , lookupPath );
151
196
}
152
197
}
153
198
throw new IllegalStateException ("HandlerMapping is not a MatchableHandlerMapping" );
@@ -158,7 +203,7 @@ public MatchableHandlerMapping getMatchableHandlerMapping(HttpServletRequest req
158
203
@ Nullable
159
204
public CorsConfiguration getCorsConfiguration (HttpServletRequest request ) {
160
205
AttributesPreservingRequest wrappedRequest = new AttributesPreservingRequest (request );
161
- return doWithMatchingMappingIgnoringException (wrappedRequest , (handlerMapping , executionChain ) -> {
206
+ return doWithHandlerMappingIgnoringException (wrappedRequest , (handlerMapping , executionChain ) -> {
162
207
for (HandlerInterceptor interceptor : executionChain .getInterceptorList ()) {
163
208
if (interceptor instanceof CorsConfigurationSource ) {
164
209
return ((CorsConfigurationSource ) interceptor ).getCorsConfiguration (wrappedRequest );
@@ -172,15 +217,15 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
172
217
}
173
218
174
219
@ Nullable
175
- private <T > T doWithMatchingMapping (
220
+ private <T > T doWithHandlerMapping (
176
221
HttpServletRequest request , boolean ignoreException ,
177
- BiFunction <HandlerMapping , HandlerExecutionChain , T > matchHandler ) throws Exception {
222
+ BiFunction <HandlerMapping , HandlerExecutionChain , T > extractor ) throws Exception {
178
223
179
- Assert .notNull (this .handlerMappings , "Handler mappings not initialized" );
224
+ Assert .state (this .handlerMappings != null , "HandlerMapping's not initialized" );
180
225
181
- boolean parseRequestPath = !this .pathPatternHandlerMappings .isEmpty ();
226
+ boolean parsePath = !this .pathPatternMappings .isEmpty ();
182
227
RequestPath previousPath = null ;
183
- if (parseRequestPath ) {
228
+ if (parsePath ) {
184
229
previousPath = (RequestPath ) request .getAttribute (ServletRequestPathUtils .PATH_ATTRIBUTE );
185
230
ServletRequestPathUtils .parseAndCache (request );
186
231
}
@@ -198,79 +243,30 @@ private <T> T doWithMatchingMapping(
198
243
if (chain == null ) {
199
244
continue ;
200
245
}
201
- return matchHandler .apply (handlerMapping , chain );
246
+ return extractor .apply (handlerMapping , chain );
202
247
}
203
248
}
204
249
finally {
205
- if (parseRequestPath ) {
250
+ if (parsePath ) {
206
251
ServletRequestPathUtils .setParsedRequestPath (previousPath , request );
207
252
}
208
253
}
209
254
return null ;
210
255
}
211
256
212
257
@ Nullable
213
- private <T > T doWithMatchingMappingIgnoringException (
258
+ private <T > T doWithHandlerMappingIgnoringException (
214
259
HttpServletRequest request , BiFunction <HandlerMapping , HandlerExecutionChain , T > matchHandler ) {
215
260
216
261
try {
217
- return doWithMatchingMapping (request , true , matchHandler );
262
+ return doWithHandlerMapping (request , true , matchHandler );
218
263
}
219
264
catch (Exception ex ) {
220
265
throw new IllegalStateException ("HandlerMapping exception not suppressed" , ex );
221
266
}
222
267
}
223
268
224
269
225
- private static List <HandlerMapping > initHandlerMappings (ApplicationContext applicationContext ) {
226
- Map <String , HandlerMapping > beans = BeanFactoryUtils .beansOfTypeIncludingAncestors (
227
- applicationContext , HandlerMapping .class , true , false );
228
- if (!beans .isEmpty ()) {
229
- List <HandlerMapping > mappings = new ArrayList <>(beans .values ());
230
- AnnotationAwareOrderComparator .sort (mappings );
231
- return Collections .unmodifiableList (mappings );
232
- }
233
- return Collections .unmodifiableList (initFallback (applicationContext ));
234
- }
235
-
236
- private static List <HandlerMapping > initFallback (ApplicationContext applicationContext ) {
237
- Properties props ;
238
- String path = "DispatcherServlet.properties" ;
239
- try {
240
- Resource resource = new ClassPathResource (path , DispatcherServlet .class );
241
- props = PropertiesLoaderUtils .loadProperties (resource );
242
- }
243
- catch (IOException ex ) {
244
- throw new IllegalStateException ("Could not load '" + path + "': " + ex .getMessage ());
245
- }
246
-
247
- String value = props .getProperty (HandlerMapping .class .getName ());
248
- String [] names = StringUtils .commaDelimitedListToStringArray (value );
249
- List <HandlerMapping > result = new ArrayList <>(names .length );
250
- for (String name : names ) {
251
- try {
252
- Class <?> clazz = ClassUtils .forName (name , DispatcherServlet .class .getClassLoader ());
253
- Object mapping = applicationContext .getAutowireCapableBeanFactory ().createBean (clazz );
254
- result .add ((HandlerMapping ) mapping );
255
- }
256
- catch (ClassNotFoundException ex ) {
257
- throw new IllegalStateException ("Could not find default HandlerMapping [" + name + "]" );
258
- }
259
- }
260
- return result ;
261
- }
262
-
263
- private static Map <HandlerMapping , PathPatternMatchableHandlerMapping > initPathPatternMatchableHandlerMappings (
264
- List <HandlerMapping > mappings ) {
265
-
266
- return mappings .stream ()
267
- .filter (mapping -> mapping instanceof MatchableHandlerMapping )
268
- .map (mapping -> (MatchableHandlerMapping ) mapping )
269
- .filter (mapping -> mapping .getPatternParser () != null )
270
- .collect (Collectors .toMap (mapping -> mapping , PathPatternMatchableHandlerMapping ::new ));
271
- }
272
-
273
-
274
270
/**
275
271
* Request wrapper that buffers request attributes in order protect the
276
272
* underlying request from attribute changes.
@@ -316,26 +312,27 @@ public void removeAttribute(String name) {
316
312
}
317
313
318
314
319
- private static class PathSettingHandlerMapping implements MatchableHandlerMapping {
315
+ private static class LookupPathMatchableHandlerMapping implements MatchableHandlerMapping {
320
316
321
317
private final MatchableHandlerMapping delegate ;
322
318
323
- private final Object path ;
319
+ private final Object lookupPath ;
324
320
325
321
private final String pathAttributeName ;
326
322
327
- PathSettingHandlerMapping (MatchableHandlerMapping delegate , Object path ) {
323
+ LookupPathMatchableHandlerMapping (MatchableHandlerMapping delegate , Object lookupPath ) {
328
324
this .delegate = delegate ;
329
- this .path = path ;
330
- this .pathAttributeName = (path instanceof RequestPath ?
325
+ this .lookupPath = lookupPath ;
326
+ this .pathAttributeName = (lookupPath instanceof RequestPath ?
331
327
ServletRequestPathUtils .PATH_ATTRIBUTE : UrlPathHelper .PATH_ATTRIBUTE );
332
328
}
333
329
334
330
@ Nullable
335
331
@ Override
336
332
public RequestMatchResult match (HttpServletRequest request , String pattern ) {
333
+ pattern = (StringUtils .hasLength (pattern ) && !pattern .startsWith ("/" ) ? "/" + pattern : pattern );
337
334
Object previousPath = request .getAttribute (this .pathAttributeName );
338
- request .setAttribute (this .pathAttributeName , this .path );
335
+ request .setAttribute (this .pathAttributeName , this .lookupPath );
339
336
try {
340
337
return this .delegate .match (request , pattern );
341
338
}
0 commit comments