javaeclipsejarmanifest.mf

What defines the main class if MANIFEST.MF is not present


There are two options when exporting to JAR in Eclipse: export as runnable JAR and export as JAR.

I understand that the runnable jar contains a MANIFEST.MF file, which defines the Main class to be executed when a jar is executed.

I also understand that non-runnable jars are just libraries of classes, that can be added to the classpath so that code is reused. It contains a manifest file, but there is no defined main class within it.

How is a non-runnable JAR file able to execute if the main class is not defined? What are the pros/cons of having a MANIFEST.MF file that defines the main class? Is one more stable than the other?


Solution

  • What defines the main class if MANIFEST.MF is not present

    If a JAR file doesn't have a "META-INF/MANIFEST.MF" component, then it is not a JAR file. It is just a ZIP file and you cannot use java -jar ... with a ZIP file. (You can include a ZIP file on the classpath, but it is not normally done.)

    If a JAR file has a MANIFEST.MF without a Main-Class attribute, then is not an executable JAR file, and java -jar ... will fail.

    But (as noted) many JAR files are libraries rather than applications. For them an entry-point class makes no sense.


    How is a non-runnable JAR file able to execute if the main class is not defined?

    (The preferred Java terminology is "executable" rather than "runnable".)

    In that case, java -jar ... will fail. Instead, you can run the application like this:

      java -cp <classpath> <other-options> com.example.MyApp.Main <args>
    

    where com.example.MyApp.Main is a main / entry-point class, and <classpath> includes the JAR (or ZIP) file and any other runtime dependencies.

    Note that an application JAR file could contain more than one entry-point class, and the user can decide which one to use.


    What are the pros/cons of having a MANIFEST.MF file that defines the main class?

    First of all, if you create a JAR file using the jar command, then it will have a MANIFEST.MF. The command won't create a JAR without one.

    Also, there are other useful things that you can include in a MANIFEST.MF. These include digital hashes (for signed JARs) and a Class-Path attribute for use when the JAR is launched with -jar. For more details, refer to the JAR file specification.

    The pros of having a Main-Class attribute in a JAR file are:

    1. It is necessary if you want to use -jar.
    2. It means that the user doesn't need to know (or type) the full name for the entry-point class.

    There are no significant cons of having a Main-Class attribute. If the user doesn't use the java -jar ... launch method, then any such attribute will be ignored. But I guess you could say that putting a nonsensical Main-Class attribute on a library JAR could lead to a naive user getting a misleading error. This is hair-splitting ...


    Is one more stable than the other?

    Not directly.

    You could argue that using -jar is more stable because an executable JAR ignores the CLASSPATH environment variable and -cp arguments on the command line. But the flipside is that you can't force the user to use -jar (or double-click) to launch a command. And you can get similar stability by providing a shell script or BAT file to launch the application with an appropriate entry-point class name and an appropriate classpath.


    I executed a non-runnable jar in Eclipse without the classpath or project files and then I ran it and it worked. It was able to identify the main class and run it from there. my question is: how was it able to identify it?

    OK ... that is a different question.

    What actually happens here is that the Eclipse project has a bunch of configuration information that includes the build dependencies. These provide a default classpath for the Eclipse launcher. Then, when you use Eclipse's run command without an existing run configuration, Eclipse will search all of the classes in the current project looking for any classes with a public static void main(String[]) method. If it finds only one such class, it assumes that it is the entry-point class, and creates a run configuration for the project / class. When that config is launched, Eclipse does the equivalent of java -cp <classpath> <class-name> <args>.

    Notes:

    1. This is Eclipse specific behavior. The standard Java tool chain doesn't do anything like this.

    2. Eclipse is not using java -jar here, and hence the manifest won't be consulted to find the entry-point class.

    3. This has been known to break. For example, I have heard that if you delete the main class and create a new one, the launch config doesn't update, and it gives a JVM launch error when you attempt to "run" it.