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:


Dependency Graph

Module Dependency

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();


Back to top

Version: 0.1.0. Last Published: 2018-10-08.

Earcam Maven Skin.