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 a reference to Java's default http- and https-URLStreamHandlers
, so I can specify one of them in the URL
's constructor to open a standard http connection without using the protocol overridden by the library?

- 12,349
- 8
- 52
- 116
-
I think you can set your own stream handler factory using static method on URL before opening url. – Bimalesh Jha Aug 02 '13 at 13:59
-
@BimaleshJha Correct, but then I'd have to re-implement the protocol handling. I'd like to reuse what Java already provides. – Markus A. Aug 02 '13 at 14:01
-
@BimaleshJha Actually, there is another problem with trying to set my own factory: I can't! :) The docs for `URL.setURLStreamHandlerFactory(...)` say "This method can be called at most once in a given Java Virtual Machine." And since the library uses up this call, I just get an error thrown in my face, if I tried to overwrite the library's factory... unless... See update to my answer! ;) – Markus A. May 07 '14 at 02:09
-
@MarkusA. but if you have control on the `main()` you should be able to call that method before the other library does, no? – Matthieu Jun 03 '16 at 15:00
-
@Matthieu In general, yes, but unfortunately the library that I'm using calls my main function after it is already done setting its handler. Also, if I could get to the method before hand, I might be able to query the default handler, but if I set my own handler it might crash the library, which is then no longer able to register its handler... – Markus A. Jun 03 '16 at 23:56
3 Answers
Found it:
sun.net.www.protocol.http.Handler
With that, 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 a normal Java HttpURLConnection and not the one provided by the library.
Update:
I discovered another, more general, approach: Remove the library's URLStreamHandlerFactory
!
This is a bit tricky, since the URL-class technically doesn't allow you to set the factory more than once or to clear it with an official function call, but with a bit of reflection-magic, we can do it anyways:
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 grabs a hold of the static field factory
in the URL
-class, makes it accessible, grabs its current value and changes it to null. Afterwards, it calls URL.setStreamHandlerFactory(null) (which now completes without error) to make this setting "official", i.e. give the function a chance to do any other clean-up that it might want to do. Then it returns the previously registered factory's class name, just for reference. If anything goes wrong, it swallows the exception (I know, bad idea...) and returns null.
For reference: Here is the relevant source-code for URL.java.
Note: This approach might be even more risky than using the internal sun-classes (as far as portability goes) since it relies on the specific internal structure of the URL-class (namely the existence and exact function of the factory
-field), but it does have the advantage that I don't need to go through all of my code to find all URL-constructors and add the handler-parameter... Also, it might break some functionality of the library that relies on their registered handlers. Luckily, neither issue (portability and partially broken library functionality) are issues that are relevant in my case.
Update: #2
While we're using reflection: Here is the probably safest way to get a reference 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 as:
URLStreamHandler hander = getURLStreamHandler("http");
Note: This call needs to happen before the library registers its URLStreamHandlerFactory
, otherwise you will end up with a reference to their handler.
Why would I consider this the safest approach? Because URL.getURLStreamHandler(...)
is not a fully private method, but only package-private. So, modifying its call-signature could break other code in the same package. Also, its name doesn't really leave much room for returning anything other than what we are looking for. Thus, I would expect it to be unlikely (albeit still not impossible) that a different/future implementation of the URL
-class would be incompatible with the assumptions made here.

- 12,349
- 8
- 52
- 116
-
1I am sure some java code checker would flag it as warning since you are directly calling some internal Sun implementation class :). I would implement my own handler and stay at public API level. – Bimalesh Jha Aug 02 '13 at 14:09
-
@BimaleshJha Unfortunately, to register my own handler, I also need to break away from the public API level... – Markus A. May 07 '14 at 02:28
-
Here's Markus A solution rewritten for Android:
public static URLStreamHandler getURLStreamHandler(String protocolIdentifier) {
try {
URL url = new URL(protocolIdentifier);
Field handlerField = URL.class.getDeclaredField("handler");
handlerField.setAccessible(true);
return (URLStreamHandler)handlerField.get(url);
} catch (Exception e) {
return null;
}
}
The method getURLStreamHandler doesn't exist in android, so it needs to be done differently. The protocolIdentifier is the protocol name plus the colon. You need to pass in a value so that can be used to instantiate a URL instance for the protocol URLStreamHandler you want. If you want the standard "jar:" protocol handler you must enter something like this: "jar:file:!/". The "file" could be replaced with "http" or "https", as they all get you the same handler instance.
The standard Handlers that android supports are http, https, file, jar, ftp.

- 1,183
- 1
- 12
- 15
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 standard handler
EDIT: Found this code

- 2,097
- 1
- 14
- 10

- 17,829
- 2
- 47
- 69
-
1Actually, officially I can not, since the setURLStreamHandlerFactory-method can only be called "at most once in a given Java Virtual Machine" (see JavaDoc for `URL`). And this one call is already used up by the library. But I found a reflection-based approach that can circumvent this restriction. It even allows me to just remove the library's factory altogether, so I don't actually need my own any more. Things will just go back to the default handlers. (For details, see update to my answer.) – Markus A. May 07 '14 at 02:19