チュートリアル:Apache Antを使ったHello World

このドキュメントは、Apache Antを使ったJavaプログラミング入門のステップバイステップチュートリアルです。JavaやAntに関する深い知識は**含まれていません**。このチュートリアルの目的は、Antでの最も簡単な手順を実行する方法を理解することです。

目次

プロジェクトの準備

ソースファイルと生成されたファイルを分離するため、Javaソースファイルはsrcフォルダに配置します。生成されたファイルはすべてbuildフォルダに配置し、個々の手順に合わせて複数のサブディレクトリに分割します。classesはコンパイルされたファイル用、jarは独自のJARファイル用です。

srcディレクトリのみを作成する必要があります。(Windowsで作業しているため、ここではWindowsの構文を使用しています。ご自身のシェルに合わせて翻訳してください)

md src

次の単純なJavaクラスは、固定メッセージをSTDOUTに出力するだけです。このコードをsrc\oata\HelloWorld.javaに記述してください。

package oata;

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}

コンパイルして実行してみてください

md build\classes
javac -sourcepath src -d build\classes src\oata\HelloWorld.java
java -cp build\classes oata.HelloWorld
結果は次のようになります
Hello World

jarファイルの作成はそれほど難しくありません。しかし、*起動可能な* jarファイルを作成するには、さらにいくつかの手順が必要です。開始クラスを含むマニフェストファイルの作成、ターゲットディレクトリの作成、ファイルのアーカイブです。

echo Main-Class: oata.HelloWorld>myManifest
md build\jar
jar cfm build\jar\HelloWorld.jar myManifest -C build\classes .
java -jar build\jar\HelloWorld.jar

**注意**:echo Main-Class命令の>-記号の前後に空白を入れないでください。空白を入れると、命令が正しく解釈されません!

アプリケーションを実行するための4つの手順

Javaのみの手順が完了したら、ビルドプロセスについて考える必要があります。コードをコンパイル*する必要があり*ます。そうしないと、プログラムを開始できません。「開始」といえば、そのためのターゲットを提供できます。アプリケーションをパッケージ化*する必要があり*ます。今は1つのクラスだけですが、ダウンロードを提供する場合、誰も数百ものファイルをダウンロードしません...(複雑なSwing GUIを考えてみてください)。そのため、jarファイルを作成しましょう。起動可能なjarファイルがあれば便利です...そして、「クリーン」ターゲットを用意することをお勧めします。これは、生成されたものをすべて削除します。多くのエラーは、「クリーンビルド」によって解決できます。

デフォルトでは、Antはビルドファイルの名前としてbuild.xmlを使用するため、.\build.xmlは次のようになります。

<project>

    <target name="clean">
        <delete dir="build"/>
    </target>

    <target name="compile">
        <mkdir dir="build/classes"/>
        <javac srcdir="src" destdir="build/classes"/>
    </target>

    <target name="jar">
        <mkdir dir="build/jar"/>
        <jar destfile="build/jar/HelloWorld.jar" basedir="build/classes">
            <manifest>
                <attribute name="Main-Class" value="oata.HelloWorld"/>
            </manifest>
        </jar>
    </target>

    <target name="run">
        <java jar="build/jar/HelloWorld.jar" fork="true"/>
    </target>

</project>

これで、次のコマンドを使用してアプリケーションをコンパイル、パッケージ化、実行できます。

ant compile
ant jar
ant run

または、次のように短縮できます。

ant compile jar run

ビルドファイルを見ると、AntとJavaのみのコマンドの間にいくつかの類似した手順があることがわかります。

Javaのみ Ant
md build\classes
javac
    -sourcepath src
    -d build\classes
    src\oata\HelloWorld.java
echo Main-Class: oata.HelloWorld>mf
md build\jar
jar cfm
    build\jar\HelloWorld.jar
    mf
    -C build\classes
    .



java -jar build\jar\HelloWorld.jar
<mkdir dir="build/classes"/>
<javac
    srcdir="src"
    destdir="build/classes"/>
<!-- automatically detected -->
<!-- obsolete; done via manifest tag -->
<mkdir dir="build/jar"/>
<jar
    destfile="build/jar/HelloWorld.jar"

    basedir="build/classes">
    <manifest>
        <attribute name="Main-Class" value="oata.HelloWorld"/>
    </manifest>
</jar>
<java jar="build/jar/HelloWorld.jar" fork="true"/>

ビルドファイルの拡張

これで動作するビルドファイルができました。いくつかの拡張を行うことができます。多くの場合、同じディレクトリを参照しており、メインクラスとjar名がハードコードされており、呼び出すときに正しいビルド手順を覚えておく必要があります。

最初と2番目のポイントは*プロパティ*で、3番目のポイントは特別なプロパティ(<project>タグの属性)で、4番目の問題は依存関係を使用して解決できます。

<project name="HelloWorld" basedir="." default="main">

    <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="main-class"  value="oata.HelloWorld"/>



    <target name="clean">
        <delete dir="${build.dir}"/>
    </target>

    <target name="compile">
        <mkdir dir="${classes.dir}"/>
        <javac srcdir="${src.dir}" destdir="${classes.dir}"/>
    </target>

    <target name="jar" depends="compile">
        <mkdir dir="${jar.dir}"/>
        <jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}">
            <manifest>
                <attribute name="Main-Class" value="${main-class}"/>
            </manifest>
        </jar>
    </target>

    <target name="run" depends="jar">
        <java jar="${jar.dir}/${ant.project.name}.jar" fork="true"/>
    </target>

    <target name="clean-build" depends="clean,jar"/>

    <target name="main" depends="clean,run"/>

</project>

これで簡単になりました。antを実行するだけで、次の結果が得られます。

Buildfile: build.xml

clean:

compile:
    [mkdir] Created dir: C:\...\build\classes
    [javac] Compiling 1 source file to C:\...\build\classes

jar:
    [mkdir] Created dir: C:\...\build\jar
      [jar] Building jar: C:\...\build\jar\HelloWorld.jar

run:
     [java] Hello World

main:

BUILD SUCCESSFUL

外部ライブラリの使用

誰かがSystemステートメントを使用しないように言いました。出力には、高度にカスタマイズ可能な(通常のライフ(=開発ではない)実行中はオフにすることも含む)ロギングAPIを使用する必要があります。そのため、Log4Jを使用します。理由は次のとおりです。

外部ライブラリは新しいディレクトリlibに保存します。Log4Jは、ロギングのホームページからダウンロード[1]できます。libディレクトリを作成し、log4j-1.2.17.jarをそのディレクトリに解凍します。その後、そのライブラリを使用するようにJavaソースファイルを修正し、コンパイルと実行中にこのライブラリにアクセスできるようにビルドファイルを修正する必要があります。

Log4Jの使用方法については、マニュアルに記載されています。ここでは、ショートマニュアル[2]MyApp例を使用します。最初に、ロギングフレームワークを使用するようにJavaソースを修正する必要があります。

package oata;

import org.apache.log4j.Logger;
import org.apache.log4j.BasicConfigurator;

public class HelloWorld {
    static Logger logger = Logger.getLogger(HelloWorld.class);

    public static void main(String[] args) {
        BasicConfigurator.configure();
        logger.info("Hello World");          // the old SysO-statement
    }
}

変更のほとんどは、一度だけ実行する必要がある「フレームワークのオーバーヘッド」です。青い行は、以前の「System-out」ステートメントです。

antを実行しようとしないでください。コンパイラエラーがたくさん発生するだけです。Log4Jはクラスパスにないため、ここで少し作業を行う必要があります。ただし、CLASSPATH環境変数は変更しないでください!これはこのプロジェクト専用であり、他の環境を壊してしまう可能性があります(これは、Antで作業する際の最も一般的なミスの1つです)。Log4J(より正確には、.\libの下にあるすべてのライブラリ(jarファイル))をビルドファイルに導入します。

<project name="HelloWorld" basedir="." default="main">
    ...
    <property name="lib.dir"     value="lib"/>

    <path id="classpath">
        <fileset dir="${lib.dir}" includes="**/*.jar"/>
    </path>

    ...

    <target name="compile">
        <mkdir dir="${classes.dir}"/>
        <javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath"/>
    </target>

    <target name="run" depends="jar">
        <java fork="true" classname="${main-class}">
            <classpath>
                <path refid="classpath"/>
                <path location="${jar.dir}/${ant.project.name}.jar"/>
            </classpath>
        </java>
    </target>

    ...

</project>

この例では、アプリケーションをMain-Classマニフェスト属性を介して開始しません。jar名*と*クラスパスを指定できないためです。そのため、赤い行にあるクラスを既に定義されているパスに追加し、通常どおり開始します。antを実行すると、(通常のコンパイル処理の後)次のようになります。

[java] 0 [main] INFO oata.HelloWorld  - Hello World

これは何ですか?

別のレイアウトについては、他のPatternLayoutの使用に関するLog4Jのドキュメントを参照してください。

設定ファイル

なぜLog4Jを使用したのですか?「高度に設定可能」だからですか?いいえ、すべてハードコードされています!しかし、それはLog4Jのせいではなく、私たちのせいです。単純ですがハードコードされた設定を意味するBasicConfigurator.configure();をコーディングしました。プロパティファイルを使用する方が便利です。Javaソースファイルで、main()メソッドからBasicConfiguration行(および関連するimportステートメント)を削除します。Log4Jは、マニュアルに記載されているように設定を検索します。次に、新しいファイルsrc/log4j.propertiesを作成します。これはLog4Jの設定のデフォルト名であり、この名前を使用すると、フレームワークだけでなく、あなたにとっても жизнь が楽になります!

log4j.rootLogger=DEBUG, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender

log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%m%n

この設定では、コンソールに出力チャネル(「Appender」)を作成し、stdoutという名前を付けます。このチャネルは、メッセージ(「%m」)の後に改行(「%n」)を出力します。これは、以前のSystem.out.println()と同じです:-) わかりました。しかし、まだ終わりではありません。設定ファイルも配信する必要があります。そのため、ビルドファイルを変更します。

    ...
    <target name="compile">
        <mkdir dir="${classes.dir}"/>
        <javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath"/>
        <copy todir="${classes.dir}">
            <fileset dir="${src.dir}" excludes="**/*.java"/>
        </copy>
    </target>
    ...

これは、すべてのリソース(サフィックスが.javaでない限り)をビルドディレクトリにコピーするため、そのディレクトリからアプリケーションを開始でき、これらのファイルはjarに含まれます。

クラスのテスト

この手順では、Antと組み合わせてJUnit [3]テストフレームワークの使用方法を紹介します。AntにはJUnit 4.13.1が組み込まれているため、すぐに使用を開始できます。src\oata\HelloWorldTest.javaにテストクラスを記述します。

package oata;

import org.junit.Test;

import static org.junit.Assert.fail;

public class HelloWorldTest {

    @Test
    public void testNothing() {
    }

    @Test
    public void testWillAlwaysFail() {
        fail("An error message");
    }

}

テストする実際のビジネスロジックがないため、このテストクラスは非常に小さく、開始方法を示すだけです。詳細については、JUnitのドキュメント[3]とjunitタスクのマニュアルを参照してください。次に、ビルドファイルにjunit命令を追加します。

    ...

    <path id="application" location="${jar.dir}/${ant.project.name}.jar"/>

    <target name="run" depends="jar">
        <java fork="true" classname="${main-class}">
            <classpath>
                <path refid="classpath"/>
                <path refid="application"/>
            </classpath>
        </java>
    </target>

    <target name="junit" depends="jar">
        <junit printsummary="yes">
            <classpath>
                <path refid="classpath"/>
                <path refid="application"/>
            </classpath>

            <batchtest fork="yes">
                <fileset dir="${src.dir}" includes="**/*Test.java"/>
            </batchtest>
        </junit>
    </target>

    ...

「実行」ターゲットで定義されている独自のjarファイルへのパスを、idを指定してグローバルに利用できるようにすることで再利用します。printsummary=yesを使用すると、「FAILED」または「PASSED」メッセージだけでなく、より詳細な情報が表示されます。いくつのテストが失敗しましたか?エラーはありましたか?printsummaryで知ることができます。クラスパスは、クラスを見つけるように設定されています。テストを実行するために、ここではbatchtestが使用されているため、将来、*Test.javaという名前を付けるだけで、簡単にテストクラスを追加できます。これは一般的な命名スキームです。

ant junitを実行すると、次のようになります。

...
junit:
    [junit] Running oata.HelloWorldTest
    [junit] Tests run: 2, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0,01 sec
    [junit] Test oata.HelloWorldTest FAILED

BUILD SUCCESSFUL
...

レポートを作成することもできます。シェルを閉じた後、あなた(と他の人)が読めるもの...2つの手順があります。1.<junit>に情報を記録させる。2.これらのログファイルを何か読みやすいもの(ブラウズ可能なもの)に変換する。

    ...
    <property name="report.dir"  value="${build.dir}/junitreport"/>
    ...
    <target name="junit" depends="jar">
        <mkdir dir="${report.dir}"/>
        <junit printsummary="yes">
            <classpath>
                <path refid="classpath"/>
                <path refid="application"/>
            </classpath>

            <formatter type="xml"/>

            <batchtest fork="yes" todir="${report.dir}">
                <fileset dir="${src.dir}" includes="**/*Test.java"/>
            </batchtest>
        </junit>
    </target>

    <target name="junitreport">
        <junitreport todir="${report.dir}">
            <fileset dir="${report.dir}" includes="TEST-*.xml"/>
            <report todir="${report.dir}"/>
        </junitreport>
    </target>

多くのファイルが生成され、デフォルトではこれらのファイルが現在のディレクトリに書き込まれるため、レポートディレクトリを定義し、「junit」を実行する前に作成し、ロギングをそこにリダイレクトします。ログ形式はXMLであるため、「junitreport」で解析できます。2番目のターゲット「junitreport」では、レポートディレクトリに生成されたすべてのXMLログファイルのブラウズ可能なHTMLレポートを作成する必要があります。これで、${report.dir}\index.htmlを開いて結果を確認できます(JavaDocのような外観です)。
個人的には、<junit><junitreport>に2つの異なるターゲットを使用します。HTMLレポートの生成には時間がかかり、テストのためだけにHTMLレポートは必要ありません。たとえば、エラーを修正している場合や、統合サーバーがジョブを実行している場合などです。

リソース

  1. https://archive.apache.org/dist/logging/log4j/1.2.17/log4j-1.2.17.zip
  2. https://logging.apache.org/log4j/1.2/manual.html
  3. https://junit.dokyumento.jp/junit4