简体   繁体   中英

Is spring Resource a file or directory?

I am using the spring Resource API and using a ResourcePatternResolver to scan my classpath for files.

In one situation the scan is picking up some directories and files that are in a pre-built jar and some that are on the file system.

In either case a 'resource' will either be a file or a directory. How can I reliably detect whether a resource points to a directory or file, whether in a jar file or not? Calling getFile() on a Resource inside a jar throws an Exception so I can't use that plus isFile() as I initially tried.

Spring's Resource interface is meant to be a more capable interface for abstracting access to low-level resources.

It wraps File sometimes while sometimes not.

It has six built-in implements: UrlResource , ClassPathResource , FileSystemResource , ServletContextResource , InputStreamResource , ByteArrayResource .

You can implement yourself resource form.

The UrlResource wraps a java.net.URL , and may be used to access any Object that is normally accessible via a URL. If you use http: prefix,the resource is a URL.

The ClassPathResource represents a resource which should be obtained from the classpath. This Resource implementation supports resolution as java.io.File if the class path resource resides in the file system, but not for classpath resources which reside in a jar and have not been expanded (by the servlet engine, or whatever the environment is) to the filesystem. To address this the various Resource implementations always support resolution as a java.net.URL .

FileSystemResource is an implement for java.io.File handles.It obviously supports resolution as a File and as a URL .

InputStreamResource is a resource implements for a given InputStream . Do not use it if you need to keep the resource descriptor somewhere, or if you need read a stream multiple times.

ByteArrayResource is a Resource implement for a given byte array. It creates a ByteArrayInputStream for the given byte array.

So you should not always use getFile() as Spring's Resource doesn't always represent a file system resource.For this reason, we recommend that you use getInputStream() to access resource contents because it is likely to function for all possible resource types.

Refer to: Resources

I think you can just surround the code checking for file by a try catch block:

boolean isFile = true;

try {
   resource.getFile()
   ...
} catch (...Exception e) {
   ifFile = false
}

I had a similar requirement, and solved it by excluding directories from my search pattern. Then for each resource found I lookup the parent item in the path, and ensure the directory has been created before writing the file.
In my case the file could be in the filesystem, or in the classpath, so I check the scheme of the URI first..

Although my search pattern may still pickup dirs if they have a dot in the name, so it would be better to catch the exception in that case -
search pattern - classpath*:/**/sprout/plugins/**/*.*

Example code -

private void extractClientPlugins() throws IOException {
    Resource[] resourcePaths = resolver.getResourcePaths(sproutPluginSearchPattern);
    Path pluginFolderPath = Paths.get(sproutHome, "./plugins/");
    pluginFolderPath.toFile().mkdirs();
    if (resourcePaths.length == 0) {
        log.info("No Sprout client side plugins found");
    }
    for (Resource resource : resourcePaths) {
        try {
            Path destinationPath = generateDestinationPath(pluginFolderPath, resource);
            File parentFolder = destinationPath.getParent().toFile();
            if (!parentFolder.exists()) {
                parentFolder.mkdirs();
            }
            destinationPath.toFile().mkdirs();
            copy(resource, destinationPath.toFile());
        } catch (IOException e) {
            log.error("could not access resource", e);
            throw e;
        }
    }
}

private Path generateDestinationPath(Path rootDir, Resource resource) throws IOException {
    String relativePath = null;
    String scheme = resource.getURI().getScheme();
    if ("JAR".contains(scheme.toUpperCase())) {
        String[] uriParts = resource.getURL().toString().split("!");
        relativePath = trimPluginPathPrefix(uriParts[1]);
    } else {
        String filePath = resource.getFile().getAbsolutePath();
        relativePath = trimPluginPathPrefix(filePath);
    }
    return Paths.get(rootDir.toString(), relativePath);
}

private String trimPluginPathPrefix(String filePath) {
    String[] pathParts = filePath.split("sprout/plugins/");
    if (pathParts.length != 2) {
        throw new RuntimeException("The plugins must be located in a path containing '**/sprout/plugins/*'");
    }
    return pathParts[1];
}  

Using it in this project -
https://github.com/savantly-net/sprout-platform/blob/master/sprout-core/src/main/java/net/savantly/sprout/core/ui/UiLoader.java

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM