Skip to content

Commit 08748ec

Browse files
committed
PathMatchingResourcePatternResolver evaluates classpath manifest entries as well
Issue: SPR-13685
1 parent 2cfe00c commit 08748ec

File tree

1 file changed

+51
-3
lines changed

1 file changed

+51
-3
lines changed

spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@
144144
* root of expanded directories. This originates from a limitation in the JDK's
145145
* {@code ClassLoader.getResources()} method which only returns file system
146146
* 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.
147150
*
148151
* <p><b>WARNING:</b> Ant-style patterns with "classpath:" resources are not
149152
* guaranteed to find matching resources if the root package to search is available
@@ -156,16 +159,17 @@
156159
* classpath:com/mycompany/**&#47;service-context.xml
157160
* </pre>
158161
* 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
162165
* Ant-style pattern in such a case, which will search <i>all</i> class path
163166
* locations that contain the root package.
164167
*
165168
* @author Juergen Hoeller
166169
* @author Colin Sampaleanu
167170
* @author Marius Bogoevici
168171
* @author Costin Leau
172+
* @author Phil Webb
169173
* @since 1.0.2
170174
* @see #CLASSPATH_ALL_URL_PREFIX
171175
* @see org.springframework.util.AntPathMatcher
@@ -316,6 +320,7 @@ protected Resource[] findAllClassPathResources(String location) throws IOExcepti
316320
* Called by {@link #findAllClassPathResources(String)}.
317321
* @param path the absolute path within the classpath (never a leading slash)
318322
* @return a mutable Set of matching Resource instances
323+
* @since 4.1.1
319324
*/
320325
protected Set<Resource> doFindAllClassPathResources(String path) throws IOException {
321326
Set<Resource> result = new LinkedHashSet<Resource>(16);
@@ -350,6 +355,7 @@ protected Resource convertClassLoaderURL(URL url) {
350355
* given set of resources in the form of pointers to the root of the jar file content.
351356
* @param classLoader the ClassLoader to search (including its ancestors)
352357
* @param result the set of resources to add jar roots to
358+
* @since 4.1.1
353359
*/
354360
protected void addAllClassLoaderJarRoots(ClassLoader classLoader, Set<Resource> result) {
355361
if (classLoader instanceof URLClassLoader) {
@@ -379,8 +385,15 @@ protected void addAllClassLoaderJarRoots(ClassLoader classLoader, Set<Resource>
379385
}
380386
}
381387
}
388+
389+
if (classLoader == ClassLoader.getSystemClassLoader()) {
390+
// "java.class.path" manifest evaluation...
391+
addClassPathManifestEntries(result);
392+
}
393+
382394
if (classLoader != null) {
383395
try {
396+
// Hierarchy traversal...
384397
addAllClassLoaderJarRoots(classLoader.getParent(), result);
385398
}
386399
catch (Exception ex) {
@@ -392,6 +405,41 @@ protected void addAllClassLoaderJarRoots(ClassLoader classLoader, Set<Resource>
392405
}
393406
}
394407

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+
395443
/**
396444
* Find all resources that match the given location pattern via the
397445
* Ant-style PathMatcher. Supports resources in jar files and zip files

0 commit comments

Comments
 (0)