How to get hold on the flattenmapper result in ant? - ant

Please, find below a few targets from my ant file:
<fileset id="test-dep-jars" dir="o:/java">
<include name="junit-4.10.jar"/>
<include name="easymock-3.1\easymock-3.1.jar"/>
<include name="easymockclassextension-3.1\easymockclassextension-3.1.jar"/>
</fileset>
<target name="copy-test-deps">
<mkdir dir="${deploy.dir}"/>
<copy todir="${deploy.dir}">
<fileset refid="test-dep-jars"/>
<flattenmapper/>
</copy>
</target>
<target name="jar" depends="copy-test-deps">
<jar destfile="${deploy.dir}/test-${ant.project.name}.jar" basedir="${test.classes.dir}"
includes="**/*.class" filesetmanifest="skip">
<manifest>
<attribute name="Class-Path"
value="${ant.project.name}.jar junit-4.10.jar easymock-3.1.jar easymockclassextension-3.1.jar"/>
</manifest>
</jar>
</target>
My problem is that I have to state the test dependency jars twice - once when defining the test-dep-jars fileset and the second time when specifying the Class-Path manifest attribute of the produced jar.
If I only could get hold on the flattenmapper result, then I would be able to use it in the Class-Path as is.
How can I get hold on the flattenmapper result?
Thanks.

If you want to use flattenmapper you can use following...
<pathconvert property="mf.classpath" pathsep=" ">
<path refid="build.class.path" />
<flattenmapper />
</pathconvert>
<manifest>
<attribute name="Class-Path"
value="${ant.project.name}.jar ${mf.classpath}"/>
</manifest>

I would recommend using the manifestclasspath task instead:
<manifestclasspath property="jar.classpath" jarfile="${jar.file}">
<classpath>
<fileset dir="${deploy.dir}" includes="*.jar"/>
</classpath>
</manifestclasspath>
<jar destfile="${jar.file}" basedir="${classes.dir}">
<manifest>
<attribute name="Main-Class" value="${jar.main.class}" />
<attribute name="Class-Path" value="${jar.classpath}" />
</manifest>
</jar>
It will generate the correct classpath property definition and even works with relative paths (for example if you were to place the dependent jars in sub-directory).

Related

How do I exclude a folder in an ant jar task?

I am trying to build a java project using ant. I have to exclude a particular directory from base directory for jar packaging. Here is the code snippet.
<target name="jar" depends="wsdl2java,oss.init,oss.request.compile">
<copy todir="${build.lib.dir}">
<fileset dir="${oss.lib.dir}" includes="**/*.*" excludes="**/weblogic.jar"/>
</copy>
<copy todir="${build.conf.dir}">
<fileset dir="${oss.conf.dir}" includes="**/*.*"/>
</copy>
<copy todir="${oss.build.dir}">
<fileset dir="${oss.run.dir}" includes="**/*.*"/>
</copy>
<jar destfile="${oss.build.dir}/osstool2.5.5.jar" basedir="${oss.class.dir}" excludes="**/dms/*">
<manifest>
<attribute name="Main-Class" value="${main-class}"/>
<attribute name="Created-By" value="${owner}"/>
<attribute name="Class-Path" value=". lib/antlr-runtime-3.0.1.jar.jar lib/log4j.jar
lib/commons-discovery-0.2.jar lib/commons-logging-1.1.1.jar
lib/spring.jar lib/axis.jar lib/axis-ant.jar lib/jaxrpc-api.jar
lib/webserviceclient.jar lib/webserviceclient+ssl.jar
lib/wlclient.jar lib/wsdl4j-1.5.1.jar lib/wsse.jar lib/ala-castor.jar lib/log4j.jar lib/log4j.jar lib/xercesImpl.jar
lib/ala-nbi-commons-1.3.0.jar lib/ala-nbi-notification-plugins.jar lib/ala-nbi-webservice-client-1.3.0.jar
lib/axis.jar lib/axis-ant.jar lib/dom4j-1.6.1.jar lib/jaxrpc-api.jar lib/webserviceclient.jar lib/webserviceclient+ssl.jar
lib/wlclient.jar lib/wsdl4j-1.5.1.jar lib/wsse.jar lib/commons-logging.jar">
</attribute>
</manifest>
</jar>
</target>
What am I missing here?
Thanks in advance.

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.

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.

Execute a jar file using 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

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