ChatGPT解决这个技术问题 Extra ChatGPT

Multiple runnable classes inside JAR, how to run them?

I'm having problems with running multiple different classes from one JAR file. I know that I can set one of the classes inside JAR to by Main class that will be run after command java -jar myjar.jar, but what I want is something like:

java -jar myjar.jar MyClass

Is it possible to do this that way, or do I have to create multiple JAR (each for one runnable class), or is it better to create 'manager' class that will run my other classes passing to them command line arguments? I was looking for documentation or reference, but I couldn't find any.


i
iggymoran

The executable Jar file format only allows you to specify one main class. In order for you to be able to execute different applications, you'll need to either create a "manager" as you suggest, or to use the classpath instead:

java -cp myjar.jar MyClass

However, this approach will ignore the classpath you have configured in the Jar's manifest file.


Ignorig classpath inside manifest was one of my concerns. But I have tested this solution, and it seems to work (but I don't know why really, because I have set classpath inside manifest)
It's because this form of startup does not bother reading the manifest. Only the -jar form reads the manifest.
G
Gareth Davis

you will have to use:

java -cp myjar.jar MyClass

and

java -cp myjar.jar OtherMainClass

How to I pass multiple arguments. I mean when I pass a single argument its working java -cp myjar.jar OtherMainClass foo but java -cp myjar.jar OtherMainClass foo bar is not working .Only taking the first argument foo.
M
Michael Borgwardt

You do it like this:

java -cp myjar.jar MyClass

i.e. put the JAR into the classpath, then any class with a main method can be run by specifying its fully qualified name. The -jar option only exists as a shortcut to use the information in the JAR's manifest instead (which can also include other JARs in the classpath as well as specify the main class).


D
Dale

Wouldn't you be better served with using a "Launcher" main class, whose function is just to dispatch the calls to the actual controller classes, and using a link file as a final wrapper, instead of fiddling with the -cp option of the wm?

In windows, it is surprisingly easy to do so.

The "main class" needs not be anything much complex, something like

/**
 * Sample launcher
 */
public class Launcher {
    /**
     * @param args
     */
    public static void main(String[] args) throws Exception {
        if (args != null && args.length > 0) {
            String option= args[0]; 
            String[] args2=new String[0];               
            
            if( args.length>1){
                args2= new String[args.length-1];
                System.arraycopy(args, 1, args2, 0, args2.length); 
            }
            
            if(option.equals("a")) {
                new ClassA().exec(args2);
            }
            else if(option.equals("b")){                
                new ClassB().exec(args2);
            }
        }
    }
}

On the windows side of things, it is enough something like creating a link of this kind

javaw.exe -jar "jarfile" "a"

It is very useful for placing link in the "sendTo" folder... one jar, hidden, called by many links that activate one of its aspects makes simpler to deploy updates of the jar logic.

The actual files selected are passed as a list of string after the params in the link definition.

This way, you should not worry about the whole classpath issues.


C
Cameron Skinner

Jar files can contain only one Main-Class attribute in the manifest, which means java -jar myjar.jar can only start one class.

You can start other runnable classes with

java -cp myjar.jar OtherClass

but that won't support users double-clicking on the jar file.

Depending on how skilled your users are, maybe the command line is OK for them. If not, you can create a script for each runnable class or one script that takes arguments to choose the right class.


B
Brett Ryan

As the correct answer has been provided there is a solution that you could use to build a stub jar for each main class with different manifests. This would allow you to create runnable jar files by allowing double-clicking for each separate program.

There are several ways of accomplishing this but the basics are to put a single class similar to the following which invokes the intended main method passing args.

package com.acme.myapp;

public final class Stub1 {
    public static void main(String[] args) {
        App1.main(args);
    }
}

As for packaging this, one way using maven would be with the maven-assembly-plugin:jar-with-dependencies mojo. The advantage here is that the mojo will build a jar for the target main method that is self contained and does not need to have other assemblies on the classpath. It does this by copying the contents of each dependency jar into the resultant jar.