Commit a5cddf79 authored by Phillip Webb's avatar Phillip Webb

Reduce JarURLConnection allocations

Update JarURLConnection & Handler so that a shared static final
connection is returned for entries that cannot be found.

See gh-6215
parent 44b7f29e
...@@ -65,7 +65,7 @@ final class CentralDirectoryFileHeader implements FileHeader { ...@@ -65,7 +65,7 @@ final class CentralDirectoryFileHeader implements FileHeader {
} }
void load(byte[] data, int dataOffset, RandomAccessData variableData, void load(byte[] data, int dataOffset, RandomAccessData variableData,
int variableOffset) throws IOException { int variableOffset, JarEntryFilter filter) throws IOException {
// Load fixed part // Load fixed part
this.header = data; this.header = data;
this.headerOffset = dataOffset; this.headerOffset = dataOffset;
...@@ -81,6 +81,9 @@ final class CentralDirectoryFileHeader implements FileHeader { ...@@ -81,6 +81,9 @@ final class CentralDirectoryFileHeader implements FileHeader {
dataOffset = 0; dataOffset = 0;
} }
this.name = new AsciiBytes(data, dataOffset, (int) nameLength); this.name = new AsciiBytes(data, dataOffset, (int) nameLength);
if (filter != null) {
this.name = filter.apply(this.name);
}
this.extra = NO_EXTRA; this.extra = NO_EXTRA;
this.comment = NO_COMMENT; this.comment = NO_COMMENT;
if (extraLength > 0) { if (extraLength > 0) {
...@@ -172,10 +175,10 @@ final class CentralDirectoryFileHeader implements FileHeader { ...@@ -172,10 +175,10 @@ final class CentralDirectoryFileHeader implements FileHeader {
} }
public static CentralDirectoryFileHeader fromRandomAccessData(RandomAccessData data, public static CentralDirectoryFileHeader fromRandomAccessData(RandomAccessData data,
int offset) throws IOException { int offset, JarEntryFilter filter) throws IOException {
CentralDirectoryFileHeader fileHeader = new CentralDirectoryFileHeader(); CentralDirectoryFileHeader fileHeader = new CentralDirectoryFileHeader();
byte[] bytes = Bytes.get(data.getSubsection(offset, 46)); byte[] bytes = Bytes.get(data.getSubsection(offset, 46));
fileHeader.load(bytes, 0, data, offset); fileHeader.load(bytes, 0, data, offset, filter);
return fileHeader; return fileHeader;
} }
......
...@@ -65,7 +65,7 @@ class CentralDirectoryParser { ...@@ -65,7 +65,7 @@ class CentralDirectoryParser {
CentralDirectoryFileHeader fileHeader = new CentralDirectoryFileHeader(); CentralDirectoryFileHeader fileHeader = new CentralDirectoryFileHeader();
int dataOffset = 0; int dataOffset = 0;
for (int i = 0; i < endRecord.getNumberOfRecords(); i++) { for (int i = 0; i < endRecord.getNumberOfRecords(); i++) {
fileHeader.load(bytes, dataOffset, null, 0); fileHeader.load(bytes, dataOffset, null, 0, null);
visitFileHeader(dataOffset, fileHeader); visitFileHeader(dataOffset, fileHeader);
dataOffset += this.CENTRAL_DIRECTORY_HEADER_BASE_SIZE dataOffset += this.CENTRAL_DIRECTORY_HEADER_BASE_SIZE
+ fileHeader.getName().length() + fileHeader.getComment().length() + fileHeader.getName().length() + fileHeader.getComment().length()
......
/* /*
* Copyright 2012-2015 the original author or authors. * Copyright 2012-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -85,10 +85,10 @@ public class Handler extends URLStreamHandler { ...@@ -85,10 +85,10 @@ public class Handler extends URLStreamHandler {
@Override @Override
protected URLConnection openConnection(URL url) throws IOException { protected URLConnection openConnection(URL url) throws IOException {
if (this.jarFile != null) { if (this.jarFile != null) {
return new JarURLConnection(url, this.jarFile); return JarURLConnection.get(url, this.jarFile);
} }
try { try {
return new JarURLConnection(url, getRootJarFileFromUrl(url)); return JarURLConnection.get(url, getRootJarFileFromUrl(url));
} }
catch (Exception ex) { catch (Exception ex) {
return openFallbackConnection(url, ex); return openFallbackConnection(url, ex);
......
...@@ -39,8 +39,8 @@ class JarEntry extends java.util.jar.JarEntry implements FileHeader { ...@@ -39,8 +39,8 @@ class JarEntry extends java.util.jar.JarEntry implements FileHeader {
private long localHeaderOffset; private long localHeaderOffset;
JarEntry(JarFile jarFile, String name, CentralDirectoryFileHeader header) { JarEntry(JarFile jarFile, CentralDirectoryFileHeader header) {
super(name); super(header.getName().toString());
this.jarFile = jarFile; this.jarFile = jarFile;
this.localHeaderOffset = header.getLocalHeaderOffset(); this.localHeaderOffset = header.getLocalHeaderOffset();
setCompressedSize(header.getCompressedSize()); setCompressedSize(header.getCompressedSize());
......
...@@ -200,6 +200,10 @@ public class JarFile extends java.util.jar.JarFile { ...@@ -200,6 +200,10 @@ public class JarFile extends java.util.jar.JarFile {
return (JarEntry) getEntry(name); return (JarEntry) getEntry(name);
} }
public boolean containsEntry(String name) {
return this.entries.containsEntry(name);
}
@Override @Override
public ZipEntry getEntry(String name) { public ZipEntry getEntry(String name) {
return this.entries.getEntry(name); return this.entries.getEntry(name);
...@@ -320,8 +324,7 @@ public class JarFile extends java.util.jar.JarFile { ...@@ -320,8 +324,7 @@ public class JarFile extends java.util.jar.JarFile {
@Override @Override
public String getName() { public String getName() {
String path = this.pathFromRoot; return this.rootFile.getFile() + this.pathFromRoot;
return this.rootFile.getFile() + path;
} }
boolean isSigned() { boolean isSigned() {
......
...@@ -66,11 +66,12 @@ class JarFileEntries implements CentralDirectoryVisitor, Iterable<JarEntry> { ...@@ -66,11 +66,12 @@ class JarFileEntries implements CentralDirectoryVisitor, Iterable<JarEntry> {
private int[] positions; private int[] positions;
private final Map<Integer, JarEntry> entriesCache = Collections private final Map<Integer, FileHeader> entriesCache = Collections
.synchronizedMap(new LinkedHashMap<Integer, JarEntry>(16, 0.75f, true) { .synchronizedMap(new LinkedHashMap<Integer, FileHeader>(16, 0.75f, true) {
@Override @Override
protected boolean removeEldestEntry(Map.Entry<Integer, JarEntry> eldest) { protected boolean removeEldestEntry(
Map.Entry<Integer, FileHeader> eldest) {
if (JarFileEntries.this.jarFile.isSigned()) { if (JarFileEntries.this.jarFile.isSigned()) {
return false; return false;
} }
...@@ -165,6 +166,10 @@ class JarFileEntries implements CentralDirectoryVisitor, Iterable<JarEntry> { ...@@ -165,6 +166,10 @@ class JarFileEntries implements CentralDirectoryVisitor, Iterable<JarEntry> {
return new EntryIterator(); return new EntryIterator();
} }
public boolean containsEntry(String name) {
return getEntry(name, FileHeader.class, true) != null;
}
public JarEntry getEntry(String name) { public JarEntry getEntry(String name) {
return getEntry(name, JarEntry.class, true); return getEntry(name, JarEntry.class, true);
} }
...@@ -235,21 +240,17 @@ class JarFileEntries implements CentralDirectoryVisitor, Iterable<JarEntry> { ...@@ -235,21 +240,17 @@ class JarFileEntries implements CentralDirectoryVisitor, Iterable<JarEntry> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private <T extends FileHeader> T getEntry(int index, Class<T> type, private <T extends FileHeader> T getEntry(int index, Class<T> type,
boolean cacheEntry) { boolean cacheEntry) {
JarEntry entry = this.entriesCache.get(index);
if (entry != null) {
return (T) entry;
}
try { try {
CentralDirectoryFileHeader header = CentralDirectoryFileHeader FileHeader cached = this.entriesCache.get(index);
.fromRandomAccessData(this.centralDirectoryData, FileHeader entry = (cached != null ? cached
this.centralDirectoryOffsets[index]); : CentralDirectoryFileHeader.fromRandomAccessData(
if (FileHeader.class.equals(type)) { this.centralDirectoryData,
// No need to convert this.centralDirectoryOffsets[index], this.filter));
return (T) header; if (CentralDirectoryFileHeader.class.equals(entry.getClass())
&& type.equals(JarEntry.class)) {
entry = new JarEntry(this.jarFile, (CentralDirectoryFileHeader) entry);
} }
entry = new JarEntry(this.jarFile, applyFilter(header.getName()).toString(), if (cacheEntry && cached != entry) {
header);
if (cacheEntry) {
this.entriesCache.put(index, entry); this.entriesCache.put(index, entry);
} }
return (T) entry; return (T) entry;
......
...@@ -35,9 +35,15 @@ import java.security.Permission; ...@@ -35,9 +35,15 @@ import java.security.Permission;
* @author Phillip Webb * @author Phillip Webb
* @author Andy Wilkinson * @author Andy Wilkinson
*/ */
class JarURLConnection extends java.net.JarURLConnection { final class JarURLConnection extends java.net.JarURLConnection {
private static final FileNotFoundException FILE_NOT_FOUND_EXCEPTION = new FileNotFoundException(); private static ThreadLocal<Boolean> useFastExceptions = new ThreadLocal<Boolean>();
private static final FileNotFoundException FILE_NOT_FOUND_EXCEPTION = new FileNotFoundException(
"Jar file or entry not found");
private static final IllegalStateException NOT_FOUND_CONNECTION_EXCEPTION = new IllegalStateException(
FILE_NOT_FOUND_EXCEPTION);
private static final String SEPARATOR = "!/"; private static final String SEPARATOR = "!/";
...@@ -63,7 +69,8 @@ class JarURLConnection extends java.net.JarURLConnection { ...@@ -63,7 +69,8 @@ class JarURLConnection extends java.net.JarURLConnection {
private static final String READ_ACTION = "read"; private static final String READ_ACTION = "read";
private static ThreadLocal<Boolean> useFastExceptions = new ThreadLocal<Boolean>(); private static final JarURLConnection NOT_FOUND_CONNECTION = JarURLConnection
.notFound();
private final JarFile jarFile; private final JarFile jarFile;
...@@ -75,48 +82,20 @@ class JarURLConnection extends java.net.JarURLConnection { ...@@ -75,48 +82,20 @@ class JarURLConnection extends java.net.JarURLConnection {
private JarEntry jarEntry; private JarEntry jarEntry;
protected JarURLConnection(URL url, JarFile jarFile) throws IOException { private JarURLConnection(URL url, JarFile jarFile, JarEntryName jarEntryName)
throws IOException {
// What we pass to super is ultimately ignored // What we pass to super is ultimately ignored
super(EMPTY_JAR_URL); super(EMPTY_JAR_URL);
this.url = url; this.url = url;
String spec = extractFullSpec(url, jarFile.getPathFromRoot());
int separator;
int index = 0;
while ((separator = spec.indexOf(SEPARATOR, index)) > 0) {
jarFile = getNestedJarFile(jarFile, spec.substring(index, separator));
index += separator + SEPARATOR.length();
}
this.jarFile = jarFile; this.jarFile = jarFile;
this.jarEntryName = getJarEntryName(spec.substring(index)); this.jarEntryName = jarEntryName;
}
private String extractFullSpec(URL url, String pathFromRoot) {
String file = url.getFile();
int separatorIndex = file.indexOf(SEPARATOR);
if (separatorIndex < 0) {
return "";
}
int specIndex = separatorIndex + SEPARATOR.length() + pathFromRoot.length();
return file.substring(specIndex);
}
private JarFile getNestedJarFile(JarFile jarFile, String name) throws IOException {
JarEntry jarEntry = jarFile.getJarEntry(name);
if (jarEntry == null) {
throwFileNotFound(jarEntry, jarFile);
}
return jarFile.getNestedJarFile(jarEntry);
}
private JarEntryName getJarEntryName(String spec) {
if (spec.length() == 0) {
return EMPTY_JAR_ENTRY_NAME;
}
return new JarEntryName(spec);
} }
@Override @Override
public void connect() throws IOException { public void connect() throws IOException {
if (this.jarFile == null) {
throw FILE_NOT_FOUND_EXCEPTION;
}
if (!this.jarEntryName.isEmpty() && this.jarEntry == null) { if (!this.jarEntryName.isEmpty() && this.jarEntry == null) {
this.jarEntry = this.jarFile.getJarEntry(getEntryName()); this.jarEntry = this.jarFile.getJarEntry(getEntryName());
if (this.jarEntry == null) { if (this.jarEntry == null) {
...@@ -126,15 +105,6 @@ class JarURLConnection extends java.net.JarURLConnection { ...@@ -126,15 +105,6 @@ class JarURLConnection extends java.net.JarURLConnection {
this.connected = true; this.connected = true;
} }
private void throwFileNotFound(Object entry, JarFile jarFile)
throws FileNotFoundException {
if (Boolean.TRUE.equals(useFastExceptions.get())) {
throw FILE_NOT_FOUND_EXCEPTION;
}
throw new FileNotFoundException(
"JAR entry " + entry + " not found in " + jarFile.getName());
}
@Override @Override
public JarFile getJarFile() throws IOException { public JarFile getJarFile() throws IOException {
connect(); connect();
...@@ -143,6 +113,9 @@ class JarURLConnection extends java.net.JarURLConnection { ...@@ -143,6 +113,9 @@ class JarURLConnection extends java.net.JarURLConnection {
@Override @Override
public URL getJarFileURL() { public URL getJarFileURL() {
if (this.jarFile == null) {
throw NOT_FOUND_CONNECTION_EXCEPTION;
}
if (this.jarFileUrl == null) { if (this.jarFileUrl == null) {
this.jarFileUrl = buildJarFileUrl(); this.jarFileUrl = buildJarFileUrl();
} }
...@@ -167,7 +140,7 @@ class JarURLConnection extends java.net.JarURLConnection { ...@@ -167,7 +140,7 @@ class JarURLConnection extends java.net.JarURLConnection {
@Override @Override
public JarEntry getJarEntry() throws IOException { public JarEntry getJarEntry() throws IOException {
if (this.jarEntryName.isEmpty()) { if (this.jarEntryName == null || this.jarEntryName.isEmpty()) {
return null; return null;
} }
connect(); connect();
...@@ -176,11 +149,17 @@ class JarURLConnection extends java.net.JarURLConnection { ...@@ -176,11 +149,17 @@ class JarURLConnection extends java.net.JarURLConnection {
@Override @Override
public String getEntryName() { public String getEntryName() {
if (this.jarFile == null) {
throw NOT_FOUND_CONNECTION_EXCEPTION;
}
return this.jarEntryName.toString(); return this.jarEntryName.toString();
} }
@Override @Override
public InputStream getInputStream() throws IOException { public InputStream getInputStream() throws IOException {
if (this.jarFile == null) {
throw FILE_NOT_FOUND_EXCEPTION;
}
if (this.jarEntryName.isEmpty()) { if (this.jarEntryName.isEmpty()) {
throw new IOException("no entry name specified"); throw new IOException("no entry name specified");
} }
...@@ -192,8 +171,20 @@ class JarURLConnection extends java.net.JarURLConnection { ...@@ -192,8 +171,20 @@ class JarURLConnection extends java.net.JarURLConnection {
return inputStream; return inputStream;
} }
private void throwFileNotFound(Object entry, JarFile jarFile)
throws FileNotFoundException {
if (Boolean.TRUE.equals(useFastExceptions.get())) {
throw FILE_NOT_FOUND_EXCEPTION;
}
throw new FileNotFoundException(
"JAR entry " + entry + " not found in " + jarFile.getName());
}
@Override @Override
public int getContentLength() { public int getContentLength() {
if (this.jarFile == null) {
return -1;
}
try { try {
if (this.jarEntryName.isEmpty()) { if (this.jarEntryName.isEmpty()) {
return this.jarFile.size(); return this.jarFile.size();
...@@ -214,11 +205,14 @@ class JarURLConnection extends java.net.JarURLConnection { ...@@ -214,11 +205,14 @@ class JarURLConnection extends java.net.JarURLConnection {
@Override @Override
public String getContentType() { public String getContentType() {
return this.jarEntryName.getContentType(); return (this.jarEntryName == null ? null : this.jarEntryName.getContentType());
} }
@Override @Override
public Permission getPermission() throws IOException { public Permission getPermission() throws IOException {
if (this.jarFile == null) {
throw FILE_NOT_FOUND_EXCEPTION;
}
if (this.permission == null) { if (this.permission == null) {
this.permission = new FilePermission( this.permission = new FilePermission(
this.jarFile.getRootJarFile().getFile().getPath(), READ_ACTION); this.jarFile.getRootJarFile().getFile().getPath(), READ_ACTION);
...@@ -230,6 +224,56 @@ class JarURLConnection extends java.net.JarURLConnection { ...@@ -230,6 +224,56 @@ class JarURLConnection extends java.net.JarURLConnection {
JarURLConnection.useFastExceptions.set(useFastExceptions); JarURLConnection.useFastExceptions.set(useFastExceptions);
} }
static JarURLConnection get(URL url, JarFile jarFile) throws IOException {
String spec = extractFullSpec(url, jarFile.getPathFromRoot());
int separator;
int index = 0;
while ((separator = spec.indexOf(SEPARATOR, index)) > 0) {
String entryName = spec.substring(index, separator);
JarEntry jarEntry = jarFile.getJarEntry(entryName);
if (jarEntry == null) {
return JarURLConnection.notFound(jarFile, JarEntryName.get(entryName));
}
jarFile = jarFile.getNestedJarFile(jarEntry);
index += separator + SEPARATOR.length();
}
JarEntryName jarEntryName = JarEntryName.get(spec, index);
if (Boolean.TRUE.equals(useFastExceptions.get())) {
if (!jarEntryName.isEmpty()
&& !jarFile.containsEntry(jarEntryName.toString())) {
return NOT_FOUND_CONNECTION;
}
}
return new JarURLConnection(url, jarFile, jarEntryName);
}
private static String extractFullSpec(URL url, String pathFromRoot) {
String file = url.getFile();
int separatorIndex = file.indexOf(SEPARATOR);
if (separatorIndex < 0) {
return "";
}
int specIndex = separatorIndex + SEPARATOR.length() + pathFromRoot.length();
return file.substring(specIndex);
}
private static JarURLConnection notFound() {
try {
return notFound(null, null);
}
catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
private static JarURLConnection notFound(JarFile jarFile, JarEntryName jarEntryName)
throws IOException {
if (Boolean.TRUE.equals(useFastExceptions.get())) {
return NOT_FOUND_CONNECTION;
}
return new JarURLConnection(null, jarFile, jarEntryName);
}
/** /**
* A JarEntryName parsed from a URL String. * A JarEntryName parsed from a URL String.
*/ */
...@@ -316,6 +360,17 @@ class JarURLConnection extends java.net.JarURLConnection { ...@@ -316,6 +360,17 @@ class JarURLConnection extends java.net.JarURLConnection {
return type; return type;
} }
public static JarEntryName get(String spec) {
return get(spec, 0);
}
public static JarEntryName get(String spec, int beginIndex) {
if (spec.length() <= beginIndex) {
return EMPTY_JAR_ENTRY_NAME;
}
return new JarEntryName(spec.substring(beginIndex));
}
} }
} }
...@@ -18,11 +18,13 @@ package org.springframework.boot.loader.jar; ...@@ -18,11 +18,13 @@ package org.springframework.boot.loader.jar;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException;
import java.net.URL; import java.net.URL;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder; import org.junit.rules.TemporaryFolder;
import org.springframework.boot.loader.TestJarCreator; import org.springframework.boot.loader.TestJarCreator;
...@@ -33,12 +35,16 @@ import static org.assertj.core.api.Assertions.assertThat; ...@@ -33,12 +35,16 @@ import static org.assertj.core.api.Assertions.assertThat;
* Tests for {@link JarURLConnection}. * Tests for {@link JarURLConnection}.
* *
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Phillip Webb
*/ */
public class JarURLConnectionTests { public class JarURLConnectionTests {
@Rule @Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder(new File("target")); public TemporaryFolder temporaryFolder = new TemporaryFolder(new File("target"));
@Rule
public ExpectedException thrown = ExpectedException.none();
private File rootJarFile; private File rootJarFile;
private JarFile jarFile; private JarFile jarFile;
...@@ -52,76 +58,84 @@ public class JarURLConnectionTests { ...@@ -52,76 +58,84 @@ public class JarURLConnectionTests {
@Test @Test
public void connectionToRootUsingAbsoluteUrl() throws Exception { public void connectionToRootUsingAbsoluteUrl() throws Exception {
URL absoluteUrl = new URL("jar:file:" + getAbsolutePath() + "!/"); URL url = new URL("jar:file:" + getAbsolutePath() + "!/");
assertThat(new JarURLConnection(absoluteUrl, this.jarFile).getContent()) assertThat(JarURLConnection.get(url, this.jarFile).getContent())
.isSameAs(this.jarFile); .isSameAs(this.jarFile);
} }
@Test @Test
public void connectionToRootUsingRelativeUrl() throws Exception { public void connectionToRootUsingRelativeUrl() throws Exception {
URL relativeUrl = new URL("jar:file:" + getRelativePath() + "!/"); URL url = new URL("jar:file:" + getRelativePath() + "!/");
assertThat(new JarURLConnection(relativeUrl, this.jarFile).getContent()) assertThat(JarURLConnection.get(url, this.jarFile).getContent())
.isSameAs(this.jarFile); .isSameAs(this.jarFile);
} }
@Test @Test
public void connectionToEntryUsingAbsoluteUrl() throws Exception { public void connectionToEntryUsingAbsoluteUrl() throws Exception {
URL absoluteUrl = new URL("jar:file:" + getAbsolutePath() + "!/1.dat"); URL url = new URL("jar:file:" + getAbsolutePath() + "!/1.dat");
assertThat(new JarURLConnection(absoluteUrl, this.jarFile).getInputStream()) assertThat(JarURLConnection.get(url, this.jarFile).getInputStream())
.hasSameContentAs(new ByteArrayInputStream(new byte[] { 1 })); .hasSameContentAs(new ByteArrayInputStream(new byte[] { 1 }));
} }
@Test @Test
public void connectionToEntryUsingRelativeUrl() throws Exception { public void connectionToEntryUsingRelativeUrl() throws Exception {
URL relativeUrl = new URL("jar:file:" + getRelativePath() + "!/1.dat"); URL url = new URL("jar:file:" + getRelativePath() + "!/1.dat");
assertThat(new JarURLConnection(relativeUrl, this.jarFile).getInputStream()) assertThat(JarURLConnection.get(url, this.jarFile).getInputStream())
.hasSameContentAs(new ByteArrayInputStream(new byte[] { 1 })); .hasSameContentAs(new ByteArrayInputStream(new byte[] { 1 }));
} }
@Test @Test
public void connectionToEntryUsingAbsoluteUrlWithFileColonSlashSlashPrefix() public void connectionToEntryUsingAbsoluteUrlWithFileColonSlashSlashPrefix()
throws Exception { throws Exception {
URL absoluteUrl = new URL("jar:file:/" + getAbsolutePath() + "!/1.dat"); URL url = new URL("jar:file:/" + getAbsolutePath() + "!/1.dat");
assertThat(new JarURLConnection(absoluteUrl, this.jarFile).getInputStream()) assertThat(JarURLConnection.get(url, this.jarFile).getInputStream())
.hasSameContentAs(new ByteArrayInputStream(new byte[] { 1 })); .hasSameContentAs(new ByteArrayInputStream(new byte[] { 1 }));
} }
@Test @Test
public void connectionToEntryUsingAbsoluteUrlForNestedEntry() throws Exception { public void connectionToEntryUsingAbsoluteUrlForNestedEntry() throws Exception {
URL absoluteUrl = new URL( URL url = new URL("jar:file:" + getAbsolutePath() + "!/nested.jar!/3.dat");
"jar:file:" + getAbsolutePath() + "!/nested.jar!/3.dat"); assertThat(JarURLConnection.get(url, this.jarFile).getInputStream())
assertThat(new JarURLConnection(absoluteUrl, this.jarFile).getInputStream())
.hasSameContentAs(new ByteArrayInputStream(new byte[] { 3 })); .hasSameContentAs(new ByteArrayInputStream(new byte[] { 3 }));
} }
@Test @Test
public void connectionToEntryUsingRelativeUrlForNestedEntry() throws Exception { public void connectionToEntryUsingRelativeUrlForNestedEntry() throws Exception {
URL relativeUrl = new URL( URL url = new URL("jar:file:" + getRelativePath() + "!/nested.jar!/3.dat");
"jar:file:" + getRelativePath() + "!/nested.jar!/3.dat"); assertThat(JarURLConnection.get(url, this.jarFile).getInputStream())
assertThat(new JarURLConnection(relativeUrl, this.jarFile).getInputStream())
.hasSameContentAs(new ByteArrayInputStream(new byte[] { 3 })); .hasSameContentAs(new ByteArrayInputStream(new byte[] { 3 }));
} }
@Test @Test
public void connectionToEntryUsingAbsoluteUrlForEntryFromNestedJarFile() public void connectionToEntryUsingAbsoluteUrlForEntryFromNestedJarFile()
throws Exception { throws Exception {
URL absoluteUrl = new URL( URL url = new URL("jar:file:" + getAbsolutePath() + "!/nested.jar!/3.dat");
"jar:file:" + getAbsolutePath() + "!/nested.jar!/3.dat"); JarFile nested = this.jarFile
assertThat(new JarURLConnection(absoluteUrl, .getNestedJarFile(this.jarFile.getEntry("nested.jar"));
this.jarFile.getNestedJarFile(this.jarFile.getEntry("nested.jar"))) assertThat(JarURLConnection.get(url, nested).getInputStream())
.getInputStream()).hasSameContentAs( .hasSameContentAs(new ByteArrayInputStream(new byte[] { 3 }));
new ByteArrayInputStream(new byte[] { 3 }));
} }
@Test @Test
public void connectionToEntryUsingRelativeUrlForEntryFromNestedJarFile() public void connectionToEntryUsingRelativeUrlForEntryFromNestedJarFile()
throws Exception { throws Exception {
URL absoluteUrl = new URL( URL url = new URL("jar:file:" + getRelativePath() + "!/nested.jar!/3.dat");
"jar:file:" + getRelativePath() + "!/nested.jar!/3.dat"); JarFile nested = this.jarFile
assertThat(new JarURLConnection(absoluteUrl, .getNestedJarFile(this.jarFile.getEntry("nested.jar"));
this.jarFile.getNestedJarFile(this.jarFile.getEntry("nested.jar"))) assertThat(JarURLConnection.get(url, nested).getInputStream())
.getInputStream()).hasSameContentAs( .hasSameContentAs(new ByteArrayInputStream(new byte[] { 3 }));
new ByteArrayInputStream(new byte[] { 3 })); }
@Test
public void nestedJarNotFound() throws Exception {
URL url = new URL(
"jar:file:" + getAbsolutePath() + "!/nested.jar!/missing.jar!/1.dat");
JarFile nested = this.jarFile
.getNestedJarFile(this.jarFile.getEntry("nested.jar"));
JarURLConnection connection = JarURLConnection.get(url, nested);
this.thrown.expect(FileNotFoundException.class);
this.thrown.expectMessage("JAR entry missing.jar not found in");
connection.connect();
} }
private String getAbsolutePath() { private String getAbsolutePath() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment