次のような内容のjarファイルがあります。
以下は私のマニフェストファイルです
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.3
Created-By: 1.7.0_06-b24 (Oracle Corporation)
Main-Class: org.sai.com.DerbyDemo
Class-Path: derby.jar derbyclient.jar derbynet.jar derbytools.jar
Jarを実行しようとすると、ClassNotFoundExcception
がスローされました。これは、外部jar内のjarを参照していないことを意味します。
の中に Class-Path
属性、jarを参照する方法(derby.jar
など)実際のjarの中に?
これにはカスタムクラスローダーが必要です。 One Jar をご覧ください。
One-JARを使用すると、Javaアプリケーションとその依存関係Jarsを単一の実行可能Jarファイルにパッケージ化できます。
Antタスクがあり、その構築も簡単にできます。
[〜#〜] reference [〜#〜](from 背景 )
ほとんどの開発者は、依存関係のJarファイルを自分のJarファイルに入れ、クラスパス属性をMETA-INF/MANIFESTに追加するとトリックを行うと合理的に想定しています:
jarname.jar
| /META-INF
| | MANIFEST.MF
| | Main-Class: com.mydomain.mypackage.Main
| | Class-Path: commons-logging.jar
| /com/mydomain/mypackage
| | Main.class
| commons-logging.jar
残念ながら、これは機能しません。 Java
Launcher$AppClassLoader
は、この種のClass-Path
を持つJar内のJarからクラスをロードする方法を知りません。jar:file:jarname.jar!/commons-logging.jar
を使用しようとすると、行き止まり:このアプローチは、jarname.jarファイルがインストールされているディレクトリにサポートするJarファイルをインストール(分散)した場合にのみ機能します。
できません。 公式チュートリアル から:
マニフェストでClass-Pathヘッダーを使用することにより、Javaを呼び出してアプリケーションを実行するときに長い-classpathフラグを指定する必要がなくなります。
注:Class-Pathヘッダーは、ローカルネットワーク上のクラスまたはJARファイルを指し、JARファイル内のJARファイルまたはインターネットプロトコル経由でアクセス可能なクラスではありません。 JARファイル内のJARファイルのクラスをクラスパスにロードするには、それらのクラスをロードするカスタムコードを記述する必要があります。たとえば、MyJar.jarにMyUtils.jarという別のJARファイルが含まれている場合、MyJar.jarのマニフェストのClass-Pathヘッダーを使用して、MyUtils.jarのクラスをクラスパスにロードすることはできません。
Eclipseには、実行可能jarをエクスポートするオプションがあります。 すべてのプロジェクト関連のjarを生成されたjarにパッケージ化するオプションがあり、この方法でEclipseは、新しいjar内の統合されたjarを参照するカスタムクラスローダーを追加します。
クラスローダーのデフォルトの実装は、jar-within-a-jarからロードできません。そうするには、「サブjar」全体をメモリにロードする必要があり、jar形式のランダムアクセスの利点を無効にします(参照保留中-これをサポートするドキュメントが見つかったら編集します)。
JarSplice などのプログラムを使用して、すべてを1つのクリーンな実行可能jarにバンドルすることをお勧めします。
Edit:ソース参照が見つかりませんでしたが、この正確な「問題」を説明するSun Webサイトからの未解決のRFEがあります: http://bugs.Sun.com/bugdatabase/view_bug.do?bug_id=4648386
また、ライブラリjarファイルをclasses
ディレクトリの\lib
サブディレクトリに配置し、コマンドラインから実行することにより、プログラムが動作することを「テスト」できます。つまり、次のディレクトリ構造を使用します。
classes/org/sai/com/DerbyDemo.class
classes/org/sai/com/OtherClassFiles.class
classes/lib/derby.jar
classes/lib/derbyclient.jar
コマンドラインから、上記の「classes」ディレクトリに移動し、次のように入力します。
Java -cp .:lib/* org.sai.com.DerbyDemo
Jarファイルをライブラリ(netbeansを使用している場合)に追加し、マニフェストのファイルclasspath
を次のように変更します。
Class-Path: lib/derby.jar lib/derbyclient.jar lib/derbynet.jar lib/derbytools.jar
同様の答えが存在します here
カスタムクラスローダーを作成したくない場合。 jarファイルストリームを読みます。そして、それをFileオブジェクトに転送します。その後、ファイルのURLを取得できます。 URLClassLoaderに送信すると、必要に応じてjarファイルをロードできます。サンプル:
InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("example"+ ".jar");
final File tempFile = File.createTempFile("temp", ".jar");
tempFile.deleteOnExit(); // you can delete the temp file or not
try (FileOutputStream out = new FileOutputStream(tempFile)) {
IOUtils.copy(resourceAsStream, out);
}
IOUtils.closeQuietly(resourceAsStream);
URL url = tempFile.toURI().toURL();
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{url});
urlClassLoader.loadClass()
...