How to execute multiple java class files inside a jar using bash - java

I know that we can invoke a class in a jar file providing the Main-class attribute in the Manifest file. But how can we invoke multiple files in a jar in that way. Or can we invoke a class in a jar file without specifying in the Manifest file using bash.

The Main-Class property in a manifest file makes that JAR file a runnable JAR. You then can invoke that JAR with the command:
java -jar <jar-file>
But you also can directly invoke the main class with the traditional way:
java -cp <jar-file> your.pkg.MainClass
Notice, that you must include your JAR file in the class path, so that Java can find the classes inside it. An additional note: If you don't have a Class-Path property in the JAR's manifest file but your classes depend on other classes in other JARs, you must include all those JARs in the class path:
java -cp <jar-file>;<lib1>;<lib2>;... your.pkg.MainClass
Note, in Linux systems the path separator is a colon, not semicolon.

Another option, besides what #Seelenvirtuose suggested, would be to make the Main class a sort of Front Controller and pass the name of a class you want to invoke as an argument
java -jar app.jar SomeClass
And based on this argument dispatch the request to the corresponding class.

Related

Java classpath (-cp) and passing execution to that class

I am relatively new to Java but have a fair understanding about how the class path works with respect to providing a list of folder and jars that make classes available to other classes.
I have compiled a JAR (lets say example.jar) that has a main function where execution normally begins. Sometimes I want execution to begin in a different class (lets say myAlternateClass.java), with its own main. I can achieve this by doing using the -cp argument when executing the jar, for example;
java -cp example.jar myAlternateClass
This works as I require but I am unsure of what exactly is happening here.
I'm not 100% sure on exactly what you're looking for, but I'll give it a shot.
There are two ways to use a jar file. If the jar file has a Main-Class specified in its META-INF/MANIFEST.MF file, then you can load java with the jar file and execution will start in the main method of that class.
java -jar example.jar
On the other hand, a jar file can simply be loaded onto the classpath, which makes all of the classes within it available for use. This is the example you are giving:
java -cp example.jar org.somewhere.MySecondClass
The -cp example.jar puts all of the classes within the jar on the class path and the second argument org.somewhere.MySecondClass gives the class at which execution should begin. This second argument would have to be within the jar since specifying a classpath overrides the default (which is just the current directory). In this case, java ignores any Main-Class specified in the MANIFEST.MF file of the jar (if one even is specified).
Multiple jar files as well as directories of java files not in a jar can be specified by putting colons between them. So,
java -jar example.jar:. MyClass
could launch MyClass from the current directory, but place example.jar on the classpath so that MyClass could create instances of whatever classes are available within example.jar.

Bat file set classpath

Can you see anything wrong with the below code? It's a bat file and I'm trying to set some dependency classes before executing my jar (jdbc oracle driver).
set CLASSPATH=lib\dbdriver.zip;%CLASSPATH%
java -jar sql2java.jar test.properties
pause
I always get class not found exception (the class is in the zip I'm trying to add in the classpath).
I even tried this by executing as admin, but to no avail
set CLASSPATH=lib\dbdriver.zip;%CLASSPATH%
java -jar %~dp0sql2java.jar %~dp0test.properties
pause
The class is inside the zip file (path \oracle\jdbc\OracleDriver) and I'm trying to retrieve it with
jdbc.driver=oracle.jdbc.driver.OracleDriver
Check this doc about java (Java application launcher).
For the -jar option it says -
Executes a program encapsulated in a JAR file. The first argument is the name of a JAR file instead of a startup class name. For this option to work, the manifest of the JAR file must contain a line in the form Main-Class: classname. Here, classname identifies the class with the public static void main(String[] args) method that serves as your application's starting point.
When you use this option, the JAR file is the source of all user classes, and other user class path settings are ignored.
So you either need to package everything in your jar (sql2java.jar) or don't use the -jar option with java launcher command.
You can use java -jar to execute it and define a classpath for the application within the jar's manifest file. See the Java Tutorial on jars for how to set a classpath for the application at http://docs.oracle.com/javase/tutorial/deployment/jar/downman.html
It says:
For example, in a typical situation an applet is bundled in a JAR file
whose manifest references a different JAR file (or several different
JAR files) that serves as utilities for the purposes of that applet.
You specify classes to include in the Class-Path header field in the
manifest file of an applet or application. The Class-Path header takes
the following form:
Class-Path: jar1-name jar2-name directory-name/jar3-name
By using the Class-Path header in the manifest, you can avoid having
to specify a long -classpath flag when invoking Java to run the your
application.

How to set CLASSPATH in Linux to let java find jar file?

Under Linux I am trying to run a jar file as follows:
java -jar plantuml.jar -testdot
while having CLASSPATH set to any of the following (the file is located at /home/user/plantuml.jar):
export CLASSPATH=/home/user
export CLASSPATH=/home/user/
export CLASSPATH=/home/user/plantuml.jar
In either case, no matter how I define CLASSPATH, the java command gives an error Unable to access jarfile plantuml.jar. What am I doing wrong here?
You have to supply the complete path after the parameter -jar. So for your example you have to call
java -jar /home/user/plantuml.jar -testdot
The $CLASSPATH is only evaluated to find additional files (classes/resources) but not the jar file defined in the command line.
export CLASSPATH="/path/to/class_or_jar1":"/path/to/class_or_jar2":"${CLASSPATH}"
Maybe you are missing name of the main class or path to the jar. Have you tried execute it:
java -jar full_path/plantuml.jar package.YourClass -testdot
Is your program depending on other classes? If yes you might want to add -cp parameter.
The classpath is used to find classes when you refer to them by name. It's essentially a list of paths (directories AND jar/zip files) where the JVM needs to look for classes, or other resources when using methods like ClassLoader.getResourceAsStream().
The value passed to the -jar option on the command line is the file-path to the JAR file.
So, it won't find a jar file if you are only referring to the jar file by name. The JAR file path in the CLASSPATH is supposed to be a path element that 'contains' other resources.
What you need to do here, is either
Provide the full path to the jar file when trying to execute the jar
Set the classpath to the jar file's path, and run the java command giving the name of the main class you want to execute.

Java run jar file & include external jar

Is there a way to pass an external jar file when running a .jar application?
I'm trying to run my jar like this:
java -jar myJar.jar -cp externalJar.jar
The jar file executes fine but I want to look for classes in the external file. I can't include the other classes into my jar, because I want to be able to put any jar file in the same folder as my Jar file and look for classes in there.
The only way to do this right now is by running my app like this:
java -cp myJar.jar;externalJar.jar MainClass
I do not want to explicitly enter the path to my MainClass to run it's main method.
It really seems that the -cp option is completely ignored when you use the -jar option. At least this is what you can read on the manpage of java about the -jar option:
Execute a program encapsulated in a JAR file. The first argument is
the name of a JAR file instead of a startup class name. In order for
this option to work, the manifest of the JAR file must contain a line
of the form Main-Class: classname. Here, classname identifies the
class having the public static void main(String[] args) method that
serves as your application's starting point. See the Jar tool
reference page and the Jar trail of the Java Tutorial for information
about working with Jar files and Jar-file manifests.
When you use this option, the JAR file is the source of all user classes, and other user
class path settings are ignored.
Note that JAR files that can be run with the "java -jar" option can
have their execute permissions set so they can be run without using
"java -jar". Refer to Java Archive (JAR) Files.
I found this in this blogpost here: http://happygiraffe.net/blog/2009/04/30/java-jar-blats-your-classpath/
Did you try adding a specific folder to the classpath during startup and then add your jar file to the folder at later point ?

How do I use manifest.mf class-path for alternative main in same jar?

I have created an executable jar file that contains two main classes. All libraries are included in the jar and the main Main-Class works fine when executing like this:
java -jar MyApplication.jar
But when I try to run the other main class like this:
java -cp MyApplication.jar my.other.mainClass
It does not include the classpath of the manifest.mf and it can not find the libraries that are in the jar file.
Is there a simple way so that the other main class can use the classpath from the manifest.mf? or should I create two separate executable jars?
You could write a class that invokes the main method of whatever class is passed as its first argument using Reflection - and configure this as the Main-class in your jar. This way you can invoke multiple main methods from the same jar with java -jar file.jar my.other.mainClass
Is there a simple way so that the other main class can use the classpath from the manifest.mf? or should I create two separate executable jars?
The JAR manifest classpath is only used if you use -jar option, and conversely the command line argument is only interpreted as a classname if -jar is NOT used. You cannot mix the two approaches.
However, this doesn't mean you have to create a second JAR file. For instance, you could write a simple shell script to launch the JVM using the classpath copied from the manifest and the secondary entry point classname.
Are you sure your problem is with libraries within the jar? What version of java are you using?
I suggest you try the following:
java -cp MyApplication.jar <add external libraries here> my.other.mainClass
So you only need to add paths to classes that are not already in the jar. You can use wild cards to shorten the list.
Here is another interesting option, Enable your unrunnable JARs to run with the java -jar command. It describes how to select a main class in the jar file and make another runnable copy.

Categories