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

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


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

You can execute any class which has a public final static 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.


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

    }
}

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