I have craated a Java application with an Ant build file containing the jar-task task that generate a jar file from the application.
<target name="jar-task" depends="compile">
<mkdir dir="${jar.dir}"/>
<jar destfile="jar/guix.jar" basedir="${bin.dir}">
<fileset dir="${basedir}">
<include name="${basedir}/images/**/" />
</fileset>
<manifest>
<attribute name="Main-Class" value="IO.Deep.clk.GUI"/>
<attribute name="Class-Path" value="${basedir}/SPLASH-2.0.0.jar ${basedir}/lib/dist/* ${basedir}/user.properties"/>
</manifest>
<filelist dir="${basedir}" files="user.properties"/>
</jar>
</target>
When I execute on the command line however a NoClassDefFoundError stating
Could not find the main class IO.Deep.clk.GUI. Program will exit.
Now, the GUI file is exactly in the specific folder and in the same package, I really can't understand where the error may be...can anyone help?
The name images suggests, that the jar file will contain only images. But where is the actual code?
<fileset dir="${basedir}">
<include name="${basedir}/images/**/" />
</fileset>
This piece
<attribute name="Class-Path" value="${basedir}/SPLASH-2.0.0.jar ${basedir}/lib/dist/* ${basedir}/user.properties"/>
will write full qualified pathnames into the manifest. Are sure, that this is correct? Also note, that the code will not find user.properties by putting the file on the classpath. The classpath can contain only directories or jar-files in which classes or other stuff will be searched for. But simple files won't work.
I'm also not sure about the lib/* part. Is the class IO.Deep.clk.GUI in one of the jar files in that directory? That would be a hint, that all directories must be listed explicitly. If that's not a problem - good.
EDIT:
The classpath problems can be avoided by adding the task manifestclasspath (Ant docs) before the call of jar and by using the generated classpath value inside the manifest attribute. Outline:
<manifestclasspath property="jar.class.path" jarfile="jar/guix.jar">
<classpath>
<fileset dir="." includes="*.jar" />
<fileset dir="." includes="lib/*.jar" />
</classpath>
</manifestclasspath>
<echo message="Class-Path will be: ${jar.class.path}" />
<jar ....>
....
<attribute name="Class-Path" value="${jar.class.path}" />
Are you sure your resulting filest inside the jar task contains all the files you need?
For debugging you can use a path convert to the fileset out of the jar task and echo it so that you can verfiy that you have the correct files. If this is OK then I don't see something else wrong in your file although I have limited experience with the jar task myself.
Related
I'm attempting to add a splash-screen to a large Java project. The application is compiled into an executable .jar file using ANT.
I am able to get the splash screen working easily from NetBeans by simply adding -splash:src/com/.../.../image.PNG to my main project's VM options. However, adding SplashScreen-Image: com/.../.../image.PNG to my manifest file fails with "SplashScreen.getSplashScreen() returned null"
I have already opened up my .jar archive to confirm that things were set up correctly: my META-INF\MANIFEST.MF file includes the SplashScreen-Image line. I have tried moving it before or after Main-Class. My actual image.PNG is also in the archive, in the correct path location.
I compile this java project with ANT, which I can guess is the source of my problems (I was able to make a simple, "jar cmf ..." example work just fine).
I use the following to get the project elements ready for achiving:
<target name="compile" depends="init"
description="Compile the source">
<!-- Compile the java code from ${src} into ${build} -->
<path id="lib.path.ref">
<fileset dir="${path_to_jre}" includes="*.jar"/>
</path>
<javac srcdir="${src}" destdir="${build}" source="${java_ver}" target="${java_ver}"
includeantruntime="false">
<!--compilerarg value="-Xbootclasspath/p:${toString:lib.path.ref}" compiler="javac1.7"/-->
<compilerarg value="-Xlint:unchecked"/>
<classpath>
<fileset dir="${LibDir}">
<include name="*.jar"/>
</fileset>
<pathelement path="${dependant_jar}"/>
<pathelement path="${another_dependant_jar}"/>
</classpath>
</javac>
<!-- Copy the .png files -->
<copy todir="${build}">
<fileset dir="${src}" casesensitive="false">
<include name="**/*.PNG"/>
</fileset>
</copy>
</target>
Notice that I use a copy to move .PNG files in with .class files. My image.PNG for the Splash Screen is just in with the others. I added it to my netbeans project by simply copying it there - nothing fancy.
My achieve target is as follows:
<target name="archive" depends="compile"
description="Generate the .jar file">
<!-- Put everything in ${build} into the .jar file -->
<jar jarfile="${jarfile}" basedir="${build}">
<!-- Merge in contents of dependency .jars -->
<zipfileset src="${LibDir}/snakeyaml.jar"/>
<zipfileset src="${dependant_jar}"/>
<zipfileset src="${another_dependant_jar}"/>
<!-- Specify main class in manifest -->
<manifest>
<attribute name="SplashScreen-Image" value="com/../../image.PNG"/>
<attribute name="Main-Class" value="${mainclass}"/>
</manifest>
</jar>
</target>
So my manifest in the eventual .jar is created here, which is also where I eventually realized to add the splashscreen tag.
I am somewhat new to working with ANT, so any advice regarding how to handle this or what to look for is appreciated.
It is not an issue with Ant. The problem is that the -splash option takes a file name, but the SplashScreen-Image manifest attribute must refer to a jar entry. If com/example/brian/image.PNG isn’t in the .jar file, it won’t be usable by SplashScreen-Image. The purpose of a .jar file is to be act as a self-contained module or application, so it should include all of the resources it needs.
The solution is to include the image in your .jar file:
<jar jarfile="${jarfile}" basedir="${build}">
<fileset dir="${src}" includes="**/*.PNG"/>
Update: Your build file was already adding the images to the .jar with a <copy> task, and I failed to notice it.
I have a solution, although I'm sure someone else will understand this better than I do.
I was able to run, with a splash-screen, using the Java binary in ../jre/lib/Java.exe, however I had initially been working from ../lib/Java.exe.
Looks like this is a known bug? Link here: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=7129420. I guess the path to the SplashScreen dll is hardcoded.
Note: Thanks to user VGR for the exhaustive help.
I'm making a JAR file using Ant, but I need to specify the classpath loading order for the JAR file generated in the Manifiest file.
The reason for this is because some of the dependencies I have use different version of another library, and I need to make sure that the latest one is loaded. This is easy using Eclipse interface, but I'm not sure how to do this with Ant.
This is what I have now, for the JAR task:
<target depends="build-project" name="jar">
<!-- Get the timestamp -->
<set.timestamp/>
<!-- Create our own manifest file for our JAR -->
<manifest file="MANIFEST.MF">
<attribute name="Built-By" value="${username} - ${company.name}"/>
<attribute name="Main-Class" value="some.package.Main"/>
<attribute name="Class-path" value=". ${lib.list}"/>
<attribute name="Implementation-Version"
value="${major.version.number}.${minor.version.number}.${revision.number}"/>
<attribute name="Built-Date" value="${current.time}"/>
</manifest>
<jar whenmanifestonly="fail" destfile="${dist.dir}/${jar.name}_${major.version.number}.${minor.version.number}.${revision.number}.jar" manifest="MANIFEST.MF">
</target>
Now this is the Classpath property:
<manifestclasspath property="lib.list" jarfile="${dist.dir}/${jar.name}_${major.version.number}.${minor.version.number}.${revision.number}.jar">
<classpath refid="manifest.classpath" />
</manifestclasspath>
And this is the manifest.classpath:
<!-- Manifest classpaht -->
<path id="manifest.classpath">
<fileset dir="${dist.dir}/lib">
<include name="*.jar"/>
</fileset>
</path>
To me it looks like I?l have to define each library manually one by one above, instead of using a wildcard...but will that order be matained afterwards?
Thanks!
Alejandro
When you define the classpath, you can duplicate jars in that path, much like you can duplicate directories in $PATH. It's sloppy, but it's not bad:
PATH="/bin:/usr/bin:$HOME/bin:/usr/local/bin:/bin"
The /bin directory is specified twice, but that doesn't matter. If I specify ls, The first instance of /bin in my $PATH will find it. The last instance of /bin in my $PATH doesn't do anything. No real harm done with the duplication.
If you need to specify your classpath that certain jars must be first, then specify what you need first. If $PATH contains that particular jar name again, it doesn't matter:
<path id="manifest.classpath">
<pathelement location="${first.jar}"/>
<pathelement location="${second.jar}"/>
<fileset dir="${manifest.jars.dir}"/>
</path>
Even if ${first.jar} and ${second.jar} are in that ${manifest.jars.dir}, it doesn't matter. They'll still be picked up first in your path, and ignored later in your path.
Now, you can do this:
<manifestclasspath property="manifest.path">
<pathelement location="."/>
<classpath refid="manifest.classpath"/>
</manifestclasspath>
And finally:
<jar destdir="....">
<manifest>
<attribute name="Class-path" value="${manifest.path}"/>
...
</manifest>
</jar>
As far as I know, the the classpath in the manifest will be defined with the entries ordered in the same order you provided them. I know it works like this in Maven, and pretty sure the same is in Ant, so what you can do is provided the "critical" entries first - and then put the wildcard, hence providing the order needed - while not manually defining all the required dependencies.
I have a package(with some outdated Java files) which i need to build using ant tool. I have some updated classes for which source is not available. So, I need to add the updated class to the jar during build and skip the outdated Java files from the build. Please let me know how to achieve this.
For example - I dont have the updated source java file for com.org.auth.ABC.Java, but i have the updated class file which i got from the another source ie com.org.auth.ABC.class. During build i need to point to the updated class(com.org.auth.ABC.class) for this class alone and create a new jar.
Please find how i am currently pointing to the class files below.
<target name="xxx.jar" depends="xjc,compile">
<jar destfile="${dist.dir}/xxx.jar">
<fileset dir="${classes.dir}" includes="**/*.class"/>
<fileset dir="${jaxb-classes.dir}" includes="**/*.class"/>
<fileset dir="${jaxb-source.dir}" includes="**/bgm.ser,**/jaxb.properties"/>
</jar>
</target>
If you want to leave some package from compilation you can use excludes attribute of fileset ant tag.
for example:
<fileset dir="src/">
<exclude name="**/dir_name_to_exclude/**" />
</fileset>
In order to include the specified class in compilation you can put the containing folder in your class-path using ant.
<path id="project.class.path">
<pathelement location="lib/"/>
<pathelement path="${java.class.path}/"/>
<pathelement path="path to your class file's base folder"/>
</path>
<javac srcdir="${src.dir}"
destdir="${classes.dir}"
classpathref="project.class.path">
... put source files here..
</javac>
And if you want to include that class-file in your jar then add it to fileset using include tag:
<fileset dir="classfiles">
<include name="your class file name"/>
</fileset>
Hope this helps
I want to include external jar to my java project. I'm using ant. External .jar is in folder lib. My build.xml looks something like that:
<?xml version="1.0" encoding="UTF-8"?>
<project>
<path id="classpath">
<fileset dir="lib" includes="**/*.jar"/>
</path>
<target name="clean">
<delete dir="build"/>
</target>
<target name="compile">
<mkdir dir="build"/>
<javac srcdir="src" destdir="build" classpathref="classpath" />
</target>
<target name="jar">
<mkdir dir="trash"/>
<jar destfile="trash/test.jar" basedir="build">
<zipgroupfileset dir="lib" includes="**/*.jar"/>
<manifest>
<attribute name="Main-Class" value="com.Test"/>
</manifest>
</jar>
</target>
<target name="run">
<java jar="trash/test.jar" fork="true"/>
</target>
</project>
But it doesn't work. When I want to import something from the external .jar, there is an error after command ant compile: package com.something does not exist.. What should I edit to get it working?
Exact error:
Compiling 23 source files to xy/build
xy/src/com/Test.java:5: package com.thoughtworks.xstream does not exist
import com.thoughtworks.xstream.*;
^
1 error
You should try without the includes attribute:
<fileset dir="lib" />
And in the jar part you include the classes like this:
<zipgroupfileset includes="*.jar" dir="lib"/>
You can't put external libraries into a jar and expect the classloader to use those jars. Unfortunately this is not supported.
There are ant tasks like one jar that help you, to create a jar file, that contains everything you need.
This bit is from the background information of one jar:
Unfortunately this is does not work. The Java Launcher$AppClassLoader
does not know how to load classes from a Jar inside a Jar with this
kind of Class-Path. Trying to use
jar:file:jarname.jar!/commons-logging.jar also leads down a dead-end.
This approach will only work if you install (i.e. scatter) the
supporting Jar files into the directory where the jarname.jar file is
installed.
Another approach is to unpack all dependent Jar files and repack them
inside the jarname.jar file. This approach tends to be fragile and
slow, and can suffer from duplicate resource issues.
Other Alternative:
jarjar: Jar Jar Links is a utility that makes it easy to repackage Java libraries and embed them into your own distribution
I also use ant to include a number of dependency JARs in my JAR. My compile task looks like this. Perhaps something similar will work for you.
<target name="compile" depends="init">
<javac srcdir="${src}" destdir="${build}" includeantruntime="false">
<classpath>
<pathelement path="${classpath}" />
<fileset dir="${deps}">
<include name="**/*.jar"/>
</fileset>
</classpath>
</javac>
<copy todir="${build}">
<fileset dir="${src}" excludes="**/*.java"/>
</copy>
</target>
sometimes u can use jar contents directly, just unzip
<unzip src="/Developer-Java/mysql-connector-java/mysql-connector-java-5.1.22-bin.jar" dest="${build_dir}" />
I've compiled a java project into a Jar file, and am having issues running it.
When I run:
java -jar myJar.jar
I get the following error
Could not find the main class: myClass
The class file is not in the root directory of the jar so I've tried changing the path of the main class to match the path to the class file and I get the same issue.
Should I be flattening the file structure? if so how do I do this. I'm using Ant to build the Jar file if thats of any use.
UPDATE
Here is the contents of the jar and the relevant Ant sections, I've changed the name of the firm I work for to "org":
META-INF/
META-INF/MANIFEST.MF
dataAccessLayer/
dataAccessLayer/databaseTest.class
org/
org/eventService/
org/eventService/DatabaseObject.class
org/eventService/DatabaseObjectFactory.class
org/eventService/DbEventClientImpl$HearBeatMonitor.class
org/eventService/DbEventClientImpl.class
org/eventService/EmptyQueryListException.class
org/eventService/EventHandlerWorkItem.class
org/eventService/EventProcessor.class
org/eventService/EventTypeEnum.class
org/eventService/EventWorkQueue$MonitorThread.class
org/eventService/EventWorkQueue$PoolWorker.class
org/eventService/EventWorkQueue.class
org/eventService/FailedToLoadDriverException.class
org/eventService/IConnectionFailureListener.class
org/eventService/InvalidEventTypeException.class
org/eventService/JdbcInterfaceConnection.class
org/eventService/NullArgumentException.class
org/eventService/OracleDatabaseObject.class
org/eventService/ProactiveClientEventLogger.class
org/eventService/ProactiveClientEventLoggerException.class
org/eventService/PropertyMap.class
org/eventService/SQLServerDatabaseObject.class
org/eventService/TestHarness.class
org/eventService/Utilities.class
And the ant target:
<target name="compile" depends="init" description="compile the source ">
<javac srcdir="src" destdir="bin" classpathref="project.class.path"/>
</target>
<target name="buildjar" description="build jar file" depends="compile">
<mkdir dir="dist"/>
<jar destfile="dist/myJar.jar" basedir="bin" includes="**/*.class" >
<manifest>
<attribute name="Main-Class" value="org.eventService.ProactiveClientEventLogger"/>
</manifest>
</jar>
</target>
In your manifest file, make sure you have the attribute Main-Class set to the name of the class containing your main() method. For example, if the package-qualified name of the class is my.cool.Class, then, in your JAR manifest, Main-Class should be set to my.cool.Class.
Also made sure that you have a package declaration in your .java files (for example, in Class.java, make sure you have the proper package my.cool; declaration). Also, make sure your directory hierarchy is set up correctly (my.cool.Class should be in $SRC/my/cool/Class.java).
You should specify your main class during jar creation with full path, something like:
<target name="jar" depends="compile">
<delete file="myJar.jar"/>
<delete file="MANIFEST.MF"/>
<manifest file="MANIFEST.MF">
<attribute name="Main-Class" value="my.package.myClass"/>
</manifest>
<jar destfile="myJar.jar"
basedir="."
includes="**/*.class"
manifest="MANIFEST.MF" />
</target>