Avoid parsing nested jar URLs for cached resource lookups

Construct JarFileUrlKey directly from already-parsed URL specification
to avoid unnecessary URL construction and parsing on cache hits.
A URL is only created on a cache miss when the JarFile needs to be
instantiated.

This eliminates redundant object allocation in the hot path when
frameworks probe for optional classes or package-info metadata across
a large executable JAR.

See gh-51827

Signed-off-by: sharanrenukeshbharmshetty <sbharmshetty@gmail.com>
This commit is contained in:
sharan bharmshetty
2026-09-28 19:34:17 -07:00
committed by Phillip Webb
parent b00a873c00
commit 986ad2da2b
4 changed files with 60 additions and 6 deletions
@@ -44,6 +44,14 @@ final class JarFileUrlKey {
this.runtimeRef = "runtime".equals(url.getRef());
}
JarFileUrlKey(String protocol, String host, int port, String file, boolean runtimeRef) {
this.protocol = protocol;
this.host = host;
this.port = port;
this.file = file;
this.runtimeRef = runtimeRef;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
@@ -337,13 +337,19 @@ final class JarUrlConnection extends java.net.JarURLConnection {
int separator = spec.indexOf("!/");
boolean specHasEntry = (separator != -1) && (separator + 2 != spec.length());
if (specHasEntry) {
URL jarFileUrl = new URL(spec.substring(0, separator));
if ("runtime".equals(url.getRef())) {
jarFileUrl = new URL(jarFileUrl, "#runtime");
String jarFileSpec = spec.substring(0, separator);
boolean runtimeRef = "runtime".equals(url.getRef());
JarFileUrlKey urlKey = new JarFileUrlKey("jar", "", -1, jarFileSpec, runtimeRef);
JarFile jarFile = jarFiles.getCached(urlKey);
if (jarFile == null) {
URL jarFileUrl = new URL(jarFileSpec);
if (runtimeRef) {
jarFileUrl = new URL(jarFileUrl, "#runtime");
}
jarFile = jarFiles.getOrCreate(true, jarFileUrl);
jarFiles.cacheIfAbsent(true, jarFileUrl, jarFile);
}
String entryName = UrlDecoder.decode(spec.substring(separator + 2));
JarFile jarFile = jarFiles.getOrCreate(true, jarFileUrl);
jarFiles.cacheIfAbsent(true, jarFileUrl, jarFile);
if (!hasEntry(jarFile, entryName)) {
return notFoundConnection(jarFile.getName(), entryName);
}
@@ -81,6 +81,15 @@ class UrlJarFiles {
return this.cache.get(jarFileUrl);
}
/**
* Return the cached {@link JarFile} if available.
* @param urlKey the jar file URL key
* @return the cached jar or {@code null}
*/
JarFile getCached(JarFileUrlKey urlKey) {
return this.cache.get(urlKey);
}
/**
* Cache the given {@link JarFile} if caching can be used and there is no existing
* entry.
@@ -154,7 +163,15 @@ class UrlJarFiles {
* @return the cached {@link JarFile} or {@code null}
*/
JarFile get(URL jarFileUrl) {
JarFileUrlKey urlKey = new JarFileUrlKey(jarFileUrl);
return get(new JarFileUrlKey(jarFileUrl));
}
/**
* Get a {@link JarFile} from the cache given a jar file URL key.
* @param urlKey the jar file URL key
* @return the cached {@link JarFile} or {@code null}
*/
JarFile get(JarFileUrlKey urlKey) {
synchronized (this) {
return this.jarFileUrlToJarFile.get(urlKey);
}
@@ -101,4 +101,27 @@ class JarFileUrlKeyTests {
return new JarFileUrlKey(new URL(spec));
}
@Test
void directKeyEqualsUrlKey() throws Exception {
JarFileUrlKey fromUrl = key("jar:nested:/my.jar/!mynested.jar!/my/path");
JarFileUrlKey direct = new JarFileUrlKey("jar", "", -1, "nested:/my.jar/!mynested.jar!/my/path", false);
assertThat(direct).isEqualTo(fromUrl);
assertThat(direct.hashCode()).isEqualTo(fromUrl.hashCode());
}
@Test
void directKeyWithRuntimeRefEqualsUrlKey() throws Exception {
JarFileUrlKey fromUrl = key("jar:nested:/my.jar/!mynested.jar!/my/path#runtime");
JarFileUrlKey direct = new JarFileUrlKey("jar", "", -1, "nested:/my.jar/!mynested.jar!/my/path", true);
assertThat(direct).isEqualTo(fromUrl);
assertThat(direct.hashCode()).isEqualTo(fromUrl.hashCode());
}
@Test
void directKeyWithRuntimeRefNotEqualToKeyWithout() {
JarFileUrlKey k1 = new JarFileUrlKey("jar", "", -1, "nested:/my.jar/!mynested.jar!/my/path", true);
JarFileUrlKey k2 = new JarFileUrlKey("jar", "", -1, "nested:/my.jar/!mynested.jar!/my/path", false);
assertThat(k1).isNotEqualTo(k2);
}
}