Execute a jar file using Ant - ant

I am trying to create a runnable jar file from java classes using ant. The java classes use external jars. When I execute the build.xml its showing class not found exception while running the java program. Its compiling fine.
Part of My source code:
<path id="project-libpath">
<fileset dir="${lib.dir}">
<include name="*.jar"/>
</fileset>
</path>
<path id="project-classpath">
<fileset dir="C:/xmldecode/lib">
<include name="*.jar"/>
</fileset>
</path>
<target name="compile" depends="prepare">
<javac srcdir="${src.dir}" destdir="${classes.dir}">
<classpath refid="project-classpath"/>
</javac>
</target>
<target name="jar" depends="compile">
<copy todir="${classes.dir}">
<fileset dir="C:/xmldecode/lib"/>
</copy>
<pathconvert property="mf.classpath" pathsep=";">
<path refid="project-classpath" />
<flattenmapper />
</pathconvert>
<jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}">
<manifest>
<attribute name="Main-Class" value="${main-class}"/>
<attribute name="Class-Path" value="${mf.classpath}"/>
</manifest>
</jar>
</target>
<target name="run" depends="jar">
<java jar="${jar.dir}/${ant.project.name}.jar" fork="true">
</java>

Your problem is that the manifest classpath entries are not separated by a ";" character.
The following will work better I think:
<pathconvert property="mf.classpath" pathsep=" ">
<path refid="project-classpath" />
<flattenmapper />
</pathconvert>
Could I suggest using the new ANT task manifestclasspath ?
<manifestclasspath property="mf.classpath" jarfile="${jar.dir}/${ant.project.name}.jar">
<classpath refid="project-classpath" />
</manifestclasspath>
This powerful method will determine paths relative to the jar's location, for example if the jar's dependencies are located in a lib directory

Related

Ant Build issue : Additonal folder getting created

need your help at the earliest and I have been breaking my head over this for a while.
Below is my Ant Script.
<property name="build.dir" value="${basedir}/build"/>
<property name="lib.dir" value="${basedir}/lib"/>
<property name="src.dir" value="${basedir}/allocator"/>
<property name="classes.dir" value="${basedir}/classes"/>
<property name="jar.dir" value="${basedir}/jar"/>
<property name="main-class" value="allocator.Allocator"/>
<path id="classpath_ref">
<pathelement path="${basedir}/"/>
<fileset dir="${lib.dir}" includes="*.jar"/>
</path>
<target name="clean">
<delete dir="${classes.dir}" />
<delete dir="${build.dir}" />
<delete dir="${jar.dir}" />
</target>
<target name="compile">
<mkdir dir="${classes.dir}"/>
<javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath_ref" includeantruntime="false">
<src path="${basedir}/supportlibraries"/>
<src path="${basedir}/com/xyz/framework"/>
</javac>
<copy todir="${build.dir}"><fileset dir="${src.dir}" excludes="**/*.java"/>
</copy>
</target>
<target name="jar" depends="compile">
<mkdir dir="${jar.dir}"/>
<jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${build.dir}">
<manifest>
<attribute name="Main-Class" value="${main-class}"/>
</manifest>
</jar>
</target>
<target name="run" depends="jar">
<java classname="${main-class}" fork="true" >
<arg line="username"/>
<arg line="password"/>
<classpath>
<path refid="classpath_ref"/>
<pathelement location="${jar.dir}/${ant.project.name}.jar"/>
</classpath>
</java>
</target>
<target name="main" depends="clean,run"/>
</project>
when i try to run the ant build from eclipse it is creating an additional folder allocator, supportlibraries and com/xyz/framework inside the class folder. why is it creating additional folder? because of the additional folders when the run target executes its not able to locate the allocator class. Please let me know if i am missing anything
Remove the <copy> from the "compile" <target>.
The <jar> in the "jar" target should be:
<jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}">
<manifest>
<attribute name="Main-Class" value="${main-class}"/>
</manifest>
</jar>
In the above snippet, basedir is ${classes.dir} instead of ${build.dir}.
I don't see a need for build.dir in your script. All references to it can likely be removed.

ant multiple source directories with copied resources

Consider minimal build.xml fragment which builds jar from sources and includes all non-java resources:
<property name="src.dir" value="src" />
<target name="build">
<javac destdir="bin">
<src path="${src.dir}" />
</javac>
<copy includeemptydirs="false" todir="bin">
<fileset dir="${src.dir}">
<exclude name="**/*.java" />
</fileset>
</copy>
<jar destfile="dist/foo.jar" basedir="bin"/>
</target>
Now imagine that I need to support a list of source directories:
<property name="src.dirs" value="src;src-gen" />
How can i modify above script to make it happen ?
javac will happily take list of directories but for copy I need to transform string into list of filesets with exclusions or find some other way.
Normally, you simply list them all together:
<javac destdir="bin">
<src path="${src.dir}"/>
<src path="${src2.dir}"/>
<src path="${src3.dir}"/>
</javac>
You can try the <sourcepath/> attribute. I've never used it, but I believe you can use it to define a path of various source files, and use that:
<path id="source.path">
<pathelement path="${src.dir}"/>
<pathelement path="${src2.dir}"/>
<pathelement path="${src4.dir}"/>
</path>
<javac destdir="bin">
srcpathref="source.path"/>
The first will work, but not 100% sure about the second.
I'm not sure of a way to do it with built-in Ant tasks but you could use an ant-contrib <for> task
<path id="src.path">
<pathelement location="src" />
<pathelement location="src-gen" />
</path>
<target name="build">
<javac destdir="bin">
<src refid="src.path" />
</javac>
<for param="dir">
<path refid="src.path" />
<sequential>
<copy includeemptydirs="false" todir="bin">
<fileset dir="#{dir}">
<exclude name="**/*.java" />
</fileset>
</copy>
</sequential>
</for>
<jar destfile="dist/foo.jar" basedir="bin"/>
</target>
The simple solution is to just specify multiple filesets, in the same manner as the javac task supports multiple "src" attributes:
<target name="build" depends="init" description="Create the package">
<javac destdir="${classes.dir}" includeantruntime="false">
<src path="src/main1/java"/>
<src path="src/main2/java"/>
</javac>
<copy todir="${classes.dir}" includeemptydirs="false">
<fileset dir="src/main1" excludes="**/*.java"/>
<fileset dir="src/main2" excludes="**/*.java"/>
<flattenmapper/>
</copy>
</target>
This of course assumes that the number of source code locations is fixed, which is not unreasonable to expect.
If you want to drive this using a list property you must resort to embedding a script within your build to process this list (I can't endorse ant-contrib):
<project name="demo" default="build">
<property name="src.dirs" value="src/main1,src/main2"/>
<property name="build.dir" location="build"/>
<property name="classes.dir" location="${build.dir}/classes"/>
<target name="bootstrap">
<mkdir dir="${user.home}/.ant/lib"/>
<get dest="${user.home}/.ant/lib/groovy-all.jar" src="http://search.maven.org/remotecontent?filepath=org/codehaus/groovy/groovy-all/2.1.6/groovy-all-2.1.6.jar"/>
</target>
<target name="init">
<mkdir dir="${classes.dir}"/>
</target>
<target name="build" depends="init" description="Create the package">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy"/>
<groovy>
def srcDirs = properties["src.dirs"].split(",")
ant.javac(destdir:properties["classes.dir"], includeantruntime:false) {
srcDirs.each {
src(path:"${it}/java")
}
}
ant.copy(todir:properties["classes.dir"], includeemptydirs:false) {
srcDirs.each {
fileset(dir:it, excludes:"**/*.java")
}
flattenmapper()
}
</groovy>
</target>
<target name="clean" description="Cleanup build dirs">
<delete dir="${build.dir}"/>
</target>
</project>
Notes:
Compare the "build" targets. You'll notice that the groovy solution calls ANT in the same manner. This is why I really like groovy's integration with ANT.
Example also includes a "bootstrap" target to download the groovy jar dependency from Maven Central. You could alternatively use ivy to manage your build's dependencies.
A simple solution without ant-contrib tasks or embedded scripts:
<property name="src.dirs" value="src,src-gen" />
<path id="src.path">
<multirootfileset type="dir" basedirs="${src.dirs}"/>
</path>
<target name="build">
<javac destdir="bin">
<src refid="src.path"/>
</javac>
<copy todir="bin">
<multirootfileset type="file" basedirs="${src.dirs}">
<exclude name="**/*.java"/>
</multirootfileset>
</copy>
<jar destfile="dist/foo.jar" basedir="bin"/>
</target>
multirootfileset to the rescue! ;-) Needs Ant 1.9.4 or higher.

can't make jar with dependencies extracted in it via ant

I want to build my project using ant but I have a small problem. My problem is that I need the output jar have all my .class and all my jar dependencies extracted not zipped.
<project name="ivy example" default="compress" xmlns:ivy="antlib:org.apache.ivy.ant">
<target name="resolve" description="Resolve and retrieve with ivy">
<ivy:resolve />
<ivy:cachepath pathid="compile.path" />
</target>
<target name="compile" depends="resolve" description="compilation">
<mkdir dir="build/classes" />
<javac srcdir="src" destdir="build/classes">
<classpath refid="compile.path" />
</javac>
</target>
<target name="compress" depends="compile">
<jar destfile="output/engine.jar" filesonly="true" update="true">
<fileset dir="build/classes" />
<fileset dir="lib"/>
<manifest>
<attribute name="Created-By" value="vireton"/>
<attribute name="Main-Class" value="HelloIvy"/>
</manifest>
</jar>
<echo>Building .jar file completed successfully!</echo>
</target>
</project>
That code generates my engine.jar with the output classes + dependencies.jar.
I want it to generate my classes and the dependencies extracted.
Can anyone help?
i did it by extracting the dependencies to a tmp directory then make a jar of both directories (src & tmp)
<target name="compress" depends="compile">
<delete file="output/engine.jar" />
<mkdir dir="tmp" />
<unzip dest="tmp">
<fileset dir="lib">
<include name="*.jar" />
</fileset>
</unzip>
<delete dir="tmp/META-INF" />
<jar destfile="output/engine.jar" update="true">
<fileset dir="build/classes" />
<fileset dir="tmp"/>
<manifest>
<attribute name="Created-By" value="vireton"/>
<attribute name="Main-Class" value="HelloIvy"/>
</manifest>
</jar>
</target>
and i found an even better way to do it using
<target name="compress" depends="compile">
<delete file="output/engine.jar" />
<jar destfile="output/engine.jar" update="true">
<zipgroupfileset dir="lib" includes="*.jar"/>
<zipfileset dir="build/classes" />
</jar>
</target>
Extract all the jars of the lib folder to some temporary folder (using the unjar task), then create the engine.jar by adding this temporary folder as a fileset.
Just like you would do it by hand.
You have your dependency jar files available as a path thanks to
<ivy:cachepath pathid="compile.path" />
so the simplest way to bundle them all into your final jar would be (assuming Ant 1.8 or later)
<jar destfile="output/engine.jar" filesonly="true" update="true">
<fileset dir="build/classes" />
<archives>
<zips>
<path refid="compile.path"/>
</zips>
</archives>
<manifest>
<attribute name="Created-By" value="vireton"/>
<attribute name="Main-Class" value="HelloIvy"/>
</manifest>
</jar>
This will read the jars directly from your ivy cache, you don't need to retrieve them into a local lib directory first.

Compiled classes are not included in generated Jar

I am creating a jar bundle using ant build script. The problem is that the .class files are not included in the generated .jar file. I have also tried the {build.dest} in making the jar, but with no effect.
remaining all the files i require are in .jar file.
Here is my build script
<?xml version="1.0"?>
<project name="TaskNodeBundle" default="all" basedir=".">
<!-- Sets variables which can later be used. -->
<!-- The value of a property is accessed via ${} -->
<property name="bundlename" value="task-node-bundle" />
<property name="src.dir" location="../src" />
<property name="lib.dir" location="../lib" />
<property name="build.dir" location="/buildoutput" />
<property name="build.dest" location="../build/dest" />
<!--
Create a classpath container which can be later used in the ant task
-->
<path id="classpath">
<fileset dir="${lib.dir}/">
<include name="*.jar" />
</fileset>
</path>
<target name="clean">
<delete dir="${build.dir}" />
<delete dir="${build.dest}" />
</target>
<!-- Deletes the existing build directory -->
<target name="mkdir" depends="clean">
<mkdir dir="${build.dest}"/>
</target>
<!-- Compiles the java code -->
<target name="compile" depends="mkdir">
<javac srcdir="${src.dir}" destdir="${build.dest}" classpathref="classpath" />
</target>
<target name="package-bundle" depends="compile" description="Generates the bundle" >
<jar destfile="${build.dest}/${bundlename}.jar" manifest="${src.dir}/META-INF/MANIFEST.MF">
<fileset dir="${src.dir}">
<include name="**/**.class" />
<include name="**/**.properties"/>
<include name="/META-INF/**.*" />
<include name="/META-INF/spring/**.*" />
</fileset>
</jar>
</target>
<target name="all" depends="package-bundle">
</target>
</project>
Firstly, what do you mean by "tried {build.dest} in making the jar"?
Whatever, you need to take a look at this part of your build:
<jar destfile="${build.dest}/${bundlename}.jar" manifest="${src.dir}/META-INF/MANIFEST.MF">
<fileset dir="${src.dir}">
<include name="**/**.class" />
<include name="**/**.properties"/>
<include name="/META-INF/**.*" />
<include name="/META-INF/spring/**.*" />
</fileset>
</jar>
You compiled class files are in ${build.dest}, so you should use ${build.dest} as the root dir for the nested <fileset> of the <jar> task. But now you are pointing the <fileset> to your source code folder.
You should avoid putting the generated jar file in the same directory where the class files are. For example, you can put the jar in ${dist.dir}, which is another directory.
So try this:
You have a property:
<property name="dist.dir" value="../build/dist" />
And then,
<jar destfile="${dist.dir}/${bundlename}.jar" manifest="${src.dir}/META-INF/MANIFEST.MF">
<fileset dir="${build.dest}">
<include name="**/*.class" />
</fileset>
<fileset dir="${src.dir}">
<include name="**/*.properties"/>
<include name="/META-INF/**/*.*" />
<include name="/META-INF/spring/**/*.*" />
</fileset>
</jar>

Generate manifest class-path from <classpath> in Ant

In the build file below, the jar target refers to the jar.class.path property for the manifest class-path. The compile target refers to project.class.path
There is redundancy here, because jar.class.path and project.class.path are very similar. They must be both updated when libraries are added, which can be a pain if the list of libraries gets very long. Is there a better way? Any solution must be cross-platform and always use relative paths.
Edit:
It should generate the JAR classpath from a fileset and not the other way around, so I can use wildcards to e.g. include all JAR files in a directory.
<?xml version="1.0"?>
<project name="Higgins" default="jar" basedir=".">
<property name="jar.class.path" value="lib/forms-1.2.0.jar lib/BrowserLauncher.jar"/>
<path id="project.class.path">
<pathelement location="build"/>
<fileset dir="lib">
<include name="forms-1.2.0.jar"/>
<include name="BrowserLauncher.jar"/>
</fileset>
</path>
<target name="prepare">
<mkdir dir="build"/>
</target>
<target name="compile" depends="prepare" description="Compile core sources">
<javac srcdir="src"
includes="**"
destdir="build"
debug="true"
source="1.5">
<classpath refid="project.class.path"/>
</javac>
</target>
<target name="jar" depends="compile" description="Generates executable jar file">
<jar jarfile="higgins.jar">
<manifest>
<attribute name="Main-Class" value="nl.helixsoft.higgins.Main"/>
<attribute name="Class-Path" value="${jar.class.path}"/>
</manifest>
<fileset dir="build" includes="**/*.class"/>
<fileset dir="src" includes="**/*.properties"/>
</jar>
</target>
</project>
<path id="build.classpath">
<fileset dir="${basedir}">
<include name="lib/*.jar"/>
</fileset>
</path>
<pathconvert property="manifest.classpath" pathsep=" ">
<path refid="build.classpath"/>
<mapper>
<chainedmapper>
<flattenmapper/>
<globmapper from="*.jar" to="lib/*.jar"/>
</chainedmapper>
</mapper>
</pathconvert>
<target depends="compile" name="buildjar">
<jar jarfile="${basedir}/${test.jar}">
<fileset dir="${build}" />
<manifest>
<attribute name="Main-Class" value="com.mycompany.TestMain"/>
<attribute name="Class-Path" value="${manifest.classpath}"/>
</manifest>
</jar>
</target>
For further information check out this article.
Assuming Ant 1.7 or above, you can use the manifestclasspath task.
<path id="dep.runtime">
<fileset dir="./lib">
<include name="**/*.jar" />
</fileset>
</path>
<property name="dep_cp" value="${toString:dep.runtime}" />
<target name="default">
<manifestclasspath property="manifest_cp" jarfile="myjar.jar">
<classpath refid="dep.runtime" />
</manifestclasspath>
<echo message="Build Classpath: ${dep_cp}" />
<echo message="Manifest Classpath: ${manifest_cp}" />
</target>
If you just want a common subpath shared between two (or more) paths, that is easy to do:
<path id="lib.path>
<fileset dir="lib">
<include name="forms-1.2.0.jar"/>
<include name="BrowserLauncher.jar"/>
</fileset>
</path>
<path id="project.class.path">
<pathelement location="build"/>
<path refid="lib.path"/>
</path>
<property name="jar.class.path" refid="lib.path"/>
EDIT Sorry, I misunderstood the question. Try this:
<property name="jar.class.path" value="lib/forms-1.2.0.jar lib/BrowserLauncher.jar"/>
<path id="project.class.path">
<pathelement location="build"/>
<fileset dir="." includes="${jar.class.path}"/>
</path>
You can use <pathconvert> to convert a path (which can contain a fileset) into a plain string. You'll likely need to <echo> that string to a file, use either <replace> or <replaceregexp> to chop the leading path bits, then finally use <loadfile> to load the manipulated string into the final property.
Implementation left as an exercise to the reader.

Resources