Create/read archives in-memory/on-disk, supports Multi-Release JARs

Code for handling JARs.

  • Construct archives using fluid builders
  • Read from the file-system or in-memory (with optional filtering)
  • Write to the file-system (zipped up or exploded to a directory), or in-memory (byte array, output stream, classloader, etc)

Use with:

Integration Module Description
compile.glue archive output of programmatic compilation
archive.jpms JPMS modules support
archive.osgi OSGi Bundles support
archive.sign Digital signature (jar signing)
archive.maven Resolve dependency graphs and install to a local repo
archive.glue use an in-memory archive as a dependency for compilation

Dependency Graph

Module Dependency


The following creates an in-memory JAR with the supplied class and a manifest header indicating the Main-Class:

	Archive archive = archive()

The following demonstrates creating a JAR with 2 SPI implementations, and loading into a classloader:

	byte[] archive = archive().configured(asJar()

	ClassLoader loader = ClassLoaders.inMemoryClassLoader().jar(archive);

	List<String> imps = spiServices(Comparator.class, loader);

	assertThat(imps, containsInAnyOrder(

View full source of associated test.

Archive architecture - brief implementation notes

To support the various extensions (e.g. sourcing in-memory/filesystem, signing, OSGi/JPMS meta) a simple plugin architecture is employed.

Generalising towards Plugins

A plugin typically implements ArchiveConfigurationPlugin giving it double-dispatch powers wrt the archive builder, where it may register any of:

  • ArchiveResourceSource - proves content for the archive
  • ArchiveResourceFilter - modify or even exclude content
  • ArchiveResourceListener - observes content that is finally added to the archive
  • ManifestProcessor - permits mutation of the manifest in the final stages of construction

Construction Lifecycle

Once an archive is configured, it may be constructed. A basic staged lifecycle is defined via an enumeration:


Construction then proceeds as follows:

  1. ArchiveResourceSource sources are drained (INITIAL)
  2. ArchiveResourceFilter drained resources are filtered
  3. ArchiveResourceListener listeners are informed of new resources
  4. ArchiveResourceSource sources are drained (PRE_MANIFEST)
  5. ArchiveResourceFilter drained resources are filtered
  6. ArchiveResourceListener listeners are informed of new resources
  7. ManifestProcessor processors manipulate the manifest
  8. ArchiveResourceSource sources are drained (FINAL)
  9. ArchiveResourceFilter drained resources are filtered
  10. ArchiveResourceListener listeners are informed of new resources

As observed above, the subcycle for resources is; drain sources, filter and inform listeners. The lifecycle staging is a rather simplistic approach, but sufficient currently.

Back to top

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

Earcam Maven Skin.