144
144
* root of expanded directories. This originates from a limitation in the JDK's
145
145
* {@code ClassLoader.getResources()} method which only returns file system
146
146
* locations for a passed-in empty String (indicating potential roots to search).
147
+ * This {@code ResourcePatternResolver} implementation is trying to mitigate the
148
+ * jar root lookup limitation through {@link URLClassLoader} introspection and
149
+ * "java.class.path" manifest evaluation; however, without portability guarantees.
147
150
*
148
151
* <p><b>WARNING:</b> Ant-style patterns with "classpath:" resources are not
149
152
* guaranteed to find matching resources if the root package to search is available
156
159
* classpath:com/mycompany/**/service-context.xml
157
160
* </pre>
158
161
* is used to try to resolve it, the resolver will work off the (first) URL
159
- * returned by {@code getResource("com/mycompany");}. If this base package
160
- * node exists in multiple classloader locations, the actual end resource may
161
- * not be underneath. Therefore, preferably, use "{@code classpath*:}" with the same
162
+ * returned by {@code getResource("com/mycompany");}. If this base package node
163
+ * exists in multiple classloader locations, the actual end resource may not be
164
+ * underneath. Therefore, preferably, use "{@code classpath*:}" with the same
162
165
* Ant-style pattern in such a case, which will search <i>all</i> class path
163
166
* locations that contain the root package.
164
167
*
165
168
* @author Juergen Hoeller
166
169
* @author Colin Sampaleanu
167
170
* @author Marius Bogoevici
168
171
* @author Costin Leau
172
+ * @author Phil Webb
169
173
* @since 1.0.2
170
174
* @see #CLASSPATH_ALL_URL_PREFIX
171
175
* @see org.springframework.util.AntPathMatcher
@@ -316,6 +320,7 @@ protected Resource[] findAllClassPathResources(String location) throws IOExcepti
316
320
* Called by {@link #findAllClassPathResources(String)}.
317
321
* @param path the absolute path within the classpath (never a leading slash)
318
322
* @return a mutable Set of matching Resource instances
323
+ * @since 4.1.1
319
324
*/
320
325
protected Set <Resource > doFindAllClassPathResources (String path ) throws IOException {
321
326
Set <Resource > result = new LinkedHashSet <Resource >(16 );
@@ -350,6 +355,7 @@ protected Resource convertClassLoaderURL(URL url) {
350
355
* given set of resources in the form of pointers to the root of the jar file content.
351
356
* @param classLoader the ClassLoader to search (including its ancestors)
352
357
* @param result the set of resources to add jar roots to
358
+ * @since 4.1.1
353
359
*/
354
360
protected void addAllClassLoaderJarRoots (ClassLoader classLoader , Set <Resource > result ) {
355
361
if (classLoader instanceof URLClassLoader ) {
@@ -379,8 +385,15 @@ protected void addAllClassLoaderJarRoots(ClassLoader classLoader, Set<Resource>
379
385
}
380
386
}
381
387
}
388
+
389
+ if (classLoader == ClassLoader .getSystemClassLoader ()) {
390
+ // "java.class.path" manifest evaluation...
391
+ addClassPathManifestEntries (result );
392
+ }
393
+
382
394
if (classLoader != null ) {
383
395
try {
396
+ // Hierarchy traversal...
384
397
addAllClassLoaderJarRoots (classLoader .getParent (), result );
385
398
}
386
399
catch (Exception ex ) {
@@ -392,6 +405,41 @@ protected void addAllClassLoaderJarRoots(ClassLoader classLoader, Set<Resource>
392
405
}
393
406
}
394
407
408
+ /**
409
+ * Determine jar file references from the "java.class.path." manifest property and add them
410
+ * to the given set of resources in the form of pointers to the root of the jar file content.
411
+ * @param result the set of resources to add jar roots to
412
+ * @since 4.3
413
+ */
414
+ protected void addClassPathManifestEntries (Set <Resource > result ) {
415
+ try {
416
+ String javaClassPathProperty = System .getProperty ("java.class.path" );
417
+ for (String url : StringUtils .delimitedListToStringArray (
418
+ javaClassPathProperty , System .getProperty ("path.separator" ))) {
419
+ try {
420
+ if (url .endsWith (ResourceUtils .JAR_FILE_EXTENSION )) {
421
+ UrlResource jarResource = new UrlResource (ResourceUtils .JAR_URL_PREFIX +
422
+ ResourceUtils .FILE_URL_PREFIX + url + ResourceUtils .JAR_URL_SEPARATOR );
423
+ if (jarResource .exists ()) {
424
+ result .add (jarResource );
425
+ }
426
+ }
427
+ }
428
+ catch (MalformedURLException ex ) {
429
+ if (logger .isDebugEnabled ()) {
430
+ logger .debug ("Cannot search for matching files underneath [" + url +
431
+ "] because it cannot be converted to a valid 'jar:' URL: " + ex .getMessage ());
432
+ }
433
+ }
434
+ }
435
+ }
436
+ catch (Exception ex ) {
437
+ if (logger .isDebugEnabled ()) {
438
+ logger .debug ("Failed to evaluate 'java.class.path' manifest entries: " + ex );
439
+ }
440
+ }
441
+ }
442
+
395
443
/**
396
444
* Find all resources that match the given location pattern via the
397
445
* Ant-style PathMatcher. Supports resources in jar files and zip files
0 commit comments