☕ Java
Manifest File
The manifest file (META-INF/MANIFEST.MF) is a text file inside every JAR that contains metadata about the JAR and its contents. It specifies the main class for executable JARs, the classpath for dependency resolution, the JAR's version and vendor information, digital signature information, and any custom attributes. The manifest follows a specific key-value format with rules about line length, encoding, and section structure that must be followed precisely.
Manifest File Format and Structure
The manifest file is a plain text file with a precise format. Each line contains a key-value pair separated by a colon and a single space: Key: value. Attribute names are case-insensitive by convention though typically written in title case. Values are on the same line as the key and continue on the next line if the continuation line begins with a single space. Lines must not exceed 72 bytes — longer values are split across multiple lines using the continuation format.
The manifest is divided into sections. The first section before any blank line is the main section, which contains attributes that apply to the entire JAR. Subsequent sections begin with a Name: entry (specifying a class or package) and contain attributes specific to that entry — primarily signature-related attributes for JAR signing. Sections are separated by blank lines.
The format has several surprising rules that catch developers off guard. The very last line of the manifest file must end with a newline character — a manifest that ends without a trailing newline is malformed and the last attribute may be silently ignored. This has caused real production bugs where the Main-Class attribute in the last line was missing a trailing newline and the JAR could not be executed. All manifests generated by build tools include this trailing newline automatically.
The file must be encoded in UTF-8. Non-ASCII characters are represented using Unicode escapes (\uXXXX). The value on each line must start immediately after the ": " separator — there must be exactly one space between the colon and the value. These strict rules exist because the manifest parser is deliberately simple and unforgiving.
Java
// ── MANIFEST.MF format: ─────────────────────────────────────────────
//
// Manifest-Version: 1.0
// Created-By: Apache Maven 3.9.5
// Built-By: alice
// Build-Jdk: 21.0.1
// Main-Class: com.example.Main
// Class-Path: lib/gson-2.10.1.jar lib/logback-1.4.jar
// Implementation-Title: My Application
// Implementation-Version: 2.1.0
// Implementation-Vendor: Example Corp
// Specification-Version: 2.1
//
// ← IMPORTANT: file must end with a blank line (newline after last attribute)
// ── Format rules: ─────────────────────────────────────────────────────
// Key: Value ← key, colon, ONE space, value
// Continuation: ← lines longer than 72 bytes split like this:
// Class-Path: lib/gson.jar lib
// /logback.jar lib/jackson.jar ← continuation line starts with ONE space
// ── Main section vs named sections: ──────────────────────────────────
//
// Manifest-Version: 1.0 ← main section (applies to entire JAR)
// Main-Class: com.example.Main ← main section
//
// ← blank line separates sections
// Name: com/example/service/ ← named section (for this package)
// Sealed: true ← package sealing attribute
//
// ← blank line
// Name: com/example/model/Order.class
// Content-Type: application/java-vm
// ── Reading manifest programmatically: ───────────────────────────────
import java.util.jar.*;
JarFile jar = new JarFile("myapp.jar");
Manifest manifest = jar.getManifest();
Attributes mainAttrs = manifest.getMainAttributes();
String mainClass = mainAttrs.getValue("Main-Class");
String version = mainAttrs.getValue("Implementation-Version");
String classpath = mainAttrs.getValue("Class-Path");
System.out.println("Main-Class: " + mainClass);
System.out.println("Implementation-Version: " + version);
System.out.println("Class-Path: " + classpath);
jar.close();Key Manifest Attributes
Several manifest attributes have special meaning to the JVM and tools. Understanding each attribute's purpose and when to use it enables you to create JARs with exactly the right behaviour.
Manifest-Version specifies the manifest format version. This must be 1.0 — no other version exists in practice, but the attribute must be present and it must be the first attribute in the main section.
Main-Class is the most important attribute for executable JARs. It specifies the fully qualified name of the class whose main(String[] args) method will be invoked when the JAR is executed with java -jar. Without this attribute, java -jar fails with an error. With it, the named class is loaded and main() is invoked. The class must exist in the JAR or on the classpath.
Class-Path specifies additional JAR files or directories that should be added to the classpath when this JAR is loaded. Paths are relative to the directory containing the JAR file and separated by spaces. This attribute enables a deployment pattern where an application JAR and its dependencies are distributed together in a known directory structure, with the manifest's Class-Path listing all the dependency JARs. When java -jar is run, the JVM automatically extends the classpath with all listed entries.
Implementation-Title, Implementation-Version, Implementation-Vendor, Specification-Title, Specification-Version, and Specification-Vendor are informational attributes that identify the JAR. They are read by Package.getPackage() for any package in the JAR, and by tools and frameworks that report version information.
Sealed: true on a package's named section seals the package — all classes in the package must come from the same JAR, preventing other JARs from adding classes to the same package. This prevents split-package scenarios and enforces package integrity.
Java
// ── Minimal executable manifest: ─────────────────────────────────────
//
// Manifest-Version: 1.0
// Main-Class: com.example.Application
// ← trailing newline REQUIRED
// ── Executable manifest with dependencies: ────────────────────────────
//
// Manifest-Version: 1.0
// Main-Class: com.example.Application
// Class-Path: lib/gson-2.10.1.jar lib/logback-classic-1.4.14.jar
// lib/logback-core-1.4.14.jar lib/slf4j-api-2.0.9.jar
// ↑ continuation line starts with space
// ↑ the two lib entries are on the same logical value
// Directory layout for Class-Path to work:
// deployment/
// ├── myapp.jar ← the application JAR
// └── lib/
// ├── gson-2.10.1.jar ← all deps listed in Class-Path
// ├── logback-classic-1.4.14.jar
// └── slf4j-api-2.0.9.jar
//
// java -jar deployment/myapp.jar
// → JVM adds deployment/lib/gson-2.10.1.jar etc. to classpath automatically
// ── Full manifest with version information: ───────────────────────────
//
// Manifest-Version: 1.0
// Main-Class: com.example.Application
// Class-Path: lib/gson-2.10.1.jar lib/logback-1.4.jar
// Implementation-Title: Order Management System
// Implementation-Version: 3.2.1
// Implementation-Vendor: Example Corp Ltd
// Implementation-Vendor-Id: com.example
// Specification-Title: Order Management API
// Specification-Version: 3.0
// Specification-Vendor: Example Corp Ltd
// Built-By: GitHub Actions
// Build-Jdk-Spec: 21
// Created-By: Apache Maven 3.9.5
// ── Reading version info programmatically: ────────────────────────────
Package pkg = OrderService.class.getPackage();
System.out.println(pkg.getImplementationVersion()); // 3.2.1
System.out.println(pkg.getImplementationTitle()); // Order Management System
System.out.println(pkg.getSpecificationVersion()); // 3.0
// ── Sealed package manifest section: ─────────────────────────────────
//
// Manifest-Version: 1.0
//
// Name: com/example/secure/
// Sealed: true
// ← blank line required before each named section
// Name: com/example/internal/
// Sealed: trueGenerating Manifests with Build Tools
In practice, manifests are generated by Maven, Gradle, or IDEs rather than written by hand. Understanding how to configure these tools to produce the right manifest is more important than knowing the raw manifest format. Build tools can add custom attributes, set the main class, compute the classpath, include build metadata, and generate multi-release jar manifests.
Maven uses several plugins for JAR creation. The default maven-jar-plugin creates a simple JAR with basic manifest attributes. The maven-shade-plugin creates a fat JAR (uber-jar) with all dependencies merged and a special manifest. The spring-boot-maven-plugin creates a layered Spring Boot JAR with a custom manifest and class loader. All of these allow configuration in the pom.xml to control what appears in the manifest.
Gradle's jar task creates a basic JAR and allows full customisation of the manifest through the manifest { } closure in the jar task configuration. Attributes are set as key-value pairs; sections can be added programmatically. The Gradle Shadow plugin adds a similar capability for fat JARs.
Multi-Release JARs (MRJARs), introduced in Java 9, use a special manifest attribute Multi-Release: true combined with a special directory structure (META-INF/versions/N/) to include different class versions for different JVM versions. The JVM uses the highest version of a class that is less than or equal to the current JVM version, falling back to the root class if no version-specific class exists. This allows library authors to ship a single JAR that uses newer Java APIs when run on newer JVMs while remaining compatible with older JVMs.
Java
// ── Maven jar plugin configuration (pom.xml): ───────────────────────
// <plugin>
// <groupId>org.apache.maven.plugins</groupId>
// <artifactId>maven-jar-plugin</artifactId>
// <version>3.3.0</version>
// <configuration>
// <archive>
// <manifest>
// <mainClass>com.example.Application</mainClass>
// <addClasspath>true</addClasspath>
// <classpathPrefix>lib/</classpathPrefix>
// <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
// <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
// </manifest>
// <manifestEntries>
// <Built-By>GitHub Actions</Built-By>
// <Build-Jdk>${java.version}</Build-Jdk>
// <Implementation-Version>${project.version}</Implementation-Version>
// </manifestEntries>
// </archive>
// </configuration>
// </plugin>
// ── Gradle jar task configuration (build.gradle): ────────────────────
// tasks.jar {
// manifest {
// attributes(
// "Main-Class" to "com.example.Application",
// "Implementation-Title" to project.name,
// "Implementation-Version" to project.version,
// "Built-By" to System.getProperty("user.name"),
// "Build-Jdk" to System.getProperty("java.version")
// )
// }
// }
// ── Spring Boot executable JAR manifest: ─────────────────────────────
//
// Manifest-Version: 1.0
// Main-Class: org.springframework.boot.loader.launch.JarLauncher
// Start-Class: com.example.Application ← YOUR main class
// Spring-Boot-Version: 3.2.5
// Spring-Boot-Classes: BOOT-INF/classes/
// Spring-Boot-Lib: BOOT-INF/lib/
// Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
// Spring-Boot-Layers-Index: BOOT-INF/layers.idx
//
// Spring Boot uses a custom JarLauncher as Main-Class.
// JarLauncher unpacks and sets up the nested JAR structure,
// then delegates to Start-Class (your Application class).
// ── Multi-Release JAR manifest and structure: ─────────────────────────
//
// Manifest-Version: 1.0
// Multi-Release: true ← enables version-specific class loading
//
// Directory structure:
// com/example/StreamUtils.class ← Java 8 compatible implementation
// META-INF/versions/11/com/example/StreamUtils.class ← Java 11 version
// META-INF/versions/17/com/example/StreamUtils.class ← Java 17 version
//
// On Java 8: root StreamUtils.class is loaded
// On Java 11: META-INF/versions/11/StreamUtils.class is loaded
// On Java 17: META-INF/versions/17/StreamUtils.class is loadedRelated Topics in Packages and Access Control
Package Concept
A package in Java is a namespace that groups related classes, interfaces, enums, and annotations into a logical unit. Packages solve three fundamental problems in large software systems: name collision (two classes can have the same simple name if they are in different packages), access control (package-private visibility limits access to the same package), and organisation (related types live together and can be found intuitively). Every Java class belongs to a package — either explicitly declared or the unnamed default package.
Built-in Packages
Java ships with a rich standard library organised into packages under the java and javax namespaces. These built-in packages provide data structures, I/O, networking, concurrency, database access, XML processing, GUI components, and much more. Knowing which package contains which functionality, and understanding the most important classes in the most frequently used packages, is foundational knowledge for every Java developer.
User-defined Packages
User-defined packages are packages you create to organise your own application's classes and interfaces. They follow the same rules as Java's built-in packages — the package declaration must be the first statement in the file, the directory structure must match the package hierarchy, and access modifiers control visibility across package boundaries. Designing a meaningful package structure is a foundational software engineering skill that directly affects how maintainable and navigable a codebase remains as it grows.
import
The import statement allows you to use a class, interface, or enum by its simple name rather than its fully qualified name. Without an import, every reference to java.util.ArrayList requires writing the full name java.util.ArrayList. With import java.util.ArrayList, you write simply ArrayList. Imports are a compile-time convenience — they have no effect on performance, do not load classes, and are not present in the compiled bytecode. The compiler uses them only to resolve simple names to fully qualified names.