Does the JAR entry point actually have to be inside the JAR?

A bit of context

I am trying to design a minimal framework with a launcher which will be common to several projects. I am however encountering difficulties when it comes to running the JARs.

My purpose is to have a self-sufficient java -jar command: the MANIFEST knows the classpath and the entry point. The delicate bit is this: since I want the launcher to be common to all projects, and to be DRY-compliant, I have a specific JAR with it, which will always be on the classpath.

Now, I have trouble launching my jar:

java -jar test.jar

should load classpath and entry point from the Manifest. It does find the Manifest, but I end up with the Could not find or load main class.

Launching with more explicit details does work:

java -cp test.jar;lib/* org.keyboardplaying.test.TestLauncher

My question

I did not find any specification to say whether it is possible or not, and this is not the standard case, but can I specify in my MANIFEST.MF an entry point that will be found on classpath but is not included within my JAR?


Some more details

My MANIFEST.MF

Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: Chop
Build-Jdk: 1.7.0_45
Main-Class: org.keyboardplaying.test.TestLauncher
Class-Path: lib/slf4j-api-1.7.12.jar lib/logback-classic-1. 1.3.jar lib/logback-core-1.1.3.jar

Notes for people with problems

  • I previously tried Class-Path: lib/* which I like better, but you cannot use wild cards for classpath in Manifest1. You can still use directories, but the class loader will not examine the content of jars within this directory.

1. One source among others: https://stackoverflow.com/a/4756762/1734119
2. Very interesting link for Class-Path entry of MANIFEST: http://todayguesswhat.blogspot.com/2011/03/jar-manifestmf-class-path-referencing.html

Jon Skeet
people
quotationmark

Does the JAR entry point actually have to be inside the JAR?

No, it doesn't. It's entirely reasonable to put the launcher into a separate jar file, and so long as that's in the classpath specified by the manifest, it should be fine. Here's an example:

launch\Launchable.java:

package launch;

public interface Launchable {
    void launch();
}

launch\Launcher.java:

package launch;

public class Launcher {
    public static void main(String[] args) throws Exception {
        System.out.println("I am the launcher!");
        Class<?> clazz = Class.forName(args[0]);
        Launchable launchable = (Launchable) clazz.newInstance();
        launchable.launch();
    }
}

demo\Test.java:

package demo;

import launch.Launchable;

public class Test implements Launchable {
    public void launch() {
        System.out.println("I am Test, being launched");
    }
}

manifest.txt:

Manifest-Version: 1.0
Main-Class: launch.Launcher
Class-Path: launcher.jar

Now compile and run:

$ javac -d . launcher/*.java
$ javac -d . demo/*.java
$ jar cvf launcher.jar launcher
$ jar cvfm demo.jar manifest.txt demo
$ java -jar demo.jar demo.Test
I am the launcher!
I am Test, being launched

people

See more on this question at Stackoverflow