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.
Related
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.
I have read in docs, especially here
https://docs.oracle.com/javase/7/docs/technotes/tools/solaris/java.html
https://docs.oracle.com/javase/1.5.0/docs/guide/jar/jar.html#JAR%20Manifest
that -classpath is ignored when java is called with -jar option.
In this case, resources are read from manifest file.
Maybe I misunderstanding and the way to set paths from out resource is exist when call java -jar?
If not why so?
This is just how the java programs was coded to behave.
What's important is that you can still use a JAR and specify the class path on the command line. This requires that you make the jar itself part of the class path, and then specify the class, such as:
java -cp javafile.jar fully.qualified.ClassName
Java will run the fully.qualified.ClassName main class, which it will find on the class path (in which the jar file is included).
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.
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.
Let's say I have:
core.jar
client.jar (contains main-method) (uses core.jar)
super_mega_client.jar (uses core.jar, client.jar)
To run my program I use "java -jar super_mega_client.jar"
How could I get the manifest-file from "super_mega_client.jar" knowing nothing about it's name and content?
Actualy I need to create an util in core.jar which will work with the jar, executed with "java -jar ***.jar"
OK, here is proper question:
I have main.jar with main-method (lets say in my.app.Main class)
I also have fisrt.jar(with some classes and resources) and second.jar (with some other classes and resources). Both have no main-classes, both have "main.jar" in CLASSPATH, both have Main-Class property defined as "my.app.Main".
I can run my app by executing "java -jar first.jar" or "java -jar second.jar"
In my my.app.Main.main(String[] args) method (contained in main.jar) I want to know the name of the executed jar (I want to get either "first.jar" or "second.jar")
How could I do it?
In any jar that declares its main class, the location and name is fixed by the standard to META-INF/MANIFEST.MF
You can retrieve the manifest file using the jar command that comes with the Java SDK (any zip tool that you can run from the command might suffice too) by running:
jar -xvf anyjar.jar META-INF/MANIFEST.MF
this will create the META-INF directory and put the manifest file in it. You can leave out the -v if you want less verbose output.
Not quite sure I understand what you need here, but check out this article (for instance)
http://java.sun.com/j2se/1.5.0/docs/guide/lang/resources.html
You ask the CLASSLOADER (so use a class you have loaded already and request what classloader it used is probably good enough) to load the resource for you.
You can use the -verbose option of the java command to see the names of all loaded classes.