Ant Script Example - java

I would like to make a very simple ant script that does 1 thing, which is to bulid a jar file. But when I try to use a very simple example, it fails due to dependancies on jars that my source depends on. So, How you you specify jars that there are jars that need to be in the class path when building an Ant target.
<project name="project" default="default">
<property name="src.dir" value="src"/>
<property name="build.dir" value="build"/>
<property name="classes.dir" value="${build.dir}/classes"/>
<property name="jar.dir" value="${build.dir}/jar"/>
<property name="lib.dir" value="//tomcat/common/lib"/>
<description> description </description>
<!-- =================================
target: default
================================= -->
<target name="default" depends="compile" description="description">
<jar destfile="/path/to/dir/Library.jar">
</jar>
</target>
<target name="compile">
<mkdir dir="${classes.dir}"/>
<javac srcdir="${src.dir}" destdir="${classes.dir}"/>
</target>
</project>

Your question isn't entirely clear - I suspect you mean you want to compile your source (with the javac task) and then build a jar file from the results. If that's not the case, I don't see where your source dependencies come into it. If that is the case, then the jar task is irrelevant.
In the javac task, use the classpath attribute to specify other jar dependencies.

Here's an ANT script generated by using the Eclipse Runnable JAR Export Wizard. This is a project that updates stats on a Google Spreadsheet for a small fantasy baseball league with some friends. It gets the stats by scraping ESPN.com player pages.
Class-Path attribute inside the manifest element is used to set the classpath used by the jar. This defaulted "." but I had to add my src path explicitly so that log4j would pick up log4j.properties.
zipfileset elements are external jars used by my source that I wanted to be included with my jar. I suspect this might be what you're looking for.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project default="create_run_jar" name="Create Runnable Jar for Project cob_fantasy_baseball">
<!--this file was created by Eclipse Runnable JAR Export Wizard-->
<!--ANT 1.7 is required -->
<target name="create_run_jar">
<jar destfile="C:/workspace/cob_fantasy_baseball/cob_fantasy_baseball.jar" filesetmanifest="mergewithoutmain">
<manifest>
<attribute name="Built-By" value="${user.name}"/>
<attribute name="Main-Class" value="com.me.cob_fantasy_baseball.UpdateCobStats"/>
<attribute name="Class-Path" value=".;src/com/me/cob_fantasy_baseball"/>
</manifest>
<fileset dir="C:/workspace/cob_fantasy_baseball/classes"/>
<zipfileset excludes="META-INF/*.SF" src="C:/workspace/gdata/java/lib/gdata-core-1.0.jar"/>
<zipfileset excludes="META-INF/*.SF" src="C:/workspace/gdata/java/lib/gdata-spreadsheet-2.0.jar"/>
<zipfileset excludes="META-INF/*.SF" src="C:/workspace/jericho-html-2.6/lib/jericho-html-2.6.jar"/>
<zipfileset excludes="META-INF/*.SF" src="C:/workspace/apache-log4j-1.2.15/log4j-1.2.15.jar"/>
<zipfileset excludes="META-INF/*.SF" src="C:/workspace/jaf-1.1.1/activation.jar"/>
<zipfileset excludes="META-INF/*.SF" src="C:/workspace/javamail-1.4.2/mail.jar"/>
<zipfileset excludes="META-INF/*.SF" src="C:/workspace/javamail-1.4.2/lib/smtp.jar"/>
<fileset dir="C:/workspace/cob_fantasy_baseball/src/com/me/cob_fantasy_baseball"/>
</jar>
</target>
</project>
Also, here's a link to the Ant documentation for the jar task: http://ant.apache.org/manual/Tasks/jar.html

Based on your example you can just put libs inside javac:
<javac srcdir="${src.dir}" destdir="${classes.dir}">
<classpath>
<pathelement location="${lib.dir}/lib1.jar"/>
<pathelement location="${lib.dir}/lib2.jar"/>
</classpath>
</javac>

Here is the ant file we use to build the Timeline opensource project. It is pretty straight forward. It doesn't build a jar, but it does use libraries to minimize JS files.
http://simile-widgets.googlecode.com/svn/timeline/trunk/build.xml
Larry

Related

java.util.logger.Logging: keeping logger.properties file outside the jar file

In my project I have a properties file which I use to set the level of logging. Now when I export my project as a jar and use it to run the project on a remote machine (linux), I cannot set the level. Is there a way to keep the properties file outside the jar file such that I can set the level and make the jar read that properties file. (preferred using environment variable)
There are several ways to achieve this, for example:
Configure your IDE to export resources outside the JAR: usually I don't consider this option since the specific solution depends by the developer's IDE
Use a generic build tool, for example Ant, and specify in the build.xml file which properties files should be packaged outside the jar
Integrate your project with Maven and customize the package goal in order to copy some specific properties file outside jar
From your question I guess you are exporting the JAR from your IDE, but as I stated above the solution depends by the IDE. For this reason, in order to adopt an IDE independent solution, I would suggest to use Ant. This would allow you to solve this and many similar issues that could arise in the future.
You can get Ant here: just download and unpackage it in any folder, it takes a couple of minutes. Then add a reference to Ant bin directory in your PATH variable (not strictly necessary but suggested) and create a sample build.xml file. Here it is a template example:
<project name="template" default="compile" basedir=".">
<description>Build file template</description>
<property name="project.name" value="myProject"/>
<property name="driver.log" value="log4j-1.2.15.jar"/>
<property name="driver.database" value="ojdbc6.jar"/>
<property name="library.home" value="lib"/>
<property name="env.type" value="dev"/>
<property name="src.version" value="Demo" />
<property name="src.folder" value="root/folder/template"/>
<property name="src.package" value="root.folder.template"/>
<property name="src.home" value="${basedir}/src/${src.folder}"/>
<property name="dist.home" value="${basedir}/dist"/>
<property name="build.home" value="${basedir}/build"/>
<property name="docs.home" value="${basedir}/docs"/>
<!-- Setting the classpath necessary to compile -->
<path id="compile.classpath">
<pathelement location="${library.home}/${driver.log}"/>
<pathelement location="${library.home}/${driver.database}"/>
</path>
<!-- DELETE the class files from the ${build.home} directory tree -->
<target name="clean" description="Clean up the build folder">
<delete dir="${build.home}"/>
<delete dir="${dist.home}"/>
</target>
<!-- CREATE the build directory structure used by compile -->
<target name="init" description="Creates the necessary directories">
<mkdir dir="${dist.home}"/>
<mkdir dir="${build.home}"/>
</target>
<!-- COMPILE the project and copy all necessary resources -->
<!-- Options: <compilerarg value="-Xlint"/> -->
<target name="compile" depends="init" description="Compile the sources">
<javac srcdir="${src.home}" destdir="${build.home}" includeantruntime="false">
<classpath refid="compile.classpath"/>
</javac>
<copy todir="${build.home}/${src.folder}/resources">
<fileset dir="${src.home}/resources">
<include name="messages_list.properties"/>
<include name="messages_list_en.properties"/>
</fileset>
</copy>
<copy file="${src.home}/resources/log4j_${env.type}.properties" tofile="${build.home}/${src.folder}/resources/log4j_${project.name}.properties"/>
<copy file="${src.home}/resources/configuration_${env.type}.properties" tofile="${build.home}/${src.folder}/resources/${project.name}_config.properties"/>
</target>
<!-- Creates the DISTRIBUTABLE JAR package and add 3d part libraries -->
<target name="dist" description="Create the distributable JAR archive">
<jar destfile="${dist.home}/${project.name}.jar">
<fileset dir="${build.home}">
<exclude name="place_holder\"/>
</fileset>
<!-- Setting MANIFEST properties -->
<manifest>
<section name="${ant.project.name} - ver. ${src.version}">
<attribute name="Built_By" value="${user.name}"/>
<attribute name="Created" value="${ts}"/>
</section>
<attribute name="Main-Class" value="package.mine.MainClass"/>
<attribute name="Class-Path" value=". lib/${driver.log} lib/${driver.database}"/>
</manifest>
</jar>
<!-- Adding third part libraries -->
<mkdir dir="${dist.home}/lib"/>
<copy file="${library.home}/${driver.database}" todir="${dist.home}/lib"/>
<copy file="${library.home}/${driver.log}" todir="${dist.home}/lib"/>
</target>
<tstamp><format property="ts" pattern="dd/MM/yyyy HH:mm:ss" /></tstamp>
</project>
Remark: in the template above you should replace the sample JARS (log4j and the OJDBC driver) with the actual JARS needed by your project. Then you can customize the copy task in order to place the properties files where you wish. You can copy those file in any directory you like, as long as such path appears in the application's classpath.

Deployed jar can't find the main class while using Apache Ant

I built a jar file using the following build.xml below:
<project name="sampleproject">
<!--Source Directory-->
<property name="src.dir" value="src" />
<property name="deploy.name" value="samplejar.jar" />
<property name="lib.dir" value="./lib" />
<property name="deploy.dir" value="target" />
<property name="compile.dir" value="target/classes" />
<!--Define directory name for third party libraries-->
<property name="jar-all" location="${lib.dir}" />
<!--Fileset is a group of files, here **/* matches all jar files across all directory levels-->
<fileset id="jars" dir="${jar-all}">
</fileset>
<!--Setting the classpath-->
<path id="classpath">
<fileset refid="jars" />
<pathelement location="." />
<pathelement location="${src.dir}" />
<pathelement location="${compile.dir}" />
</path>
<path id="cp">
<fileset refid="jars" />
</path>
<pathconvert property="classpath.path" refid="cp" pathsep=" " dirsep="/">
<map from="${jar-all}" to="lib" />
</pathconvert>
<echo>${classpath}</echo>
<!--Clean-->
<target name="clean">
<delete dir="${deploy.dir}" />
</target>
<!--Jar-->
<target name="jar" depends="compile">
<jar destfile="${deploy.dir}/${deploy.name}.jar" basedir="${compile.dir}">
<manifest>
<attribute name="Main-Class" value="main.java.Main" />
<attribute name="Class-Path" value="${classpath.path}" />
</manifest>
<include name="${src.dir}/META-INF/persistence.xml" />
<restrict>
<not>
<or>
<name name="**/*.RSA" />
<name name="**/*.SF" />
<name name="**/*.DSA" />
</or>
</not>
<archives>
<zips>
<fileset dir="lib" includes="**/*.jar" />
</zips>
</archives>
</restrict>
</jar>
</target>
<!--Compile-->
<target name="compile">
<mkdir dir="${compile.dir}" />
<javac includeantruntime="false" srcdir="${src.dir}" destdir="${compile.dir}">
<classpath refid="classpath" />
</javac>
</target>
</project>
My folder structure is like this:
.
./.settings
./bin
./bin/main
./bin/main/java
./bin/META-INF
./lib
./lib/aws
./lib/hibernate
./src
./src/main
./src/main/java
./src/META-INF
./target
./target/classes
./target/classes/main
./target/classes/main/java
My MANIFEST.MF
Created-By: 1.8.0_45-b14 (Oracle Corporation)
Built-Date: ${TODAY}
Main-Class: main.java.Main
Class-Path: lib/activation.jar lib/aws/aws-java-sdk-1.3.2.jar lib/aws/
httpclient-4.1.1.jar lib/aws/httpcore-4.4.1.jar lib/aws/mail-1.4.3.ja
r lib/aws/stax-1.2.0.jar lib/aws/stax-api-1.0.1.jar lib/commons-beanu
tils-1.8.3.jar lib/commons-codec-1.4.jar lib/commons-configuration-1.
8.jar lib/commons-httpclient-3.0.1.jar lib/commons-io-2.1.jar lib/com
mons-lang-2.4.jar lib/commons-logging-1.1.1.jar lib/hibernate/antlr-2
.7.7.jar lib/hibernate/c3p0-0.9.1.jar lib/hibernate/commons-collectio
ns-3.2.1.jar lib/hibernate/dom4j-1.6.1.jar lib/hibernate/hibernate-c3
p0-4.0.1.Final.jar lib/hibernate/hibernate-commons-annotations-4.0.1.
Final.jar lib/hibernate/hibernate-core-4.0.1.Final.jar lib/hibernate/
hibernate-entitymanager-4.0.1.Final.jar lib/hibernate/hibernate-jpa-2
.0-api-1.0.1.Final.jar lib/hibernate/javassist-3.15.0-GA.jar lib/hibe
rnate/jboss-logging-3.1.0.CR2.jar lib/hibernate/jboss-transaction-api
_1.1_spec-1.0.0.Final.jar lib/jackson-all-1.9.5.jar lib/log4j-1.2.16.
jar lib/mail.jar lib/mongo-2.8.0.jar lib/morphia-0.99.jar lib/mysql-c
onnector-java-5.1.12-bin.jar lib/mysql-connector-java-5.1.25-bin.jar
lib/org.json.jar lib/ymmi-utilities-2.0.jar
Whenever I run the jar produced it gives me, Error: Could not find or load main class main.java.Main.
Also, I want to include lib folder & it's subfolders as well since it contains the libraries required to run the jar.
Before it gave me, No Persistence provider for EntityManager named but I solved that by using <include name="${src.dir}/META-INF/persistence.xml" />. Any where I am might wrong?
Your problem is the <include> element in the jar task.
I executed your script and the Main.class file is not added to the jar.
Replace the
<include
by
<fileset dir="${src.dir}" includes="META-INF/persistence.xml" />
This way it will still add all files located in your ${compile.dir}.
Are you new to java ? Normally you put your source files in src/main/java and resources in src/main/resources.
These folders are the root folder of your classpath meaning: If your project classes would be in package org.myproject, than you would put the Main.java file in src/main/java/org/myproject/Main.java
In your build script you than set the property "src.dir" to "src/main/java".
With all resources (=files which do not need to be compiled but must be available in the jar) in src/main/resources the fileset element in the jar task could just be:
<fileset dir="scr/main/resources"/>
This way all resource files you plan to add to your project will automatically added to your jar.
Why do I tell you this ? If one day you would think of using maven instead of ant, maven expects the sources to be in src/main/java and resources in src/main/resources. (https://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html)
Regarding you other dependant jars:
Now you include all jars twice: you add the content of them using the <archives> element within the jar and you define them in the Class-Path attribute of the manifest.mf file.
If you really like to build a single jar containing all dependant files, you don't need to specify the manifest attribute Class-Path.
If you want your jar file containing only your files and deliver the dependant jars separately: remove the <archives> element within the jar task.

Convert to jar while retaining classpath

I have a Java program that uses an external library, whose location is specified through the classpath. I would now like to make the Java program into a standalone jar file (so I can use my IDE for other things whilst the program is running).
How do I turn my existing .java file into an executable jar file?
I am able to make a jar file that includes the class file, manifest file, and the jar file of the library (that was specified in the classpath), but that still appears to be wrong because I get class not found errors.
Ant script for you. What you missed was the classpath generation as a string for the jar task.
<target name="all">
<property name="dir" value="yourProjectDir" />
<property name="name" value="$yourProjectName" />
<!-- clean -->
<delete dir="temp/" />
<mkdir dir="temp/bin/" />
<!-- prepare libs -->
<copy todir="temp/libs/"><fileset dir="${dir}/lbs/" /></copy>
<!-- prepare classpath -->
<pathconvert property="classpath" pathsep=" ">
<path><fileset dir="temp/libs/" /></path>
<chainedmapper><flattenmapper /><globmapper from="*" to="libs/*" /></chainedmapper>
</pathconvert>
<!-- compile -->
<javac destdir="temp/bin/" srcdir="${dir}/src/" target="1.6" source="1.6" includeAntRuntime="false">
<classpath>
<pathelement location="temp/bin/" />
<fileset dir="temp/libs/" />
</classpath>
</javac>
<!-- jar -->
<jar destfile="temp/${name}.jar" basedir="temp/bin/">
<manifest>
<attribute name="Main-Class" value="Main" />
<attribute name="Class-Path" value="${classpath}" />
</manifest>
</jar>
<!-- zip jar + libs -->
<zip destfile="${name}-${version}.zip">
<fileset dir="temp" includes="${name}.jar, libs/" />
</zip>
</target>
The following is the steps, how run stand alone App from command prompt.
1. Create a sample java file then save in particular location(like d:\sample\Hello.java.
2. open command prompt compile that java class, then create jar like Hello.jar file
3. then set classpath in Environment file(like D:\sample\Hello.jar ;
4. Now run your java class , it will work(d:sample>java Hello

Eclipse Ant Builder problem

I made a custom ant script to automatically create a jar file each time I do a build.
This is how it looks like:
<?xml version="1.0" encoding="UTF-8"?>
<project name="TestProj" basedir="." default="jar">
<property name="dist" value="dist" />
<property name="build" value="bin/test/testproj" />
<target name="jar">
<jar destfile="${dist}/TestProj.jar">
<manifest>
<attribute name="Main-Class" value="test.testproj.TestProj" />
</manifest>
<fileset dir="${build}" />
</jar>
</target>
</project>
I added it by Right clicking my project > properties > builders > clicked new > Ant builder > then I specified the location of the above xml file.
However, when I run it by doing:
java -jar TestProj.jar
I get a NoClassDefFoundError test/testproj/TestProj
I'm using Eclipse in Ubuntu. TestProj is the name of the class and it's in package test.testproj
I'm pretty sure there's something wrong with the manifest and probably the location of the xml file as well but I'm not sure how to fix this. Any ideas?
Did you try with:
<property name="build" value="bin" /> <!-- instead of bin/test/testproj -->
<target name="jar">
<jar destfile="${dist}/TestProj.jar">
<manifest>
<attribute name="Main-Class" value="test.testproj.TestProj" />
</manifest>
<fileset dir="${build}" />
</jar>
</target>
just to see if it solves the issue?
The Ant Task mentions:
This task forms an implicit FileSet and supports most attributes of <fileset> (dir becomes basedir)
That means you are trying to jar any class within the root bin/test/testproj (so TestProj get included), instead of referencing all classes within root bin (which would include test.testproj.TestProj)

How can include multiple jars in the classpath using ant?

I have a bunch of .java files in a "src" folder that depend on three jars in a "lib" folder. I have the following build.xml file:
<?xml version="1.0"?>
<project name="MyProj" basedir=".">
<property name="src" value="src"/>
<property name="build" value="build"/>
<property name="lib" value="lib"/>
<path id="master-classpath">
<fileset dir="${lib}">
<include name="activemq-all-5.1-SNAPSHOT.jar"/>
<include name="geronimo-jms_1.1_spec-1.1.1.jar"/>
<include name="activemq-core-5.3.0.jar"/>
</fileset>
</path>
<javac destdir="${build}">
<src path="${src}"/>
<classpath refid="master-classpath"/>
</javac>
</project>
This compiles fine, but when I try and run I get
"java.lang.NoClassDefFoundError:
javax/jms/Destination"
This program runs and compiles fine when I include the jars in the buildpath using Eclipse, though.
EDIT: So I copied the jars into the folder that has the compiled classes. The class with the main method is NDriver.class. When I try:
java -classpath
./geronimo-jms_1.1_spec-1.1.1.jar:./activemq-core-5.3.0.jar:./activemq-all-5.1-SNAPSHOT.jar
NDriver
This gives:
Exception in thread "main"
java.lang.NoClassDefFoundError:
NDriver
I'd appreciate any help.
You need to put the jars used at compile time on the classpath when running the application. Sadly, you didn't provide any detail on how you are actually running it so its hard to provide more guidance.
UPDATE: The directory containing the compiled classes needs to be added to the classpath too. If you launch java from the directory containing the compiled classes, then you can use . to designate the current directory. Add it to the classpath as shown below to tell java to look for classes there too (I've added . right after activemq-all-5.1-SNAPSHOT.jar):
java -classpath ./geronimo-jms_1.1_spec-1.1.1.jar:./activemq-core-5.3.0.jar:./activemq-all-5.1-SNAPSHOT.jar:. NDriver
One way (slightly different variables than yours)
<path id="classpath">
<fileset dir="${lib.dir}" includes="**/*.jar"/>
</path>
<manifestclasspath property="manifest.classpath" jarfile="${jarfile}">
<classpath refid="classpath"/>
</manifestclasspath>
<target name="jar" depends="compile" description="create the jar">
<jar destfile="${jarfile}" basedir="${build.dir}">
<manifest>
<attribute name="Manifest-Version" value="${manifest-version}"/>
<attribute name="Created-By" value="${ant.java.version}"/>
<attribute name="Main-Class" value="${main-class}"/>
<attribute name="Class-Path" value="${manifest.classpath}"/>
</manifest>
</jar>
</target>
Of course here I'm assuming that you are creating a jar and running it (including the classpath there). Another option would be to have a run target which use the <java> tag and explicitly use the classpath there.
Are the library jars included in the classpath when you run the program? Eclipse automatically add these, but you need to specifying them when you run the program from the command line.
From my experience it seems Eclipse will often include classes and jars in the classpath without explicitly using the classpath declaration. Indeed it can sometimes be quite hard to remove classes from Eclipse's build (they have to be deleted or clean'ed).

Categories

Resources