Java開発において、作成したプログラムを配布したり、サーバー上で実行したりする際に欠かせないのがJAR(Java Archive)ファイルです。

複数のクラスファイルや設定ファイル、リソースを一まとめにするこの仕組みは、Javaエコシステムの根幹を支えています。

本記事では、JARファイルの基礎知識から、コマンドラインでの作成・実行方法、マニフェストファイルの詳細な設定、さらにはMavenやGradleといったモダンなビルドツールを用いた自動化手法まで、プロフェッショナルな現場で求められる知識を網羅的に解説します。

JARファイルを正しく理解し、効率的なデプロイメントを実現しましょう。

JARファイルの基本概念

JARファイルとは、複数のJavaクラスファイルや関連するメタデータ、リソース(画像や設定ファイルなど)を一つのファイルにまとめたアーカイブ形式のことです。

実態はZIP形式の圧縮ファイルであり、標準的な解凍ソフトで中身を確認することも可能ですが、Java実行環境(JRE)が認識できる特定の構造を持っています。

JARファイルを利用するメリット

JARファイルを利用する主な目的は、配布の簡略化と実行効率の向上にあります。

まず、配布の観点では、数百、数千に及ぶクラスファイルを個別に転送するのではなく、一つのファイルとして扱うことで、ファイルの欠落を防ぎ、転送時間を短縮できます。

また、JavaランタイムはJARファイル内のクラスを効率的にロードするように最適化されており、アプリケーションの起動や実行時のパフォーマンスにも寄与します。

さらに、JARファイルにはデジタル署名を付与することができ、改ざん防止や配布元の証明といったセキュリティ機能も提供されています。

JARファイルの種類

一般的にJARファイルは、その用途に応じて大きく2つの種類に分類されます。

ライブラリJAR

他のプログラムから呼び出されることを前提とした、再利用可能なコンポーネントをまとめたもの。

単体では実行されません。

実行可能JAR(Executable JAR)

エントリポイント(Main-Class)が定義されており、java -jar コマンドで直接起動できるもの。

JARコマンドの主要オプション一覧

JARファイルの操作には、JDKに標準で付属している jar コマンドを使用します。

このコマンドは多機能であり、オプションの組み合わせによって作成、表示、展開などの操作を行います。

以下に、頻繁に使用される主要なオプションをまとめます。

オプション意味解説
ccreate新しいアーカイブファイルを作成します。
vverbose処理の経過を標準出力に詳しく表示します(詳細モード)。
ffile作成または操作対象となるファイル名を指定します。
xextractアーカイブからファイルを展開(解凍)します。
tlistアーカイブの内容を一覧表示します。
uupdate既存のJARファイルの内容を更新します。
mmanifest指定したマニフェストファイルを取り込みます。
eentrypoint実行可能JARのエントリポイントとなるクラスを指定します。
Cdirectory指定したディレクトリに移動して処理を行います。

これらのオプションは、ハイフンを付けずに jar cvf ... のように連結して記述するのが一般的です。

ステップバイステップ:JARファイルの作成手順

ここでは、最も基本的な「複数のクラスファイルを一つのJARにまとめる方法」を解説します。

1. ソースコードの用意とコンパイル

まず、簡単なJavaプログラムを用意します。

以下の例では、挨拶を表示するシンプルなクラスを作成します。

Java
// HelloWorld.java
public class HelloWorld {
    public static void main(String[] args) {
        // 標準出力にメッセージを表示
        System.out.println("Hello, JAR World!");
    }
}

このファイルをコンパイルし、クラスファイルを生成します。

Shell
javac HelloWorld.java

実行結果として、HelloWorld.class が作成されます。

2. jarコマンドによるアーカイブ作成

次に、生成されたクラスファイルをJARファイルにまとめます。

Shell
jar cvf MyProgram.jar HelloWorld.class

このコマンドの実行結果は以下のようになります。

実行結果
マニフェストが追加されました
HelloWorld.classを追加中です(入=427)(出=283)(33%収縮されました)

これで、カレントディレクトリに MyProgram.jar が作成されました。

3. JARファイルの内容確認

作成されたJARファイルに正しくファイルが含まれているかを確認するには、t オプションを使用します。

Shell
jar tf MyProgram.jar
実行結果
META-INF/
META-INF/MANIFEST.MF
HelloWorld.class

META-INF/MANIFEST.MF は、jarコマンドによって自動的に生成される管理用ファイルです。

JARファイルの実行方法

JARファイルを実行する方法は、そのJARファイルが「実行可能」として構成されているかどうかによって異なります。

メインクラスを指定して実行する

マニフェストファイルでメインクラスが指定されていない(または指定したくない)場合は、クラスパスにJARファイルを含めた上で、実行するクラス名を直接指定します。

Shell
java -cp MyProgram.jar HelloWorld
実行結果
Hello, JAR World!

この方法では、-cp(または -classpath)オプションを使用してJARファイルを読み込み対象として指定しています。

java -jar コマンドによる実行

もしJARファイルが正しく設定されていれば、以下のシンプルなコマンドで実行できます。

Shell
java -jar MyProgram.jar

しかし、先ほどの手順で作成しただけのJARファイルでこれを実行すると、以下のようなエラーが発生します。

MyProgram.jarにメイン・マニフェスト属性がありません

これは、JARファイル内のどのクラスに main メソッドがあるのかをJVMが判断できないためです。

これを解決するには、次節で解説するマニフェストファイルの設定が必要になります。

マニフェストファイル(MANIFEST.MF)の徹底解説

マニフェストファイルは、JARファイル全体の性格を定義する非常に重要なメタデータファイルです。

マニフェストファイルの役割

マニフェストファイル(META-INF/MANIFEST.MF)には、以下のような情報が記述されます。

  • Main-Classjava -jar で実行する際のエントリポイント。
  • Class-Path:このJARが依存する他のライブラリのパス。
  • Implementation-Version:プログラムのバージョン情報。

Main-Classを指定する

手動でマニフェストファイルを作成して、実行可能JARを作る方法を確認しましょう。

まず、任意のテキストファイル(例:manifest.txt)を作成し、以下の内容を記述します。

Main-Class: HelloWorld

注意点として、ファイルの最後には必ず改行を入れてください。

改行がない場合、最後の行が無視されるというJavaの仕様上の制限があります。

このマニフェストファイルを使用してJARを再作成します。

Shell
jar cvfm MyProgram.jar manifest.txt HelloWorld.class

m オプションを指定することで、自作のマニフェストファイルの内容を META-INF/MANIFEST.MF に反映させることができます。

これにより、java -jar MyProgram.jar での実行が可能になります。

Class-Pathによる依存関係の解決

アプリケーションが外部のライブラリ(他のJARファイル)に依存している場合、マニフェストファイルでそれらの場所を指定できます。

Main-Class: com.example.MainApp
Class-Path: lib/library1.jar lib/library2.jar

このように記述すると、実行時に lib ディレクトリ内にあるJARファイルが自動的にクラスパスに追加されます。

複数のパスを指定する場合は、半角スペースで区切ります。

実行可能JAR(Executable JAR)の作り方

コマンドラインでの操作に慣れてきたら、より効率的な作成方法をマスターしましょう。

e オプションを使用すると、外部のマニフェストファイルを用意することなく、コマンドライン引数だけでエントリポイントを指定できます。

Shell
jar cfe MyProgram.jar HelloWorld HelloWorld.class

このコマンドでは、e オプションの直後にメインクラス名(HelloWorld)を指定しています。

これにより、内部で自動生成されるマニフェストファイルに Main-Class: HelloWorld が書き込まれます。

パッケージ構造を持つ場合の作成

実際のプロジェクトでは、クラスはパッケージ(ディレクトリ構造)に属していることがほとんどです。

例えば、com.example.App クラスを作成する場合、ファイル構成は以下のようになります。

src/
  └─ com/
      └─ example/
          └─ App.class

この場合、パッケージのルートディレクトリからアーカイブを作成する必要があります。

Shell
jar cvfe MyApp.jar com.example.App com/example/App.class

JARファイル内部の構造が、Javaのパッケージ規則(ディレクトリ構造)と一致していることが、正常に動作するための絶対条件です。

外部ライブラリを含めたJAR(Fat JAR / Uber JAR)の作成

現代のJava開発では、多数の外部ライブラリ(Apache Commons, Jackson, Springなど)を使用します。

しかし、標準の jar コマンドでは、ライブラリのJARファイルを別のJARファイルの中に含めても、そのままではクラスパスとして認識されません。

そこで用いられるのが、Fat JAR(またはUber JAR)と呼ばれる手法です。

Fat JARとは

Fat JARとは、自作のクラスファイルと、依存しているすべての外部ライブラリのクラスファイルを「展開した状態」ですべて一つにまとめたJARファイルのことです。

これにより、一つのファイルを持ち運ぶだけで、依存関係を気にせずにどこでも実行できるようになります。

手動での作成(非推奨)

論理的には、すべての依存ライブラリを一度解凍(jar xf)し、それらを自作クラスと一緒に再度固めることで作成できます。

しかし、これを手動で行うのは非常に手間がかかり、ライセンスファイル(LICENSE)やマニフェストファイルの衝突といった問題も発生します。

そのため、実務では後述するビルドツール(MavenやGradle)を使用するのが一般的です。

ビルドツール(Maven/Gradle)による自動化

現代的なJava開発において、JARファイルの作成を手動の jar コマンドで行うことは稀です。

ビルドツールを使用することで、依存関係の解決からJARのパッケージングまでを完全に自動化できます。

MavenでのJAR作成

Mavenでは、デフォルトで mvn package コマンドを実行するとJARファイルが作成されます。

実行可能JARの設定

pom.xmlmaven-jar-plugin の設定を記述することで、マニフェストファイルのメインクラス指定を自動化できます。

XML
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>3.3.0</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <mainClass>com.example.MainApp</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>

Fat JARの作成(Maven Assembly Plugin)

すべての依存関係を一つにまとめるには、maven-assembly-plugin を使用します。

XML
<plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <mainClass>com.example.MainApp</mainClass>
            </manifest>
        </archive>
        <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
    </configuration>
    <executions>
        <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
        </execution>
    </executions>
</plugin>

これにより、target ディレクトリに *-jar-with-dependencies.jar という名前で、すべてのライブラリを含んだJARが生成されます。

GradleでのJAR作成

Gradleも非常にシンプルです。

build.gradle に以下の記述を追加します。

gradle
jar {
    manifest {
        attributes(
            'Main-Class': 'com.example.MainApp'
        )
    }
}

Fat JARを作成する場合は、shadow プラグインを使用するのが標準的です。

gradle
plugins {
    id 'com.github.johnrengelman.shadow' version '8.1.1'
    id 'java'
}

shadowJar {
    archiveBaseName.set('my-app-all')
    manifest {
        attributes 'Main-Class': 'com.example.MainApp'
    }
}

gradle shadowJar を実行するだけで、配布に最適な巨大なJARファイルが生成されます。

JARファイル運用のベストプラクティス

JARファイルをより高度に、かつ安全に運用するためのポイントをいくつか紹介します。

バージョン管理の徹底

JARファイルの名前にバージョン番号を含めることは、運用上の鉄則です(例:app-1.2.3.jar)。

これにより、どのバージョンのプログラムがサーバー上で動いているのかを即座に判断できます。

ビルドツールを使えば、プロジェクト設定から自動的にファイル名を生成できます。

マルチリリースJAR(Multi-Release JAR)の活用

Java 9以降、異なるJavaバージョン向けに異なるクラスファイルを持たせることができるマルチリリースJARという仕組みが登場しました。

特定のJavaバージョンのみで利用可能な最適化されたAPIを使用しつつ、古いバージョンとの互換性を保ちたい場合に有用です。

これは META-INF/versions/ ディレクトリ内にバージョンごとのクラスを配置することで実現されます。

モジュールシステム(Project Jigsaw)との兼ね合い

Java 9で導入されたモジュールシステムにより、JARファイルは単なるアーカイブから「モジュール」としての役割も担うようになりました。

module-info.class をJARのルートに含めることで、公開するパッケージや依存するモジュールを厳密に制御でき、より堅牢なアプリケーション構築が可能になります。

トラブルシューティング:よくあるエラーと解決策

JARファイルの作成や実行で躓きやすいポイントを整理しました。

1. 「メイン・マニフェスト属性がありません」

前述の通り、これは Main-Class がマニフェストに定義されていない場合に発生します。

解決策

マニフェストファイルを正しく指定してJARを再作成するか、java -cp でメインクラスを明示してください。

2. 「ClassNotFoundException」または「NoClassDefFoundError」

JARの実行中にクラスが見つからない場合に発生します。

解決策
  • マニフェストのClass-Path指定が正しいか確認。
  • 外部ライブラリをまとめたFat JARになっているか確認。
  • パッケージ構造(ディレクトリ)がJAR内部で正しく再現されているか確認。

3. 「Invalid or corrupt jarfile」

JARファイルが壊れているか、空の状態で作成された可能性があります。

解決策

jar tf コマンドで中身が正常に見えるか確認し、不備があれば再ビルドを行ってください。

4. 文字化けやリソースの読み込み失敗

JARファイル内部にあるプロパティファイルやテキストファイルを読み込む際、パスの指定方法が間違っていることがあります。

解決策

ファイルシステム上のパス(Fileクラス)ではなく、クラスパスからの相対パス(Class.getResourceAsStream()など)を使用するようにコードを修正してください。

まとめ

JARファイルは、Javaアプリケーションの配布と実行を支える非常に強力で柔軟な仕組みです。

基本的な jar コマンドの操作を理解することは、トラブルシューティングや環境構築において大きな武器となります。

最後に、JARファイル運用の要点を振り返ります。

  • マニフェストファイルの Main-Class 設定が実行可能JARの鍵となる。
  • パッケージ構造を維持してアーカイブすることが不可欠。
  • 現代の開発では、MavenやGradleを使用して依存関係を含めたFat JARを作成するのが主流。
  • エラー発生時は、jar tf コマンドで内部構造を真っ先に確認する。

これらの知識を活用することで、Javaプログラムのデプロイ作業はよりスムーズで確実なものになるはずです。

まずは手元の小さなプログラムをJAR化することから始め、徐々にビルドツールを用いた高度な自動化へとステップアップしていきましょう。