Amber
Amber is a Java library and Gradle plugin for managing and downloading dependencies from repositories at runtime.
This offers you a unique way to lower your jar's size by offloading dependencies to be downloaded by Amber when your application starts.
Using a
Class-Pathproperty inMANIFEST.MF, JVM loads the dependencies just like they were bundled with your jar.You may find all the documentation about Amber on this page.

Quick example
Add Amber to your Gradle build script:
Then, create instance of Amber and bootstrap the dependencies:
Installation
Amber is available on Maven Central and Gradle Plugin Portal.
Creating an Amber instance
There are more ways to create your Amber instance. Amber has five built-in static methods that should cover the majority of use cases.
Amber.classLoader()Uses current thread's context classloader.
Amber.classLoader(ClassLoader)Uses the specified classloader.
Amber.classLoader(ClassLoader, Logger)Uses the specified classloader with a custom logger.
Amber.jarFiles(List<Path>)Uses the specified list of jar files.
Amber.jarFiles(List<Path>, Logger)Uses the specified list of jar files with a custom logger.
Manifest loader
Amber has to load MANIFEST.MF to read the required dependencies and repositories to download from. This is done using a Manifest loader. There are two built-in manifest loader implementations. All implementations return a List of AmberManifest instances.
ClassLoaderManifestLoaderLoads MANIFEST.MF from the specified classloader.
JarFileManifestLoaderLoads MANIFEST.MF from the specified list of jar files.
Dependency downloaders
Amber uses dependency downloaders to... download dependencies. There is one in-built dependency downloader implementation. All implementations are required to correctly handle the specified repository URL and allow for Jar and checksum file downloads.
MavenDependencyDownloaderDownloads dependencies from Maven repositories. Also supports Maven's
maven-metadata.xmlfor version specification.
Checksum validators
Amber uses checksum validators to validate the integrity of downloaded dependencies. There is one default checksum validator implementation. All implementations are required to support all algorithms in ChecksumType.
ChecksumValidatorImplSupports all available algorithms in
ChecksumType
Checksum types
When validating, Amber tries to find a checksum file for the dependency. It checks them in the following order:
SHA-512
SHA-256
SHA-1
MD5
Logger
Amber uses a simple Logger interface to log messages. This interface has three methods: info(String), debug(String) and error(String, Throwable). These methods are used throughout the Amber bootstrapping process to write various logs. The Throwable parameter in the error method may be null. There are two built-in logger implementations.
PrintStreamLoggerAccepts two
PrintStreams for info/debug and error logs.ConsoleLoggerUses
System.outandSystem.errfor info/debug and error logs.
Bootstrapping
Amber has two methods to bootstrap dependencies: bootstrap() and bootstrap(BootstrapOptions). Using the latter you may customize the bootstrapping process.
An example of bootstrapping:
Bootstrap options
You may easily create the BootstrapOptions using its builder, BootstrapOptions.builder(). Here are all available options:
tempDirectoryThe temporary directory that is used to store downloaded dependencies. Defaults to the system's temporary directory.
validateChecksumsDetermines if checksums should be validated. Defaults to true.
failOnInvalidChecksumDetermines if invalid/no checksums should cause the bootstrapping process to fail. Defaults to true.
forceRedownloadDetermines if dependencies should be redownloaded even if they are already present in the library path. Defaults to false.
failOnMissingDependencyDetermines if the bootstrapping process should fail if a dependency could not be found in any repository. Defaults to true.
exitCodeAfterDownloadSpecifies an exit code to be used after the bootstrapping process is completed. If set to null, the application will continue running after bootstrapping. Defaults to null.
exitMessageAfterDownloadSpecifies a message to be logged after the bootstrapping process is completed and before exiting, if
exitCodeAfterDownloadis not null. If set to null, no message will be logged. Defaults to null.libraryDirectoryOverrideOverrides the library directory specified in the MANIFEST.MF. If set to null, the library directory from the MANIFEST.MF will be used. Defaults to null.
downloaderThreadCountSpecifies the number of threads to be used for downloading dependencies. A higher number of threads may speed up the bootstrapping process significantly, especially when downloading many small dependencies. Defaults to twice the number of available processors.
Bootstrapping process
There are few steps in the bootstrapping process.
1. Load manifests
Amber loads manifests using the specified manifest loader. If no manifests are found, the bootstrapping process returns early.
2. Dependency existence check
Amber checks if the dependency is already present in the library path. If it is, the dependency is skipped. This can be overridden using the forceRedownload option.
3. Dependency download
Amber processes all found manifests and their dependencies. During this step, a library path is created, temporary directory is created and the final jar's library path is resolved by the dependency's name and version. After that, Amber tries all the repositories specified in the manifest to find the dependency. If a dependency is found, it is downloaded to the temporary directory with its name and random UUID, thus preventing duplicate file names.
This process can fail if the dependency is not found or able to be downloaded from any repository and failOnMissingDependency is true. This process may also fail if there's an exception during download or I/O exception when moving the downloaded dependency.
4. Checksum validation
After the dependency is downloaded, its checksum is validated against the checksum file found in the repository. If no checksum is found, the validation fails as well. If the checksum is valid, the process continues.
This process can fail if the checksum is invalid or not found and failOnInvalidChecksum is true.
5. Move to library path
After the dependency is downloaded and validated, it is moved to the final library path with its name and version.
6. Program exit
If exitCodeAfterDownload is not null, the program exits with the specified exit code after all dependencies are processed. Otherwise, the program continues running.
Amber manifest and MANIFEST.MF
Amber loads META-INF/MANIFEST.MF files to read the required dependencies and repositories to download from. The specified dependencies and repositories are usually generated by the Amber Gradle plugin. Additionally, the desired library directory is here specified as well. The
The MANIFEST.MF file may look like this:
Amber-DirectorySpecifies the library directory where dependencies will be stored. Should match with the
Class-Pathproperty.Amber-DependenciesA comma-separated list of dependencies in the format
groupId:artifactId:version.Class-PathA space-separated list of jar files that should be added to the classpath. Should match with the
Amber-Directoryproperty.Amber-Maven-RepositoriesA comma-separated list of Maven repository URLs to download dependencies from.
Gradle plugin
Amber uses a Gradle plugin to simplify the process of adding Amber to your project and generating the required MANIFEST.MF entries. The usage is very straightforward.
Amber dependencies
You may declare all Amber dependencies using the amber configuration. This configuration is similar to compileOnly. All dependencies declared in this configuration will be available at compile time, but will not be bundled with your jar. All the dependencies with this configuration will be added into the MANIFEST.MF and downloaded by Amber at runtime.
Here's an example of Amber dependency declaration:
Transitive dependencies
Amber supports transitive dependencies. If a dependency has its own dependencies, they will be included in the MANIFEST.MF and downloaded by Amber as well.
Dependency version conflict resolution
Currently, there is no version conflict resolution, as this is handled by Gradle's dependency resolution.
Gradle's platform support
Amber supports Gradle's platform thingy. As you may see in the example, Hibernate's platform is used to manage Hibernate's dependencies. The versions are resolved correctly.
Class-Path merging
If you define your own Class-Path property in MANIFEST.MF, it will be merged with the one generated by Amber plugin. The ShadowJar plugin is supported.
Task generation
Amber creates tasks named by currently available jar tasks. For example, for task jar, Amber creates generateJarAmberManifest. For shadowJar, it creates generateShadowJarAmberManifest. These tasks generate the required MANIFEST.MF entries.
Amber configuration
You may customize the Amber plugin using the amber configuration block. Here are all available options:
libraryDirSpecifies the library directory where dependencies will be stored. Defaults to
amber-lib.