archive
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 |
Examples
The following creates an in-memory JAR with the supplied class and a manifest header indicating the Main-Class:
Archive archive = archive() .configured(asJar() .launching(DummyMain.class)) .toObjectModel();
The following demonstrates creating a JAR with 2 SPI implementations, and loading into a classloader:
byte[] archive = archive().configured(asJar() .providing(Comparator.class, CaseInsensitiveToStringComparator.class, WhitespaceIgnorantToStringComparator.class)) .toByteArray(); ClassLoader loader = ClassLoaders.inMemoryClassLoader().jar(archive); List<String> imps = spiServices(Comparator.class, loader); assertThat(imps, containsInAnyOrder( cn(CaseInsensitiveToStringComparator.class), cn(WhitespaceIgnorantToStringComparator.class)));
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:
- INITIAL
- PRE_MANIFEST
- FINAL
Construction then proceeds as follows:
- ArchiveResourceSource sources are drained (INITIAL)
- ArchiveResourceFilter drained resources are filtered
- ArchiveResourceListener listeners are informed of new resources
- ArchiveResourceSource sources are drained (PRE_MANIFEST)
- ArchiveResourceFilter drained resources are filtered
- ArchiveResourceListener listeners are informed of new resources
- ManifestProcessor processors manipulate the manifest
- ArchiveResourceSource sources are drained (FINAL)
- ArchiveResourceFilter drained resources are filtered
- 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.