|
|
@ -144,6 +144,9 @@ import org.springframework.util.StringUtils; |
|
|
|
* root of expanded directories. This originates from a limitation in the JDK's |
|
|
|
* root of expanded directories. This originates from a limitation in the JDK's |
|
|
|
* {@code ClassLoader.getResources()} method which only returns file system |
|
|
|
* {@code ClassLoader.getResources()} method which only returns file system |
|
|
|
* locations for a passed-in empty String (indicating potential roots to search). |
|
|
|
* locations for a passed-in empty String (indicating potential roots to search). |
|
|
|
|
|
|
|
* This {@code ResourcePatternResolver} implementation is trying to mitigate the |
|
|
|
|
|
|
|
* jar root lookup limitation through {@link URLClassLoader} introspection and |
|
|
|
|
|
|
|
* "java.class.path" manifest evaluation; however, without portability guarantees. |
|
|
|
* |
|
|
|
* |
|
|
|
* <p><b>WARNING:</b> Ant-style patterns with "classpath:" resources are not |
|
|
|
* <p><b>WARNING:</b> Ant-style patterns with "classpath:" resources are not |
|
|
|
* guaranteed to find matching resources if the root package to search is available |
|
|
|
* guaranteed to find matching resources if the root package to search is available |
|
|
@ -156,9 +159,9 @@ import org.springframework.util.StringUtils; |
|
|
|
* classpath:com/mycompany/**/service-context.xml |
|
|
|
* classpath:com/mycompany/**/service-context.xml |
|
|
|
* </pre> |
|
|
|
* </pre> |
|
|
|
* is used to try to resolve it, the resolver will work off the (first) URL |
|
|
|
* is used to try to resolve it, the resolver will work off the (first) URL |
|
|
|
* returned by {@code getResource("com/mycompany");}. If this base package
|
|
|
|
* returned by {@code getResource("com/mycompany");}. If this base package node |
|
|
|
* node exists in multiple classloader locations, the actual end resource may |
|
|
|
* exists in multiple classloader locations, the actual end resource may not be |
|
|
|
* not be underneath. Therefore, preferably, use "{@code classpath*:}" with the same |
|
|
|
* underneath. Therefore, preferably, use "{@code classpath*:}" with the same |
|
|
|
* Ant-style pattern in such a case, which will search <i>all</i> class path |
|
|
|
* Ant-style pattern in such a case, which will search <i>all</i> class path |
|
|
|
* locations that contain the root package. |
|
|
|
* locations that contain the root package. |
|
|
|
* |
|
|
|
* |
|
|
@ -166,6 +169,7 @@ import org.springframework.util.StringUtils; |
|
|
|
* @author Colin Sampaleanu |
|
|
|
* @author Colin Sampaleanu |
|
|
|
* @author Marius Bogoevici |
|
|
|
* @author Marius Bogoevici |
|
|
|
* @author Costin Leau |
|
|
|
* @author Costin Leau |
|
|
|
|
|
|
|
* @author Phil Webb |
|
|
|
* @since 1.0.2 |
|
|
|
* @since 1.0.2 |
|
|
|
* @see #CLASSPATH_ALL_URL_PREFIX |
|
|
|
* @see #CLASSPATH_ALL_URL_PREFIX |
|
|
|
* @see org.springframework.util.AntPathMatcher |
|
|
|
* @see org.springframework.util.AntPathMatcher |
|
|
@ -316,6 +320,7 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol |
|
|
|
* Called by {@link #findAllClassPathResources(String)}. |
|
|
|
* Called by {@link #findAllClassPathResources(String)}. |
|
|
|
* @param path the absolute path within the classpath (never a leading slash) |
|
|
|
* @param path the absolute path within the classpath (never a leading slash) |
|
|
|
* @return a mutable Set of matching Resource instances |
|
|
|
* @return a mutable Set of matching Resource instances |
|
|
|
|
|
|
|
* @since 4.1.1 |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
protected Set<Resource> doFindAllClassPathResources(String path) throws IOException { |
|
|
|
protected Set<Resource> doFindAllClassPathResources(String path) throws IOException { |
|
|
|
Set<Resource> result = new LinkedHashSet<Resource>(16); |
|
|
|
Set<Resource> result = new LinkedHashSet<Resource>(16); |
|
|
@ -350,6 +355,7 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol |
|
|
|
* given set of resources in the form of pointers to the root of the jar file content. |
|
|
|
* given set of resources in the form of pointers to the root of the jar file content. |
|
|
|
* @param classLoader the ClassLoader to search (including its ancestors) |
|
|
|
* @param classLoader the ClassLoader to search (including its ancestors) |
|
|
|
* @param result the set of resources to add jar roots to |
|
|
|
* @param result the set of resources to add jar roots to |
|
|
|
|
|
|
|
* @since 4.1.1 |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
protected void addAllClassLoaderJarRoots(ClassLoader classLoader, Set<Resource> result) { |
|
|
|
protected void addAllClassLoaderJarRoots(ClassLoader classLoader, Set<Resource> result) { |
|
|
|
if (classLoader instanceof URLClassLoader) { |
|
|
|
if (classLoader instanceof URLClassLoader) { |
|
|
@ -379,8 +385,15 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (classLoader == ClassLoader.getSystemClassLoader()) { |
|
|
|
|
|
|
|
// "java.class.path" manifest evaluation...
|
|
|
|
|
|
|
|
addClassPathManifestEntries(result); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (classLoader != null) { |
|
|
|
if (classLoader != null) { |
|
|
|
try { |
|
|
|
try { |
|
|
|
|
|
|
|
// Hierarchy traversal...
|
|
|
|
addAllClassLoaderJarRoots(classLoader.getParent(), result); |
|
|
|
addAllClassLoaderJarRoots(classLoader.getParent(), result); |
|
|
|
} |
|
|
|
} |
|
|
|
catch (Exception ex) { |
|
|
|
catch (Exception ex) { |
|
|
@ -392,6 +405,41 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Determine jar file references from the "java.class.path." manifest property and add them |
|
|
|
|
|
|
|
* to the given set of resources in the form of pointers to the root of the jar file content. |
|
|
|
|
|
|
|
* @param result the set of resources to add jar roots to |
|
|
|
|
|
|
|
* @since 4.3 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
protected void addClassPathManifestEntries(Set<Resource> result) { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
String javaClassPathProperty = System.getProperty("java.class.path"); |
|
|
|
|
|
|
|
for (String url : StringUtils.delimitedListToStringArray( |
|
|
|
|
|
|
|
javaClassPathProperty, System.getProperty("path.separator"))) { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
if (url.endsWith(ResourceUtils.JAR_FILE_EXTENSION)) { |
|
|
|
|
|
|
|
UrlResource jarResource = new UrlResource(ResourceUtils.JAR_URL_PREFIX + |
|
|
|
|
|
|
|
ResourceUtils.FILE_URL_PREFIX + url + ResourceUtils.JAR_URL_SEPARATOR); |
|
|
|
|
|
|
|
if (jarResource.exists()) { |
|
|
|
|
|
|
|
result.add(jarResource); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
catch (MalformedURLException ex) { |
|
|
|
|
|
|
|
if (logger.isDebugEnabled()) { |
|
|
|
|
|
|
|
logger.debug("Cannot search for matching files underneath [" + url + |
|
|
|
|
|
|
|
"] because it cannot be converted to a valid 'jar:' URL: " + ex.getMessage()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
catch (Exception ex) { |
|
|
|
|
|
|
|
if (logger.isDebugEnabled()) { |
|
|
|
|
|
|
|
logger.debug("Failed to evaluate 'java.class.path' manifest entries: " + ex); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Find all resources that match the given location pattern via the |
|
|
|
* Find all resources that match the given location pattern via the |
|
|
|
* Ant-style PathMatcher. Supports resources in jar files and zip files |
|
|
|
* Ant-style PathMatcher. Supports resources in jar files and zip files |
|
|
|