Getting Java default link http (s) URLStreamHandler

I have a library that I need to use in one of my projects, which unfortunately registers its own URLStreamHandler to handle http URLs . Is there a way to get the default Java link http and https URLStreamHandlers , so I can specify one of them in the URL constructor to open a standard http connection without using the protocol overridden by the library?

+4
source share
2 answers

Found:

 sun.net.www.protocol.http.Handler 

With this I can now do:

 URL url = new URL(null, "http://...", new sun.net.www.protocol.http.Handler()); HttpURLConnection cxn = (HttpURLConnection) url.openConnection(); 

And I get the normal Java HttpURLConnection, and not the one provided by the library.


Update:

I found a different, more general approach: Remove the URLStreamHandlerFactory library!

This is a bit complicated, as the class of URLs does not technically allow you to set the factory more than once or clear it with an official function call, but with a little reflection-magic we can do it anyway:

 public static String unsetURLStreamHandlerFactory() { try { Field f = URL.class.getDeclaredField("factory"); f.setAccessible(true); Object curFac = f.get(null); f.set(null, null); URL.setURLStreamHandlerFactory(null); return curFac.getClass().getName(); } catch (Exception e) { return null; } } 

This method captures the static factory field in the URL class, makes it available, captures its current value, and changes it to null . After that, it calls URL.setStreamHandlerFactory ( null ) (which now exits without errors) to make this parameter "official", i.e. give the function the ability to do any other cleanup that it might want to do. It then returns the previously registered class name of the factory, for reference only. If something goes wrong, it swallows the exception (I know, a bad idea ...) and returns null .

For reference: Here is the corresponding source code for URL.java .

Note. . This approach can be even more risky than using internal solar classes (as far as portability is concerned), since it depends on the specific internal structure of the URL class (namely, the existence and exact function of the factory field), but it has the advantage that I donโ€™t have to go through all my code to find all the URL constructors and add a handler parameter ... In addition, it may disrupt some library functionality that relies on their registered handlers. Fortunately, not a single problem (portability and partially impaired library functionality) is important in my case.


Update: # 2

For now, we are using reflection: here is probably the safest way to get a link to the default handler:

 public static URLStreamHandler getURLStreamHandler(String protocol) { try { Method method = URL.class.getDeclaredMethod("getURLStreamHandler", String.class); method.setAccessible(true); return (URLStreamHandler) method.invoke(null, protocol); } catch (Exception e) { return null; } } 

which you then simply call:

 URLStreamHandler hander = getURLStreamHandler("http"); 

Note. . This call must be set to , the library registers its URLStreamHandlerFactory , otherwise you will get a link to your handler.

Why do I consider this the safest approach? Because URL.getURLStreamHandler(...) not a fully private method, but only a private package. Thus, changing his call signature may break another code in the same package. In addition, its name does not leave much space for the return of anything other than what we are looking for. Thus, I would expect that it is unlikely (although still not impossible) that another / future implementation of the URL class would be incompatible with the assumptions made here.

+11
source

You can register your own URLStreamHandlerFactory wirh URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory());

 public class URLStreamHandlerFactory implements java.net.URLStreamHandlerFactory { public URLStreamHandlerFactory() {} public URLStreamHandler createURLStreamHandler(String protocol) { if(protocol.equals("http")) { return new sun.net.www.protocol.http.Handler(); } else if(protocol.equals("https")) { return new sun.net.www.protocol.https.Handler(); } return null; } } 

so you can use a standard handler

EDIT: this code found

+1
source

Source: https://habr.com/ru/post/1492467/


All Articles