web-dev-qa-db-ja.com

Antを使用して新しいjarファイルビルドに外部jarファイルを含める

私はJavaプロジェクトを「継承」しましたが、Javaのバックグラウンドから来たのではなく、時々少し迷います。 Eclipseは、開発中にアプリケーションをデバッグおよび実行するために使用されます。 Eclipseを使用して、Log4J、xmlrpc-serverなどの必要なすべての外部jarを「含む」.jarファイルの作成に成功しました。この大きな.jarは、次を使用して正常に実行できます。

Java -jar myjar.jar

次のステップは、Ant(バージョン1.7.1)を使用してビルドを自動化することです。そのため、ビルドとデプロイメントを行うためにEclipseを関与させる必要はありません。 Javaの知識が不足しているため、これは難題であることが証明されています。プロジェクトのルートは次のようになります。

|-> jars (where external jars have been placed)
|-> Java
| |-> bin (where the finished .class / .jars are placed)
| |-> src (Where code lives)
| |-> ++files like build.xml etc
|-> sql (you guessed it; sql! )

私のbuild.xmlには次のものが含まれています。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project basedir="." default="build" name="Seraph">
    <property environment="env"/>
    <property name="debuglevel" value="source,lines,vars"/>
    <property name="target" value="1.6"/>
    <property name="source" value="1.6"/>

    <property name="build.dir"     value="bin"/>
    <property name="src.dir"       value="src"/>
    <property name="lib.dir"       value="../jars"/>
    <property name="classes.dir"   value="${build.dir}/classes"/>
    <property name="jar.dir"       value="${build.dir}/jar"/>
    <property name="jar.file"      value="${jar.dir}/seraph.jar"/>
    <property name="manifest.file" value="${jar.dir}/MANIFEST.MF"/>

    <property name="main.class" value="no.easyconnect.seraph.core.SeraphCore"/>

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

    <path id="project.classpath">
        <pathelement location="${src.dir}"/>
        <path refid="external.jars" />
    </path>

    <target name="init">
        <mkdir dir="${build.dir}"/>
        <mkdir dir="${classes.dir}"/>
        <mkdir dir="${jar.dir}"/>
        <copy includeemptydirs="false" todir="${build.dir}">
            <fileset dir="${src.dir}">
                <exclude name="**/*.launch"/>
                <exclude name="**/*.Java"/>
            </fileset>
        </copy>
    </target>

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

    <target name="cleanall" depends="clean"/>

    <target name="build" depends="init">
        <echo message="${ant.project.name}: ${ant.file}"/>
        <javac debug="true" debuglevel="${debuglevel}" destdir="bin" source="${source}" target="${target}" classpathref="project.classpath">
            <src path="${src.dir}"/>
        </javac>
    </target>

    <target name="build-jar" depends="build">
        <delete file="${jar.file}" />
        <delete file="${manifest.file}" />

        <manifest file="${manifest.file}" >
            <attribute name="built-by" value="${user.name}" />
            <attribute name="Main-Class" value="${main.class}" />
        </manifest>

        <jar destfile="${jar.file}" 
            basedir="${build.dir}" 
            manifest="${manifest.file}">
            <fileset dir="${classes.dir}" includes="**/*.class" />
            <fileset dir="${lib.dir}" includes="**/*.jar" />
        </jar>
    </target>
</project>

次に実行します:ant clean build-jar

また、seraph.jarという名前のファイルがJava/bin/jar-directoryに配置されます。次に、次のコマンドを使用してこのjarを実行しようとします。Java -jar bin/jar/seraph.jar

結果はコンソールでこの出力です:

Exception in thread "main" Java.lang.NoClassDefFoundError: org/Apache/log4j/Logger
    at no.easyconnect.seraph.core.SeraphCore.<clinit>(SeraphCore.Java:23)
Caused by: Java.lang.ClassNotFoundException: org.Apache.log4j.Logger
    at Java.net.URLClassLoader$1.run(URLClassLoader.Java:200)
    at Java.security.AccessController.doPrivileged(Native Method)
    at Java.net.URLClassLoader.findClass(URLClassLoader.Java:188)
    at Java.lang.ClassLoader.loadClass(ClassLoader.Java:307)
    at Sun.misc.Launcher$AppClassLoader.loadClass(Launcher.Java:301)
    at Java.lang.ClassLoader.loadClass(ClassLoader.Java:252)
    at Java.lang.ClassLoader.loadClassInternal(ClassLoader.Java:320)
    ... 1 more
Could not find the main class: no.easyconnect.seraph.core.SeraphCore. Program will exit.

私はbuild.xml-fileで驚くほど愚かなことをして、2日間の大部分を構成のバリエーションの試行に費やしたが、役に立たないと思う。これを機能させるための助けは大歓迎です。

ああ、私はいくつかの重要な情報を残してすみませんでした。 SOに投稿するのは初めてです。

38
Christopher

ここで答えてくれた人々からの有益なアドバイスで、私はOne-Jarを掘り始めました。いくつかの行き止まりの後(および以前の結果とまったく同じ結果がいくつかありましたが、なんとか動作するようになりました。他の人々の参考のために、私のために働いたbuild.xmlをリストしています。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project basedir="." default="build" name="<INSERT_PROJECT_NAME_HERE>">
    <property environment="env"/>
    <property name="debuglevel" value="source,lines,vars"/>
    <property name="target" value="1.6"/>
    <property name="source" value="1.6"/>

    <property name="one-jar.dist.dir" value="../onejar"/>
    <import file="${one-jar.dist.dir}/one-jar-ant-task.xml" optional="true" />

    <property name="src.dir"          value="src"/>
    <property name="bin.dir"          value="bin"/>
    <property name="build.dir"        value="build"/>
    <property name="classes.dir"      value="${build.dir}/classes"/>
    <property name="jar.target.dir"   value="${build.dir}/jars"/>
    <property name="external.lib.dir" value="../jars"/>
    <property name="final.jar"        value="${bin.dir}/<INSERT_NAME_OF_FINAL_JAR_HERE>"/>

    <property name="main.class"       value="<INSERT_MAIN_CLASS_HERE>"/>

    <path id="project.classpath">
        <fileset dir="${external.lib.dir}">
            <include name="*.jar"/>
        </fileset>
    </path>

    <target name="init">
        <mkdir dir="${bin.dir}"/>
        <mkdir dir="${build.dir}"/>
        <mkdir dir="${classes.dir}"/>
        <mkdir dir="${jar.target.dir}"/>
        <copy includeemptydirs="false" todir="${classes.dir}">
            <fileset dir="${src.dir}">
                <exclude name="**/*.launch"/>
                <exclude name="**/*.Java"/>
            </fileset>
        </copy>
    </target>

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

    <target name="cleanall" depends="clean"/>

    <target name="build" depends="init">
        <echo message="${ant.project.name}: ${ant.file}"/>
        <javac debug="true" debuglevel="${debuglevel}" destdir="${classes.dir}" source="${source}" target="${target}">
            <src path="${src.dir}"/>
            <classpath refid="project.classpath"/>   
        </javac>
    </target>

    <target name="build-jar" depends="build">
        <delete file="${final.jar}" />
        <one-jar destfile="${final.jar}" onejarmainclass="${main.class}">
            <main>
                <fileset dir="${classes.dir}"/>
            </main>
            <lib>
                <fileset dir="${external.lib.dir}" />
            </lib>
        </one-jar>
    </target>
</project>

他の誰かがこの恩恵を受けることを願っています。

15
Christopher

Antビルドファイルから、アプリケーションクラスだけでなく、アプリケーションに必要な他のJARの内容も含む単一のJARアーカイブを作成することを想定しています。

ただし、build-jarファイルは、必要なJARを独自のJAR内に配置しているだけです。これは説明されているように機能しません here (注を参照)。

これを変更してみてください:

<jar destfile="${jar.file}" 
    basedir="${build.dir}" 
    manifest="${manifest.file}">
    <fileset dir="${classes.dir}" includes="**/*.class" />
    <fileset dir="${lib.dir}" includes="**/*.jar" />
</jar>

これに:

<jar destfile="${jar.file}" 
    basedir="${build.dir}" 
    manifest="${manifest.file}">
    <fileset dir="${classes.dir}" includes="**/*.class" />
    <zipgroupfileset dir="${lib.dir}" includes="**/*.jar" />
</jar>

より柔軟で強力なソリューションは、 JarJar または One-Jar プロジェクトです。上記が要件を満たさない場合は、それらを調べてください。

49
Grodriguez

Cheesle が正しい。クラスローダーが埋め込みjarを見つける方法はありません。コマンドラインに十分なデバッグコマンドを配置すると、クラスパスへのjarの追加に失敗する「Java」コマンドが表示されるはずです。

あなたが作りたいものは時々「ユーバージャー」と呼ばれます。 one-jar を作成するためのツールとして見つけましたが、試していません。もちろん、他にも多くのアプローチがあります。

2
Julian Simpson

Cheesleが言ったように、次の変更を加えて、ライブラリーのジャーを解凍し、すべて再ジャールできます。

    <jar destfile="${jar.file}"  
        basedir="${build.dir}"  
        manifest="${manifest.file}"> 
        <fileset dir="${classes.dir}" includes="**/*.class" /> 
        <zipgroupfileset dir="${lib.dir}" includes="**/*.jar" /> 
    </jar> 

Jarファイルは、実際にはマニフェストファイルが埋め込まれた単なるZipファイルです。依存関係Jarを抽出して、アプリケーションのJarファイルに再パッケージ化できます。

http://ant.Apache.org/manual/Tasks/Zip.html "Zipタスクは、複数のZipファイルのZipファイルへのマージもサポートしています。これは、ネストされたファイルセット、または特別なネストされたファイルセットzipgroupfilesetを使用します。」

依存ライブラリに関係するライセンスに注意してください。外部からライブラリにリンクし、ライブラリをアプリケーションに含めることは、法的に非常に異なります。

編集1:ゆっくり入力してください。グロドリゲスは私を打ち負かした。 :)

編集2:依存関係をアプリケーションに含めることができないと判断した場合、起動時のコマンドラインまたはマニフェストファイルを介してJarのクラスパスでそれらを指定する必要があります。 ANTには、マニフェストファイルのクラスパスの特別なフォーマットを処理するNiceコマンドがあります。

<manifestclasspath property="manifest.classpath" jarfile="${jar.file}">
    <classpath location="${lib.dir}" />
</manifestclasspath>

 <manifest file="${manifest.file}" >      
        <attribute name="built-by" value="${user.name}" />      
        <attribute name="Main-Class" value="${main.class}" />    
        <attribute name="Class-Path" value="${manifest.classpath}" />
 </manifest>
0
Tansir1

クラスパス内の新しいjarを参照するか、囲まれているjar内のすべてのクラスをアンパックして、全体を再ジャーリングする2つのオプションがあります!私が知っている限りでは、jar内のjarのパッケージ化は推奨されておらず、クラスが見つからないという例外は永遠にあります!

0
Cheesle

これは、次のように実行可能jarを実行する場合のクラスパスの問題です。

Java -jar myfile.jar

問題を修正する1つの方法は、Javaコマンドラインでクラスパスを次のように設定し、欠落しているlog4j jarを追加することです。

Java -cp myfile.jar:log4j.jar:otherjar.jar com.abc.xyz.MyMainClass

もちろん、最良の解決策は、jarマニフェストにクラスパスを追加して、「-jar」Javaオプションを使用できるようにすることです。

<jar jarfile="myfile.jar">
    ..
    ..
    <manifest>
       <attribute name="Main-Class" value="com.abc.xyz.MyMainClass"/>
       <attribute name="Class-Path" value="log4j.jar otherjar.jar"/>
    </manifest>
</jar>

次の回答は、 manifestclasspath を使用してクラスパスマニフェストエントリのシーティングを自動化する方法を示しています

Antでコンパイルされたファイルにメインクラスが見つかりません

0
Mark O'Connor

私はNetBeansを使用していますが、これに対するソリューションも必要でした。グーグルでクリストファーの答えから始めた後、NetBeansでこれを簡単に行うのに役立つスクリプトを作成できました。他の誰かがそれらを必要とする場合のために、私はここに指示を入れています。

あなたがしなければならないことは、1つのjarをダウンロードすることです。ここからリンクを使用できます。 http://one-jar.sourceforge.net/index.php?page=getting-started&file=ant jarアーカイブを抽出し、one-jar\distを探しますone-jar-ant-task-。jar、one-jar-ant-task.xmlおよびone-jar-boot-。jarを含むフォルダー。それらを抽出するか、プロパティone-jar.dist.dirの値として、以下のスクリプトに追加するパスにコピーします。

Build.xmlスクリプトの最後(NetBeansプロジェクトから)の/ projectタグの直前に次のスクリプトをコピーし、one-jar.dist.dirの値を正しいパスに置き換えて、1-jarターゲットを実行します。

ターゲットの実行に不慣れな方は、このチュートリアルが役立つかもしれません: http://www.Oracle.com/technetwork/articles/javase/index-139904.html また、ソースを1つのjarに配置する方法も示していますが、それらは展開されており、jarに圧縮されていません。

<property name="one-jar.dist.dir" value="path\to\one-jar-ant"/>
<import file="${one-jar.dist.dir}/one-jar-ant-task.xml" optional="true" />

<target name="one-jar" depends="jar">
<property name="debuglevel" value="source,lines,vars"/>
<property name="target" value="1.6"/>
<property name="source" value="1.6"/>
<property name="src.dir"          value="src"/>
<property name="bin.dir"          value="bin"/>
<property name="build.dir"        value="build"/>
<property name="dist.dir"         value="dist"/>
<property name="external.lib.dir" value="${dist.dir}/lib"/>
<property name="classes.dir"      value="${build.dir}/classes"/>
<property name="jar.target.dir"   value="${build.dir}/jars"/>
<property name="final.jar"        value="${dist.dir}/${ant.project.name}.jar"/>
<property name="main.class"       value="${main.class}"/>

<path id="project.classpath">
    <fileset dir="${external.lib.dir}">
        <include name="*.jar"/>
    </fileset>
</path>

<mkdir dir="${bin.dir}"/>
<!-- <mkdir dir="${build.dir}"/> -->
<!-- <mkdir dir="${classes.dir}"/> -->
<mkdir dir="${jar.target.dir}"/>
<copy includeemptydirs="false" todir="${classes.dir}">
    <fileset dir="${src.dir}">
        <exclude name="**/*.launch"/>
        <exclude name="**/*.Java"/>
    </fileset>
</copy>

<!-- <echo message="${ant.project.name}: ${ant.file}"/> -->
<javac debug="true" debuglevel="${debuglevel}" destdir="${classes.dir}" source="${source}" target="${target}">
    <src path="${src.dir}"/>
    <classpath refid="project.classpath"/>   
</javac>

<delete file="${final.jar}" />
<one-jar destfile="${final.jar}" onejarmainclass="${main.class}">
    <main>
        <fileset dir="${classes.dir}"/>
    </main>
    <lib>
        <fileset dir="${external.lib.dir}" />
    </lib>
</one-jar>

<delete dir="${jar.target.dir}"/>
<delete dir="${bin.dir}"/>
<delete dir="${external.lib.dir}"/>

</target>

幸運を祈ります。それがあなたを助けたなら、投票することを忘れないでください。

0
Alex Burdusel

Ant jarタスクにすでに組み込まれている少しの機能を使用できます。

ant jarタスクのドキュメント に移動し、「アーカイブのマージ」セクションまでスクロールダウンすると、「lib/main」内のすべてのjarのすべての* .classファイルを含めるためのスニペットがあります。 "ディレクトリ:

<jar destfile="build/main/checksites.jar">
    <fileset dir="build/main/classes"/>
    <restrict>
        <name name="**/*.class"/>
        <archives>
            <zips>
                <fileset dir="lib/main" includes="**/*.jar"/>
            </zips>
        </archives>
    </restrict>
    <manifest>
      <attribute name="Main-Class" value="com.acme.checksites.Main"/>
    </manifest>
</jar>

これはメインクラス「com.acme.checksites.Main」で実行可能なjarファイルを作成し、lib/mainのすべてのjarからすべてのクラスを埋め込みます。

名前空間の競合、複製などが発生した場合、巧妙な処理は行われません。また、使用しないクラスファイルもすべて含まれるため、結合されたjarファイルはフルサイズになります。

そのようなより高度なものが必要な場合は、 one-jar および jar jar links のように見てください

0
s3v1