From e9aab1e90cfaa493f0a6b7e9a9ae6b3425762661 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 17 Jun 2014 21:14:00 -0700 Subject: [PATCH 1/5] Drop JarEntryFilters from constructor and methods Drop JarEntryFilter arguments from the JarFile constructor and the getNestedJarFile methods. Filtered JarFiles can still be obtained by using the getFilteredJarFile() method. This helps simplify the code a little and will make it easier to add caching. See gh-1119 --- .../boot/loader/jar/JarFile.java | 51 ++++++++----------- 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java index 0e2ff7cbd2..739e6b8051 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java @@ -43,15 +43,12 @@ import org.springframework.boot.loader.util.AsciiBytes; * Extended variant of {@link java.util.jar.JarFile} that behaves in the same way but * offers the following additional functionality. * * @@ -90,21 +87,19 @@ public class JarFile extends java.util.jar.JarFile implements Iterable Date: Fri, 20 Jun 2014 08:54:04 -0700 Subject: [PATCH 2/5] Reuse previously parsed entries for filtered JARs Update JarFile to reuse the previously parsed entries when creating filtered jars. This saves needing to re-scan the underlying file to recreate a subset of entries. See gh-1119 --- .../boot/loader/jar/JarEntryData.java | 16 +++- .../boot/loader/jar/JarFile.java | 78 +++++++++++-------- 2 files changed, 60 insertions(+), 34 deletions(-) diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarEntryData.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarEntryData.java index cdf7559273..cce9f96d7a 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarEntryData.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarEntryData.java @@ -55,20 +55,26 @@ public final class JarEntryData { public JarEntryData(JarFile source, byte[] header, InputStream inputStream) throws IOException { - this.source = source; this.header = header; long nameLength = Bytes.littleEndianValue(header, 28, 2); long extraLength = Bytes.littleEndianValue(header, 30, 2); long commentLength = Bytes.littleEndianValue(header, 32, 2); - this.name = new AsciiBytes(Bytes.get(inputStream, nameLength)); this.extra = Bytes.get(inputStream, extraLength); this.comment = new AsciiBytes(Bytes.get(inputStream, commentLength)); - this.localHeaderOffset = Bytes.littleEndianValue(header, 42, 4); } + private JarEntryData(JarEntryData master, JarFile source, AsciiBytes name) { + this.header = master.header; + this.extra = master.extra; + this.comment = master.comment; + this.localHeaderOffset = master.localHeaderOffset; + this.source = source; + this.name = name; + } + void setName(AsciiBytes name) { this.name = name; } @@ -154,6 +160,10 @@ public final class JarEntryData { return this.comment; } + JarEntryData createFilteredCopy(JarFile jarFile, AsciiBytes name) { + return new JarEntryData(this, jarFile, name); + } + /** * Create a new {@link JarEntryData} instance from the specified input stream. * @param source the source {@link JarFile} diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java index 739e6b8051..e1d917a30f 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java @@ -68,18 +68,16 @@ public class JarFile extends java.util.jar.JarFile implements Iterable entries; + private final List entries; private SoftReference> entriesByName; + private boolean signed; + private JarEntryData manifestEntry; private SoftReference manifest; @@ -108,18 +106,25 @@ public class JarFile extends java.util.jar.JarFile implements Iterable entries, JarEntryFilter... filters) throws IOException { + super(rootFile.getFile()); + this.rootFile = rootFile; + this.name = name; + this.data = data; + this.entries = filterEntries(entries, filters); } private RandomAccessData getArchiveData(CentralDirectoryEndRecord endRecord, @@ -131,35 +136,47 @@ public class JarFile extends java.util.jar.JarFile implements Iterable loadJarEntries(CentralDirectoryEndRecord endRecord) + throws IOException { RandomAccessData centralDirectory = endRecord.getCentralDirectory(this.data); int numberOfRecords = endRecord.getNumberOfRecords(); - this.entries = new ArrayList(numberOfRecords); + List entries = new ArrayList(numberOfRecords); InputStream inputStream = centralDirectory.getInputStream(ResourceAccess.ONCE); try { JarEntryData entry = JarEntryData.fromInputStream(this, inputStream); while (entry != null) { - addJarEntry(entry, filters); + entries.add(entry); + processEntry(entry); entry = JarEntryData.fromInputStream(this, inputStream); } } finally { inputStream.close(); } + return entries; } - private void addJarEntry(JarEntryData entry, JarEntryFilter[] filters) { - AsciiBytes name = entry.getName(); - for (JarEntryFilter filter : filters) { - name = (filter == null || name == null ? name : filter.apply(name, entry)); - } - if (name != null) { - entry.setName(name); - this.entries.add(entry); - if (name.startsWith(META_INF)) { - processMetaInfEntry(name, entry); + private List filterEntries(List entries, + JarEntryFilter[] filters) { + List filteredEntries = new ArrayList(entries.size()); + for (JarEntryData entry : entries) { + AsciiBytes name = entry.getName(); + for (JarEntryFilter filter : filters) { + name = (filter == null || name == null ? name : filter.apply(name, entry)); } + if (name != null) { + JarEntryData filteredCopy = entry.createFilteredCopy(this, name); + filteredEntries.add(filteredCopy); + processEntry(filteredCopy); + } + } + return filteredEntries; + } + + private void processEntry(JarEntryData entry) { + AsciiBytes name = entry.getName(); + if (name.startsWith(META_INF)) { + processMetaInfEntry(name, entry); } } @@ -322,8 +339,7 @@ public class JarFile extends java.util.jar.JarFile implements Iterable Date: Fri, 20 Jun 2014 09:20:55 -0700 Subject: [PATCH 3/5] Add JarFile caching Cache root jar files in the Handler and also store nested jar files in the JarEntryData. See gh-1119 --- .../boot/loader/jar/Handler.java | 32 ++++++++++++++++++- .../boot/loader/jar/JarEntryData.java | 2 ++ .../boot/loader/jar/JarFile.java | 19 +++++++---- 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/Handler.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/Handler.java index 5f91138d92..fcc4b3d946 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/Handler.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/Handler.java @@ -18,11 +18,14 @@ package org.springframework.boot.loader.jar; import java.io.File; import java.io.IOException; +import java.lang.ref.SoftReference; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import java.util.logging.Logger; @@ -55,6 +58,11 @@ public class Handler extends URLStreamHandler { OPEN_CONNECTION_METHOD = method; } + private static SoftReference> rootFileCache; + static { + rootFileCache = new SoftReference>(null); + } + private final Logger logger = Logger.getLogger(getClass().getName()); private final JarFile jarFile; @@ -153,7 +161,14 @@ public class Handler extends URLStreamHandler { throw new IllegalStateException("Not a file URL"); } String path = name.substring(FILE_PROTOCOL.length()); - return new JarFile(new File(path)); + File file = new File(path); + Map cache = rootFileCache.get(); + JarFile jarFile = (cache == null ? null : cache.get(file)); + if (jarFile == null) { + jarFile = new JarFile(file); + addToRootFileCache(file, jarFile); + } + return jarFile; } catch (Exception ex) { throw new IOException("Unable to open root Jar file '" + name + "'", ex); @@ -168,4 +183,19 @@ public class Handler extends URLStreamHandler { } return jarFile.getNestedJarFile(jarEntry); } + + /** + * Add the given {@link JarFile} to the root file cache. + * @param sourceFile the source file to add + * @param jarFile the jar file. + */ + static void addToRootFileCache(File sourceFile, JarFile jarFile) { + Map cache = rootFileCache.get(); + if (cache == null) { + cache = new ConcurrentHashMap(); + rootFileCache = new SoftReference>(cache); + } + cache.put(sourceFile, jarFile); + } + } diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarEntryData.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarEntryData.java index cce9f96d7a..1a336d93eb 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarEntryData.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarEntryData.java @@ -53,6 +53,8 @@ public final class JarEntryData { private SoftReference entry; + JarFile nestedJar; + public JarEntryData(JarFile source, byte[] header, InputStream inputStream) throws IOException { this.source = source; diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java index e1d917a30f..e52bc6c0f9 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java @@ -322,13 +322,13 @@ public class JarFile extends java.util.jar.JarFile implements Iterable Date: Fri, 20 Jun 2014 09:24:00 -0700 Subject: [PATCH 4/5] Improve performance of fat jar loading Tweak 'fat jar' handling to generally improve performance: - Allow JarURLConnection to throw a static FileNotFoundException when loading classes. This exception is thrown many times when attempting to load a class and is silently swallowed so there is no point in providing the entry name. - Expose JarFile.getJarEntryData(AsciiBytes) and store AsciiBytes in the JarURLConnection. Previously AsciiBytes were created, discarded then created again. - Use EMPTY_JAR_URL for the JarURLConnection super constructor. The URL is never actually used so we can improve performance by using a constant. - Extract JarEntryName for possible caching. The jar entry name extracted from the URL is now contained in an inner JarEntryName class. This could be cached if necessary (although currently it is not because no perceivable performance benefit was observed) Fixes gh-1119 --- .../boot/loader/LaunchedURLClassLoader.java | 11 +- .../boot/loader/jar/Handler.java | 12 +- .../boot/loader/jar/JarFile.java | 15 +- .../boot/loader/jar/JarURLConnection.java | 205 ++++++++++++------ .../boot/loader/util/AsciiBytes.java | 7 + 5 files changed, 176 insertions(+), 74 deletions(-) diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/LaunchedURLClassLoader.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/LaunchedURLClassLoader.java index b840f22e90..e27f1bec33 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/LaunchedURLClassLoader.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/LaunchedURLClassLoader.java @@ -25,6 +25,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; +import org.springframework.boot.loader.jar.Handler; import org.springframework.boot.loader.jar.JarFile; /** @@ -93,7 +94,6 @@ public class LaunchedURLClassLoader extends URLClassLoader { @Override public Enumeration getResources(String name) throws IOException { - if (this.rootClassLoader == null) { return findResources(name); } @@ -116,6 +116,7 @@ public class LaunchedURLClassLoader extends URLClassLoader { } return localResources.nextElement(); } + }; } @@ -128,7 +129,13 @@ public class LaunchedURLClassLoader extends URLClassLoader { synchronized (this) { Class loadedClass = findLoadedClass(name); if (loadedClass == null) { - loadedClass = doLoadClass(name); + Handler.setUseFastConnectionExceptions(true); + try { + loadedClass = doLoadClass(name); + } + finally { + Handler.setUseFastConnectionExceptions(false); + } } if (resolve) { resolveClass(loadedClass); diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/Handler.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/Handler.java index fcc4b3d946..25569b2b5c 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/Handler.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/Handler.java @@ -42,7 +42,7 @@ public class Handler extends URLStreamHandler { private static final String FILE_PROTOCOL = "file:"; - private static final String SEPARATOR = JarURLConnection.SEPARATOR; + private static final String SEPARATOR = "!/"; private static final String[] FALLBACK_HANDLERS = { "sun.net.www.protocol.jar.Handler" }; @@ -198,4 +198,14 @@ public class Handler extends URLStreamHandler { cache.put(sourceFile, jarFile); } + /** + * Set if a generic static exception can be thrown when a URL cannot be connected. + * This optimization is used during class loading to save creating lots of exceptions + * which are then swallowed. + * @param useFastConnectionExceptions if fast connection exceptions can be used. + */ + public static void setUseFastConnectionExceptions(boolean useFastConnectionExceptions) { + JarURLConnection.setUseFastExceptions(useFastConnectionExceptions); + } + } diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java index e52bc6c0f9..600bde4203 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java @@ -66,6 +66,8 @@ public class JarFile extends java.util.jar.JarFile implements Iterable useFastExceptions = new ThreadLocal(); + + private final String jarFileUrlSpec; private final JarFile jarFile; private JarEntryData jarEntryData; - private String jarEntryName; - - private String contentType; - private URL jarFileUrl; + private JarEntryName jarEntryName; + protected JarURLConnection(URL url, JarFile jarFile) throws MalformedURLException { - super(new URL(buildRootUrl(jarFile))); + // What we pass to super is ultimately ignored + super(EMPTY_JAR_URL); this.url = url; this.jarFile = jarFile; - String spec = url.getFile(); int separator = spec.lastIndexOf(SEPARATOR); if (separator == -1) { throw new MalformedURLException("no " + SEPARATOR + " found in url spec:" + spec); } - if (separator + 2 != spec.length()) { - this.jarEntryName = decode(spec.substring(separator + 2)); - } + this.jarFileUrlSpec = spec.substring(0, separator); + this.jarEntryName = getJarEntryName(spec.substring(separator + 2)); + } - String container = spec.substring(0, separator); - if (container.indexOf(SEPARATOR) == -1) { - this.jarFileUrl = new URL(container); - } - else { - this.jarFileUrl = new URL("jar:" + container); + private JarEntryName getJarEntryName(String spec) { + if (spec.length() == 0) { + return EMPTY_JAR_ENTRY_NAME; } + return new JarEntryName(spec); } @Override public void connect() throws IOException { - if (this.jarEntryName != null) { - this.jarEntryData = this.jarFile.getJarEntryData(this.jarEntryName); + if (!this.jarEntryName.isEmpty()) { + this.jarEntryData = this.jarFile.getJarEntryData(this.jarEntryName + .asAsciiBytes()); if (this.jarEntryData == null) { + if (Boolean.TRUE.equals(useFastExceptions.get())) { + throw FILE_NOT_FOUND_EXCEPTION; + } throw new FileNotFoundException("JAR entry " + this.jarEntryName + " not found in " + this.jarFile.getName()); } @@ -103,9 +127,24 @@ class JarURLConnection extends java.net.JarURLConnection { @Override public URL getJarFileURL() { + if (this.jarFileUrl == null) { + this.jarFileUrl = buildJarFileUrl(); + } return this.jarFileUrl; } + private URL buildJarFileUrl() { + try { + if (this.jarFileUrlSpec.indexOf(SEPARATOR) == -1) { + return new URL(this.jarFileUrlSpec); + } + return new URL("jar:" + this.jarFileUrlSpec); + } + catch (MalformedURLException ex) { + throw new IllegalStateException(ex); + } + } + @Override public JarEntry getJarEntry() throws IOException { connect(); @@ -114,13 +153,13 @@ class JarURLConnection extends java.net.JarURLConnection { @Override public String getEntryName() { - return this.jarEntryName; + return this.jarEntryName.toString(); } @Override public InputStream getInputStream() throws IOException { connect(); - if (this.jarEntryName == null) { + if (this.jarEntryName.isEmpty()) { throw new IOException("no entry name specified"); } return this.jarEntryData.getInputStream(); @@ -130,8 +169,10 @@ class JarURLConnection extends java.net.JarURLConnection { public int getContentLength() { try { connect(); - return this.jarEntryData == null ? this.jarFile.size() : this.jarEntryData - .getSize(); + if (this.jarEntryData != null) { + return this.jarEntryData.getSize(); + } + return this.jarFile.size(); } catch (IOException ex) { return -1; @@ -146,58 +187,86 @@ class JarURLConnection extends java.net.JarURLConnection { @Override public String getContentType() { - if (this.contentType == null) { - // Guess the content type, don't bother with steams as mark is not - // supported - this.contentType = (this.jarEntryName == null ? "x-java/jar" : null); - this.contentType = (this.contentType == null ? guessContentTypeFromName(this.jarEntryName) - : this.contentType); - this.contentType = (this.contentType == null ? "content/unknown" - : this.contentType); - } - return this.contentType; + return this.jarEntryName.getContentType(); } - private static String buildRootUrl(JarFile jarFile) { - String path = jarFile.getRootJarFile().getFile().getPath(); - StringBuilder builder = new StringBuilder(PREFIX.length() + path.length() - + SEPARATOR.length()); - builder.append(PREFIX); - builder.append(path); - builder.append(SEPARATOR); - return builder.toString(); + static void setUseFastExceptions(boolean useFastExceptions) { + JarURLConnection.useFastExceptions.set(useFastExceptions); } - private static String decode(String source) { - int length = source.length(); - if ((length == 0) || (source.indexOf('%') < 0)) { - return source; + /** + * A JarEntryName parsed from a URL String. + */ + private static class JarEntryName { + + private final AsciiBytes name; + + private String contentType; + + public JarEntryName(String spec) { + this.name = decode(spec); } - ByteArrayOutputStream bos = new ByteArrayOutputStream(length); - for (int i = 0; i < length; i++) { - int ch = source.charAt(i); - if (ch == '%') { - if ((i + 2) >= length) { - throw new IllegalArgumentException("Invalid encoded sequence \"" - + source.substring(i) + "\""); - } - ch = decodeEscapeSequence(source, i); - i += 2; + + private AsciiBytes decode(String source) { + int length = (source == null ? 0 : source.length()); + if ((length == 0) || (source.indexOf('%') < 0)) { + return new AsciiBytes(source); } - bos.write(ch); + ByteArrayOutputStream bos = new ByteArrayOutputStream(length); + for (int i = 0; i < length; i++) { + int ch = source.charAt(i); + if (ch == '%') { + if ((i + 2) >= length) { + throw new IllegalArgumentException("Invalid encoded sequence \"" + + source.substring(i) + "\""); + } + ch = decodeEscapeSequence(source, i); + i += 2; + } + bos.write(ch); + } + // AsciiBytes is what is used to store the JarEntries so make it symmetric + return new AsciiBytes(bos.toByteArray()); + } + + private char decodeEscapeSequence(String source, int i) { + int hi = Character.digit(source.charAt(i + 1), 16); + int lo = Character.digit(source.charAt(i + 2), 16); + if (hi == -1 || lo == -1) { + throw new IllegalArgumentException("Invalid encoded sequence \"" + + source.substring(i) + "\""); + } + return ((char) ((hi << 4) + lo)); + } + + @Override + public String toString() { + return this.name.toString(); + } + + public AsciiBytes asAsciiBytes() { + return this.name; + } + + public boolean isEmpty() { + return this.name.length() == 0; + } + + public String getContentType() { + if (this.contentType == null) { + this.contentType = deduceContentType(); + } + return this.contentType; + } + + private String deduceContentType() { + // Guess the content type, don't bother with streams as mark is not supported + String type = (isEmpty() ? "x-java/jar" : null); + type = (type != null ? type : guessContentTypeFromName(toString())); + type = (type != null ? type : "content/unknown"); + return type; } - // AsciiBytes is what is used to store the JarEntries so make it symmetric - return new AsciiBytes(bos.toByteArray()).toString(); } - private static char decodeEscapeSequence(String source, int i) { - int hi = Character.digit(source.charAt(i + 1), 16); - int lo = Character.digit(source.charAt(i + 2), 16); - if (hi == -1 || lo == -1) { - throw new IllegalArgumentException("Invalid encoded sequence \"" - + source.substring(i) + "\""); - } - return ((char) ((hi << 4) + lo)); - } } diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/util/AsciiBytes.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/util/AsciiBytes.java index 15df426ffd..2291c9ce5a 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/util/AsciiBytes.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/util/AsciiBytes.java @@ -128,6 +128,13 @@ public final class AsciiBytes { return append(string.getBytes(UTF_8)); } + public AsciiBytes append(AsciiBytes asciiBytes) { + if (asciiBytes == null || asciiBytes.length() == 0) { + return this; + } + return append(asciiBytes.bytes); + } + public AsciiBytes append(byte[] bytes) { if (bytes == null || bytes.length == 0) { return this; From 20fb55ea47606e83a755e619b4c4b78fadbc8ef5 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Fri, 20 Jun 2014 09:36:01 -0700 Subject: [PATCH 5/5] Polish --- .../main/java/org/springframework/boot/loader/JarLauncher.java | 1 + .../org/springframework/boot/loader/JavaAgentDetector.java | 1 + .../springframework/boot/loader/LaunchedURLClassLoader.java | 1 + .../main/java/org/springframework/boot/loader/WarLauncher.java | 1 + .../org/springframework/boot/loader/data/RandomAccessData.java | 2 ++ .../springframework/boot/loader/data/RandomAccessDataFile.java | 3 +++ .../main/java/org/springframework/boot/loader/jar/Bytes.java | 1 + .../boot/loader/jar/CentralDirectoryEndRecord.java | 1 + .../main/java/org/springframework/boot/loader/jar/JarFile.java | 1 + 9 files changed, 12 insertions(+) diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/JarLauncher.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/JarLauncher.java index 10569575a1..c52a76fc47 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/JarLauncher.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/JarLauncher.java @@ -44,4 +44,5 @@ public class JarLauncher extends ExecutableArchiveLauncher { public static void main(String[] args) { new JarLauncher().launch(args); } + } diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/JavaAgentDetector.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/JavaAgentDetector.java index 42823b6131..b3ac8844cc 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/JavaAgentDetector.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/JavaAgentDetector.java @@ -32,4 +32,5 @@ public interface JavaAgentDetector { * @param url The url to examine */ public boolean isJavaAgentJar(URL url); + } diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/LaunchedURLClassLoader.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/LaunchedURLClassLoader.java index e27f1bec33..b805dee5cf 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/LaunchedURLClassLoader.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/LaunchedURLClassLoader.java @@ -221,4 +221,5 @@ public class LaunchedURLClassLoader extends URLClassLoader { // Ignore } } + } diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/WarLauncher.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/WarLauncher.java index 56c8b4fe34..909a1e8b74 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/WarLauncher.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/WarLauncher.java @@ -79,4 +79,5 @@ public class WarLauncher extends ExecutableArchiveLauncher { public static void main(String[] args) { new WarLauncher().launch(args); } + } diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/data/RandomAccessData.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/data/RandomAccessData.java index 7ae0e74750..e2b3d10b88 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/data/RandomAccessData.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/data/RandomAccessData.java @@ -65,5 +65,7 @@ public interface RandomAccessData { * Obtain access to the underlying resource on each read, releasing it when done. */ PER_READ + } + } diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/data/RandomAccessDataFile.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/data/RandomAccessDataFile.java index 492b81b543..51121fcad0 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/data/RandomAccessDataFile.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/data/RandomAccessDataFile.java @@ -221,6 +221,7 @@ public class RandomAccessDataFile implements RandomAccessData { this.position += amount; return amount; } + } /** @@ -277,5 +278,7 @@ public class RandomAccessDataFile implements RandomAccessData { throw new IOException(ex); } } + } + } diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/Bytes.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/Bytes.java index c9d348f150..8244f0871c 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/Bytes.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/Bytes.java @@ -76,4 +76,5 @@ class Bytes { } return value; } + } diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/CentralDirectoryEndRecord.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/CentralDirectoryEndRecord.java index 748aa9ce55..4f6a34ea2e 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/CentralDirectoryEndRecord.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/CentralDirectoryEndRecord.java @@ -119,4 +119,5 @@ class CentralDirectoryEndRecord { public int getNumberOfRecords() { return (int) Bytes.littleEndianValue(this.block, this.offset + 10, 2); } + } diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java index 600bde4203..907c4767ee 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java @@ -478,4 +478,5 @@ public class JarFile extends java.util.jar.JarFile implements Iterable