I made a small proof of concept project in order to learn to use ant:
I created a small JAR file that only contains one class that you can see here:
public class Dummy {
private String name;
public Dummy(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
I made a JAR of that called lib/dummy.jar
. Here is its manifest:
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.10.5
Created-By: 1.8.0_232-b09 (Oracle Corporation)
Class-Path:
Now, I want to use that JAR in a main class that looks like this:
public class Main {
public static void main(String[] args) {
Dummy f = new Dummy("Hello, World!");
System.out.println(f.getName());
}
}
I can compile it without a problem (if I include my JAR in the classpath).
Then, I try to make a JAR of that main class. The JAR contains this:
META-INF/
|- MANIFEST.MF
Main.class
dummy.jar
The manifest contains:
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.10.5
Created-By: 1.8.0_232-b09 (Oracle Corporation)
Main-Class: Main
Class-Path: dummy.jar
The JAR is created successfully.
If I try to run the JAR, I've got an Exception in thread "main" java.lang.NoClassDefFoundError: Dummy
The code should work, because if I include my initial dummy.jar
in the classpath when running, everything works fine. (java -cp build/jar/run-me.jar:lib/dummy.jar Main
)
Why is it not working when I run the JAR all by itself?
If it is of any use, here is my build.xml
(improvements gladly accepted in the comments):
<project default="all">
<path id="build.classpath">
<fileset dir="lib">
<include name="**/*.jar" />
</fileset>
</path>
<pathconvert property="mf.classpath" pathsep=" ">
<path refid="build.classpath" />
<flattenmapper />
</pathconvert>
<target name="all" depends="compile,jar,run" />
<target name="compile">
<mkdir dir="build/classes" />
<javac srcdir="src" destdir="build/classes" includeantruntime="false">
<classpath>
<fileset dir="lib">
<include name="**/*.jar" />
</fileset>
</classpath>
</javac>
</target>
<target name="jar">
<mkdir dir="build/jar" />
<jar destfile="build/jar/run-me.jar" basedir="build/classes">
<manifest>
<attribute name="Main-Class" value="Main" />
<attribute name="Class-Path" value="${mf.classpath}" />
</manifest>
<path id="build.classpath">
<fileset dir="lib">
<include name="**/*.jar" />
<include name="**/*.zip" />
</fileset>
</path>
</jar>
</target>
<target name="run">
<java jar="build/jar/run-me.jar" fork="true"></java>
</target>
<target name="clean">
<delete dir="build" />
</target>
</project>
Class-Path: dummy.jar
means that it looks for dummy.jar
in the same folder as run-me.jar
. It doesn't look for it inside run-me.jar
.
Since run-me.jar
is in build/jar
, and dummy.jar
is in lib
, you need to specify Class-Path: ../../lib/dummy.jar
for it to work.
Better to keep the Class-Path: dummy.jar
and place both jar files in the same folder when running it.