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 75a963f2698..5f91138d926 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,10 +18,13 @@ package org.springframework.boot.loader.jar; import java.io.File; import java.io.IOException; +import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; +import java.util.logging.Level; +import java.util.logging.Logger; /** * {@link URLStreamHandler} for Spring Boot loader {@link JarFile}s. @@ -38,8 +41,26 @@ public class Handler extends URLStreamHandler { private static final String SEPARATOR = JarURLConnection.SEPARATOR; + private static final String[] FALLBACK_HANDLERS = { "sun.net.www.protocol.jar.Handler" }; + + private static final Method OPEN_CONNECTION_METHOD; + static { + Method method = null; + try { + method = URLStreamHandler.class + .getDeclaredMethod("openConnection", URL.class); + } + catch (Exception ex) { + } + OPEN_CONNECTION_METHOD = method; + } + + private final Logger logger = Logger.getLogger(getClass().getName()); + private final JarFile jarFile; + private URLStreamHandler fallbackHandler; + public Handler() { this(null); } @@ -50,8 +71,60 @@ public class Handler extends URLStreamHandler { @Override protected URLConnection openConnection(URL url) throws IOException { - JarFile jarFile = (this.jarFile != null ? this.jarFile : getJarFileFromUrl(url)); - return new JarURLConnection(url, jarFile); + if (this.jarFile != null) { + return new JarURLConnection(url, this.jarFile); + } + try { + return new JarURLConnection(url, getJarFileFromUrl(url)); + } + catch (Exception ex) { + return openFallbackConnection(url, ex); + } + } + + private URLConnection openFallbackConnection(URL url, Exception reason) + throws IOException { + try { + return openConnection(getFallbackHandler(), url); + } + catch (Exception ex) { + this.logger.log(Level.WARNING, "Unable to open fallback handler", ex); + if (reason instanceof IOException) { + throw (IOException) reason; + } + if (reason instanceof RuntimeException) { + throw (RuntimeException) reason; + } + throw new IllegalStateException(reason); + } + } + + private URLStreamHandler getFallbackHandler() { + if (this.fallbackHandler != null) { + return this.fallbackHandler; + } + + for (String handlerClassName : FALLBACK_HANDLERS) { + try { + Class handlerClass = Class.forName(handlerClassName); + this.fallbackHandler = (URLStreamHandler) handlerClass.newInstance(); + return this.fallbackHandler; + } + catch (Exception ex) { + // Ignore + } + } + throw new IllegalStateException("Unable to find fallback handler"); + } + + private URLConnection openConnection(URLStreamHandler handler, URL url) + throws Exception { + if (OPEN_CONNECTION_METHOD == null) { + throw new IllegalStateException( + "Unable to invoke fallback open connection method"); + } + OPEN_CONNECTION_METHOD.setAccessible(true); + return (URLConnection) OPEN_CONNECTION_METHOD.invoke(handler, url); } public JarFile getJarFileFromUrl(URL url) throws IOException {