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
156159 * classpath:com/mycompany/**/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