jarコマンド入門

# 第５章 成果物をアーカイブする

JARファイルのオプションについて理解するための事前知識として、
まずはJARファイルの仕様について説明します。

## JARファイルの構成

JARファイルには、以下の要素を含めることができます。
それぞれの要素について、「sample-root.jar」というJARファイルがあると仮定し、説明します。
<img width="291" alt="スクリーンショット 2020-05-27 15.11.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619923/62d3f8f6-d43b-9cb0-3f51-e757304a3e8f.png">

それぞれの概要について、以下に説明します。

### INDEX.LIST
jarコマンドの-iオプションで生成されるファイル。
このファイルが格納されているJARファイルと、それが依存している他のJARファイル内に
格納されているパッケージの位置情報をインデックス化することで、
クラスローダの処理高速化に利用される。

```text:INDEX.LISTのサンプル
JarIndex-Version: 1.0

sample-root.jar
com
com/example
com/example/app
依存しているJARファイルがある場合、その情報も以下に続く...
```

### MANIFEST.MF

マニュフェストファイルは、JARファイルの各種メタ情報を保持するファイルです。
メインセクションと個別セクションから構成され、「属性: 値」のペア方式で設定が可能です。
同じ属性が複数設定された場合は、個別セクションのものが優先されます。

```mf
#==========メインセクション==========
# バージョン情報(必須)
Manifest-Version: 1.0
# メイン属性
# 属性: 値

# メインセクションと個別セクションの間は必ず1行空ける
# ===========個別セクション===========
# エントリ別属性
# 属性: 値
```
以下、マニフェストファイルに設定できる主な属性です。

【メイン属性】

- Manifest-Version: <バージョン>  
マニフェストファイルのバージョンを定義する。整数およびピリオドしか設定できない。
- Created-By: <作成者>  
このマニフェストファイルが生成されるJavaのバージョンおよびベンダーを定義する。  
この属性は、jar ツールによって自動生成される
- Signature-Version: <バージョン>  
jarファイルの署名のバージョンを定義する。
- Class-Path: <URL>  
JARファイル内のクラスローダでは、この属性の値を使って内部検索パスが構築される。  
必要な拡張機能またはライブラリの相対URLを指定する。URL は 1 つ以上の空白で区切る。

その他にも、

- スタンドアロンアプリケーションに対して定義する属性(Main-Classヘッダなど)
- アプレットに対して定義する属性
- 拡張機能の識別のために定義する属性
- 拡張機能およびパッケージのバージョン管理とシーリング情報のために定義する属性

など、様々な属性が存在する。

【エントリ別属性】

- Content-Type: <データタイプ>  
JARファイルの特定のファイルのMIMEタイプおよびサブタイプを指定する。  
値は、「タイプ/サブタイプ」の形式の文字列でなければならない。
- Java-Bean: <boolean>  
特定のjarファイルエントリが、Java Beansオブジェクトかどうかを定義する。
- 拡張機能およびパッケージのバージョン管理とシーリング情報のために定義する属性  
メイン属性に同じ。

### 署名付きJARファイル
sample-root.DSAやsample-root.SFは、署名に関するファイルですが、
今回の記事ではJavaのセキュリティ面に関するツールに言及しないため割愛します。
 
### servicesディレクトリ
外部のJARファイルの機能を利用するためのサービスプロバイダーという機能があり、
外部のJARファイルとのインターフェースとなる具象クラスを格納するディレクトリ。
今回は説明を割愛するため、詳しく知りたい人は以下の記事を参照してください。
参照記事：[JARファイル - サービスプロバイダ機能](https://www.ne.jp/asahi/hishidama/home/tech/java/jar.html#h_Service_Provider)

## jarコマンドのオプション

### ファイルの操作系のオプション

- c : 新規作成
- u : 更新
- x : ファイル、ディレクトリの抽出
- t : アーカイブ内容の一覧表示
- f : JARファイルの指定

### マニュフェスト系のオプション

- M : マニフェストファイルを作成しない
    - cまたはuの場合 : マニフェストファイルを作成しない
    - uかつマニフェストファイルが存在する場合 : マニフェストファイルを削除する
- m : 指定したマニフェストファイルの属性ペアを追加する
    - 同名の属性が存在する場合 : 指定したマニフェストファイルの属性ペアで上書きする
    - 同名の属性が存在しない場合 : 指定したマニフェストファイルの属性ペアを追加する

### その他のオプション

- v : jarコマンドが行なった操作や格納されているファイルの一覧などの詳細情報を表示する
- 0 : ZIPによる圧縮をしないでJARファイルを生成する
- i <JARファイル> : 指定したJARファイルにINDEX.LISTを作成する
- -C <ディレクトリ> <対象>: 一時的にディレクトリを移動する  
処理中にディレクトリに移動するため、jarコマンドを実行したカレントディレクトリから  
ではなく引数に渡したディレクトリからの相対パスで対象を指定できる
- -J<オプション> : JREにオプションを渡す。渡すことができるオプションはjavaコマンドのもの

## jarコマンドの実例集
※オプション内の[v0M]などの表記は必須ではないが使用可能なオプションです。

### 作成(cオプション)

```shell
# inputfiles以下のリソースでjarfileという名前のJARファイルを作成する
jar c[v0M]f jarfile [-C dir] inputfiles [-Joption]
# inputfiles以下のリソースでjarfileを作成し、
# manifestに値を追記する(削除はしない)
jar c[v0]mf manifest jarfile [-C dir] inputfiles [-Joption]
```

> 【mオプションとfオプションの記載順について】
mオプションとfオプションの記載順は決まっていないが、
cmfならばmanifest jarfile、cfmならjarfile manifestというように、
後続の引数の順番を合わせる必要がある。

### 更新(uオプション)

```shell
# inputfiles以下のリソースで、変更のあった箇所のみをjarfileに反映し、更新する
jar u[v0M]f jarfile [-C dir] inputfiles [-Joption]
# inputfiles以下のリソースで変更のあった箇所のみをjarfileに反映し、
# manifestの更新を行う(値の追加もしくは削除)
jar u[v0]mf manifest jarfile [-C dir] inputfiles [-Joption]
```

### 抽出(xオプション)

```shell
# jarファイル内の全てのディレクトリとファイルを抽出(解凍)する
# inputfilesを指定した場合は、指定した対象以下を抽出する
jar x[v]f jarfile [inputfiles] [-Joption]
```

### 一覧表示(tオプション)

```shell
# jarファイル内の全てのディレクトリとファイルを一覧表示する
# inputfilesを指定した場合は、指定した対象以下を一覧表示する
jar t[v]f jarfile [inputfiles] [-Joption]
```
### インデックスの作成(iオプション)

```shell
# 指定したjarfileにINDEX.LISTを作成する
jar i jarfile [-Joption]
```

## 実行

以下、最初のフォルダ構成です。
<img width="285" alt="スクリーンショット 2020-05-27 18.00.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619923/c63df988-eda5-b984-965a-9887e0a61e6a.png">


### JARファイルの作成
JARファイルを指定して(f)、詳細な情報を出力し(v)、
java-sample.jarというJARファイルを新規作成(c)します。

```shell
# カレントディレクトリは/java-sampleです
$ jar cvf java-sample.jar .
マニフェストが追加されました
.DS_Storeを追加中です(入=6148)(出=411)(93%収縮されました)
lib/を追加中です(入=0)(出=0)(0%格納されました)
lib/commons-lang3-3.10.jarを追加中です(入=523372)(出=481881)(7%収縮されました)
src/を追加中です(入=0)(出=0)(0%格納されました)
src/com/を追加中です(入=0)(出=0)(0%格納されました)
src/com/example/を追加中です(入=0)(出=0)(0%格納されました)
src/com/example/app/を追加中です(入=0)(出=0)(0%格納されました)
src/com/example/app/UseCommons.javaを追加中です(入=647)(出=286)(55%収縮されました)
src/com/example/app/StrFactory.classを追加中です(入=308)(出=234)(24%収縮されました)
src/com/example/app/UseCommons$CommonsHelper.classを追加中です(入=592)(出=398)(32%収縮されました)
src/com/example/app/StrFactory.javaを追加中です(入=115)(出=101)(12%収縮されました)
src/com/example/app/UseCommons.classを追加中です(入=732)(出=441)(39%収縮されました)
```

カレントディレクトリにjava-sample.jarが作成されます。
<img width="282" alt="スクリーンショット 2020-05-27 18.07.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619923/4bac94e1-d641-d234-dba7-bfc098f037b8.png">

### JARファイルの一覧表示

```shell
# カレントディレクトリは/java-sampleです
$ jar tf java-sample.jar
META-INF/
META-INF/MANIFEST.MF
.DS_Store
lib/
lib/commons-lang3-3.10.jar
src/
src/com/
src/com/example/
src/com/example/app/
src/com/example/app/UseCommons.java
src/com/example/app/StrFactory.class
src/com/example/app/UseCommons$CommonsHelper.class
src/com/example/app/StrFactory.java
src/com/example/app/UseCommons.class
```

### JARファイルの解凍
java-sample直下で実行すると既存のファイルと解凍されたファイルが混じるので、
unzipというフォルダを作成し、そこへ解凍します。

```shell
# カレントディレクトリは/unzipです
$ jar xf ../java-sample/java-sample.jar
```

unzip直下にJARファイルの解凍結果が展開されます。
<img width="368" alt="スクリーンショット 2020-05-27 18.12.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619923/6bb02c60-f211-e544-f027-d28aa3aab90e.png">

[メインページに戻る](https://qiita.com/maple_syrup/items/c0aa2eacb8f486dc52a8)