web-dev-qa-db-ja.com

jar内の参照jar

次のような内容のjarファイルがあります。

enter image description here

以下は私のマニフェストファイルです

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の中に?

52
srk

これにはカスタムクラスローダーが必要です。 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ファイルをインストール(分散)した場合にのみ機能します。

34
epoch

できません。 公式チュートリアル から:

マニフェストでClass-Pathヘッダーを使用することにより、Javaを呼び出してアプリケーションを実行するときに長い-classpathフラグを指定する必要がなくなります。

注:Class-Pathヘッダーは、ローカルネットワーク上のクラスまたはJARファイルを指し、JARファイル内のJARファイルまたはインターネットプロトコル経由でアクセス可能なクラスではありません。 JARファイル内のJARファイルのクラスをクラスパスにロードするには、それらのクラスをロードするカスタムコードを記述する必要があります。たとえば、MyJar.jarにMyUtils.jarという別のJARファイルが含まれている場合、MyJar.jarのマニフェストのClass-Pathヘッダーを使用して、MyUtils.jarのクラスをクラスパスにロードすることはできません。

21
JB Nizet

Eclipseには、実行可能jarをエクスポートするオプションがあります。 enter image description here すべてのプロジェクト関連のjarを生成されたjarにパッケージ化するオプションがあり、この方法でEclipseは、新しいjar内の統合されたjarを参照するカスタムクラスローダーを追加します。

enter image description here

12
vogash

クラスローダーのデフォルトの実装は、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
6
bfishman

Jarファイルをライブラリ(netbeansを使用している場合)に追加し、マニフェストのファイルclasspathを次のように変更します。

Class-Path: lib/derby.jar lib/derbyclient.jar lib/derbynet.jar lib/derbytools.jar

同様の答えが存在します here

2
BWGathecha

カスタムクラスローダーを作成したくない場合。 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()
...
1
蜡笔小新