This workspace repository contains the Plurl library.
Plurl is a small Java library that solves a long‑standing Java/OSGi problem: the JDK only lets you set certain URL “factory” hooks once per JVM, but modular systems (like OSGi) often need multiple independent parties to contribute URL handlers.
In plurl’s own words, it “multiplex[es] the URL factory singletons” for:
URL#setURLStreamHandlerFactory(URLStreamHandlerFactory)URLConnection#setContentHandlerFactory(ContentHandlerFactory)
So instead of one global factory, plurl provides one global “router” factory that can delegate to many registered factories.
In standard Java:
- A
URLStreamHandlerFactoryis how you teach the JVM new URL protocols (e.g.bundleresource:,foo:). - A
ContentHandlerFactoryis how you teach the JVM how to turn a URLConnection into typed content for a MIME type.
But the JVM treats these as singletons: once someone sets them, nobody else can (or you get errors). That’s a big mismatch for OSGi / plugin ecosystems where:
- multiple bundles may want to register their own URL protocols/content handlers
- bundles come and go at runtime (so handlers need to be addable/removable)
Plurl was created to make those “singleton hooks” behave like a registry instead.
(See Javadoc in Plurl.java where it explains multiplexing and add/remove behavior, and that it may need deep reflection in some cases.)
- Install plurl once into the JVM (it becomes the one factory the JVM knows about).
- Other components register their
URLStreamHandlerFactoryand/orContentHandlerFactorywith plurl. - When Java needs a handler for protocol
X(or MIME typeY), plurl chooses which registered factory should handle it and delegates.
Plurl uses a callback shouldHandle(Class<?> clazz) (from PlurlFactory) and walks the call stack to decide which factory “owns” the request. If there’s only one factory registered, it uses that. If multiple are registered, it tries to find one whose shouldHandle matches the calling code.
That selection logic is described in the Plurl Javadoc.
One particularly interesting design choice: plurl defines a special protocol plurl://... that acts like an operations channel to add/remove factories.
From Plurl.java, you can do operations like:
plurl://op/addURLStreamHandlerFactoryplurl://op/removeURLStreamHandlerFactoryplurl://op/addContentHandlerFactoryplurl://op/removeContentHandlerFactory
Those URLs return a Consumer<...> from getContent() that you call to perform the operation.
This exists so that factories can be added even if the code adding them was compiled against a different copy/version of the plurl API (common in modular/plugin worlds). In that case plurl may use reflection/proxying to interoperate.
Note: It largely should be thought of as an internal implementation detail that allows various copies of the plurl library to live and coordinate in the same JVM instance. Most users should just use the methods directly on the Plurl interface to add/remove their factories.Under the covers it uses the plurl: protocol to communicate with the multiple copies of the library that may be present.
-
OSGi / Eclipse / plugin-based apps
- Multiple bundles want to contribute URL protocols (common in OSGi:
bundle:,bundleresource:, etc.). - You don’t want whichever bundle starts first to “win” the singleton forever.
- Multiple bundles want to contribute URL protocols (common in OSGi:
-
Application servers / large platforms embedding many libraries
- Different subsystems want URL handlers without coordinating global JVM initialization order.
-
Dynamic add/remove of handlers
- Plurl’s API and tests indicate factories should not be strongly referenced and should behave as removed if GC’d (useful for dynamic module lifecycles).
-
Avoiding (or controlling) overriding built-in JDK protocols
- The implementation tracks “forbidden protocols” by default (
jar,jmod,file,jrt) to reduce the risk of accidentally hijacking core behavior.
- The implementation tracks “forbidden protocols” by default (
- Some features rely on deep reflection into
java.netinternals (the code mentions needing--add-opens java.base/java.net=ALL-UNNAMEDin some situations). - For more details see Javadoc of
Plurl.javaand the tests.
Want to hack on plurl? See CONTRIBUTING.md for information on building, testing and contributing changes.
They are probably not perfect, please let us know if anything feels wrong or incomplete.
We use Maven to build and the repo includes mvnw.
You can use your system mvn but we require a recent version.
./mvnw clean install- Assembles and tests the project
Snapshot plurl artifacts are available from the Sonatype OSS snapshot repository:
https://oss.sonatype.org/content/repositories/snapshots/
The contents of this repository are made available to the public under the terms of the Apache License, Version 2.0. Bundles may depend on non Apache Licensed code.