public class PathMatchingResourcePatternResolver extends java.lang.Object implements ResourcePatternResolver
ResourcePatternResolver
implementation that is able to resolve a
specified resource location path into one or more matching Resources.
The source path may be a simple path which has a one-to-one mapping to a
target Resource
, or alternatively
may contain the special "classpath*:
" prefix and/or
internal Ant-style regular expressions (matched using Spring's
AntPathMatcher
utility).
Both of the latter are effectively wildcards.
No Wildcards:
In the simple case, if the specified location path does not start with the
"classpath*:
" prefix, and does not contain a PathMatcher pattern,
this resolver will simply return a single resource via a
getResource()
call on the underlying ResourceLoader
.
Examples are real URLs such as "file:C:/context.xml
", pseudo-URLs
such as "classpath:/context.xml
", and simple unprefixed paths
such as "/WEB-INF/context.xml
". The latter will resolve in a
fashion specific to the underlying ResourceLoader
(e.g.
ServletContextResource
for a WebApplicationContext
).
Ant-style Patterns:
When the path location contains an Ant-style pattern, e.g.:
/WEB-INF/*-context.xml com/mycompany/**/applicationContext.xml file:C:/some/path/*-context.xml classpath:com/mycompany/**/applicationContext.xmlthe resolver follows a more complex but defined procedure to try to resolve the wildcard. It produces a
Resource
for the path up to the last
non-wildcard segment and obtains a URL
from it. If this URL is
not a "jar:
" URL or container-specific variant (e.g.
"zip:
" in WebLogic, "wsjar
" in WebSphere", etc.),
then a java.io.File
is obtained from it, and used to resolve the
wildcard by walking the filesystem. In the case of a jar URL, the resolver
either gets a java.net.JarURLConnection
from it, or manually parses
the jar URL, and then traverses the contents of the jar file, to resolve the
wildcards.
Implications on portability:
If the specified path is already a file URL (either explicitly, or
implicitly because the base ResourceLoader
is a filesystem one,
then wildcarding is guaranteed to work in a completely portable fashion.
If the specified path is a classpath location, then the resolver must
obtain the last non-wildcard path segment URL via a
Classloader.getResource()
call. Since this is just a
node of the path (not the file at the end) it is actually undefined
(in the ClassLoader Javadocs) exactly what sort of a URL is returned in
this case. In practice, it is usually a java.io.File
representing
the directory, where the classpath resource resolves to a filesystem
location, or a jar URL of some sort, where the classpath resource resolves
to a jar location. Still, there is a portability concern on this operation.
If a jar URL is obtained for the last non-wildcard segment, the resolver
must be able to get a java.net.JarURLConnection
from it, or
manually parse the jar URL, to be able to walk the contents of the jar,
and resolve the wildcard. This will work in most environments, but will
fail in others, and it is strongly recommended that the wildcard
resolution of resources coming from jars be thoroughly tested in your
specific environment before you rely on it.
classpath*:
Prefix:
There is special support for retrieving multiple class path resources with
the same name, via the "classpath*:
" prefix. For example,
"classpath*:META-INF/beans.xml
" will find all "beans.xml"
files in the class path, be it in "classes" directories or in JAR files.
This is particularly useful for autodetecting config files of the same name
at the same location within each jar file. Internally, this happens via a
ClassLoader.getResources()
call, and is completely portable.
The "classpath*:" prefix can also be combined with a PathMatcher pattern in
the rest of the location path, for example "classpath*:META-INF/*-beans.xml".
In this case, the resolution strategy is fairly simple: a
ClassLoader.getResources()
call is used on the last non-wildcard
path segment to get all the matching resources in the class loader hierarchy,
and then off each resource the same PathMatcher resolution strategy described
above is used for the wildcard subpath.
Other notes:
WARNING: Note that "classpath*:
" when combined with
Ant-style patterns will only work reliably with at least one root directory
before the pattern starts, unless the actual target files reside in the file
system. This means that a pattern like "classpath*:*.xml
" will
not retrieve files from the root of jar files but rather only from the
root of expanded directories. This originates from a limitation in the JDK's
ClassLoader.getResources()
method which only returns file system
locations for a passed-in empty String (indicating potential roots to search).
This ResourcePatternResolver
implementation is trying to mitigate the
jar root lookup limitation through URLClassLoader
introspection and
"java.class.path" manifest evaluation; however, without portability guarantees.
WARNING: Ant-style patterns with "classpath:" resources are not guaranteed to find matching resources if the root package to search is available in multiple class path locations. This is because a resource such as
com/mycompany/package1/service-context.xmlmay be in only one location, but when a path such as
classpath:com/mycompany/**/service-context.xmlis used to try to resolve it, the resolver will work off the (first) URL returned by
getResource("com/mycompany");
. If this base package node
exists in multiple classloader locations, the actual end resource may not be
underneath. Therefore, preferably, use "classpath*:
" with the same
Ant-style pattern in such a case, which will search all class path
locations that contain the root package.ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
,
AntPathMatcher
,
ResourceLoader.getResource(String)
,
ClassLoader.getResources(String)
Modifier and Type | Class and Description |
---|---|
private static class |
PathMatchingResourcePatternResolver.PatternVirtualFileVisitor
VFS visitor for path matching purposes.
|
private static class |
PathMatchingResourcePatternResolver.VfsResourceMatchingDelegate
Inner delegate class, avoiding a hard JBoss VFS API dependency at runtime.
|
Modifier and Type | Field and Description |
---|---|
private static java.lang.reflect.Method |
equinoxResolveMethod |
private static Log |
logger |
private PathMatcher |
pathMatcher |
private ResourceLoader |
resourceLoader |
CLASSPATH_ALL_URL_PREFIX
CLASSPATH_URL_PREFIX
Constructor and Description |
---|
PathMatchingResourcePatternResolver()
Create a new PathMatchingResourcePatternResolver with a DefaultResourceLoader.
|
PathMatchingResourcePatternResolver(java.lang.ClassLoader classLoader)
Create a new PathMatchingResourcePatternResolver with a DefaultResourceLoader.
|
PathMatchingResourcePatternResolver(ResourceLoader resourceLoader)
Create a new PathMatchingResourcePatternResolver.
|
Modifier and Type | Method and Description |
---|---|
protected void |
addAllClassLoaderJarRoots(java.lang.ClassLoader classLoader,
java.util.Set<Resource> result)
Search all
URLClassLoader URLs for jar file references and add them to the
given set of resources in the form of pointers to the root of the jar file content. |
protected void |
addClassPathManifestEntries(java.util.Set<Resource> result)
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.
|
protected Resource |
convertClassLoaderURL(java.net.URL url)
Convert the given URL as returned from the ClassLoader into a
Resource . |
protected java.lang.String |
determineRootDir(java.lang.String location)
Determine the root directory for the given location.
|
protected java.util.Set<Resource> |
doFindAllClassPathResources(java.lang.String path)
Find all class location resources with the given path via the ClassLoader.
|
protected java.util.Set<Resource> |
doFindMatchingFileSystemResources(java.io.File rootDir,
java.lang.String subPattern)
Find all resources in the file system that match the given location pattern
via the Ant-style PathMatcher.
|
protected java.util.Set<Resource> |
doFindPathMatchingFileResources(Resource rootDirResource,
java.lang.String subPattern)
Find all resources in the file system that match the given location pattern
via the Ant-style PathMatcher.
|
protected java.util.Set<Resource> |
doFindPathMatchingJarResources(Resource rootDirResource,
java.lang.String subPattern)
Deprecated.
as of Spring 4.3, in favor of
doFindPathMatchingJarResources(Resource, URL, String) |
protected java.util.Set<Resource> |
doFindPathMatchingJarResources(Resource rootDirResource,
java.net.URL rootDirURL,
java.lang.String subPattern)
Find all resources in jar files that match the given location pattern
via the Ant-style PathMatcher.
|
protected void |
doRetrieveMatchingFiles(java.lang.String fullPattern,
java.io.File dir,
java.util.Set<java.io.File> result)
Recursively retrieve files that match the given pattern,
adding them to the given result list.
|
protected Resource[] |
findAllClassPathResources(java.lang.String location)
Find all class location resources with the given location via the ClassLoader.
|
protected Resource[] |
findPathMatchingResources(java.lang.String locationPattern)
Find all resources that match the given location pattern via the
Ant-style PathMatcher.
|
java.lang.ClassLoader |
getClassLoader()
Expose the ClassLoader used by this ResourceLoader.
|
protected java.util.jar.JarFile |
getJarFile(java.lang.String jarFileUrl)
Resolve the given jar file URL into a JarFile object.
|
PathMatcher |
getPathMatcher()
Return the PathMatcher that this resource pattern resolver uses.
|
Resource |
getResource(java.lang.String location)
Return a Resource handle for the specified resource.
|
ResourceLoader |
getResourceLoader()
Return the ResourceLoader that this pattern resolver works with.
|
Resource[] |
getResources(java.lang.String locationPattern)
Resolve the given location pattern into Resource objects.
|
protected boolean |
isJarResource(Resource resource)
Return whether the given resource handle indicates a jar resource
that the
doFindPathMatchingJarResources method can handle. |
protected Resource |
resolveRootDirResource(Resource original)
Resolve the specified resource for path matching.
|
protected java.util.Set<java.io.File> |
retrieveMatchingFiles(java.io.File rootDir,
java.lang.String pattern)
Retrieve files that match the given path pattern,
checking the given directory and its subdirectories.
|
void |
setPathMatcher(PathMatcher pathMatcher)
Set the PathMatcher implementation to use for this
resource pattern resolver.
|
private static final Log logger
private static java.lang.reflect.Method equinoxResolveMethod
private final ResourceLoader resourceLoader
private PathMatcher pathMatcher
public PathMatchingResourcePatternResolver()
ClassLoader access will happen via the thread context class loader.
DefaultResourceLoader
public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader)
ClassLoader access will happen via the thread context class loader.
resourceLoader
- the ResourceLoader to load root directories and
actual resources withpublic PathMatchingResourcePatternResolver(java.lang.ClassLoader classLoader)
classLoader
- the ClassLoader to load classpath resources with,
or null
for using the thread context class loader
at the time of actual resource accessDefaultResourceLoader
public ResourceLoader getResourceLoader()
public java.lang.ClassLoader getClassLoader()
ResourceLoader
Clients which need to access the ClassLoader directly can do so in a uniform manner with the ResourceLoader, rather than relying on the thread context ClassLoader.
getClassLoader
in interface ResourceLoader
null
if even the system
ClassLoader isn't accessible)ClassUtils.getDefaultClassLoader()
public void setPathMatcher(PathMatcher pathMatcher)
AntPathMatcher
public PathMatcher getPathMatcher()
public Resource getResource(java.lang.String location)
ResourceLoader
InputStreamSource.getInputStream()
calls.
Note that a Resource handle does not imply an existing resource;
you need to invoke Resource.exists()
to check for existence.
getResource
in interface ResourceLoader
location
- the resource locationResourceLoader.CLASSPATH_URL_PREFIX
,
Resource.exists()
,
InputStreamSource.getInputStream()
public Resource[] getResources(java.lang.String locationPattern) throws java.io.IOException
ResourcePatternResolver
Overlapping resource entries that point to the same physical resource should be avoided, as far as possible. The result should have set semantics.
getResources
in interface ResourcePatternResolver
locationPattern
- the location pattern to resolvejava.io.IOException
- in case of I/O errorsprotected Resource[] findAllClassPathResources(java.lang.String location) throws java.io.IOException
doFindAllClassPathResources(String)
.location
- the absolute path within the classpathjava.io.IOException
- in case of I/O errorsClassLoader.getResources(java.lang.String)
,
convertClassLoaderURL(java.net.URL)
protected java.util.Set<Resource> doFindAllClassPathResources(java.lang.String path) throws java.io.IOException
findAllClassPathResources(String)
.path
- the absolute path within the classpath (never a leading slash)java.io.IOException
protected Resource convertClassLoaderURL(java.net.URL url)
Resource
.
The default implementation simply creates a UrlResource
instance.
url
- a URL as returned from the ClassLoaderClassLoader.getResources(java.lang.String)
,
Resource
protected void addAllClassLoaderJarRoots(java.lang.ClassLoader classLoader, java.util.Set<Resource> result)
URLClassLoader
URLs for jar file references and add them to the
given set of resources in the form of pointers to the root of the jar file content.classLoader
- the ClassLoader to search (including its ancestors)result
- the set of resources to add jar roots toprotected void addClassPathManifestEntries(java.util.Set<Resource> result)
result
- the set of resources to add jar roots toprotected Resource[] findPathMatchingResources(java.lang.String locationPattern) throws java.io.IOException
locationPattern
- the location pattern to matchjava.io.IOException
- in case of I/O errorsdoFindPathMatchingJarResources(org.springframework.core.io.Resource, java.net.URL, java.lang.String)
,
doFindPathMatchingFileResources(org.springframework.core.io.Resource, java.lang.String)
,
PathMatcher
protected java.lang.String determineRootDir(java.lang.String location)
Used for determining the starting point for file matching,
resolving the root directory location to a java.io.File
and passing it into retrieveMatchingFiles
, with the
remainder of the location as pattern.
Will return "/WEB-INF/" for the pattern "/WEB-INF/*.xml", for example.
location
- the location to checkretrieveMatchingFiles(java.io.File, java.lang.String)
protected Resource resolveRootDirResource(Resource original) throws java.io.IOException
By default, Equinox OSGi "bundleresource:" / "bundleentry:" URL will be resolved into a standard jar file URL that be traversed using Spring's standard jar file traversal algorithm. For any preceding custom resolution, override this method and replace the resource handle accordingly.
original
- the resource to resolvejava.io.IOException
- in case of resolution failureprotected boolean isJarResource(Resource resource) throws java.io.IOException
doFindPathMatchingJarResources
method can handle.
By default, the URL protocols "jar", "zip", "vfszip and "wsjar"
will be treated as jar resources. This template method allows for
detecting further kinds of jar-like resources, e.g. through
instanceof
checks on the resource handle type.
resource
- the resource handle to check
(usually the root directory to start path matching from)java.io.IOException
doFindPathMatchingJarResources(org.springframework.core.io.Resource, java.net.URL, java.lang.String)
,
ResourceUtils.isJarURL(java.net.URL)
protected java.util.Set<Resource> doFindPathMatchingJarResources(Resource rootDirResource, java.net.URL rootDirURL, java.lang.String subPattern) throws java.io.IOException
rootDirResource
- the root directory as ResourcerootDirURL
- the pre-resolved root directory URLsubPattern
- the sub pattern to match (below the root directory)java.io.IOException
- in case of I/O errorsJarURLConnection
,
PathMatcher
@Deprecated protected java.util.Set<Resource> doFindPathMatchingJarResources(Resource rootDirResource, java.lang.String subPattern) throws java.io.IOException
doFindPathMatchingJarResources(Resource, URL, String)
rootDirResource
- the root directory as ResourcesubPattern
- the sub pattern to match (below the root directory)java.io.IOException
- in case of I/O errorsprotected java.util.jar.JarFile getJarFile(java.lang.String jarFileUrl) throws java.io.IOException
java.io.IOException
protected java.util.Set<Resource> doFindPathMatchingFileResources(Resource rootDirResource, java.lang.String subPattern) throws java.io.IOException
rootDirResource
- the root directory as ResourcesubPattern
- the sub pattern to match (below the root directory)java.io.IOException
- in case of I/O errorsretrieveMatchingFiles(java.io.File, java.lang.String)
,
PathMatcher
protected java.util.Set<Resource> doFindMatchingFileSystemResources(java.io.File rootDir, java.lang.String subPattern) throws java.io.IOException
rootDir
- the root directory in the file systemsubPattern
- the sub pattern to match (below the root directory)java.io.IOException
- in case of I/O errorsretrieveMatchingFiles(java.io.File, java.lang.String)
,
PathMatcher
protected java.util.Set<java.io.File> retrieveMatchingFiles(java.io.File rootDir, java.lang.String pattern) throws java.io.IOException
rootDir
- the directory to start frompattern
- the pattern to match against,
relative to the root directoryjava.io.IOException
- if directory contents could not be retrievedprotected void doRetrieveMatchingFiles(java.lang.String fullPattern, java.io.File dir, java.util.Set<java.io.File> result) throws java.io.IOException
fullPattern
- the pattern to match against,
with prepended root directory pathdir
- the current directoryresult
- the Set of matching File instances to add tojava.io.IOException
- if directory contents could not be retrieved