マニフェストファイルのMain-ClassではないJarからクラスを実行する方法


166

4つのクラスを持つJARがあり、それぞれにMainメソッドがあります。必要に応じて、それぞれを実行できるようにしたいと考えています。Linuxボックスのコマンドラインから実行しようとしています。

E.g. The name of my JAR is MyJar.jar

主なクラスのディレクトリ構造は次のとおりです。

com/mycomp/myproj/dir1/MainClass1.class
com/mycomp/myproj/dir2/MainClass2.class
com/mycomp/myproj/dir3/MainClass3.class
com/mycomp/myproj/dir4/MainClass4.class

マニフェストファイルでメインとして1つのクラスを指定できることを知っています。しかし、実行したいクラスを実行するためにコマンドラインで引数を指定する方法はありますか?

私はこれを試しました:

jar cfe MyJar.jar com.mycomp.myproj.dir2.MainClass2 com/mycomp/myproj/dir2/MainClass2.class /home/myhome/datasource.properties /home/myhome/input.txt

そして私はこのエラーを受け取りました:

com/mycomp/myproj/dir2/MainClass2.class : no such file or directory

(上記のコマンドでは、「/ home / myhome / datasource.properties」および「/home/myhome/input.txt」がコマンドライン引数です)。


依存関係を保持するために別のjarを使用して、それらを異なるjarにパッケージ化するだけですか?
Nick

11
コマンドライン引数に基づいて(4つのうちの)特定のメソッドを呼び出す単一のメインクラスがないのはなぜですか?
は言えない

回答:


215

マニフェストファイルにMain-Classなしでjarを作成できます。次に:

java -cp MyJar.jar com.mycomp.myproj.dir2.MainClass2 /home/myhome/datasource.properties /home/myhome/input.txt

2
ドキュメントによると、これは機能しません:「このオプションが機能するためには、JARファイルのマニフェストには、Main-Class:classnameの形式の行が含まれている必要があります。」
Thomas

「MyJar.jarからMain-Classマニフェスト属性を読み込めませんでした」
Bhushan

10
トーマスは正しいです。「-jar」を「-cp」に置き換える必要があります。私の更新されたコードを参照してください
lxu4net 2011年

9
@chrisdewによって提供される答えは、Main-Class属性を変更/削除することによってJarファイルを変更する必要なく機能します。
Ed Griebel

155

JARファイルに定義されている場合でも、JARファイルからのメソッドを持つ任意のクラスを実行できますpublic final static mainMain-Class

メインクラスを実行:

java -jar MyJar.jar  // will execute the Main-Class

public static void mainメソッドで別のクラスを実行します。

java -cp MyJar.jar com.mycomp.myproj.AnotherClassWithMainMethod

注:最初の用途-jarは、2番目の用途は-cpです。


10
また、クラスパス上の現在のディレクトリにすべてのjarが必要な場合(たとえば、libディレクトリからMain classを実行する場合)java -cp "./*" com.mycomp.myproj.AnotherClassWithMainMethod./*UNIXマシンによる展開を防ぐために二重引用符を使用できます。また、"./*.jar"動作しないことに注意してください。
PetrÚjezdský2016年

19

の呼び出しとは別にjava -jar myjar.jar com.mycompany.Myclass、マニフェストのメインクラスをDispatcherクラスにすることもできます。

例:

public class Dispatcher{

    private static final Map<String, Class<?>> ENTRY_POINTS =
        new HashMap<String, Class<?>>();
    static{
        ENTRY_POINTS.put("foo", Foo.class);
        ENTRY_POINTS.put("bar", Bar.class);
        ENTRY_POINTS.put("baz", Baz.class);
    }

    public static void main(final String[] args) throws Exception{

        if(args.length < 1){
            // throw exception, not enough args
        }
        final Class<?> entryPoint = ENTRY_POINTS.get(args[0]);
        if(entryPoint==null){
            // throw exception, entry point doesn't exist
        }
        final String[] argsCopy =
            args.length > 1
                ? Arrays.copyOfRange(args, 1, args.length)
                : new String[0];
        entryPoint.getMethod("main", String[].class).invoke(null,
            (Object) argsCopy);

    }
}

1
これは、これを行うための優れた代替方法です。私のjarは「spring-boot:repackage」を使用して作成されたため、「-cp」の方法では他の入口クラスを実行できません。スプリングブートプラグインがjarファイルに何をしたのかわかりません。この場合、ディスパッチクラスが役立ちます。

6

この回答はSpring-bootユーザー向けです:

JARがSpring-bootプロジェクトからのものであり、コマンドを使用して作成された場合mvn package spring-boot:repackage、上記の「-cp」メソッドは機能しません。あなたは得るでしょう:

エラー:メインクラスyour.alternative.class.pathが見つからないか、ロードできませんでした

あなたがJARでクラスを見ることができる場合でもjar tvf yours.jar

この場合、次のコマンドで代替クラスを実行します。

java -cp yours.jar -Dloader.main=your.alternative.class.path org.springframework.boot.loader.PropertiesLauncher

私が理解したように、Spring-bootのorg.springframework.boot.loader.PropertiesLauncherクラスはディスパッチング入り口クラスとして機能し、-Dloader.mainパラメーターはそれに何を実行するかを指示します。

リファレンス:https : //github.com/spring-projects/spring-boot/issues/20404


jarが実行可能である場合はどうでしょうか。つまり、jarを解凍すると、すべてのクラスの前に "/ BOOT-INF / classes /"が付きます
slashdottir

2

まずjar、jarを作成し、実行しません。java -jar代わりに試してください。

次に、クラスをFQCN(com.mycomp.myproj.dir2.MainClass2)とファイル(com/mycomp/myproj/dir2/MainClass2.class)として2回渡すのはなぜですか?

編集:

java -jarメインクラスを指定する必要があるようです。java -cp your.jar com.mycomp.myproj.dir2.MainClass2 ...代わりに試すことができます。-cpjarをクラスパスに設定し、javaがメインクラスをそこで検索できるようにします。


私はここで述べたように行いました:download.oracle.com/javase/tutorial/deployment/jar/appman.html
Bhushan

1
そのページから:「jarファイルの作成または更新時に使用できます。」-これは、jarを実行するためではなく、メインクラス属性を設定するために使用されます。
トーマス

1

Nickがコメントで簡単に触れたと私が思う別の同様のオプションは、複数のラッパーjarを作成することです。まだ試していませんが、ロードするメインクラスとクラスパスへのMyJar.jarのインクルードを指定するマニフェストファイル以外は、完全に空である可能性があると思います。

MyJar 1 .jar \ META-INF \ MANIFEST.MF

Manifest-Version: 1.0
Main-Class: com.mycomp.myproj.dir1.MainClass1
Class-Path: MyJar.jar

MyJar 2 .jar \ META-INF \ MANIFEST.MF

Manifest-Version: 1.0
Main-Class: com.mycomp.myproj.dir2.MainClass2
Class-Path: MyJar.jar

など。次に、それを実行します java -jar MyJar2.jar


-4

以下のプラグインをpom.xmlファイルに追加し、要素に完全修飾名でメインクラスを指定します。

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <version>1.2.5.RELEASE</version>
    <configuration>
        <mainClass>**main Class name with full qualified name**</mainClass>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>repackage</goal>
            </goals>
        </execution>
    </executions>
</plugin>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.