Setting Class-Path in Ant build script - java

I'm trying to build my console application and I'm using Ant to build it. I can run my application in Eclipse, but when I try to run it from jar that I get - the ClassNotFoundException: is thrown. is in one of jars, that I use for my application. Here is a part of build.xml where I create manifest:
<manifest>
<attribute name="Main-Class" value="com.package.Reporter" />
<attribute name="Class-Path" value="lib/commons-httpclient-3.1.jar
lib/commons-logging-api.jar
...lot of jars...
lib/stax-api-1.0.1.jar" />
</manifest>
The required class is in commons-httpclient-3.1.jar
And here is how I set up classpath for compiling, that is fine:
<path id="libs.dir">
<fileset dir="lib" includes="**/*.jar"/>
</path>
UPD: Should I put jars with libs to my jar? Now I'm putting them to "lib" directory of my jar. So myjar.jar contains package with my classes, META-INF directory and lib directory.

Max, you can't insert jar libs into jar, assuming normal usage. Either you don't have to specify them manually at runtime as Romski suggested. When invoking java -jar myjar.jar it should locate all your jars provided that they are located in the lib directory. lib directory must be in the same directory that jar resides in. Doesn't matter if you call java executable directly or through ant java task.
Note that the current directory doesn't matter only the relation between the jar and the lib.
Now being overly explicit. Perform sanity test as follows: create a new tmp directory and copy files to it:
tmp/myjar.jar
tmp/lib/commons-httpclient-3.1.jar
Run java -jar tmp/myjar.jar
Edit: now I see I just wrote the same what is in Oracle jar tutorial. But I also made tests myself with a relative directory. I also see dozens of stackoverflow questions searching for jar in jar so please first search SO, then ask.

try to change the path like this.
<path id="libs.dir">
<fileset dir="./lib" includes="**/*.jar"/>
</path>

You need the manifestclasspath task.
Example:
Ant - how to get all files' name in a specific folder

Related

Launch4J - how to attach dependent jars to generated exe

I have a simple java project, which requires external jars.
I build this with netbeans and after Clean and Build command, I can find in dist directory the following structure:
-myApp.jar
-lib/
library1.jar
library2.jar
typical, I would say.
Now, I'd like to distribute myApp.jar with dependent libraries as one exe.
Is this possible? I am trying to use Launch4J. In the GUI I create the config file, there are some options in cp section
<cp>lib/swing-layout-1.0.4.jar</cp>
but it seems to be classpath, and it is the only place I can refer to my extra jars.
After exe file is created, I can't find dependend libs in the exe (exe can be opened with winrar) and thus my application crashes.
How can I make the exe file properly then?
Thanks for your help.
As it often happens being unable to solve the problem I published it on StackOverflow ... and pretty soon after publishing the question I got an idea.
So the answer to my question is:
Put all the dependent jars into one main jar.
It took me some time to find info how can I do that.
To help people I decided to publish detailed instruction here - they are based on Netbeans 7.4.
Following article from http://mavistechchannel.wordpress.com/2010/08/17/how-to-build-a-single-jar-file-with-external-libs/ I created the ant script that build one-jar-app for me.
I could then manually create exe via Launch4J
I then decided that I want more automated task, and I did that, Ant builds exe for me (via Launch4J)
Then I realized that I must do "clean and build" before my automated task (in point 2)/ I decided that I want clean and build to be done automatically before the exe build
Putting all together I am attaching my ant build script consisting of points 1,2,3:
It is required to edit build.xml and put the content found below before "project" end tag
<target name="package-for-launch4j" depends="clean,compile,jar">
<property name="launch4jexe.dir" location="C:\Program Files (x86)\Launch4j" />
<taskdef name="launch4j"
classname="net.sf.launch4j.ant.Launch4jTask"
classpath="${launch4jexe.dir}/launch4j.jar
:${launch4jexe.dir}/lib/xstream.jar" />
<property name="launch4j.jar.name" value="MyAppJarName"/>
<property name="launch4j.dir" value="exe"/>
<property name="launch4j.jar" value="${launch4j.dir}/${launch4j.jar.name}.jar"/>
<echo message="Packaging ${application.title} into a single JAR at ${launch4j.jar}"/>
<delete dir="${launch4j.dir}"/>
<mkdir dir="${launch4j.dir}"/>
<jar destfile="${launch4j.dir}/temp_final.jar" filesetmanifest="skip">
<zipgroupfileset dir="dist" includes="*.jar"/>
<zipgroupfileset dir="dist/lib" includes="*.jar"/>
<manifest>
<attribute name="Main-Class" value="${main.class}"/>
</manifest>
</jar>
<zip destfile="${launch4j.jar}">
<zipfileset src="${launch4j.dir}/temp_final.jar"
excludes="META-INF/*.SF, META-INF/*.DSA, META-INF/*.RSA"/>
</zip>
<delete file="${launch4j.dir}/temp_final.jar"/>
<launch4j configFile="misc/l4j-myapp.xml" />
</target>
then in Netbeans rightclick on the build.xml and choose:
Run Target / Other Targets / package-for-launch4j
exe file is ready in exe folder :-)
When you are converting your .jar file
Go to classpath tab
Check custom classpath
On main class select your .jar from your dist folder after building the project
On the classpath textarea add your libraries, you add them right below that
textarea writting the full path to the lib (of course including the
lib, ie "C:\folder\lib\file.jar")
I have spent hours on this issue. So here is my contribution.
The problem here: how to sucessfully put your external jars that your .JAR program needs INSIDE the .exe that you generate.
We assume that you already, and correctly, configured the external jars on eclipse/netbeans and ALL WORK FINE with the command: java -jar yourprogram.jar.
So the real problem is how to ensure that this .EXE file will contain the external jars, otherwise it will not work properly.
1) First of all, you need to forget Launch4J and anyother program.
2) Install JSmooth, I recommend that you use the windows version.
3) On the left menu there is a button "Application". Click on it.
4) You will see a tab "Classpath" panel. Click on the plus (+) and add your external .jar's files. And that is it!!
Don't forget to put your .jar application marking checkbox "use am embedded jar" and choose the main class properly. It will work.
I also faced the same issue while migrating my .jar to exe. I also had many dependent libraries as well. So These were the steps I performed :
Download and Install launch4j.
Open your project in netbeans. Clean and build the project.
Make sure you have a folder named 'dist' in the project directory. It will have your jar files with lib folder(containing the dependent libraries).
Open launch 4j.
Create output file in the dist folder. For example : OutputFile : D:******\My_App\dist\my_application.exe
Browse your jar file in the next row. For example : Jar : D:******\My_App\dist\my_application.jar
Go to classpath tab. Tick CustomClasspath. Press browse icon, and browse to your jar file which is located in the dist folder.
Specify Min Jre version in the JRE tab.
Save the configration.
Build the wrapper(by clicking the settings icon)
Your exe file will be generated in the dist folder.
Thats it :)
Putting different links of places which had helped me
How to include all dependent Jars within a single non-executable jar?
How can I create an executable JAR with dependencies using Maven?
http://www.mkyong.com/java/how-to-make-an-executable-jar-file/
and most importantly
http://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html
quick tut
http://www.mkyong.com/java/how-to-add-your-manifest-into-a-jar-file/
To include external libraries with Launch4j you have to have the ".jar" files of the external libraries near your .exe (mine are just in the same folder) then in "Classpath" you put in the path to the .jar files into "Edit Item: "
In launch4j go to the classpath tab. Tick the custom classpath field. In the edit field, enter the full path of each jar you want included and press accept. When finished type just the name of the main class into the separate field (ie MyProg). All the jars will now be included in the exe.
PS I have all the jars in the same directory. I'm using version 3.12

How do I change the destination directory of Ant's fileset command?

I have an Ant buildfile for a Java library. It looks something like this:
<project ... ><target ... >
<jar destfile="C:\path\to\export.jar">
<manifest> ... </manifest>
<fileset dir="C:\path\to\bin" />
<fileset dir="C:\path\to\src" />
<fileset dir="C:\path\to\doc" />
<zipfileset src="C:\path\to\included\library.jar" />
</jar>
</target></project>
The only problem is that my JavaDoc is being exported directly into the root directory of the resulting jar file. Essentialy, I'd like some equivalent of the <copydir> command that can be used inside the <jar> command.
My desired structure is this:
export.jar
META-INF
Manifest.MF
com
example
whatever
Blah.class
Blah.java
org
external
somelibrary
Magic.class // contents of the included library jar file
doc
// javadoc files here
The current structure is:
export.jar
META-INF
Manifest.MF
com
example
whatever
Blah.class
Blah.java
// some javadoc files here
org
external
somelibrary
Magic.class // contents of the included library jar file
// more javadoc files here
My current "solution" is to omit the documentation <fileset> command, then, once the jar has exported, go into Windows Explorer and right click → 7-Zip → Open Archive; I can then drop the doc directory in there just fine. However, this pretty completely defeats the purpose of Ant as a completely automated build system.
If it matters, this file was originally generated by Eclipse with the Runnable JAR exporter. However, I obviously need to modify it to add source files, etc. because it's a library and not actually a runnable jar. I exported it as a runnable jar to get Eclipse to package in the required libraries; apparently libraries on the build path aren't available for export via the standard File → Export → JAR file.
A jar is actually like a zip file. Hence you can use a zipfileset. Its attribute prefix is what you are looking for.
The zipfileset command can accept either a zip file via src or a filesystem directory via dir. Using the latter, you can add the following command:
<zipfileset dir="C:\path\to\doc" prefix="doc" />
Also worth to note is that zipfileset supports all attributes of fileset. Thus if you want to include just a single file in a specific location you can use:
<zipfileset file="C:\path\to\doc\file.txt" prefix="doc" />
Further reading: http://ant.apache.org/manual/Types/zipfileset.html

Nested jar files

a question on building executable jar files. Suppose we have a jar file a.jar that contains UI.class. I have used a metafile in archiving a.jar that says
Main-Class: UI
Class-Path: . b.jar c.jar
Now, if I want to ship this executable a.jar to somebody, I have to ship 3 files - a.jar, b.jar and c.jar. The user has to put all 3 in the same folder, and then double clicking on a.jar would work. It would be simpler if I could ship a single file (a.jar), and the JVM could figure out to extract b.jar and c.jar from in there to use the classes. These 2 are external libraries and I dont want to expand them and re-jar the class files in a.jar.
Can this be done? If so, what is the jar command and what should go in the metafile? Currently the command is
jar cmf metafile a.jar UI.class
Thank you.
Have you looked at this tool OneJar? Also this is a good article to read on OneJar.
If you decide to not use an external tool then your alternative is to put the library/helper jars in the classpath in the manifest, and then copy the jars themselves in a directory path relative to your main jar.
EDIT: OP asked for an example MANIFEST.MF. I coped this from the example One-Jar example jar file.
Manifest-Version: 1.0
Main-Class: com.simontuffs.onejar.Boot
One-Jar-Expand: expand,doc
There is OneJar as people have mentioned but also (especially if you are using eclipse) you can consider fatjar.
ALternatively, you can also achieve this by using an ANT Task here's an example:
<target name="dist" depends="compile,static" description="Compiles and builds jar files">
<mkdir dir="${dist}"/>
<jar destfile="${dist}/MYAPP.jar">
<zipfileset src="${dist}/MY_OTHER_APP.jar"/>
<zipfileset src="${lib}/commons-io-1.4/commons-io-1.4.jar"/>
<zipfileset src="${lib}/commons-math-2.1/commons-math-2.1.jar"/>
<fileset dir="${res}" includes="*"/>
<manifest>
<attribute name="Main-Class" value=<where your main class is>/>
</manifest>
</jar>
</target>
OneJar is good for just bundling a few things together, but it's generally quite slow and inflexible. This isn't a dig at OneJar, it's great for what it does but unless I wanted a quick and easy distributable for a tiny program I wouldn't use it.
I did use it for a while but then switched to izpack. It provides an installer as a single jar which I've found to generally work very well, and supports things such as windows specific shortcuts as well. It's also really easy to integrate it with ant.
Another way can be use one of several available tools to create a setup deliverable and your setup pack will unpack your application when installed.
Maven users can also use the assembly plugin for this:
http://maven.apache.org/plugins/maven-assembly-plugin/usage.html

How to add resources to classpath

How do you add a folder (e.g. a resource folder containing arts) to the classpath of a netbeans project? I managed to do that manually via editing the NB generated jar file of the project (that is its MANIFEST.MF file + copying the resources manually), but there should be a way to tell netbeans as well to mind the resources, no?
The folder structure looks like this:
/project/art/
/project/dist/lib/
/project/dist/art/
/project/dist/project.jar
/project/lib/
/project/src/
I don't want to package the art into the jar because I'd like the art to be easily exchangeable. If I add the art folder to the src folder then NB compiles fine, but the art resources end up in the jar.
Adding the art folder to the netbeans project libraries (Properties -> Libraries -> Add JAR/Folder) seemed not to work, because then I ended up with an error '...\project\art is a directory or can't be read. Not copying the libraries.' which in turn prevents even the real libraries folder from being copied.
Any ideas?
Best regards
Chris
2 Observations made, based on the comments from gpeche:
a) Rather specifying the additional resources folder in the "Run" tab than in the "Compile" tab of the project properties -> Libraries doesn't seem to make a lot of difference in Netbeans (I'm currently using 6.9.1). The output (and thus error) stays the same, that is nothing gets copied at all:
Created dir: C:\Users\Chrisi\Desktop\vocabulary\VocabularyTrainer\dist
C:\Users\Chrisi\Desktop\vocabulary\VocabularyTrainer\art is a directory or can't be read. Not copying the libraries.
Not copying the libraries.
Building jar: C:\Users\Chrisi\Desktop\vocabulary\VocabularyTrainer\dist\VocabularyTrainer.jar
Another interesting aspect is that in the help menu of the Libraries panel nothing is explicitly mentioned regarding folders as libraries. Could it be possible, that the button in Netbeans is falsely named, that is only real jar's are allowed?
b) Adding the resources folder to the Libraries list does have the impact though, to add another entry to the MANIFEST.MF. While - and that's the smaller issue - the classpath entry seems to be always expecting the resource folder to be a subfolder of the library folder (e.g. "lib/arts") the major problem is that there seems to be a slash missing.
As mentioned the NB generated entry in the MANIFEST.MF will look like this "lib/arts" (which does not work for me), while (manually set) "lib/arts/" does?!
The way I use resources from the folder is something like this:
URL resource = getClass().getResource("/gui/refresh.png");
ImageIcon tmp = new ImageIcon(resource);
Edit:
Based on Tushars comment and this posting I found the following solution to be an acceptable tradeoff between functionality and comfort.
I override the ANT target from the auto generated 'build-impl.xml' file which creates the Class-Path in the MANIFEST.MF file in the basic 'build.xml' file of the Netbeans project. The code which goes to the 'build.xml' file looks like this:
<property name="art.classpath" value="art/" />
<target name="-post-jar">
<mkdir dir="${dist.dir}/art"/>
<copy todir="${dist.dir}/art">
<fileset dir="${basedir}/art">
<!-- <exclude name="**/!source/**"/> if you want to exclude something... -->
</fileset>
</copy>
</target>
<target name="-init-macrodef-copylibs">
<macrodef name="copylibs" uri="http://www.netbeans.org/ns/j2se-project/3">
<element name="customize" optional="true"/>
<sequential>
<property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
<pathconvert property="run.classpath.without.build.classes.dir">
<path path="${run.classpath}"/>
<map from="${build.classes.dir.resolved}" to=""/>
</pathconvert>
<pathconvert pathsep=" " property="jar.classpath">
<path path="${run.classpath.without.build.classes.dir}"/>
<chainedmapper>
<flattenmapper/>
<globmapper from="*" to="lib/*"/>
</chainedmapper>
</pathconvert>
<taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
<copylibs compress="${jar.compress}" index="${jar.index}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
<fileset dir="${build.classes.dir}"/>
<manifest>
<attribute name="Class-Path" value="${jar.classpath} ${art.classpath}"/>
<customize/>
</manifest>
</copylibs>
</sequential>
</macrodef>
</target>
The tradeoff is that for development in Netbeans I still have to add the resource folder (e.g. 'art') to the libraries list to make the project run in Netbeans. This will cause an additional entry in the MANIFEST.MF file ('lib/art') along with the effect that the libraries will not get automatically copied to the 'dist' folder, with the message
...\art is a directory or can't be read. Not copying the libraries.
Not copying the libraries.
This behavor is - afaik - intended (to force everything to be bundled up in a jar), even though there are discussions about it going on. To make a real distribution bundle I'd have to take away the resource folder(s) from the library list in NB and rebuild.
Ideas about a more streamlined setup without any tradeoffs are of course still welcome. :)
Adding resource folder to classpath:
When you Clean-&-Build a NetBeans Ant Based Project it creates a manifest.mf file in the root directory of the project. This file gets included in the JAR file also. Modify this file and add entry like follows:
Manifest-Version: 1.0
X-COMMENT: Main-Class will be added automatically by build
Class-Path: arts/
slash is important after arts in the class path.
Including the arts resource folder in the distribution
Either copy this folder in the dist folder after the build or add a ANT target to copy the required resources in the dist folder.
Add the target like as follows in the build.xml file:
<target name="-post-jar">
<mkdir dir="${dist.dir}/resources"/>
<copy todir="${dist.dir}/resources">
<fileset dir="${basedir}/resources" />
</copy>
</target>
Code to access such resources:
The code needed to access such resource files shall be as follows: (This will not work in design time but surely from the JAR file)
// pay attention to relative path
URL resource = ClassLoader.getSystemResource("gui/refresh.png");
ImageIcon tmp = new ImageIcon(resource);
NOTE: The files manifest.mf and build.xml located in the root directory of the project are accessible from the Files Panel in NetBeans IDE
Using NetBeans 8.0.2:
Right-click the project.
Select Properties.
Select Sources.
Click Add Folder for the Source Package Folders.
Select the the directory where the resources exist.
Click Open on the directory name.
Click OK to close the Project Properties dialog.
The resources are added to the project.
You'll see the directory added in your Navigation pane as well
In the other project, the resources are now available. For example, to read an image:
BufferedImage zero = ImageIO.read(OCR.class.getResourceAsStream("/0.bmp"));
In order to remove the lib/art from Class-Path and not get "is a directory or can't be read" need delete lib/art from path:
<pathconvert property="run.classpath.without.build.classes.dir">
<path path="${run.classpath}"/>
<map from="${build.classes.dir.resolved}" to=""/>
**<map from="${basedir}/art" to=""/> <!-- remove art from lib -->**
</pathconvert>

Java: How to compile a runnable jar from packages?

My Java application has got a package structure similar to this:
src/com/name/app
src/com/name/app/do
src/com/name/utils/db
How would I go about compiling Java files in these directories in to a runnable jar? I need to package required libraries into the generated JAR (jdbc).
I've always done these things in Eclipse but now I need to supply a couple of people with a way to compile the repository without the use of eclipse and I was thinking of making a makefile or a script that invokes the necessary javac pattern.
Take a look at Ant. It's a relatively simple build tool to understand, and provides everything that meets your requirements. Here's a quick skeleton build.xml to get you started:
<project name="my_app_name" default="jar">
<target name="compile">
<javac srcdir="src" destdir="bin">
<classpath>
<fileset dir="lib">
<include name="**/*.jar" />
</fileset>
</classpath>
</javac>
</target>
<target name="jar">
<jar manifest="manifest_file" destfile="dist/my_app_name.jar">
<fileset dir="bin" />
<fileset dir="lib" />
</jar>
</target>
You need to create a manifest file that will tell the java process which class holds the "main" method. Here is a good place to start learning about manifests.
As an alternate that produces really cluttered Ant build files, you can right click on your Eclipse project and choose "Export...", then choose "General > Ant Buildfiles".
Anyway, that should get you started. You can ask more specific questions as you run into them.
First of all, consider using Ant for such a task.
But since you asked for a manual process, you need to first create a manifest file, like so:
Manifest-Version: 1.0
Created-By: 1.6.0 (Sun Microsystems Inc.)
Class-Path: lib/jdbc.jar lib/otherlib.jar
Main-Class: com.name.app.MainClass
Replace the contents of Class-Path with your libs, and Main-Class with the fully qualified name of your main class.
Then, you need to generate the actual .jar, using the following command:
jar cfm app.jar MANIFEST.MF src/com/name/app/*.class src/com/name/app/do/*.class
Where MANIFEST.MF is the previously mentioned manifest file, and the rest is the folders where your .java classes lie in.
Finally, to run your app, you simply execute: java -jar app.jar.
Consider using Ant to do this. http://ant.apache.org/
I recommend that you use Apache Ant to implement your build scripts.
If implemented correctly, Ant is easy to use and the build scripts can be run on any platform that you can install a JDK on. Indeed, with a little bit of work, you can even set up your project so that users don't even need to download / install Ant. (Hint: add the Ant JAR files and a wrapper script to your project distro)

Categories