Come eseguire una classe da Jar che non è la classe principale nel suo file manifest


166

Ho un JAR con 4 classi, ognuna ha il metodo principale. Voglio essere in grado di eseguire ognuno di quelli secondo le necessità. Sto cercando di eseguirlo dalla riga di comando su Linux box.

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

Ha una struttura di directory per le classi principali come segue:

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

So che posso specificare una classe come principale nel mio file manifest. Ma c'è un modo in cui posso specificare qualche argomento sulla riga di comando per eseguire qualsiasi classe che desidero eseguire?

Ho provato questo:

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

E ho ricevuto questo errore:

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

(Nel comando sopra, '/home/myhome/datasource.properties' e '/home/myhome/input.txt' sono gli argomenti della riga di comando).


Basta impacchettarli in barattoli diversi, usando un altro barattolo per contenere le dipendenze?
Nick,

11
Perché non avere un'unica classe principale che chiama il metodo specifico (su 4) basato su argomenti della riga di comando?
Non posso dirlo il

Risposte:


215

Puoi creare il tuo vaso senza Main-Class nel suo file manifest. Poi :

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

2
Secondo il documento questo non funzionerà: "Affinché questa opzione funzioni, il manifest del file JAR deve contenere una riga del modulo Main-Class: classname."
Thomas

"Impossibile caricare l'attributo manifest di classe principale da MyJar.jar"
Bhushan,

10
Thomas ha ragione. devi sostituire "-jar" con "-cp". Vedi il mio codice aggiornato
lxu4net

9
La risposta fornita da @chrisdew funziona senza dover cambiare il file Jar modificando / rimuovendo l'attributo Main-Class.
Ed Griebel,

155

È possibile eseguire qualsiasi classe che ha un public final static mainmetodo da un file JAR, anche se il file jar ha un Main-Classdefinito .

Eseguire la classe principale:

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

Esegui un'altra classe con un public static void mainmetodo:

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

Nota: il primo utilizza -jar, il secondo utilizza -cp.


10
E se vuoi tutti i barattoli nella directory corrente anche sul percorso di classe (es. Eseguendo la classe principale dalla directory lib) puoi usare java -cp "./*" com.mycomp.myproj.AnotherClassWithMainMethodNota le doppie virgolette che ./*impediscono alle macchine unix di espanderlo. Si noti inoltre che "./*.jar"non funzionerà.
Petr Újezdský,

19

Oltre a chiamare java -jar myjar.jar com.mycompany.Myclass, puoi anche rendere la classe principale nella tua classe Manifest un Dispatcher.

Esempio:

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
Questo è un buon modo alternativo per farlo! Il mio barattolo è stato creato usando "spring-boot: repackage", quindi non posso semplicemente eseguire altre classi di ammissione con il metodo "-cp". Non so cosa abbia fatto il plug-in Spring-Boot al vaso. In questo caso, una classe di dispacciamento aiuta.
Zhou

6

Questa risposta è per gli utenti Spring-boot:

Se il tuo JAR proveniva da un Spring-bootprogetto e creato usando il comando mvn package spring-boot:repackage, il metodo "-cp" sopra non funzionerà. Otterrete:

Errore: Impossibile trovare o caricare la classe principale your.alternative.class.path

anche se puoi vedere la classe nel JAR di jar tvf yours.jar.

In questo caso, esegui la tua classe alternativa con il seguente comando:

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

Come ho capito, la org.springframework.boot.loader.PropertiesLauncherclasse di Spring-boot funge da classe di ingresso dispacciamento e il -Dloader.mainparametro indica cosa eseguire.

Riferimento: https://github.com/spring-projects/spring-boot/issues/20404


Che cosa succede se il tuo vaso è eseguibile. cioè quando decomprimere il jar, tutte le classi sono precedute da "/ BOOT-INF / classes /"
slashdottir

2

Prima di tutto jarcrea un barattolo e non lo esegue. Prova java -jarinvece.

Secondo, perché passi due volte la classe, come FQCN ( com.mycomp.myproj.dir2.MainClass2) e come file ( com/mycomp/myproj/dir2/MainClass2.class)?

Modificare:

Sembra che sia java -jarnecessario specificare una classe principale. Potresti java -cp your.jar com.mycomp.myproj.dir2.MainClass2 ...invece provare . -cpimposta il vaso sul percorso di classe e consente a Java di cercare lì la classe principale.



1
Da quella pagina: "Può essere usato durante la creazione o l'aggiornamento di un file jar." - Quindi questo è usato per impostare l'attributo della classe principale, non per eseguire il vaso.
Thomas,

1

Un'altra opzione simile a cui penso che Nick abbia brevemente accennato nei commenti è quella di creare più vasetti wrapper. Non l'ho provato, ma penso che potrebbero essere completamente vuoti oltre al file manifest, che dovrebbe specificare la classe principale da caricare e l'inclusione di MyJar.jar nel percorso di classe.

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

ecc. Quindi eseguilo con java -jar MyJar2.jar


-4

Aggiungi il plugin seguente nel tuo file pom.xml e specifica la classe principale con il nome completo nell'elemento.

<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>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.