Ant + Class-path Issue - ant

I have written an ANT script and finally am building the jar
here is the building of jar section
<jar jarfile="${destination}/#{name}.jar">
<fileset dir="${output}">
<include name="abc/xyz/#{name}/**"/>
</fileset>
<zipfileset dir="lib" prefix="lib/"/>
<manifest>
<attribute name="Main-Class" value="com.abc.xyz.HelloWorld"/>
<attribute name="Class-Path" value=".:lib/activation.jar:lib/antlr-2.7.6.jar:lib/asm-attrs.jar:lib/asm.jar:lib/cglib-2.1.3.jar:lib/commons-collections-2.1.1.jar:lib/commons-logging-1.1.jar:lib/dom4j-1.6.1.jar:lib/ehcache-1.2.3.jar:lib/ejb3-persistence.jar:lib/hibernate-annotations.jar:lib/hibernate-commons-annotations.jar:lib/hibernate-entitymanager.jar:lib/hibernate-tools.jar:lib/hibernate3.jar:lib/javassist.jar:lib/jdbc2_0-stdext.jar:lib/jta.jar:lib/mysql-connector-java-5.1.5-bin.jar"/>
</manifest>
</jar>
Now when I try to execute the package it executes, but whenever data is sent I get an error.
java.lang.NoClassDefFoundError: javax/persistence/NoResultException
But the persistence jar is there in the class-path, I've tried all the combinations for the class-path, but in vain.
But in another system I tried without create a jar like
set classpath=.;lib/activation.jar;lib/antlr-2.7.6.jar;lib/asm-attrs.jar;lib/asm.jar;lib/cglib-2.1.3.jar;lib/commons-collections-2.1.1.jar;lib/commons-logging-1.1.jar;lib/dom4j-1.6.1.jar;lib/ehcache-1.2.3.jar;lib/ejb3-persistence.jar;lib/hibernate-annotations.jar;lib/hibernate-commons-annotations.jar;lib/hibernate-entitymanager.jar;lib/hibernate-tools.jar;lib/hibernate3.jar;lib/javassist.jar;lib/jdbc2_0-stdext.jar;lib/jta.jar;lib/mysql-connector-java-5.1.5-bin.jar
java com.abc.xyz.HelloWorld
This works fine.
In Mac when I try like this:
java -cp .:lib/activation.jar:lib/antlr-2.7.6.jar:lib/asm-attrs.jar:lib/asm.jar:lib/cglib-2.1.3.jar:lib/commons-collections-2.1.1.jar:lib/commons-logging-1.1.jar:lib/dom4j-1.6.1.jar:lib/ehcache-1.2.3.jar:lib/ejb3-persistence.jar:lib/hibernate-annotations.jar:lib/hibernate-commons-annotations.jar:lib/hibernate-entitymanager.jar:lib/hibernate-tools.jar:lib/hibernate3.jar:lib/javassist.jar:lib/jdbc2_0-stdext.jar:lib/jta.jar:lib/mysql-connector-java-5.1.5-bin.jar com.abc.xyz.HelloWorld
Also it works fine :(, but the minute I create the jar it stops.
How can I resolve this issue?

First of all the "Main-Class" and "Class-Path" manifiest entries is only used for executeable jars. In other words when you invoke java as follows:
java -jar foo.jar
Invoking java using the -cp option means you're supplying your own classpath and note that you also have to provide the main class on the command line as well.
Secondly you need to replace the ":" characters with spaces:
<attribute name="Class-Path" value=". lib/activation.jar lib/antlr-2.7.6.jar lib/asm-attrs.jar lib/asm.jar lib/cglib-2.1.3.jar lib/commons-collections-2.1.1.jar lib/commons-logging-1.1.jar lib/dom4j-1.6.1.jar lib/ehcache-1.2.3.jar lib/ejb3-persistence.jar lib/hibernate-annotations.jar lib/hibernate-commons-annotations.jar lib/hibernate-entitymanager.jar lib/hibernate-tools.jar lib/hibernate3.jar lib/javassist.jar lib/jdbc2_0-stdext.jar lib/jta.jar lib/mysql-connector-java-5.1.5-bin.jar"/>
Finally I'd recommend using the manifestclasspath task to build your classpath string for you. It will correcly resolve any relative links between your jar and it's run-time dependencies.
<manifestclasspath property="mf.classpath" jarfile="${destination}/#{name}.jar">
<classpath>
<fileset dir="lib" includes="*.jar"/>
<classpath>
</manifestclasspath>
<jar jarfile="${destination}/#{name}.jar">
<fileset dir="${output}">
<include name="abc/xyz/#{name}/**"/>
</fileset>
<zipfileset dir="lib" prefix="lib/"/>
<manifest>
<attribute name="Main-Class" value="com.abc.xyz.HelloWorld"/>
<attribute name="Class-Path" value=". ${mf.classpath}"/>
</manifest>
</jar>
One final observation.... Why are you including the contents of the lib directory inside the jar? (The zipfileset tag in the jar command?)
This appears unnecessary, all you need to do is ensure that the run-time dependencies are present in a lib directory as specified in your Class-Path manifest entry.

The reason for it not works was there not in the class path, the explanation is given here:
Java-Jar-Ignores-Classpath-Workaround

Related

ANT: ways to include libraries and license issues

I have been trying to use Ant to compile and ready a project for distribution. I have encountered several problems along the way that I have been finally able to solve but the solution leaves me very unsatisfied. First, let me explain the set-up of the project and its dependencies.
I have a project, lets call it Primary which depends on a couple of libraries such as the fantastic Guava. It also depends on another project of mine, lets call it Secondary. The Secondary project also features some dependencies, for example, JDOM2. I have referenced the Jar I build with Ant in Primary.
Let me give you the interesting bits of the build.xml so you can get a picture of what I am doing:
<project name="Primary" default="all" basedir=".">
<property name='build' location='dist' />
<property name='application.version' value='1.0'/>
<property name='application.name' value='Primary'/>
<property name='distribution' value='${application.name}-${application.version}'/>
<path id='compile.classpath'>
<fileset dir='libs'>
<include name='*.jar'/>
</fileset>
</path>
<target name='compile' description='Compile source files.'>
<javac includeantruntime="false" srcdir="src" destdir="bin">
<classpath refid='compile.classpath'/>
</javac>
<target>
<target name='jar' description='Create a jar file for distribution.' depends="compile">
<jar destfile='${build}/${distribution}.jar'>
<fileset dir="bin"/>
<zipgroupfileset dir="libs" includes="*.jar"/>
</jar>
</target>
The Secodnary project's build.xml is nearly identical except that it features a manifest as it needs to run:
<target name='jar' description='Create a jar file for distribution.' depends="compile">
<jar destfile='${dist}/${distribution}.jar' basedir="${build}" >
<fileset dir="${build}"/>
<zipgroupfileset dir="libs" includes="*.jar"/>
<manifest>
<attribute name="Main-Class" value="lu.tudor.ssi.kiss.climate.ClimateChange"/>
</manifest>
</jar>
</target>
After I got it working, trying for many hours to not include that dependencies as class files but as Jars, I don't have the time or insight to go back and try to figure out what I did wrong. Furthermore, I believe that including these libraries as class files is bad practice as it could give rise to licensing issues while not packaging them and merely including them in a directory along the build Jar would most probably not (And if it would you could choose not to distribute them yourself).
I think my inability to correctly assemble the class path, I always received NoClassDefFoundError for classes or libraries in the Primary project when launching Second's Jar, is that I am not very experienced with Ant. Would I require to specify a class path for both projects? Specifying the class path as . should have allowed me to simply add all dependencies to the same folder as Secondary's Jar, should it not?
You may use the MANIFEST.MF "Class-Path: " to cross-reference your jars.
If they are all in the same directory this will probably work as follows (using it in both projects!):
<target name='jar' description='Create a jar file for distribution.' depends="compile">
<pathconvert property="manifest.classpath" pathsep=" ">
<path refid="compile.classpath" />
<flattenmapper />
</pathconvert>
<jar destfile='${build}/${distribution}.jar'>
<fileset dir="bin"/>
<manifest>
<attribute name="Class-Path" value="${manifest.classpath}"/>
</manifest>
</jar>
</target>
This way you can tell the java runtime environment that your jar needs others to work, expecting them to be in the same directory as the jar you are trying to run.
As a result your primary.jar should have secondary.jar in it's classpath and secondary.jar should have guava.jar in it's classpath.
Another way to create the string may be ants manifestclasspath task (https://ant.apache.org/manual/Tasks/manifestclasspath.html) that can handle subdirectories.
If you are goin to use more and more libraries, you may want to have a closer look at ivy or even maven.

CreateProcess error=206, The filename or extension is too long

I'm trying to call Findbugs via Ant, but receiving this error:
Cannot run program "C:\Program Files (x86)\Java\jre6\bin\javaw.exe" (in
directory "H:\Users\MyName\workspace\MyProject"):
CreateProcess error=206, The filename or extension is too long
How can I fix this? o.O
I had the same problem.
I used
<fileset dir="${basedir}/build">
<include name="**/*.class"/>
</fileset>
inside findbugs target and it seems that there is too much .class files to be passed to findbug (?via command line?) because when I used
<fileset dir="${basedir}/build/com/domain/package">
<include name="**/*.class"/>
</fileset>
that had low number of classes, the error was gone.
So, I solved the problem by making one jar file and feeding it to findbugs target with
<findbugs home="${findbugs.home}">
...
<class location="${basedir}/targets/classes-to-analyze.jar"/>
</findbugs>
I think one of the effective file paths are really long when java tries to compile clases.
One worth try is to put codebase in a directory such as C:\MyProject instead of something like C:\Users\MyName\workspace\MyProject
To solve this issue you need to generate a manifestclasspath and a pathing jar.
First Generate your classpath.
<path id="javac.path">
<fileset dir="lib/" includes="**/*.jar"/>
</path>
Next Generate your manifestclasspath
<target name="generate-manifest-classpath">
<manifestclasspath property="manifest.classpath" jarfile="pathing.jar">
<classpath refid="javac.path"/>
</manifestclasspath>
<jar destfile="pathing.jar" basedir="${the location of your build classes}">
<manifest>
<attribute name="Class-Path" value="${manifest.classpath}"/>
</manifest>
</jar>
<path id="javac.classpath">
<pathelement path="pathing.jar"/>
</path>
</target>
Next Implement your Manifestclasspath
<javac srcdir="${foo.dir}" destdir="${bar.dir}"
<classpath refid="javac.classpath"/>
</javac>
This will solve the 206 error message if implemented correctly.
I had the same error on IntelliJ while starting debug mode only. To fix is I've changed:
Run > Edit Configurations > "Configuration" tab > Shorten command line
to "JAR-manifest"

Ant - how to get all files' name in a specific folder

Here is my Ant script for generating jar package. I have bunch of jar packages for manifest Class-Path attribute, they are all in an specific folder.
I don't want to hard code it, how can I get them automatically?
<jar jarfile="${client_deploy_dir}/HelloWorld.jar"
basedir="${client_work_dir}/compiled">
<manifest>
<attribute name="Main-Class" value="HelloWorld.Main"/>
<attribute name="Class-Path" value="???"/>
</manifest>
</jar>
Thanks
You're on the right track, use manifestclasspath task. The jarfile attribute is used to create relative links to the jars contained in the fileset.
<manifestclasspath property="jar.classpath" jarfile="${client_work_dir}/HelloWorld.jar">
<classpath>
<fileset name="" dir="${client_work_dir}/lib" includes="*.jar"/>
</classpath>
</manifestclasspath>
<jar jarfile="${client_deploy_dir}/HelloWorld.jar" basedir="${client_work_dir}/compiled">
<manifest>
<attribute name="Main-Class" value="HelloWorld.Main"/>
<attribute name="Class-Path" value=""${jar.classpath}"/>
</manifest>
</jar>
Check out the ant pathconvert task. You can use this to expand an existing fileset into a list of files.

How do you use ant to unjar multiple JAR files and rebuild them into one JAR file?

I would like to unjar multiple JAR files and then rebuild into one JAR using an ant build script. Is this possible?
Yes, it's possible with ant. A jar file is basically a zip with a special manifest file. So to unjar, we need to unzip the jars. Ant includes an unzip task.
To unzip/unjar all the jar files in your project:
<target name="unjar_dependencies" depends="clean">
<unzip dest="${build.dir}">
<fileset dir="${lib.dir}">
<include name="**/*.jar" />
</fileset>
</unzip>
</target>
Obviously you need to declare ${build.dir} and ${lib.dir} first. The line <include name="**/*.jar" /> tells ant to include all files that end up with the jar extension, you can tweak that include to suit your needs.
To pack everything into a jar, you use the jar task:
<target name="make_jar" depends="compile, unjar_dependencies">
<jar basedir="${build.dir}"
destfile="${dist.dir}/${project_name}.jar">
<manifest>
<attribute name="Main-Class" value="${mainclass}" />
</manifest>
<fileset dir="${build.dir}">
<include name="**/*.class" />
</fileset>
<fileset dir="${src.dir}">
<include name="applicationContext.xml" />
<include name="log4j.properties" />
</fileset>
</jar>
</target>
In this example, we include different filesets. In one fileset we are including all compiled classes. In another fileset we include two config files that this particular project depends upon.
Yes it is !
You have two possibilities :
Espen answer :
One possible solution that creates one
jar file from all the jar files in a
given directory:
<target name="dependencies.jar">
<jar destfile="WebContent/dependencies.jar">
<zipgroupfileset dir="lib/default/" includes="*.jar"
excludes="*.properties" />
</jar>
</target>
This is useful if you don't need to exclude content that are in some jars (like for example some properties configuration file that might override yours, etc). Here the excludes properties is filtering out files from the dir property.
Use zipfileset
The other solution is to use the zipfileset tag where the excludes property this time will filter out content from the jar to be merged.
<jar destfile="your_final_jar.jar" filesetmanifest="mergewithoutmain">
<manifest>
<attribute name="Main-Class" value="main.class"/>
<attribute name="Class-Path" value="."/>
</manifest>
<zipfileset
excludes="META-INF/*.SF"
src="/path/to/first/jar/to/include.jar"/>
</jar>
Of course you can combine the two tags (zipfileset and zipgroupfileset) inside the same jar tag to get the best of the two.
Yes, it's possible.
One possible solution that creates one jar file from all the jar files in a given directory:
<target name="dependencies.jar">
<jar destfile="WebContent/dependencies.jar">
<zipgroupfileset dir="lib/default/" includes="*.jar"
excludes="*.properties" />
</jar>
</target>
There is also a project devoted to repackage jars called JarJar. You can use it to repackage mutiple Jars into one. Depending on your requirements, you can even rename classes to prevent version conflicts.
From their getting started page:
In this example we include classes from jaxen.jar and add a rule that changes any class name starting with "org.jaxen" to start with "org.example.jaxen" instead (in our imaginary world we control the example.org domain):
<target name="jar" depends="compile">
<taskdef name="jarjar" classname="com.tonicsystems.jarjar.JarJarTask"
classpath="lib/jarjar.jar"/>
<jarjar jarfile="dist/example.jar">
<fileset dir="build/main"/>
<zipfileset src="lib/jaxen.jar"/>
<rule pattern="org.jaxen.**" result="org.example.#1"/>
</jarjar>
</target>

how to add a complete folder to a jar file by ant

I'd like to create like a "fat" jar with ant where I have, not only the usual classes, manifest files, etc, but also my 'libs' folder too.
I tried with:
<jar destfile="myjar.jar" update="yes" basedir="${libs.dir}"/>
but this adds the files in 'libs' the root of the jar file where I'd like to have the libs folder itself in the jar (with everything it contains of course)
Can I maybe create the lib folder myself in the jar and add the files to that specific location in the jar then ?
If you specify to use the directory as the root for your file set then you can just match for the directory and it will preserve the structure.
<jar destfile="myjar.jar" >
<fileset dir=".">
<include name="**/${libs.dir}/**"/>
</fileset>
</jar>
You have to do something like the following. Specifically, the zipfileset command. You basically are saying you want to build the ${build.name}.jar (you could hard code a path to be "myjar.jar" or something along those lines) and then add the various files to the JAR.
Hope this helps!
<jar destfile="${dist}/${build.name}.jar">
<!-- Generate the MANIFEST.MF file. -->
<manifest>
<attribute name="Built-By" value="${user.name}" />
<attribute name="Release-Version" value="${version}" />
<attribute name="Main-Class" value="my.lib.Main" />
<attribute name="SplashScreen-Image" value="TitleScreen.png" />
<attribute name="Class-Path" value="${classpath}" />
</manifest>
<zipfileset dir="${build.dir}" />
<zipfileset dir="${resources}" />
<fileset file="${resources}/icons/misc_icons/TitleScreen.png" />
</jar>
Use this ant extension: http://one-jar.sourceforge.net/
There is also Eclipse plugin: FatJar
http://www.vertigrated.com/blog/2009/11/how-to-bundle-command-line-programs-into-a-single-executable-jar-file/

Resources