Skip to content

Commit 3c11270

Browse files
committed
Introduce useCaches flag on UrlResource (for URLConnection access)
Propagated from PathMatchingResourcePatternResolver's setUseCaches. Closes gh-35218
1 parent 8c44a61 commit 3c11270

File tree

4 files changed

+93
-26
lines changed

4 files changed

+93
-26
lines changed

spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,12 +361,22 @@ public long lastModified() throws IOException {
361361
* @throws IOException if thrown from URLConnection methods
362362
*/
363363
protected void customizeConnection(URLConnection con) throws IOException {
364-
ResourceUtils.useCachesIfNecessary(con);
364+
useCachesIfNecessary(con);
365365
if (con instanceof HttpURLConnection httpCon) {
366366
customizeConnection(httpCon);
367367
}
368368
}
369369

370+
/**
371+
* Apply {@link URLConnection#setUseCaches useCaches} if necessary.
372+
* @param con the URLConnection to customize
373+
* @since 6.2.10
374+
* @see ResourceUtils#useCachesIfNecessary(URLConnection)
375+
*/
376+
void useCachesIfNecessary(URLConnection con) {
377+
ResourceUtils.useCachesIfNecessary(con);
378+
}
379+
370380
/**
371381
* Customize the given {@link HttpURLConnection} before fetching the resource.
372382
* <p>Can be overridden in subclasses for configuring request headers and timeouts.

spring-core/src/main/java/org/springframework/core/io/FileUrlResource.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,9 @@ public WritableByteChannel writableChannel() throws IOException {
109109

110110
@Override
111111
public Resource createRelative(String relativePath) throws MalformedURLException {
112-
return new FileUrlResource(createRelativeURL(relativePath));
112+
FileUrlResource resource = new FileUrlResource(createRelativeURL(relativePath));
113+
resource.useCaches = this.useCaches;
114+
return resource;
113115
}
114116

115117
}

spring-core/src/main/java/org/springframework/core/io/UrlResource.java

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ public class UrlResource extends AbstractFileResolvingResource {
6767
@Nullable
6868
private volatile String cleanedUrl;
6969

70+
/**
71+
* Whether to use URLConnection caches ({@code null} means default).
72+
*/
73+
@Nullable
74+
volatile Boolean useCaches;
75+
7076

7177
/**
7278
* Create a new {@code UrlResource} based on the given URL object.
@@ -216,11 +222,22 @@ private String getCleanedUrl() {
216222
return cleanedUrl;
217223
}
218224

225+
/**
226+
* Set an explicit flag for {@link URLConnection#setUseCaches},
227+
* to be applied for any {@link URLConnection} operation in this resource.
228+
* <p>By default, caching will be applied only to jar resources.
229+
* An explicit {@code true} flag applies caching to all resources, whereas an
230+
* explicit {@code false} flag turns off caching for jar resources as well.
231+
* @since 6.2.10
232+
* @see ResourceUtils#useCachesIfNecessary
233+
*/
234+
public void setUseCaches(boolean useCaches) {
235+
this.useCaches = useCaches;
236+
}
237+
219238

220239
/**
221240
* This implementation opens an InputStream for the given URL.
222-
* <p>It sets the {@code useCaches} flag to {@code false},
223-
* mainly to avoid jar file locking on Windows.
224241
* @see java.net.URL#openConnection()
225242
* @see java.net.URLConnection#setUseCaches(boolean)
226243
* @see java.net.URLConnection#getInputStream()
@@ -251,6 +268,17 @@ protected void customizeConnection(URLConnection con) throws IOException {
251268
}
252269
}
253270

271+
@Override
272+
void useCachesIfNecessary(URLConnection con) {
273+
Boolean useCaches = this.useCaches;
274+
if (useCaches != null) {
275+
con.setUseCaches(useCaches);
276+
}
277+
else {
278+
super.useCachesIfNecessary(con);
279+
}
280+
}
281+
254282
/**
255283
* This implementation returns the underlying URL reference.
256284
*/
@@ -305,7 +333,9 @@ public File getFile() throws IOException {
305333
*/
306334
@Override
307335
public Resource createRelative(String relativePath) throws MalformedURLException {
308-
return new UrlResource(createRelativeURL(relativePath));
336+
UrlResource resource = new UrlResource(createRelativeURL(relativePath));
337+
resource.useCaches = this.useCaches;
338+
return resource;
309339
}
310340

311341
/**

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

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,8 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
260260

261261
private PathMatcher pathMatcher = new AntPathMatcher();
262262

263-
private boolean useCaches = true;
263+
@Nullable
264+
private Boolean useCaches;
264265

265266
private final Map<String, Resource[]> rootDirCache = new ConcurrentHashMap<>();
266267

@@ -342,10 +343,12 @@ public PathMatcher getPathMatcher() {
342343
* the {@link JarURLConnection} level as well as within this resolver instance.
343344
* <p>Note that {@link JarURLConnection#setDefaultUseCaches} can be turned off
344345
* independently. This resolver-level setting is designed to only enforce
345-
* {@code JarURLConnection#setUseCaches(false)} if necessary but otherwise
346-
* leaves the JVM-level default in place.
346+
* {@code JarURLConnection#setUseCaches(true/false)} if necessary but otherwise
347+
* leaves the JVM-level default in place (if this setter has not been called).
348+
* <p>As of 6.2.10, this setting propagates to {@link UrlResource#setUseCaches}.
347349
* @since 6.1.19
348350
* @see JarURLConnection#setUseCaches
351+
* @see UrlResource#setUseCaches
349352
* @see #clearCache()
350353
*/
351354
public void setUseCaches(boolean useCaches) {
@@ -355,7 +358,11 @@ public void setUseCaches(boolean useCaches) {
355358

356359
@Override
357360
public Resource getResource(String location) {
358-
return getResourceLoader().getResource(location);
361+
Resource resource = getResourceLoader().getResource(location);
362+
if (this.useCaches != null && resource instanceof UrlResource urlResource) {
363+
urlResource.setUseCaches(this.useCaches);
364+
}
365+
return resource;
359366
}
360367

361368
@Override
@@ -473,20 +480,27 @@ protected Resource convertClassLoaderURL(URL url) {
473480
}
474481
}
475482
else {
483+
UrlResource resource = null;
476484
String urlString = url.toString();
477485
String cleanedPath = StringUtils.cleanPath(urlString);
478486
if (!cleanedPath.equals(urlString)) {
479487
// Prefer cleaned URL, aligned with UrlResource#createRelative(String)
480488
try {
481489
// Retain original URL instance, potentially including custom URLStreamHandler.
482-
return new UrlResource(new URL(url, cleanedPath));
490+
resource = new UrlResource(new URL(url, cleanedPath));
483491
}
484492
catch (MalformedURLException ex) {
485493
// Fallback to regular URL construction below...
486494
}
487495
}
488496
// Retain original URL instance, potentially including custom URLStreamHandler.
489-
return new UrlResource(url);
497+
if (resource == null) {
498+
resource = new UrlResource(url);
499+
}
500+
if (this.useCaches != null) {
501+
resource.setUseCaches(this.useCaches);
502+
}
503+
return resource;
490504
}
491505
}
492506

@@ -505,6 +519,9 @@ protected void addAllClassLoaderJarRoots(@Nullable ClassLoader classLoader, Set<
505519
UrlResource jarResource = (ResourceUtils.URL_PROTOCOL_JAR.equals(url.getProtocol()) ?
506520
new UrlResource(url) :
507521
new UrlResource(ResourceUtils.JAR_URL_PREFIX + url + ResourceUtils.JAR_URL_SEPARATOR));
522+
if (this.useCaches != null) {
523+
jarResource.setUseCaches(this.useCaches);
524+
}
508525
if (jarResource.exists()) {
509526
result.add(jarResource);
510527
}
@@ -556,7 +573,7 @@ protected void addClassPathManifestEntries(Set<Resource> result) {
556573
Set<ClassPathManifestEntry> entries = this.manifestEntriesCache;
557574
if (entries == null) {
558575
entries = getClassPathManifestEntries();
559-
if (this.useCaches) {
576+
if (this.useCaches == null || this.useCaches) {
560577
this.manifestEntriesCache = entries;
561578
}
562579
}
@@ -577,7 +594,7 @@ private Set<ClassPathManifestEntry> getClassPathManifestEntries() {
577594
try {
578595
File jar = new File(path).getAbsoluteFile();
579596
if (jar.isFile() && seen.add(jar)) {
580-
manifestEntries.add(ClassPathManifestEntry.of(jar));
597+
manifestEntries.add(ClassPathManifestEntry.of(jar, this.useCaches));
581598
manifestEntries.addAll(getClassPathManifestEntriesFromJar(jar));
582599
}
583600
}
@@ -616,7 +633,7 @@ private Set<ClassPathManifestEntry> getClassPathManifestEntriesFromJar(File jar)
616633
}
617634
File candidate = new File(parent, path);
618635
if (candidate.isFile() && candidate.getCanonicalPath().contains(parent.getCanonicalPath())) {
619-
manifestEntries.add(ClassPathManifestEntry.of(candidate));
636+
manifestEntries.add(ClassPathManifestEntry.of(candidate, this.useCaches));
620637
}
621638
}
622639
}
@@ -710,7 +727,7 @@ else if (commonPrefix.equals(rootDirPath)) {
710727
if (rootDirResources == null) {
711728
// Lookup for specific directory, creating a cache entry for it.
712729
rootDirResources = getResources(rootDirPath);
713-
if (this.useCaches) {
730+
if (this.useCaches == null || this.useCaches) {
714731
this.rootDirCache.put(rootDirPath, rootDirResources);
715732
}
716733
}
@@ -729,7 +746,11 @@ else if (commonPrefix.equals(rootDirPath)) {
729746
if (resolvedUrl != null) {
730747
rootDirUrl = resolvedUrl;
731748
}
732-
rootDirResource = new UrlResource(rootDirUrl);
749+
UrlResource urlResource = new UrlResource(rootDirUrl);
750+
if (this.useCaches != null) {
751+
urlResource.setUseCaches(this.useCaches);
752+
}
753+
rootDirResource = urlResource;
733754
}
734755
if (rootDirUrl.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
735756
result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirUrl, subPattern, getPathMatcher()));
@@ -865,8 +886,8 @@ protected Set<Resource> doFindPathMatchingJarResources(Resource rootDirResource,
865886

866887
if (con instanceof JarURLConnection jarCon) {
867888
// Should usually be the case for traditional JAR files.
868-
if (!this.useCaches) {
869-
jarCon.setUseCaches(false);
889+
if (this.useCaches != null) {
890+
jarCon.setUseCaches(this.useCaches);
870891
}
871892
try {
872893
jarFile = jarCon.getJarFile();
@@ -931,7 +952,7 @@ protected Set<Resource> doFindPathMatchingJarResources(Resource rootDirResource,
931952
}
932953
}
933954
}
934-
if (this.useCaches) {
955+
if (this.useCaches == null || this.useCaches) {
935956
// Cache jar entries in TreeSet for efficient searching on re-encounter.
936957
this.jarEntriesCache.put(jarFileUrl, entriesCache);
937958
}
@@ -1257,10 +1278,10 @@ private record ClassPathManifestEntry(Resource resource, @Nullable Resource alte
12571278

12581279
private static final String JARFILE_URL_PREFIX = ResourceUtils.JAR_URL_PREFIX + ResourceUtils.FILE_URL_PREFIX;
12591280

1260-
static ClassPathManifestEntry of(File file) throws MalformedURLException {
1281+
static ClassPathManifestEntry of(File file, @Nullable Boolean useCaches) throws MalformedURLException {
12611282
String path = fixPath(file.getAbsolutePath());
1262-
Resource resource = asJarFileResource(path);
1263-
Resource alternative = createAlternative(path);
1283+
Resource resource = asJarFileResource(path, useCaches);
1284+
Resource alternative = createAlternative(path, useCaches);
12641285
return new ClassPathManifestEntry(resource, alternative);
12651286
}
12661287

@@ -1281,18 +1302,22 @@ private static String fixPath(String path) {
12811302
* @return the alternative form or {@code null}
12821303
*/
12831304
@Nullable
1284-
private static Resource createAlternative(String path) {
1305+
private static Resource createAlternative(String path, @Nullable Boolean useCaches) {
12851306
try {
12861307
String alternativePath = path.startsWith("/") ? path.substring(1) : "/" + path;
1287-
return asJarFileResource(alternativePath);
1308+
return asJarFileResource(alternativePath, useCaches);
12881309
}
12891310
catch (MalformedURLException ex) {
12901311
return null;
12911312
}
12921313
}
12931314

1294-
private static Resource asJarFileResource(String path) throws MalformedURLException {
1295-
return new UrlResource(JARFILE_URL_PREFIX + path + ResourceUtils.JAR_URL_SEPARATOR);
1315+
private static Resource asJarFileResource(String path, @Nullable Boolean useCaches) throws MalformedURLException {
1316+
UrlResource resource = new UrlResource(JARFILE_URL_PREFIX + path + ResourceUtils.JAR_URL_SEPARATOR);
1317+
if (useCaches != null) {
1318+
resource.setUseCaches(useCaches);
1319+
}
1320+
return resource;
12961321
}
12971322
}
12981323

0 commit comments

Comments
 (0)