Ant – How To Create A Jar File with external libraries
In this tutorial, we will show you how to use Ant build script to create a Jar file and working with the project’s external libraries / dependencies.
Technologies used :
- Eclipse 4.2
- JDK 1.7
- Ant 1.9.4
- Ant-Ivy 2.4
- logback 1.1.2
- joda-time 2.5
P.S Previous Ant Java project will be reused.
1. Project Structure
Figure 1.1 : The final project directory structure, in Eclipse IDE.
2. Java Project + External Libraries
In Eclipse IDE, reopen the previous Java project AntDateUtils, update the source code to use logback
and joda-time
.
package com.mkyong.core.utils;
import org.joda.time.LocalDate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DateUtils {
private static final Logger logger = LoggerFactory.getLogger(DateUtils.class);
public static void main(String[] args) {
logger.debug("[MAIN] Current Date : {}", getLocalCurrentDate());
System.out.println(getLocalCurrentDate());
}
private static String getLocalCurrentDate() {
LocalDate date = new LocalDate();
return date.toString();
}
}
Create a logback.xml
and put it in the project src
folder. Refer to figure 1.1
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
ANT + LogBack : %-5level %logger{36} - %msg%n
</Pattern>
</layout>
</appender>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>
3. Ivy – Get External Libraries
We use Apache Ivy to get the project’s external libraries / dependencies.
3.1 Create this file ivy.xml
:
<ivy-module version="2.0">
<info organisation="org.apache" module="dateUtilsProject" />
<dependencies>
<dependency org="joda-time" name="joda-time" rev="2.5" />
<dependency org="org.slf4j" name="slf4j-api" rev="1.7.6" />
<dependency org="ch.qos.logback" name="logback-classic" rev="1.1.2" />
</dependencies>
</ivy-module>
3.2 Update build.xml
, add ivy namespace on top, and “ivy” task to download the ivy module, and “resolve” task to ask Ivy module to download the external libraries.
<project xmlns:ivy="antlib:org.apache.ivy.ant"
name="dateUtilsProject" default="main" basedir=".">
<!-- ivy start -->
<!-- ivy to get dependencies and copy to project lib folder automatically -->
<target name="resolve" description="retrieve dependencies with ivy">
<ivy:retrieve />
</target>
<!-- install ivy -->
<target name="ivy" description="Install ivy">
<mkdir dir="${user.home}/.ant/lib" />
<get dest="${user.home}/.ant/lib/ivy.jar"
src="http://search.maven.org/remotecontent?filepath=org/apache/ivy/ivy/2.4.0-rc1/ivy-2.4.0-rc1.jar" />
</target>
<!-- ivy end -->
</project>
For the first time, download the ivy module from Maven center repository to local ${user.home}/.ant/lib/ivy.jar
.
$ ant ivy
To download the external libraries, run task “resolve”. The declared libraries will be downloaded to the project lib
folder.
$ ant resolve
4. build.xml
Review the updated build.xml
script, read comments for self-explanatory.
Main points :
- Manage the project external libraries with Apache Ivy, review the ivy namespace on top, and task “resolve”.
- To compile the source code, you need to declares the classpath. Review task “compile”, and “classpathref” attribute.
- In “jar” task, constructs the entire list of the external libraries and put it into the
manifest.mf
file. - In “jar” task, the project jar will be packaged to folder “dist” and the entire external libraries will be copied to from “lib” to “dist/lib”.
<project xmlns:ivy="antlib:org.apache.ivy.ant"
name="dateUtilsProject" default="main" basedir=".">
<description>
Create a Java Project (JAR) with Ant build script
</description>
<property name="projectName" value="DateUtils" />
<property name="src.dir" location="src" />
<property name="build.dir" location="bin" />
<property name="dist.dir" location="dist" />
<property name="dist.lib.dir" location="dist/lib" />
<property name="lib.dir" value="lib" />
<property name="main-class" value="com.mkyong.core.utils.DateUtils" />
<!-- ivy start -->
<!-- ivy to get dependencies and copy to project lib folder automatically -->
<target name="resolve" description="retrieve dependencies with ivy">
<ivy:retrieve />
</target>
<!-- install ivy -->
<target name="ivy" description="Install ivy">
<mkdir dir="${user.home}/.ant/lib" />
<get dest="${user.home}/.ant/lib/ivy.jar" src="http://search.maven.org/remotecontent?filepath=org/apache/ivy/ivy/2.4.0-rc1/ivy-2.4.0-rc1.jar" />
</target>
<!-- ivy end -->
<target name="init">
<mkdir dir="${build.dir}" />
</target>
<!-- external libraries classpath, we don't need sources and javadoc -->
<path id="classpath">
<fileset dir="${basedir}/">
<include name="${lib.dir}/*.jar" />
<exclude name="${lib.dir}/*sources.jar"/>
<exclude name="${lib.dir}/*javadoc.jar"/>
</fileset>
</path>
<!-- To work with external libraries, need classpath to compile -->
<target name="compile" depends="init" description="compile the source ">
<javac includeantruntime="false" srcdir="${src.dir}" destdir="${build.dir}" classpathref="classpath" />
</target>
<!-- constructs the external libraries classpath name -->
<pathconvert property="classpath.name" pathsep=" ">
<path refid="classpath" />
<mapper>
<chainedmapper>
<flattenmapper />
<globmapper from="*.jar" to="lib/*.jar" />
</chainedmapper>
</mapper>
</pathconvert>
<target name="copy-dependencies">
<copy todir="${dist.lib.dir}">
<fileset dir="${lib.dir}" includes="**/*.jar" excludes="**/*sources.jar, **/*javadoc.jar" />
</copy>
</target>
<!-- jar it, and declares the ext libraries in manifest.mf file -->
<target name="jar" depends="compile, copy-dependencies" description="package, output to JAR">
<echo message="classpath.name : ${classpath.name} " />
<mkdir dir="${dist.dir}" />
<mkdir dir="${dist.lib.dir}" />
<jar jarfile="${dist.dir}/${projectName}.jar" basedir="${build.dir}">
<manifest>
<attribute name="Main-Class" value="${main-class}" />
<attribute name="Class-Path" value="${classpath.name}" />
</manifest>
</jar>
</target>
<target name="clean" description="clean up">
<delete dir="${build.dir}" />
<delete dir="${dist.dir}" />
</target>
<!-- Default, run this -->
<target name="main" depends="clean, compile, jar" />
</project>
5. Test
Test the Java project with Ant build script.
5.1 Jar it.
$ pwd
/Users/mkyong/Documents/workspace/AntDateUtils
$ ant
Buildfile: /Users/mkyong/Documents/workspace/AntDateUtils/build.xml
clean:
[delete] Deleting directory /Users/mkyong/Documents/workspace/AntDateUtils/bin
[delete] Deleting directory /Users/mkyong/Documents/workspace/AntDateUtils/dist
init:
[mkdir] Created dir: /Users/mkyong/Documents/workspace/AntDateUtils/bin
compile:
[javac] Compiling 1 source file to /Users/mkyong/Documents/workspace/AntDateUtils/bin
copy-dependencies:
[copy] Copying 12 files to /Users/mkyong/Documents/workspace/AntDateUtils/dist/lib
jar:
[echo] classpath.name : ... lib/joda-time-2.5.jar lib/logback-classic-1.1.2.jar lib/logback-core-1.1.2.jar lib/mail-1.4.jar ...
[jar] Building jar: /Users/mkyong/Documents/workspace/AntDateUtils/dist/DateUtils.jar
main:
BUILD SUCCESSFUL
Total time: 1 second
5.2 Inspects the generated jar file.
$ jar -tf dist/DateUtils.jar
META-INF/
META-INF/MANIFEST.MF
com/
com/mkyong/
com/mkyong/core/
com/mkyong/core/utils/
com/mkyong/core/utils/DateUtils.class
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.9.4
Created-By: 1.7.0_05-b05 (Oracle Corporation)
Main-Class: com.mkyong.core.utils.DateUtils
Class-Path: lib/activation-1.1.jar lib/commons-compiler-2.6.1.jar lib/
geronimo-jms_1.1_spec-1.0.jar lib/groovy-all-2.0.7.jar lib/janino-2.6
.1.jar lib/joda-convert-1.2.jar lib/joda-time-2.5.jar lib/logback-cla
ssic-1.1.2.jar lib/logback-core-1.1.2.jar lib/mail-1.4.jar lib/servle
t-api-2.5.jar lib/slf4j-api-1.7.6.jar
5.3 Run the Jar file.
$ pwd
/Users/mkyong/Documents/workspace/AntDateUtils
$ java -jar dist/DateUtils.jar
16:28:43.957 [main] DEBUG com.mkyong.core.utils.DateUtils - [MAIN] Current Date : 2014-11-21
2014-11-21
5.4 Run the Jar file again, with logback.xml
.
$ pwd
/Users/mkyong/Documents/workspace/AntDateUtils
$ java -jar -Dlogback.configurationFile=src/logback.xml dist/DateUtils.jar
16:34:43,746 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource [src/logback.xml] at [file:/Users/mkyong/Documents/workspace/AntDateUtils/src/logback.xml]
//...
ANT + LogBack : DEBUG com.mkyong.core.utils.DateUtils - [MAIN] Current Date : 2014-11-21
2014-11-21
This is very old structure and most of the things don’t work.
ivy doesn’t work. can’t retrieve dependency
ivy doesn’t work. can’t retrieve sependency
Before today, I was working on build jar using ” jar cfm manifest.fm *class other_dic “, But It’s never worked ! Alternatively When I was build jar from eclipse it’s working…. So, What’s different in between both jar files ? I was fulfill all requirements… like .MF file same and both jar’s internal dictionary structure are same….
Can you please what’s make ant’s jar special then normal jar command.
Hi
I need a help, can you please tell me, how to generate the jar with version number. With this example, I want to build the jar as “DateUtils-1.0.jar” and if I rebuild it, I want the jar should be DateUtils-1.1.jar.
Your Help is very much appreciated.
I need one help on building the jar file using ANT. In my project under ‘src’ folder I have many .property files in different paths. While building jar files those property files are not included. Could you please update the build.xml to copy the property files aslo ..
Thanks in Advance
Pavan
Do you also have to add the jars to the project build path in Eclipse?
Your blogs are simply amazing !! Simple and neat ! Plz keep blogging