Skip to content

Commit dfe6de8

Browse files
author
Phillip Webb
committed
Fallback to JVM URL handler on exception
Update the executable JAR `Handler` to fallback to the JVM handler if the jar cannot be opened. This prevents exceptions when trying to open URLs in the form "jar:jndi:/localhost...". Fixes spring-projectsgh-347
1 parent 97c258a commit dfe6de8

File tree

1 file changed

+75
-2
lines changed
  • spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar

1 file changed

+75
-2
lines changed

spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/Handler.java

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@
1818

1919
import java.io.File;
2020
import java.io.IOException;
21+
import java.lang.reflect.Method;
2122
import java.net.MalformedURLException;
2223
import java.net.URL;
2324
import java.net.URLConnection;
2425
import java.net.URLStreamHandler;
26+
import java.util.logging.Level;
27+
import java.util.logging.Logger;
2528

2629
/**
2730
* {@link URLStreamHandler} for Spring Boot loader {@link JarFile}s.
@@ -38,8 +41,26 @@ public class Handler extends URLStreamHandler {
3841

3942
private static final String SEPARATOR = JarURLConnection.SEPARATOR;
4043

44+
private static final String[] FALLBACK_HANDLERS = { "sun.net.www.protocol.jar.Handler" };
45+
46+
private static final Method OPEN_CONNECTION_METHOD;
47+
static {
48+
Method method = null;
49+
try {
50+
method = URLStreamHandler.class
51+
.getDeclaredMethod("openConnection", URL.class);
52+
}
53+
catch (Exception ex) {
54+
}
55+
OPEN_CONNECTION_METHOD = method;
56+
}
57+
58+
private final Logger logger = Logger.getLogger(getClass().getName());
59+
4160
private final JarFile jarFile;
4261

62+
private URLStreamHandler fallbackHandler;
63+
4364
public Handler() {
4465
this(null);
4566
}
@@ -50,8 +71,60 @@ public Handler(JarFile jarFile) {
5071

5172
@Override
5273
protected URLConnection openConnection(URL url) throws IOException {
53-
JarFile jarFile = (this.jarFile != null ? this.jarFile : getJarFileFromUrl(url));
54-
return new JarURLConnection(url, jarFile);
74+
if (this.jarFile != null) {
75+
return new JarURLConnection(url, this.jarFile);
76+
}
77+
try {
78+
return new JarURLConnection(url, getJarFileFromUrl(url));
79+
}
80+
catch (Exception ex) {
81+
return openFallbackConnection(url, ex);
82+
}
83+
}
84+
85+
private URLConnection openFallbackConnection(URL url, Exception reason)
86+
throws IOException {
87+
try {
88+
return openConnection(getFallbackHandler(), url);
89+
}
90+
catch (Exception ex) {
91+
this.logger.log(Level.WARNING, "Unable to open fallback handler", ex);
92+
if (reason instanceof IOException) {
93+
throw (IOException) reason;
94+
}
95+
if (reason instanceof RuntimeException) {
96+
throw (RuntimeException) reason;
97+
}
98+
throw new IllegalStateException(reason);
99+
}
100+
}
101+
102+
private URLStreamHandler getFallbackHandler() {
103+
if (this.fallbackHandler != null) {
104+
return this.fallbackHandler;
105+
}
106+
107+
for (String handlerClassName : FALLBACK_HANDLERS) {
108+
try {
109+
Class<?> handlerClass = Class.forName(handlerClassName);
110+
this.fallbackHandler = (URLStreamHandler) handlerClass.newInstance();
111+
return this.fallbackHandler;
112+
}
113+
catch (Exception ex) {
114+
// Ignore
115+
}
116+
}
117+
throw new IllegalStateException("Unable to find fallback handler");
118+
}
119+
120+
private URLConnection openConnection(URLStreamHandler handler, URL url)
121+
throws Exception {
122+
if (OPEN_CONNECTION_METHOD == null) {
123+
throw new IllegalStateException(
124+
"Unable to invoke fallback open connection method");
125+
}
126+
OPEN_CONNECTION_METHOD.setAccessible(true);
127+
return (URLConnection) OPEN_CONNECTION_METHOD.invoke(handler, url);
55128
}
56129

57130
public JarFile getJarFileFromUrl(URL url) throws IOException {

0 commit comments

Comments
 (0)