Run jar with dependencies from the command line - java

Java can run jar files from the command line like this:
java -jar foobar.jar
However, if foobar.jar depends on baz.jar, the above will throw an exception as soon as any of the classes in baz.jar is invoked, as the JVM has no way to know where to look for these.
However, the man page (OpenJDK 8 on Linux) states that:
When you use the -jar option, the specified JAR file is the source of all user classes, and other class path settings are ignored.
If repackaging is not an option, is there a way to run a jar file with dependencies from the command line?

When you use java -jar, dependencies are not specified on the command line.
You have 2 ways to add jars to the class path:
Call java with the main class and add jar files, including your foobar.jar, on the command line:
java -cp foobar.jar:baz.jar com.mycompany.MainClass
Include dependencies in foobar.jar's manifest file (and then run java -jar)
Class-Path: baz.jar

I believe you have only 'one' main class in foobar.jar. If it is more then 1, then you need to specify which one to execute.
You can simply set the classpath, before executing the jar
export CLASSPATH=$CLASSPATH:/JAR_LOCATION/bar.jar

Related

How do I run a JAR while including another JAR as class path? [duplicate]

What is the difference between running a Java application withjava -cp CLASSPATH and java -jar JAR_FILE_PATH? Is one of them preferred to the other for running a Java application? I mean which one of these ways is more expensive for JVM (according to their machine resources usage)?
Which one will cause JVM to spawn more threads while trying to run the application?
I prefer the first version to start a java application just because it has less pitfalls ("welcome to classpath hell"). The second one requires an executable jar file and the classpath for that application has to be defined inside the jar's manifest (all other classpath declaration will be silently ignored...). So with the second version you'd have to look into the jar, read the manifest and try to find out if the classpath entries are valid from where the jar is stored... That's avoidable.
I don't expect any performance advantages or disadvantages for either version. It's just telling the jvm which class to use for the main thread and where it can find the libraries.
With the -cp argument you provide the classpath i.e. path(s) to additional classes or libraries that your program may require when being compiled or run. With -jar you specify the executable JAR file that you want to run.
You can't specify them both. If you try to run java -cp folder/myexternallibrary.jar -jar myprogram.jar then it won't really work. The classpath for that JAR should be specified in its Manifest, not as a -cp argument.
You can find more about this here and here.
PS: -cp and -classpath are synonyms.
When using java -cp you are required to provide fully qualified main class name, e.g.
java -cp com.mycompany.MyMain
When using java -jar myjar.jar your jar file must provide the information about main class via manifest.mf contained into the jar file in folder META-INF:
Main-Class: com.mycompany.MyMain
java -cp CLASSPATH is necesssary if you wish to specify all code in the classpath. This is useful for debugging code.
The jarred executable format: java -jar JarFile can be used if you wish to start the app with a single short command. You can specify additional dependent jar files in your MANIFEST using space separated jars in a Class-Path entry, e.g.:
Class-Path: mysql.jar infobus.jar acme/beans.jar
Both are comparable in terms of performance.
Like already said, the -cp is just for telling the jvm in the command line which class to use for the main thread and where it can find the libraries (define classpath). In -jar it expects the class-path and main-class to be defined in the jar file manifest. So other is for defining things in command line while other finding them inside the jar manifest. There is no difference in performance. You can't use them at the same time, -jar will override the -cp.
Though even if you use -cp, it will still check the manifest file. So you can define some of the class-paths in the manifest and some in the command line. This is particularly useful when you have a dependency on some 3rd party jar, which you might not provide with your build or don't want to provide (expecting it to be found already in the system where it's to be installed for example). So you can use it to provide external jars. It's location may vary between systems or it may even have a different version on different system (but having the same interfaces). This way you can build the app with other version and add the actual 3rd party dependency to class-path on the command line when running it on different systems.
There won't be any difference in terms of performance.
Using java - cp we can specify the required classes and jar's in the classpath for running a java class file.
If it is a executable jar file . When java -jar command is used, jvm finds the class that it needs to run from /META-INF/MANIFEST.MF file inside the jar file.

Class in jar not found at runtime, but was used to compile

After I build this project from an ant file, I recieve a jar that contains all of the classes I built. When I try to run this jar, I get the following error:
Exception in thread "main" java.lang.NoClassDefFoundError: javax/media/j3d/SceneGraphObject
This error indicates that a one of the jars, specifically the j3dcore.jar from java3d, I am using can not be found. However, this jar is on the classpath when compiling through the ant build into the class files.
Why can this class not be found at runtime, but it is found at compile time? Do I have to manually change my classpath in my shell when running the jar as well as change it in the ant build?
If I add the jars to my classpath using java -cp j3d/*.jar -jar idv.jar
I get the error Error: Could not find or load main class j3d.j3dutils.jar
Do I have to manually change my classpath in my shell when running the jar as well as change it in the ant build?
Yes, absolutely. Making a class available at compile-time doesn't embed the class into your output or anything like that. It just makes it available to the compiler (to find out what methods are present etc).
If I add the jars to my classpath using java -cp j3d/*.jar -jar idv.jar
Yes, it would - because that's being expanded into:
java -cp j3d/foo.jar j3d/bar.jar ... -jar idv.jar
It's not clear to me whether -cp is meant to work at all with -jar, given this documentation:
When you use this option, the JAR file is the source of all user classes, and other user class path settings are ignored.
One option is to set the classpath within the manifest of the jar file itself. For example:
Class-Path: j3d/foo.jar j3d/bar.jar
Another would be to ignore the -jar command-line option for now, and use:
java -cp j3d/*:idv.jar your.class.name.Here
Note the * rather than *.jar, as documented:
As a special convenience, a class path element containing a basename of * is considered equivalent to specifying a list of all the files in the directory with the extension .jar or .JAR (a java program cannot tell the difference between the two invocations).

Run an execution with several jars

How can I run a jar that needs several jars to work?
Let me explain, I have for example a project with a jar "Main.jar" but to run this Main.jar I need jdom.jar(for xml file), jGit.jar...
Assume we need more than two jars. How can I run my Main.jar?
By including the needed jar files in the classpath. Something like:
java -cp "Main.jar;jdom.jar;jdom.jar" MainClass
If you are under Windows and would like to execute the Main.jar with a double click, you will need to create a .bat file and use that one instead to run your program. The content of the .bat file will have the above command.
Under Unix/Linux you will create a shell file with the similar content.
Note that the -cp argument values will need to contain all the jars that your Main.jar is depended on.
Run the jar with main class and add all other jars to classpath.
java -cp yourJars yourClass
see this post for more info. See this java tutorial

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.

How to generate one jar with different executable classes in maven2?

I have a big project that uses maven and I'm creating the project's jar. The problems is that the project has several classes that can be executed. How can I accomplish this?
Every time that I try to execute a class I get this message
java -jar library.jar ExecutableClass1
Failed to load Main-Class manifest attribute from
library.jar
The manifest.mf file in your JAR can only have one Main-Class entry.
Main-Class: classname
The jar would then by executed by running below.
java -jar library.jar
If you have several "executables" that could be run then you can either pass command line parameters to the JAR and then run the correct code or you can generate multiple JAR files for each "executable".
A possible alternative to using the -jar switch is to explicitly start one of the "executables":
java -cp library.jar ExecutableClass1
If your jar has dependencies, then these will need adding to the classpath as well.

Categories