Ensure getResources("") includes nested root URLs
Previously, if Boot's JarURLConnection pointed to the root of a nested
entry, e.g. /BOOT-INF/classes, a call to getInputStream() would throw
an IOException. This behavior is reasonable for a URL that points
to the root of a normal jar as the jar itself is on the class path
anyway. However, for a nested jar it meant that a call to
ClassLoader.getResources("") would not include URLs for any nested
jars and directories (/BOOT-INF/classes and jars in /BOOT-INF/lib).
This is due to some logic in URLClassPath.Loader.findResource that
verifies a URL by opening a connection and calling getInputStream().
The result of missing URLs for the root of nested jars and directories
is that classpath scanning that scans from the root (not a good idea
for performance reasons, but something that we should support) would
not find entries in /BOOT-INF/classes or in jars in /BOOT-INF/lib.
This commit updates our JarURLConnection so that it no longer throws
an IOException when asked for an InputStream for the root of a nested
entry (directory or jar).
Fixes gh-7003
This commit is contained in:
parent
57d5a2ebc6
commit
cdcc3d2f28
|
|
@ -371,6 +371,10 @@ public class JarFile extends java.util.jar.JarFile {
|
|||
return this.pathFromRoot;
|
||||
}
|
||||
|
||||
JarFileType getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a {@literal 'java.protocol.handler.pkgs'} property so that a
|
||||
* {@link URLStreamHandler} will be located to deal with jar URLs.
|
||||
|
|
@ -396,7 +400,10 @@ public class JarFile extends java.util.jar.JarFile {
|
|||
}
|
||||
}
|
||||
|
||||
private enum JarFileType {
|
||||
/**
|
||||
* The type of a {@link JarFile}.
|
||||
*/
|
||||
enum JarFileType {
|
||||
DIRECT, NESTED_DIRECTORY, NESTED_JAR
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ import java.net.URLEncoder;
|
|||
import java.net.URLStreamHandler;
|
||||
import java.security.Permission;
|
||||
|
||||
import org.springframework.boot.loader.data.RandomAccessData.ResourceAccess;
|
||||
|
||||
/**
|
||||
* {@link java.net.JarURLConnection} used to support {@link JarFile#getUrl()}.
|
||||
*
|
||||
|
|
@ -160,11 +162,14 @@ final class JarURLConnection extends java.net.JarURLConnection {
|
|||
if (this.jarFile == null) {
|
||||
throw FILE_NOT_FOUND_EXCEPTION;
|
||||
}
|
||||
if (this.jarEntryName.isEmpty()) {
|
||||
if (this.jarEntryName.isEmpty()
|
||||
&& this.jarFile.getType() == JarFile.JarFileType.DIRECT) {
|
||||
throw new IOException("no entry name specified");
|
||||
}
|
||||
connect();
|
||||
InputStream inputStream = this.jarFile.getInputStream(this.jarEntry);
|
||||
InputStream inputStream = (this.jarEntryName.isEmpty()
|
||||
? this.jarFile.getData().getInputStream(ResourceAccess.ONCE)
|
||||
: this.jarFile.getInputStream(this.jarEntry));
|
||||
if (inputStream == null) {
|
||||
throwFileNotFound(this.jarEntryName, this.jarFile);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import java.net.URLClassLoader;
|
|||
import java.nio.charset.Charset;
|
||||
import java.util.Enumeration;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarInputStream;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
|
|
@ -54,6 +55,7 @@ import static org.mockito.Mockito.verify;
|
|||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class JarFileTests {
|
||||
|
||||
private static final String PROTOCOL_HANDLER = "java.protocol.handler.pkgs";
|
||||
|
||||
private static final String HANDLERS_PACKAGE = "org.springframework.boot.loader";
|
||||
|
|
@ -270,6 +272,12 @@ public class JarFileTests {
|
|||
assertThat(conn.getJarFile()).isSameAs(nestedJarFile);
|
||||
assertThat(conn.getJarFileURL().toString())
|
||||
.isEqualTo("jar:" + this.rootJarFile.toURI() + "!/nested.jar");
|
||||
assertThat(conn.getInputStream()).isNotNull();
|
||||
JarInputStream jarInputStream = new JarInputStream(conn.getInputStream());
|
||||
assertThat(jarInputStream.getNextJarEntry().getName()).isEqualTo("3.dat");
|
||||
assertThat(jarInputStream.getNextJarEntry().getName()).isEqualTo("4.dat");
|
||||
assertThat(jarInputStream.getNextJarEntry().getName()).isEqualTo("\u00E4.dat");
|
||||
jarInputStream.close();
|
||||
assertThat(conn.getPermission()).isInstanceOf(FilePermission.class);
|
||||
FilePermission permission = (FilePermission) conn.getPermission();
|
||||
assertThat(permission.getActions()).isEqualTo("read");
|
||||
|
|
|
|||
Loading…
Reference in New Issue