user3403969
user3403969

Reputation: 11

passing command line arguments to a specific **class** in a non-executable jar file

Some context: I am creating a Java project in Eclipse (only used Eclipse for a week). I picked up Java after a 13 year hiatus because I had to convert files from IBM EBCDIC 5035 & 935 to UTF-16. the standalone classes (two classes in all) work great within Eclipse. Each class has two parameters - source file+location and target file+location Each class will convert about a dozen files every night.

So now I have to automate the solution and deploy it. I used Eclipse to create a regular jar (NOT a runnable jar) so that I could call each class separately without creating a "manager" class.

On the command prompt when I run the following command:

java -jar test.jar ConvFileCP_5035_To_UTF16 \\\\usanofp03\\Informatica\\Dev\\OutputFiles\\JDEJapanCustomer_CP939.txt \\\\usanofp03\\Informatica\\Dev\\OutputFiles\\JDEJapanCustomer.txt

The output (confirmed with system.out...) surprised me because args[0] = ConvFileCP_5035_To_UTF16 (the class name!) and args[1] = \\\\usanofp03\\Informatica\\Dev\\OutputFiles\\JDEJapanCustomer_CP939.txt

I flipped to using args[1] and args[2] and the program worked but I wanted to know why this is happening and what is the right thing to do here

help would be appreciated! Thanks,

Upvotes: 1

Views: 2729

Answers (1)

chritohnide
chritohnide

Reputation: 141

NB: I realise that this is an old question, but it does deserve an answer.

While the questioner said that they “used Eclipse to create a regular jar (NOT a runnable jar)”, it looks like Eclipse may have actually specified one of their classes to be the main class in the JAR, which explains the output they experienced, i.e. args[0] holding the name of the class they intended to run.

The -jar option instructs java to "run" the given JAR, which actually causes java to look in the manifest, located inside the given JAR, for a line that specifies the main class. When a JAR is run, any further arguments are passed to the manifest-specified main class.

Following on from what @fge said, it looks like the questioner’s experience may have been the result of running an accidentally-made-runnable JAR that should have instead been used as a library, specified with the -classpath option, when invoking java and supplying the intended class.

For further investigation, see the following example.

Using the following class, which enumerates the command-line arguments it receives, we can demonstrate how the different java invocations behave:

public class JarTest
{
  public static void main(String[] args)
  {
    for(int i = 0; i < args.length; i++)
    {
      System.out.println(i + ": " + args[i]);
    }
  }
}

Compiling this class as normal (i.e. javac JarTest.java), we can run it in the usual way and supply some command-line arguments to see how it behaves:

~/temp/jar-test$ java JarTest arg1 arg2
0: arg1
1: arg2

The following command will package this class into a basic JAR:

~/temp/jar-test$ jar cf jar-test.jar JarTest.class

The last section of the Running JAR-Packaged Software chapter of The Java Tutorials, headed “JAR Files as Applications”, explains that the only way to directly “run a JAR packaged application” is with the -jar option like in the following:

~/temp/jar-test$ java -jar jar-test.jar
no main manifest attribute, in jar-test.jar

However, as we can see above, this doesn’t work so easily. Notice here also that even explicitly specifying the intended main class doesn’t help:

~/temp/jar-test$ java -jar jar-test.jar JarTest arg1 arg2
no main manifest attribute, in jar-test.jar

As we will see below, this is because anything after the specified JAR becomes the command-line arguments for the main class, if one is found, thus it is effectively ignored by the java command itself. Of course, in the above case, those arguments aren’t actually passed to anything because java doesn’t yet know to which class it should pass them.

In order to actually run a JAR, the java command needs to know which class is the application’s entry point (i.e. the class with the main method) and this is specified in the JAR’s manifest via the Main-Class header. Without specifying the main class, we see the above error. The Setting an Application's Entry Point chapter of The Java Tutorials describes how to specify the main class in the JAR’s manifest. Following these instructions, we create manifest.txt with the following contents (including a final newline character):

Main-Class: JarTest

Re-create the JAR and include the manifest (see this and this for further details on the jar command):

~/temp/jar-test$ jar cfm jar-test.jar manifest.txt JarTest.class

Now we can try to run our new JAR:

~/temp/jar-test$ java -jar jar-test.jar JarTest arg1 arg2
0: JarTest
1: arg1
2: arg2

As we can see, our JAR now runs successfully and the output is similar to the questioner’s curious output. When running a JAR that specifies the main class via the included manifest, there is no need to specify the intended class, indeed if we do, that string is passed to the main class as args[0].

In order to achieve the desired outcome, we should instead run our program by adding the JAR to the classpath (the easiest way being via either the -classpath or -cp options) and specify the class to run:

~/temp/jar-test$ java -cp jar-test.jar JarTest arg1 arg2
0: arg1
1: arg2

If we compare this with the previous command, the only difference is that then we used the -jar option, whereas now we've used the -cp option and achieved what was likely the questioner’s intention.

It might be worth noting here that the above (-cp) method would work with either a basic JAR (i.e. one without a manifest-specified main class) or a runnable JAR, because we are now simply telling java to look within the given JAR for the specified class.

Upvotes: 2

Related Questions