Apache Ant is a task-based build tool that can compile Java source code and package web and enterprise archives for J2EE applications (now commonly referred to as Jakarta EE). This guide is for engineers maintaining or modernizing Ant-based projects, and it covers a practical build flow, a reusable build.xml pattern, and CI-friendly command usage.
Originally published on 2010-03-21; fully revised and updated.
Slide deck reference from the original post
The original article was a short embed-only post. The Slideshare shortcode is preserved below for archival continuity.
{slideshare}[slideshare id=1117755&doc=usinganttobuildj2eeapplications-090308134153-phpapp02]{/slideshare}
How the Ant workflow maps to J2EE packaging
In a typical Ant-driven Java enterprise build, you clean old artifacts, compile Java classes, assemble a WAR for the web module, then optionally wrap that WAR into an EAR for deployment to an application server.
flowchart LR
A[Developer updates source] --> B[Run ant clean]
B --> C[Compile Java classes]
C --> D[Copy web resources]
D --> E[Build WAR file]
E --> F[Assemble EAR file]
F --> G[Publish artifact]
G --> H[Deploy to application server]
Recommended project layout
A predictable directory structure keeps Ant targets easy to read and maintain.
src/main/javafor Java source filessrc/main/webappfor JSP/static files andWEB-INF/web.xmlsrc/main/applicationfor EAR-level metadata such asMETA-INF/application.xmllibfor third-party JAR dependencies used at compile/package timebuildfor intermediate output (classes, temp files)distfor final deployable artifacts (.war,.ear)
Example build.xml for compile, WAR, and EAR targets
This example shows a straightforward target chain: clean → compile → war → ear.
<project name="sample-j2ee-app" default="ear" basedir=".">
<property name="src.dir" value="src/main/java"/>
<property name="web.dir" value="src/main/webapp"/>
<property name="build.dir" value="build"/>
<property name="classes.dir" value="${build.dir}/classes"/>
<property name="dist.dir" value="dist"/>
<path id="compile.classpath">
<fileset dir="lib">
<include name="**/*.jar"/>
</fileset>
</path>
<target name="clean">
<delete dir="${build.dir}"/>
<delete dir="${dist.dir}"/>
</target>
<target name="init">
<mkdir dir="${classes.dir}"/>
<mkdir dir="${dist.dir}"/>
</target>
<target name="compile" depends="init">
<javac srcdir="${src.dir}" destdir="${classes.dir}" includeantruntime="false">
<classpath refid="compile.classpath"/>
</javac>
</target>
<target name="war" depends="compile">
<war destfile="${dist.dir}/sample.war" webxml="${web.dir}/WEB-INF/web.xml">
<fileset dir="${web.dir}"/>
<classes dir="${classes.dir}"/>
<lib dir="lib"/>
</war>
</target>
<target name="ear" depends="war">
<ear destfile="${dist.dir}/sample.ear" appxml="src/main/application/META-INF/application.xml">
<fileset dir="${dist.dir}">
<include name="sample.war"/>
</fileset>
</ear>
</target>
</project>Code language: HTML, XML (xml)
Run common Ant commands
Use explicit targets in local development and CI so the build path is predictable.
ant clean
ant compile
ant war
ant ear
ant -Dbuild.number=20261012 ear
Ant vs Maven vs Gradle at a glance
If you are deciding whether to keep Ant or migrate, compare the build model and operational trade-offs.
| Tool | Build definition style | Dependency handling | Typical fit |
|---|---|---|---|
| Ant | Explicit XML targets and task order | Manual management or add-on tooling | Legacy builds needing fine-grained task control |
| Maven | Convention-based lifecycle (POM) | Built-in repository-driven model | Teams preferring standard Java conventions |
| Gradle | Scripted DSL with tasks and plugins | Built-in repository-driven model | Flexible multi-module builds and custom automation |
Common pitfalls and best practices
- Keep artifact assembly deterministic: avoid hidden local dependencies outside
libor repository config. - Use clear target dependencies so
ant earalways implies compile and WAR creation. - Parameterize environment-specific values with properties files instead of editing
build.xmlper environment. - Treat
distoutput as immutable deployment artifacts once built. - Document expected JDK level and app-server requirements alongside the build file.
I’m Rajesh Kumar, a DevOps, SRE, DevSecOps, Cloud, and Platform Engineering expert passionate about sharing practical knowledge, real-world experiences, and industry best practices. I have worked at Cotocus and regularly write about technology, travel, investing, health, product reviews, and digital marketing through my various platforms.
I publish technical articles at DevOps School, travel stories at Holiday Landmark, stock market insights at Stocks Mantra, health and fitness guidance at My Medic Plus, product reviews at TrueReviewNow, and SEO and digital marketing strategies at Wizbrand.
Find Trusted Cardiac Hospitals
Compare heart hospitals by city and services — all in one place.
Explore Hospitals