How to run a class from Jar which is not the Main-Class in its Manifest file
Asked Answered
S

6

234

I have a JAR with 4 classes, each one has Main method. I want to be able to run each one of those as per the need. I am trying to run it from command-line on Linux box.

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

It has directory structure for the main classes as follows:

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

I know that I can specify one class as main in my Manifest file. But is there any way by which I can specify some argument on command line to run whichever class I wish to run?

I tried this:

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

And I got this error:

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

(In the above command, '/home/myhome/datasource.properties' and '/home/myhome/input.txt' are the command line arguments).

Scalariform answered 29/3, 2011 at 15:2 Comment(2)
Just package them in different jars, using another jar to hold the dependencies?Marital
Why not have single main class that calls the specific method(out of the 4) based on command line arguments?Wingding
P
275

You can create your jar without Main-Class in its Manifest file. Then :

java -cp MyJar.jar com.mycomp.myproj.dir2.MainClass2 /home/myhome/datasource.properties /home/myhome/input.txt
Pammie answered 29/3, 2011 at 15:8 Comment(4)
According to the doc this won't work: "In order for this option to work, the manifest of the JAR file must contain a line of the form Main-Class: classname. "Debate
"Failed to load Main-Class manifest attribute from MyJar.jar"Scalariform
Thomas is right. you need replace "-jar" with "-cp". See my updated codePammie
The answer provided by @chrisdew works without having to change the Jar file by modifying/removing the Main-Class attribute.Foolery
C
220

You can execute any class which has a public static void main method from a JAR file, even if the jar file has a Main-Class defined.

Execute Main-Class:

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

Execute another class with a public static void main method:

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

Note: the first uses -jar, the second uses -cp.

Churn answered 7/9, 2015 at 13:6 Comment(1)
And if you want all jars in current directory on classpath too (eg. running Main class from lib directory) you can use java -cp "./*" com.mycomp.myproj.AnotherClassWithMainMethod Note the double quotes around ./* preventing unix machines from expanding it. Also note that "./*.jar" will not work.Human
F
41

This answer is for Spring-boot users:

If your JAR was from a Spring-boot project and created using the command mvn package spring-boot:repackage, the above "-cp" method won't work. You will get:

Error: Could not find or load main class your.alternative.class.path

even if you can see the class in the JAR by jar tvf yours.jar.

In this case, run your alternative class by the following command:

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

As I understood, the Spring-boot's org.springframework.boot.loader.PropertiesLauncher class serves as a dispatching entrance class, and the -Dloader.main parameter tells it what to run.

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

Fernand answered 4/5, 2020 at 21:12 Comment(5)
What if your jar is executable. i.e. when you unzip the jar, all the classes are preceded by "/BOOT-INF/classes/"Abortifacient
it worked for me. You can arguments as key/value pair at the end of above commandTransship
@Zhou, you are a life-saver. Thank you.Diaphysis
Using Spring Boot, exactly what I was looking for - thanks so much!Schnapp
Looks like PropertiesLauncher has been moved into a launch package. The right package is now org.springframework.boot.loader.launch.PropertiesLauncher.Disenthrone
L
24

Apart from calling java -jar myjar.jar com.mycompany.Myclass, you can also make the main class in your Manifest a Dispatcher class.

Example:

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);

    }
}
Legendary answered 29/3, 2011 at 15:33 Comment(1)
This is a good alternative way to do it! My jar was created using "spring-boot:repackage", so I just can't run other entrance classes by the "-cp" way. I don't know what the spring-boot plugin did to the jar. In this case, a dispatching class helps.Fernand
K
3

Another similar option that I think Nick briefly alluded to in the comments is to create multiple wrapper jars. I haven't tried it, but I think they could be completely empty other than the manifest file, which should specify the main class to load as well as the inclusion of the MyJar.jar to the classpath.

MyJar1.jar\META-INF\MANIFEST.MF

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

MyJar2.jar\META-INF\MANIFEST.MF

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

etc. Then just run it with java -jar MyJar2.jar

Kimbrakimbrell answered 7/5, 2015 at 14:35 Comment(0)
D
1

First of all jar creates a jar, and does not run it. Try java -jar instead.

Second, why do you pass the class twice, as FQCN (com.mycomp.myproj.dir2.MainClass2) and as file (com/mycomp/myproj/dir2/MainClass2.class)?

Edit:

It seems as if java -jar requires a main class to be specified. You could try java -cp your.jar com.mycomp.myproj.dir2.MainClass2 ... instead. -cp sets the jar on the classpath and enables java to look up the main class there.

Debate answered 29/3, 2011 at 15:6 Comment(2)
I did as mentioned here: download.oracle.com/javase/tutorial/deployment/jar/appman.htmlScalariform
From that page: "It can be used while creating or updating a jar file." - So this is used to set the main class attribute, not to run the jar.Debate

© 2022 - 2024 — McMap. All rights reserved.