URL.setURLStreamHandlerFactory

I am developing a web application using an executable jar with built-in Jetty.
My jar contains a dependent jar (a jar in a jar)
I referenced the JarRsrcLoader and RsrcURLStreamHandlerFactory developed by Eclipse.
JarRsrcLoader uses the URL#setURLStreamHandlerFactory(RsrcURLStreamHandlerFactory) to enable the rsrc protocol.
In this way, it can resolve the class path for jar.
But it becomes impossible to resolve the usual protocol as side effects.
e.g. file:xxxx or jar:xxxx .
RsrcURLStreamHandlerFactory has a setURLStreamHandlerFactory method.
Maybe I think I should set this method to default for this method.
I do not know what installed this method.

+7
source share
2 answers

Only one instance of the URLStreamHandlerFactory implementation is registered in the Java URLStreamHandlerFactory , so this implementation must be aware of all supported protocols.

By default, the Oracle / Sun behavior is not implemented this way, but directly in the java.net.URL class. Thus, you cannot just enter the default implementation as a factory chain in RsrcURLStreamHandlerFactory . The first part of the answer.

The java.net.URL method getURLStreamHandler loads the implementation for protocol X according to the policy of naming its default class name 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 to select the URLStreamHandler protocol comes from the Java system property java.protocol.handler.pkgs . I suggest you read the full java/net/URL.java source code from the JDK src.zip for details.

  • So, the right way to do this (regardless of what IBM / Eclipse did) is to leave the default mechanism in place and set for example -Djava.protocol.handler.pkgs="com.company.product.protocol" on the command line ( if you have permission / accreditation for this). When implementing the URLStreamHandler with the name com.company.product.protocol.rsrc.Handler that uses the JarRsrcLoader , you are doing the job.

  • An alternative is to write an implementation of URLStreamHandlerFactory as a factory chain in RsrcURLStreamHandlerFactory , inspired by the source code URL.getURLStreamHandler . As an example, you can read this old JBoss code . It relies on the cache of internal URL caches by preloading other known (or used) protocols before registering the factory. In my opinion, just ugly.

Warning : RsrcURLStreamHandler replaced the original 180 lines of URLStreamHandler.parseURL code URLStreamHandler.parseURL its own 10-line version without calling super.parseURL . Of course, this does not meet the URL concatenation specifications! Be careful, you may encounter an error depending on how such URLs are used.

+11
source

With Java 9, you can use SPI to provide handlers:

URL (String, String, int, String) JavaDoc constructor that describes the search algorithm:

  • If the application previously configured the URLStreamHandlerFactory instance as the factory stream handler, then the createURLStreamHandler method of this instance is called using the protocol string as an argument to create the stream protocol handler.

  • If the URL is not already configured with a URLStreamHandlerFactory or if the factory createURLStreamHandler method returns null, then the ServiceLoader mechanism is used to find the URLStreamHandlerProvider using the system class loader. . Vendor ordering is implementation-specific, and an implementation can cache local providers. A ServiceConfigurationError, Error, or RuntimeException exception thrown from createURLStreamHandler, if it occurs, will be thrown to the calling thread. The createURLStreamHandler method for each provider, if one is created, is called using the protocol string until the provider returns a non-zero value, or all providers have been exhausted.

  • If the previous step cannot find the protocol handler, the constructor reads the value of the system property: java.protocol.handler.pkgs
  • If the protocol handler cannot be found in the previous step, the constructor attempts to load the built-in protocol handler. If this class does not exist or the class exists, but it is not a subclass of URLStreamHandler, then a MalformedURLException is thrown.

Protocol handlers for the following protocols are guaranteed on the search path: http, https, file and jar

0
source

All Articles