1818
1919import java .io .File ;
2020import java .io .IOException ;
21+ import java .lang .reflect .Method ;
2122import java .net .MalformedURLException ;
2223import java .net .URL ;
2324import java .net .URLConnection ;
2425import 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