lade
Not just the usual fudge of ClassLoader.defineClass() - loads in-memory JARs returning valid resource URLs
Consists of:
- A self-first URLClassLoader
- An in-memory ClassLoader
- The usual exposure of defineClass()
- Static utility to execute a Runnable within a thread’s context ClassLoader
The io.earcam.instrumental.lade.InMemoryClassLoader:
- Briefly employs the builder pattern to add class and resources
- Loading strategy is self-first
- Load JARs from byte arrays and InputStreams
- Is parallel capable and registered as such
- URLs provide valid streams; either using the instance or, if serializing, once the URLStreamHandler is registered
- Basic support for signed content; CodeSigners associated with loaded classes, but currently archives not verified
- Works as the ClassLoader for:
- Vanilla Java
- JPMS (also supports dynamic layers with custom ModuleFinder)
- the JVM System ClassLoader (“java.system.class.loader”)
- Felix Connect (formerly known as PojoSR)
Examples
Self-first URLClassLoader:
@Test public void selfFirstClassLoader() throws IOException, ClassNotFoundException { Path junitApiJar = Paths.get(Resources.sourceOfResource(Test.class)); try(URLClassLoader selfFirst = ClassLoaders.selfFirstClassLoader(junitApiJar)) { Class<?> loaded = selfFirst.loadClass(Test.class.getCanonicalName()); assertThat(loaded, is(not(equalTo(Test.class)))); } }
View full source of associated test.
InMemoryClassLoader (loading byte array JARs in try head):
try(InMemoryClassLoader classLoader = ClassLoaders.inMemoryClassLoader() .jar(jarOneBytes, "one") .jar(jarTwoBytes, "two")) { String name = typeToResourceName(InMemoryClassLoaderTest.class); Enumeration<URL> resources = classLoader.getResources(name); List<URL> earls = enumerationToList(resources); // 3 because the loader also delegates to parent assertThat(earls, hasSize(3)); }
Orphaned InMemoryClassLoader (loading byte array JARs in try body):
try(InMemoryClassLoader classLoader = ClassLoaders.orphanedInMemoryClassLoader()) { classLoader.jar(jarOneBytes, "one"); classLoader.jar(jarTwoBytes, "two"); String name = typeToResourceName(InMemoryClassLoaderTest.class); Enumeration<URL> resources = classLoader.getResources(name); List<URL> earls = enumerationToList(resources); // 2 because the loader has no parent assertThat(earls, hasSize(2)); }
Safely add the URLStreamHandler for InMemoryClassLoader:
io.earcam.instrumental.lade.Handler.addProtocolHandlerSystemProperty();
Safely remove the URLStreamHandler for InMemoryClassLoader:
io.earcam.instrumental.lade.Handler.removeProtocolHandlerSystemProperty();