サンプルコードで身につける: Ant: 依存の扱いと、古いプロジェクトの読み方
解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。
1ivy.xml と build.xml の全文: dependency 1行と <ivy:retrieve/>
7.0.9 を に取らせる最小の2ファイルです。5行目の dependency の org、name、rev は の 、artifactId、version で、 で実行に要るものだけに絞ります。10行目で ivy の名前空間を宣言し、12行目の が へコピーします。実際のビルドでは init の を ="resolve" にして、コンパイルの前に走らせます。
# ivy.xml<ivy-module version="2.0"><info organisation="jp.co.example" module="shop"/><dependencies><dependency org="org.springframework" name="spring-webmvc" rev="7.0.9" conf="default"/></dependencies></ivy-module># build.xml(resolve の target だけの最小版)<project name="shop" default="resolve" basedir="." xmlns:ivy="antlib:org.apache.ivy.ant"><target name="resolve" description="fetch spring-webmvc and everything it needs into lib/"><ivy:retrieve/></target></project>
2lib/ に手で置く: Maven Central の URL と、build.xml での読み方
手で置く方式では、座標から URL を組み立てて取り、lib/ に置きます(隣の .sha1 と照合したのは、この記録にある と の2本です)。 側は <path> の中の < dir="${lib.dir}" includes="*"/> で lib/ 直下の 全部をにし、<war> の <lib> で に詰めます。spring-webmvc 1本に要った11本は、レッスン「 で の を作る」で人が を辿って書き出したものです。
# Maven Central の URL は座標から決まる:# https://repo.maven.apache.org/maven2/<groupId の . を / に>/<artifactId>/<version>/<artifactId>-<version>.jar# curl で取り、隣の .sha1 と照合した記録# downloaded 2026-10-03T00:19:46Z from Maven Centralhttps://repo.maven.apache.org/maven2/org/apache/commons/commons-lang3/3.21.0/commons-lang3-3.21.0.jar => 200 749083 bytessha1 remote: 7bad013a5acee0a078d75fc352a906baa57acb74sha1 local : 7bad013a5acee0a078d75fc352a906baa57acb74https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-console-standalone/6.1.3/junit-platform-console-standalone-6.1.3.jar => 200 2997949 bytessha1 remote: bb65bef57072d36433e8a863016163858c926113sha1 local : bb65bef57072d36433e8a863016163858c926113# 取ってきた JAR を lib/ に置き、build.xml ではこう読む(E-2 の WAR 版 build.xml から)<path id="compile.classpath"><fileset dir="${lib.dir}" includes="*.jar"/> ← lib/ 直下の *.jar 全部<fileset dir="lib-compile" includes="*.jar"/> ← コンパイルにだけ使う servlet-api</path><javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="compile.classpath" .../><war destfile="${dist.dir}/shop.war" webxml="${web.dir}/WEB-INF/web.xml">...<lib dir="${lib.dir}" includes="*.jar"/> ← WEB-INF/lib へ(lib-compile は入れない)</war># spring-webmvc 7.0.9 を使うために人が POM を辿って置いた 11 本(レッスン「Ant で Spring の WAR を作る」)lib/spring-webmvc-7.0.9.jar ← 自分で選んだ1本lib/spring-web-7.0.9.jar ← webmvc の POM が要求lib/spring-context-7.0.9.jar ← webmvclib/spring-beans-7.0.9.jar ← webmvc, web, context, aoplib/spring-core-7.0.9.jar ← 全モジュールlib/spring-aop-7.0.9.jar ← webmvc, contextlib/spring-expression-7.0.9.jar ← webmvc, contextlib/commons-logging-1.3.5.jar ← spring-corelib/jspecify-1.0.0.jar ← spring-corelib/micrometer-observation-1.16.7.jar ← spring-web, spring-contextlib/micrometer-commons-1.16.7.jar ← micrometer-observation# 1本ずつ抜いたとき、ビルドで気づけたのは spring-web と spring-context の2本だけ
3Ivy で同じ11本を取る: found の行と lib/ の中身
に spring-webmvc 7.0.9 を1行書いて で走らせた記録です。found の行が POM を辿って見つけた12、evicted modules が jspecify 1.0.0 を 1.0.1 に寄せた判断、最後の 11 artifacts copied が lib/ に置いた本数です。ls -l のサイズは、人が置いた11本と1バイトまで一致しました(jspecify の版だけ違います)。
$ ant -lib /bt/l3-ivy/ivylib | grep -v "^\[ivy:retrieve\] \.\|downloading" # ivy-2.6.0.jar のディレクトリを -lib で渡す。進捗の点と downloading の行は grep で省いたBuildfile: /bt/l3-ivy/webmvc/build.xmlresolve:[ivy:retrieve] :: Apache Ivy 2.6.0 - 20260712075753 :: https://ant.apache.org/ivy/ ::[ivy:retrieve] :: loading settings :: url = jar:file:/bt/l3-ivy/ivylib/ivy-2.6.0.jar!/org/apache/ivy/core/settings/ivysettings.xml[ivy:retrieve] :: resolving dependencies :: jp.co.example#shop;working@5330a5c0e463[ivy:retrieve] confs: [default][ivy:retrieve] found org.springframework#spring-webmvc;7.0.9 in public[ivy:retrieve] found org.springframework#spring-aop;7.0.9 in public[ivy:retrieve] found org.springframework#spring-beans;7.0.9 in public[ivy:retrieve] found org.springframework#spring-core;7.0.9 in public[ivy:retrieve] found commons-logging#commons-logging;1.3.5 in public[ivy:retrieve] found org.jspecify#jspecify;1.0.0 in public[ivy:retrieve] found org.springframework#spring-context;7.0.9 in public[ivy:retrieve] found org.springframework#spring-expression;7.0.9 in public[ivy:retrieve] found io.micrometer#micrometer-observation;1.16.7 in public[ivy:retrieve] found org.jspecify#jspecify;1.0.1 in public[ivy:retrieve] found io.micrometer#micrometer-commons;1.16.7 in public[ivy:retrieve] found org.springframework#spring-web;7.0.9 in public[ivy:retrieve] [SUCCESSFUL ] org.springframework#spring-webmvc;7.0.9!spring-webmvc.jar (167ms)...[ivy:retrieve] :: evicted modules:[ivy:retrieve] org.jspecify#jspecify;1.0.0 by [org.jspecify#jspecify;1.0.1] in [default]---------------------------------------------------------------------| | modules || artifacts || conf | number| search|dwnlded|evicted|| number|dwnlded|---------------------------------------------------------------------| default | 12 | 12 | 12 | 1 || 11 | 11 |---------------------------------------------------------------------[ivy:retrieve] :: retrieving :: jp.co.example#shop[ivy:retrieve] confs: [default][ivy:retrieve] 11 artifacts copied, 0 already retrieved (8459kB/27ms)BUILD SUCCESSFUL$ ls -l lib | sort -k9-rw-r--r-- 1 root root 73737 Jan 31 2025 commons-logging-1.3.5.jar-rw-r--r-- 1 root root 3064 Jul 29 22:41 jspecify-1.0.1.jar-rw-r--r-- 1 root root 51745 Aug 20 08:02 micrometer-commons-1.16.7.jar-rw-r--r-- 1 root root 83914 Aug 20 08:02 micrometer-observation-1.16.7.jar-rw-r--r-- 1 root root 426204 Aug 20 09:37 spring-aop-7.0.9.jar-rw-r--r-- 1 root root 928155 Aug 20 09:37 spring-beans-7.0.9.jar-rw-r--r-- 1 root root 1399435 Aug 20 09:37 spring-context-7.0.9.jar-rw-r--r-- 1 root root 2035755 Aug 20 09:37 spring-core-7.0.9.jar-rw-r--r-- 1 root root 327140 Aug 20 09:37 spring-expression-7.0.9.jar-rw-r--r-- 1 root root 2226342 Aug 20 09:37 spring-web-7.0.9.jar-rw-r--r-- 1 root root 1107415 Aug 20 09:37 spring-webmvc-7.0.9.jar
4よくある失敗と誤解: -lib なし、conf なしで25本、2回目のキャッシュ
-lib を付けないと Ant は ivy の名前空間を知らず、failed to create or type で止まります。dependency に conf を書かないと、その POM のテスト用の依存と 、-javadoc.jar まで取ってきて、commons-lang3 1本の指定で lib/ が25本になりました。2回目は から解決し、ダウンロードも lib/ へのコピーも起きません。
##### -lib を付けずに ant を打つ: Ant は ivy の名前空間を知らない$ ant resolveresolve:BUILD FAILED/bt/l3-ivy/hello/build.xml:8: Problem: failed to create task or type antlib:org.apache.ivy.ant:retrieveCause: The name is undefined....Action: Check that the implementing library exists in one of:-/opt/apache-ant-1.10.18/lib-/root/.ant/lib-a directory added on the command line with the -lib argument[exit 1]##### conf を書かない <dependency org="org.apache.commons" name="commons-lang3" rev="3.21.0"/>$ ant -lib /bt/l3-ivy/ivylib[ivy:retrieve] found org.apache.commons#commons-lang3;3.21.0 in public[ivy:retrieve] found org.junit.jupiter#junit-jupiter;5.14.4 in public[ivy:retrieve] found org.junit.jupiter#junit-jupiter-api;5.14.4 in public...(found は全部で 23 行。mockito、easymock、jmh なども含む)[ivy:retrieve] downloading https://repo1.maven.org/maven2/org/apache/commons/commons-lang3/3.21.0/commons-lang3-3.21.0-sources.jar ...[ivy:retrieve] downloading https://repo1.maven.org/maven2/org/apache/commons/commons-lang3/3.21.0/commons-lang3-3.21.0-javadoc.jar ......| default | 26 | 23 | 23 | 3 || 25 | 25 |[ivy:retrieve] 25 artifacts copied, 0 already retrieved (25242kB/45ms)$ find lib build dist -type f | sortbuild/classes/com/example/app/Main.classbuild/classes/com/example/greet/Greeter.classdist/app.jarlib/apiguardian-api-1.1.2.jarlib/asm-9.8.jarlib/byte-buddy-1.17.5.jarlib/byte-buddy-agent-1.12.19.jarlib/commons-lang3-3.21.0.jarlib/commons-lang3-3.21.0-javadoc.jarlib/commons-lang3-3.21.0-sources.jarlib/commons-math3-3.6.1.jarlib/commons-text-1.15.0.jarlib/easymock-5.6.0.jarlib/jmh-core-1.37.jar...lib/mockito-core-4.11.0.jarlib/mockito-inline-4.11.0.jarlib/objenesis-3.4.jarlib/opentest4j-1.3.0.jar# lib/ は 25 本(省略した行は junit-jupiter と junit-platform の 7 本と jmh-generator-annprocess、jopt-simple、junit-pioneer)##### 同じものに conf="default" を付ける$ ant -lib /bt/l3-ivy/ivylib resolve[ivy:retrieve] found org.apache.commons#commons-lang3;3.21.0 in public| default | 1 | 0 | 0 | 0 || 1 | 0 |[ivy:retrieve] 1 artifacts copied, 0 already retrieved (731kB/3ms)$ ls libcommons-lang3-3.21.0.jar##### 2回目(conf 無し版をもう一度): ダウンロードが無く、lib/ へのコピーも無い$ ant -lib /bt/l3-ivy/ivylib resolve[ivy:retrieve] :: resolution report :: resolve 148ms :: artifacts dl 6ms| default | 26 | 0 | 0 | 3 || 25 | 0 |[ivy:retrieve] 0 artifacts copied, 25 already retrieved (0kB/3ms)$ find /root/.ivy2 -type f | sort | grep commons-lang3 # キャッシュの置き方/root/.ivy2/cache/org.apache.commons/commons-lang3/ivy-3.21.0.xml ← POM を Ivy の形式に変換したもの/root/.ivy2/cache/org.apache.commons/commons-lang3/ivy-3.21.0.xml.original ← 元の POM/root/.ivy2/cache/org.apache.commons/commons-lang3/ivydata-3.21.0.properties/root/.ivy2/cache/org.apache.commons/commons-lang3/jars/commons-lang3-3.21.0.jar/root/.ivy2/cache/org.apache.commons/commons-lang3/javadocs/commons-lang3-3.21.0-javadoc.jar/root/.ivy2/cache/org.apache.commons/commons-lang3/sources/commons-lang3-3.21.0-sources.jar
5古い Ant + Spring のプロジェクトを開いたときに見る順
職場の build.xml を読むときの手がかりを、今回の実物を根拠に表にしました。上から順に、、 の値、lib/ か ivy.xml か、、、出力先、 のファイルです。頻度の分からないもの( の同居など)は、そう書いています。
1. build.xml の <project default="…">分かること: 引数なしで ant と打ったときに走る target根拠 : 「Ant で Spring の WAR を作る」の build.xml は default="war"。ant -p の最終行にも出る2. <property name="src.dir" value="src"/> など分かること: src、build、dist、lib、WebContent の実際の名前。全部ここで決まる根拠 : 公式サイトの原文 does not impose coding conventions ordirectory layouts。既定で読むファイル名 build.xml も-f で変えられる3. <target> の description分かること: ant -p に出る target の一覧。description のある target が1つでもあれば、無い target は出ない根拠 : マニュアル(deemed internal and will not be listed)と実測4. lib/ に JAR が直接ある分かること: 依存を人が置いて管理している。推移依存も人が辿る根拠 : 「Ant で Spring の WAR を作る」の lib/ に 11 本。Maven の作者の回想:all the JARs that we were depending on were stored in CVS5. ivy.xml がある分かること: Ivy に取らせている。ivy の JAR を ant -lib か~/.ant/lib に置いて動かす根拠 : <ivy:retrieve/> が lib/ へコピーする。無いと failed to create task or type6. <path id="…"><fileset dir="lib"/></path>分かること: クラスパスの定義。javac の classpathref とwar の <lib> から参照される根拠 : lib/ 直下の *.jar 全部、の意味7. WebContent/分かること: Eclipse の Dynamic Web Project が以前の既定で付けていた名前。WAR の中身の元になるフォルダ。Ant では、何を WAR に入れるかは build.xml の <war> が決める根拠 : Eclipse ヘルプ: The Web content folder representsthe contents of the WAR file。2021年1月の WTP のコミット [417874] で既定は src/main/webapp に変わった8. WebContent/WEB-INF/web.xml分かること: Tomcat が WAR を展開したあとに読む、このアプリの設定。Spring の ContextLoaderListener と DispatcherServlet根拠 : レッスン「Ant で Spring の WAR を作る」9. build/、dist/分かること: ビルドの出力。名前は property 次第。clean の target が消す根拠 : 「Ant で Spring の WAR を作る」では build/classes/ とdist/shop.war。2回目の ant は見出しだけで何もしない10. .project、.classpath分かること: Eclipse がプロジェクトごとに作る記述ファイル。Java プロジェクトなら .classpath も根拠 : Eclipse ヘルプ: This file is always called ".project"。同居の頻度は確かめていない