Back to Java
2026-03-075 min read

Java - Multi-Release Jar Files

Learn Java - Multi-Release Jar Files step by step with clear examples and exercises.

Title: Java - Multi-Release Jar Files

Why This Matters

In modern software development, managing dependencies effectively is crucial for maintaining a smooth and conflict-free environment. Multi-release JAR files offer a solution to package different versions of a library for various Java applications that require specific API levels. By using multi-release JAR files, you can prevent conflicts between libraries with incompatible versions and ensure a smoother development process.

Prerequisites

To understand this topic, you should be familiar with the following:

  • Basic understanding of Java and its file system
  • Familiarity with Maven or Gradle build tools (optional but recommended)
  • Understanding of Java modules introduced in Java 9

Important Concepts

  • Java Modules
  • Classpath
  • Dependency Management
  • JAR (Java ARchive) files

Core Concept

A JAR (Java ARchive) file is a standard format for distributing Java classes and resources. However, it can sometimes lead to issues when different applications require different versions of the same library. To address this problem, Java 9 introduced multi-release JAR files, which allow you to package multiple versions of a library in a single JAR file.

Multi-release JAR files work by separating classes based on their required module version. The module-info.class within the JAR defines which classes belong to which modules and at what API levels they are available. When an application runs, the Java Virtual Machine (JVM) loads only the necessary classes for its specified module version.

Key Components of a Multi-Release Jar File

  • module-info.class: Defines the structure of the multi-release JAR file, including which modules are present and at what API levels.
  • Class files: Organized based on their required module versions.

Worked Example

Let's create a simple multi-release JAR example using Maven:

  1. Create a new Maven project with the following pom.xml file:
<project xmlns="http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/xsd/maven-4.0.0.xsd http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.example</groupId>
<artifactId>multi-release-jar</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencies>
<!-- Add any dependencies here -->
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.openjdk.java</groupId>
<artifactId>java-maven-plugin</artifactId>
<version>0.8.2</version>
<configuration>
<release>12</release>
</configuration>
</plugin>
</plugins>
</build>
</project>
  1. Create a package structure and add the following classes:
  • src/main/java/com/example/api1/MyClass1.java
package com.example.api1;

public class MyClass1 {
public void myMethod() {
System.out.println("API Level 1: MyClass1");
}
}
  • src/main/java/com/example/api2/MyClass2.java
package com.example.api2;

public class MyClass2 {
public void myMethod() {
System.out.println("API Level 2: MyClass2");
}
}
  1. In the root of your project, create a module-info.java file:
module com.example {
requires api1; // Replace with any dependencies required by API level 1 classes
requires api2; // Replace with any dependencies required by API level 2 classes

exports com.example.api1;
opens com.example.api1;

exports com.example.api2;
opens com.example.api2;
}
  1. Add the following to your src/main/resources/META-INF/services/javax.annotation.processing.Processor file:
org.openjdk.java.jdeps.MultiReleaseJarProcessor
  1. Run the Maven build command: mvn clean compile assembly:single

After running the build, you will find a multi-release JAR file in the target/ directory. The JAR contains both MyClass1 and MyClass2, but they are separated based on their API levels.

Common Mistakes

  • Forgetting to define the required modules in the module-info.java file
  • Not specifying the correct release version in the Maven configuration
  • Failing to export or open the necessary packages in the module declaration
  • Neglecting to handle conflicts between classes with the same name but different API levels

Common Mistakes - Subheadings

  • Incorrect Module Definitions
  • Incorrect Release Version Configuration
  • Improper Export and Open Statements
  • Handling Class Conflicts

Practice Questions

  1. How can you create a multi-release JAR using Gradle instead of Maven?
  2. What happens if you try to use a class from an unsupported API level within your application?
  3. Can you explain how the module-info.class file contributes to the separation of classes based on their required module version?
  4. How can you handle conflicts between classes with the same name but different API levels when creating a multi-release JAR file?
  5. What is the purpose of adding the org.openjdk.java.jdeps.MultiReleaseJarProcessor to the META-INF/services/javax.annotation.processing.Processor file in your project resources?

FAQ

Q: Is it possible to create multi-release JAR files without using Maven or Gradle?

A: Yes, it's possible to create multi-release JAR files manually by following the Java documentation and setting up the necessary classpath configurations. However, using build tools like Maven or Gradle can simplify the process significantly.

Q: What is the purpose of opening a package in the module declaration?

A: Opening a package allows other modules to access the classes within that package, which is essential for proper modularization and dependency management.

Q: Can I use multi-release JAR files with older versions of Java (prior to Java 9)?

A: No, multi-release JAR files are only supported in Java 9 and later versions.

Q: How can I handle class conflicts when creating a multi-release JAR file?

A: To handle class conflicts, you should use the requires and opens directives in your module declaration to ensure that only the necessary version of a class is loaded. Additionally, you can consider renaming conflicting classes or using interfaces to achieve modularity.

Q: What does adding the org.openjdk.java.jdeps.MultiReleaseJarProcessor to the META-INF/services/javax.annotation.processing.Processor file do in a multi-release JAR project?

A: Adding the org.openjdk.java.jdeps.MultiReleaseJarProcessor to the META-INF/services/javax.annotation.processing.Processor file is necessary for the Java compiler to recognize and process the multi-release JAR correctly. This processor helps in creating a single JAR file with multiple versions of classes organized based on their required module version.

Java - Multi-Release Jar Files | Java | XQA Learn