|
17 | 17 | package org.springframework.core.io.support;
|
18 | 18 |
|
19 | 19 | import java.io.File;
|
20 |
| -import java.io.FileNotFoundException; |
21 | 20 | import java.io.IOException;
|
22 | 21 | import java.io.UncheckedIOException;
|
23 | 22 | import java.lang.module.ModuleFinder;
|
|
31 | 30 | import java.net.URL;
|
32 | 31 | import java.net.URLClassLoader;
|
33 | 32 | import java.net.URLConnection;
|
34 |
| -import java.util.Arrays; |
| 33 | +import java.nio.file.FileSystem; |
| 34 | +import java.nio.file.FileSystems; |
| 35 | +import java.nio.file.Files; |
| 36 | +import java.nio.file.NoSuchFileException; |
| 37 | +import java.nio.file.Path; |
35 | 38 | import java.util.Collections;
|
36 |
| -import java.util.Comparator; |
37 | 39 | import java.util.Enumeration;
|
| 40 | +import java.util.HashSet; |
38 | 41 | import java.util.LinkedHashSet;
|
| 42 | +import java.util.Map; |
39 | 43 | import java.util.Objects;
|
40 | 44 | import java.util.Set;
|
41 | 45 | import java.util.function.Predicate;
|
|
193 | 197 | * @author Phillip Webb
|
194 | 198 | * @author Sam Brannen
|
195 | 199 | * @author Sebastien Deleuze
|
| 200 | + * @author Dave Syer |
196 | 201 | * @since 1.0.2
|
197 | 202 | * @see #CLASSPATH_ALL_URL_PREFIX
|
198 | 203 | * @see org.springframework.util.AntPathMatcher
|
@@ -736,139 +741,48 @@ protected JarFile getJarFile(String jarFileUrl) throws IOException {
|
736 | 741 | protected Set<Resource> doFindPathMatchingFileResources(Resource rootDirResource, String subPattern)
|
737 | 742 | throws IOException {
|
738 | 743 |
|
739 |
| - File rootDir; |
| 744 | + Set<Resource> result = new HashSet<>(); |
| 745 | + FileSystem fileSystem; |
740 | 746 | try {
|
741 |
| - rootDir = rootDirResource.getFile().getAbsoluteFile(); |
| 747 | + fileSystem = FileSystems.getFileSystem(rootDirResource.getURI().resolve("/")); |
| 748 | + } catch (Exception e) { |
| 749 | + fileSystem = FileSystems.newFileSystem(rootDirResource.getURI().resolve("/"), Map.of(), |
| 750 | + ClassUtils.getDefaultClassLoader()); |
742 | 751 | }
|
743 |
| - catch (FileNotFoundException ex) { |
744 |
| - if (logger.isDebugEnabled()) { |
745 |
| - logger.debug("Cannot search for matching files underneath " + rootDirResource + |
746 |
| - " in the file system: " + ex.getMessage()); |
747 |
| - } |
748 |
| - return Collections.emptySet(); |
749 |
| - } |
750 |
| - catch (Exception ex) { |
751 |
| - if (logger.isInfoEnabled()) { |
752 |
| - logger.info("Failed to resolve " + rootDirResource + " in the file system: " + ex); |
753 |
| - } |
754 |
| - return Collections.emptySet(); |
755 |
| - } |
756 |
| - return doFindMatchingFileSystemResources(rootDir, subPattern); |
757 |
| - } |
758 |
| - |
759 |
| - /** |
760 |
| - * Find all resources in the file system that match the given location pattern |
761 |
| - * via the Ant-style PathMatcher. |
762 |
| - * @param rootDir the root directory in the file system |
763 |
| - * @param subPattern the sub pattern to match (below the root directory) |
764 |
| - * @return a mutable Set of matching Resource instances |
765 |
| - * @throws IOException in case of I/O errors |
766 |
| - * @see #retrieveMatchingFiles |
767 |
| - * @see org.springframework.util.PathMatcher |
768 |
| - */ |
769 |
| - protected Set<Resource> doFindMatchingFileSystemResources(File rootDir, String subPattern) throws IOException { |
770 |
| - if (logger.isTraceEnabled()) { |
771 |
| - logger.trace("Looking for matching resources in directory tree [" + rootDir.getPath() + "]"); |
772 |
| - } |
773 |
| - Set<File> matchingFiles = retrieveMatchingFiles(rootDir, subPattern); |
774 |
| - Set<Resource> result = new LinkedHashSet<>(matchingFiles.size()); |
775 |
| - for (File file : matchingFiles) { |
776 |
| - result.add(new FileSystemResource(file)); |
777 |
| - } |
778 |
| - return result; |
779 |
| - } |
780 |
| - |
781 |
| - /** |
782 |
| - * Retrieve files that match the given path pattern, |
783 |
| - * checking the given directory and its subdirectories. |
784 |
| - * @param rootDir the directory to start from |
785 |
| - * @param pattern the pattern to match against, |
786 |
| - * relative to the root directory |
787 |
| - * @return a mutable Set of matching Resource instances |
788 |
| - * @throws IOException if directory contents could not be retrieved |
789 |
| - */ |
790 |
| - protected Set<File> retrieveMatchingFiles(File rootDir, String pattern) throws IOException { |
791 |
| - if (!rootDir.exists()) { |
792 |
| - // Silently skip non-existing directories. |
793 |
| - if (logger.isDebugEnabled()) { |
794 |
| - logger.debug("Skipping [" + rootDir.getAbsolutePath() + "] because it does not exist"); |
| 752 | + String rootPath = rootDirResource.getURI().getRawPath(); |
| 753 | + if (!("file").equals(rootDirResource.getURI().getScheme()) && rootPath.startsWith("/")) { |
| 754 | + rootPath = rootPath.substring(1); |
| 755 | + if (rootPath.length()==0) { |
| 756 | + return result; |
795 | 757 | }
|
796 |
| - return Collections.emptySet(); |
797 |
| - } |
798 |
| - if (!rootDir.isDirectory()) { |
799 |
| - // Complain louder if it exists but is no directory. |
800 |
| - if (logger.isInfoEnabled()) { |
801 |
| - logger.info("Skipping [" + rootDir.getAbsolutePath() + "] because it does not denote a directory"); |
| 758 | + if (rootPath.endsWith("/")) { |
| 759 | + rootPath = rootPath.substring(0, rootPath.length()-1); |
802 | 760 | }
|
803 |
| - return Collections.emptySet(); |
804 |
| - } |
805 |
| - if (!rootDir.canRead()) { |
806 |
| - if (logger.isInfoEnabled()) { |
807 |
| - logger.info("Skipping search for matching files underneath directory [" + rootDir.getAbsolutePath() + |
808 |
| - "] because the application is not allowed to read the directory"); |
| 761 | + if (rootPath.length()==0) { |
| 762 | + return result; |
809 | 763 | }
|
810 |
| - return Collections.emptySet(); |
811 | 764 | }
|
812 |
| - String fullPattern = StringUtils.replace(rootDir.getAbsolutePath(), File.separator, "/"); |
813 |
| - if (!pattern.startsWith("/")) { |
814 |
| - fullPattern += "/"; |
815 |
| - } |
816 |
| - fullPattern = fullPattern + StringUtils.replace(pattern, File.separator, "/"); |
817 |
| - Set<File> result = new LinkedHashSet<>(8); |
818 |
| - doRetrieveMatchingFiles(fullPattern, rootDir, result); |
819 |
| - return result; |
820 |
| - } |
821 |
| - |
822 |
| - /** |
823 |
| - * Recursively retrieve files that match the given pattern, |
824 |
| - * adding them to the given result list. |
825 |
| - * @param fullPattern the pattern to match against, |
826 |
| - * with prepended root directory path |
827 |
| - * @param dir the current directory |
828 |
| - * @param result the Set of matching File instances to add to |
829 |
| - * @throws IOException if directory contents could not be retrieved |
830 |
| - */ |
831 |
| - protected void doRetrieveMatchingFiles(String fullPattern, File dir, Set<File> result) throws IOException { |
832 |
| - if (logger.isTraceEnabled()) { |
833 |
| - logger.trace("Searching directory [" + dir.getAbsolutePath() + |
834 |
| - "] for files matching pattern [" + fullPattern + "]"); |
835 |
| - } |
836 |
| - for (File content : listDirectory(dir)) { |
837 |
| - String currPath = StringUtils.replace(content.getAbsolutePath(), File.separator, "/"); |
838 |
| - if (content.isDirectory() && getPathMatcher().matchStart(fullPattern, currPath + "/")) { |
839 |
| - if (!content.canRead()) { |
840 |
| - if (logger.isDebugEnabled()) { |
841 |
| - logger.debug("Skipping subdirectory [" + dir.getAbsolutePath() + |
842 |
| - "] because the application is not allowed to read the directory"); |
| 765 | + Path path = fileSystem.getPath(rootPath); |
| 766 | + Path patternPath = path.resolve(subPattern); |
| 767 | + try (Stream<Path> files = Files.walk(path)) { |
| 768 | + files.forEach(file -> { |
| 769 | + if (getPathMatcher().match(patternPath.toString(), file.toString())) { |
| 770 | + try { |
| 771 | + result.add(new UrlResource(file.toUri())); |
| 772 | + } catch (MalformedURLException e) { |
| 773 | + // ignore |
843 | 774 | }
|
844 | 775 | }
|
845 |
| - else { |
846 |
| - doRetrieveMatchingFiles(fullPattern, content, result); |
847 |
| - } |
848 |
| - } |
849 |
| - if (getPathMatcher().match(fullPattern, currPath)) { |
850 |
| - result.add(content); |
851 |
| - } |
| 776 | + }); |
| 777 | + } catch (NoSuchFileException e) { |
| 778 | + // ignore |
852 | 779 | }
|
853 |
| - } |
854 |
| - |
855 |
| - /** |
856 |
| - * Determine a sorted list of files in the given directory. |
857 |
| - * @param dir the directory to introspect |
858 |
| - * @return the sorted list of files (by default in alphabetical order) |
859 |
| - * @since 5.1 |
860 |
| - * @see File#listFiles() |
861 |
| - */ |
862 |
| - protected File[] listDirectory(File dir) { |
863 |
| - File[] files = dir.listFiles(); |
864 |
| - if (files == null) { |
865 |
| - if (logger.isInfoEnabled()) { |
866 |
| - logger.info("Could not retrieve contents of directory [" + dir.getAbsolutePath() + "]"); |
867 |
| - } |
868 |
| - return new File[0]; |
| 780 | + try { |
| 781 | + fileSystem.close(); |
| 782 | + } catch (UnsupportedOperationException e) { |
| 783 | + // ignore |
869 | 784 | }
|
870 |
| - Arrays.sort(files, Comparator.comparing(File::getName)); |
871 |
| - return files; |
| 785 | + return result; |
872 | 786 | }
|
873 | 787 |
|
874 | 788 | /**
|
|
0 commit comments