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