Main Tutorials

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 :

  1. Eclipse 4.2
  2. JDK 1.7
  3. Ant 1.9.4
  4. Ant-Ivy 2.4
  5. logback 1.1.2
  6. 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.

ant-external-libraries-final

2. Java Project + External Libraries

In Eclipse IDE, reopen the previous Java project AntDateUtils, update the source code to use logback and joda-time.

src/com/mkyong/core/utils/DateUtils.java

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

src/logback.xml

<?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.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.

build.xml

<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 :

  1. Manage the project external libraries with Apache Ivy, review the ivy namespace on top, and task “resolve”.
  2. To compile the source code, you need to declares the classpath. Review task “compile”, and “classpathref” attribute.
  3. In “jar” task, constructs the entire list of the external libraries and put it into the manifest.mf file.
  4. 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”.
build.xml

<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
META-INF/MANIFEST.MF

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

Download Source Code

Download it – AntDateUtils-External-Libraries.zip (8 KB)

References

  1. Apache Ant Hello World Official Guide
  2. How To Create A Jar File With Maven
  3. Ant Jar task
  4. Ant Copy task

About Author

author image
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter. If you like my tutorials, consider make a donation to these charities.

Comments

Subscribe
Notify of
8 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
Bhavya Bansal
1 year ago

This is very old structure and most of the things don’t work.

Igor Igor
3 years ago

ivy doesn’t work. can’t retrieve dependency

Igor Igor
3 years ago

ivy doesn’t work. can’t retrieve sependency

shivangpatel
4 years ago

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.

Sun
6 years ago

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.

Pavan Kumar
8 years ago

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

Bob L
8 years ago

Do you also have to add the jars to the project build path in Eclipse?

Kumaran
9 years ago

Your blogs are simply amazing !! Simple and neat ! Plz keep blogging