I am developing a web application using an executable jar with embedded Jetty.
My jar contains a dependent jar.(jar in jar)
I referenced to the JarRsrcLoader
and RsrcURLStreamHandlerFactory
that developed by Eclipse.JarRsrcLoader
is using URL#setURLStreamHandlerFactory(RsrcURLStreamHandlerFactory)
to resolve rsrc
protocol.
Thereby it can resolve class path for jar.
But it becomes impossible to solve the usual protocol as side effects.
for example file:xxxx
or jar:xxxx
.RsrcURLStreamHandlerFactory
has setURLStreamHandlerFactory
method.
Maybe I think I should set the default implement to this method.
I don't know what set this method.
There is only one instance of a URLStreamHandlerFactory
implementation registered into the Java runtime, so this implementation must be aware of all supported protocols.
The default Oracle/Sun behavior is not implemented that way but directly in the java.net.URL
class. So you cannot simply inject a default implementation as a chained factory in RsrcURLStreamHandlerFactory
. First part of the answer.
The java.net.URL
getURLStreamHandler
method loads an implementation for a protocol X
according to the naming policy of its class name, by default as sun.net.www.protocol.X.Handler
If you look at jre/lib/rt.jar
, you will find:
sun/net/www/protocol/ftp/Handler.class
sun/net/www/protocol/gopher/Handler.class
sun/net/www/protocol/mailto/Handler.class
sun/net/www/protocol/netdoc/Handler.class
sun/net/www/protocol/http/Handler.class
sun/net/www/protocol/jar/Handler.class
sun/net/www/protocol/file/Handler.class
The list of base packages used for the protocol URLStreamHandler
selection comes from the java.protocol.handler.pkgs
Java system property. I invite you to read the full source code of the java/net/URL.java
from the JDK src.zip
to understand details.
So the right way to do it (whatever IBM/Eclipse did) is to leave the default mechanism in place and set for instance -Djava.protocol.handler.pkgs="com.company.product.protocol"
on the command-line (if you have permission/accreditation to do so). With a URLStreamHandler
implementation named com.company.product.protocol.rsrc.Handler
that uses JarRsrcLoader
, you get the job done.
The alternate option is to write a URLStreamHandlerFactory
implementation as a chained factory in RsrcURLStreamHandlerFactory
inspired from URL.getURLStreamHandler
source code. As an example, you can read this old JBoss code. It relies on URL
internal handlers cache by preloading other known (or used) protocols before registering the factory. In my opinion, just ugly.
Warning: RsrcURLStreamHandler
has replaced the original 180-lines-of-code of URLStreamHandler.parseURL
by its own 10-lines "version" without calling super.parseURL
. For sure it does not respect URL concatenation specifications ! Take care, you may face a bug depending on the way such URLs are used.
As of Java 9 you can use SPI to provide handlers:
URL(String, String, int, String) constructor JavaDoc describing search algorithm:
If the application has previously set up an instance of URLStreamHandlerFactory as the stream handler factory, then the createURLStreamHandler method of that instance is called with the protocol string as an argument to create the stream protocol handler.
If no URLStreamHandlerFactory has yet been set up, or if the factory's createURLStreamHandler method returns null, then the ServiceLoader mechanism is used to locate URLStreamHandlerProvider implementations using the system class loader. The order that providers are located is implementation specific, and an implementation is free to cache the located providers. A ServiceConfigurationError, Error or RuntimeException thrown from the createURLStreamHandler, if encountered, will be propagated to the calling thread. The createURLStreamHandler method of each provider, if instantiated, is invoked, with the protocol string, until a provider returns non-null, or all providers have been exhausted.
- If the previous step fails to find a protocol handler, the constructor reads the value of the system property: java.protocol.handler.pkgs
- If the previous step fails to find a protocol handler, then the constructor tries to load a built-in protocol handler. If this class does not exist, or if the class exists but it is not a subclass of URLStreamHandler, then a MalformedURLException is thrown.
Protocol handlers for the following protocols are guaranteed to exist on the search path : http, https, file, and jar
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With