Skip to content

Commit 67613f9

Browse files
committed
SPR-16838 PathMatchingResourcePatternResolver should enforce consistent
alphabetical sorting of directory content A sort was added in SPR-14085 but the default File#compareTo depends upon the underlying system. The ordering of the ressources returned by PathMatchingResourcePatternResolver#retrieveMatchingFiles may differ between OS (Windows, Unix). This leads to subtle bugs hard to track. This PR replace the default sort with one based on the file name.
1 parent fbd12e9 commit 67613f9

File tree

2 files changed

+31
-2
lines changed

2 files changed

+31
-2
lines changed

spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -790,7 +790,10 @@ protected void doRetrieveMatchingFiles(String fullPattern, File dir, Set<File> r
790790
}
791791
return;
792792
}
793-
Arrays.sort(dirContents);
793+
794+
// enforce consistent alphabetical sorting to avoid different order between OS
795+
Arrays.sort(dirContents, (f1, f2) -> f1.getName().compareTo(f2.getName()));
796+
794797
for (File content : dirContents) {
795798
String currPath = StringUtils.replace(content.getAbsolutePath(), File.separator, "/");
796799
if (content.isDirectory() && getPathMatcher().matchStart(fullPattern, currPath + "/")) {

spring-core/src/test/java/org/springframework/core/io/support/PathMatchingResourcePatternResolverTests.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,18 @@
1616

1717
package org.springframework.core.io.support;
1818

19+
import java.io.File;
1920
import java.io.FileNotFoundException;
2021
import java.io.IOException;
2122
import java.util.ArrayList;
2223
import java.util.Arrays;
2324
import java.util.List;
25+
import java.util.Set;
2426

2527
import org.junit.Ignore;
28+
import org.junit.Rule;
2629
import org.junit.Test;
27-
30+
import org.junit.rules.TemporaryFolder;
2831
import org.springframework.core.io.Resource;
2932
import org.springframework.util.StringUtils;
3033

@@ -56,6 +59,8 @@ public class PathMatchingResourcePatternResolverTests {
5659

5760
private PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
5861

62+
@Rule
63+
public TemporaryFolder folder = new TemporaryFolder();
5964

6065
@Test(expected = FileNotFoundException.class)
6166
public void invalidPrefixWithPatternElementInIt() throws IOException {
@@ -117,6 +122,27 @@ public void rootPatternRetrievalInJarFiles() throws IOException {
117122
}
118123
assertTrue("Could not find aspectj_1_5_0.dtd in the root of the aspectjweaver jar", found);
119124
}
125+
126+
127+
@Test
128+
public void testConsistentFileOrder() throws IOException {
129+
130+
List<String> expectedFileNames = new ArrayList<>();
131+
132+
expectedFileNames.add(folder.newFile("A.txt").getName());
133+
expectedFileNames.add(folder.newFile("B.txt").getName());
134+
expectedFileNames.add(folder.newFile("P.txt").getName());
135+
File newFolder = folder.newFolder("message");
136+
expectedFileNames.add(File.createTempFile("Message", ".txt", newFolder).getName());
137+
138+
Set<File> matchingFiles = resolver.retrieveMatchingFiles(folder.getRoot(), "**/*.txt");
139+
assertEquals(expectedFileNames.size(), matchingFiles.size());
140+
int i = 0;
141+
for (File file : matchingFiles) {
142+
assertEquals(expectedFileNames.get(i), file.getName());
143+
i++;
144+
}
145+
}
120146

121147

122148
private void assertProtocolAndFilenames(Resource[] resources, String protocol, String... filenames)

0 commit comments

Comments
 (0)