3

I am an Ant newbie really. Here is my problem : I have a project in netbeans which uses several external libraries which are currently present in /lib directory. I want my netbeans to dynamically fetch latest versions of those libraries when it tries to build the project. Is this doable or am I on the completely wrong path? I have URLs for each of the external libraries, where do I need to specify those in order for this experiment to work? Any help on this is appreciated, I am completely clueless about how to do this !

Thanks

Hi All, I have checked out all your answers and searched more on them. Now the problem is that although maven looks incredible, my project already uses Ant and I don't know how to migrate from ant to maven on netbeans and how difficult is it. Any help? Or else I can use Apache Ivy for this purpose. To give you an example of jar I am using : Apache commons jar

So can you guys guide me how to go about this ? This jar is wrapped inside a .zip file so not easy to detect latest version I guess.

voidMainReturn
  • 3,339
  • 6
  • 38
  • 66
  • Does http://ant.apache.org/ivy/ suit your needs? – Joachim Rohde Jun 13 '13 at 11:00
  • @Joachim Rohde : Yes it does. Can you help me out on how to install it on netbeans? I searched and it is not available in netbeans plugins. – voidMainReturn Jun 17 '13 at 19:59
  • Never used Ivy myself, but have a look at http://wiki.netbeans.org/FaqIvy – Joachim Rohde Jun 18 '13 at 06:20
  • You have changed your original question. Please accept answers provided and start new questions for new issues. Handling jars inside zip files is something Maven can't do. Ivy can (using a packager resolver) but it's not trivial. See: http://stackoverflow.com/questions/908371/apache-ivy-resolving-dependencies-embedded-in-an-installer/ – Mark O'Connor Jun 18 '13 at 07:48
  • @MarkO'Connor : As you adviced on this question and the other one I asked, that thing integrating netbeans and apache ivy worked somewhat fine. Its giving me some errors as of now. I am trying to resolve them. If it doesn;t I'll come back with some more questions. Thanks – voidMainReturn Jun 18 '13 at 08:16

2 Answers2

5

The get task is the only way to do this using standard ANT.

The problem with modern open source development is often one jar depends on several more and when one also must keep track of version compatibilities, this can become difficult if not impossible to keep track of.

Maven is a build technology that pre-dates ANT and has a dependency management feature for 3rd party build dependencies. This functionality can be replicated in ANT by using the Apache ivy plugin.

Example

Java project to demonstrate the use of ivy:

├── build.xml
├── ivy.xml
└── src
    ├── main
    │   ├── java
    │   │   └── org
    │   │       └── demo
    │   │           └── App.java
    │   └── resources
    │       └── log4j.properties
    └── test
        └── java
            └── org
                └── demo
                    └── AppTest.java

There is an additional "ivy.xml" file which lists the 3rd party dependencies. These jars will be downloaded by default from the Maven Central repository, the largest repository of open source java jars.

ivy.xml

<ivy-module version="2.0">
    <info organisation="com.myspotontheweb" module="demo"/>

    <configurations>
        <conf name="compile" description="Required to compile application"/>
        <conf name="runtime" description="Additional run-time dependencies" extends="compile"/>
        <conf name="test"    description="Required for test only" extends="runtime"/>
    </configurations>

    <dependencies>
        <!-- compile dependencies -->
        <dependency org="org.slf4j" name="slf4j-api" rev="1.7.5" conf="compile->default"/>

        <!-- runtime dependencies -->
        <dependency org="org.slf4j" name="slf4j-log4j12" rev="1.7.5" conf="runtime->default"/>

        <!-- test dependencies -->
        <dependency org="junit" name="junit" rev="4.11" conf="test->default"/>
    </dependencies>

</ivy-module>

Notes:

  • This example uses the slf4j logging library which enables you to choose the actual implementation at runtime by adding different jars.
  • The ivy file declares 3 "configurations" which are logical groupings of dependencies. Each dependency has a "conf" mapping that tells ivy what the jar will be used for.
  • In this example our code will compile against the slf4j-api jar and will be configured to use log4j at runtime.
  • junit is an example of a 3rd party jar required by ANT. These can also be downloaded and managed by ivy.

build.xml

<project name="demo" default="build" xmlns:ivy="antlib:org.apache.ivy.ant">

    <!--
    ================
    Build properties
    ================
    -->
    <property name="src.dir"          location="src/main/java"/>
    <property name="resources.dir"    location="src/main/resources"/>
    <property name="test.src.dir"     location="src/test/java"/>
    <property name="build.dir"        location="build"/>
    <property name="classes.dir"      location="${build.dir}/classes"/>
    <property name="test.classes.dir" location="${build.dir}/test-classes"/>
    <property name="ivy.reports.dir"  location="${build.dir}/ivy-reports"/>
    <property name="test.reports.dir" location="${build.dir}/test-reports"/>
    <property name="dist.dir"         location="${build.dir}/dist"/>

    <property name="jar.main.class" value="org.demo.App"/>
    <property name="jar.file"       value="${dist.dir}/${ant.project.name}.jar"/>

    <!--
    ===========
    Build setup
    ===========
    -->
    <target name="bootstrap" 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.3.0/ivy-2.3.0.jar"/>
    </target>

    <target name="resolve" description="Use ivy to resolve classpaths">
        <ivy:resolve/>

        <ivy:report todir='${ivy.reports.dir}' graph='false' xml='false'/>

        <ivy:cachepath pathid="compile.path" conf="compile"/>
        <ivy:cachepath pathid="test.path"    conf="test"/>
    </target>

    <!--
    ===============
    Compile targets
    ===============
    -->
    <target name="resources" description="Copy resources into classpath">
        <copy todir="${classes.dir}">
            <fileset dir="${resources.dir}"/>
        </copy>
    </target>

    <target name="compile" depends="resolve,resources" description="Compile code">
        <mkdir dir="${classes.dir}"/>
        <javac srcdir="${src.dir}" destdir="${classes.dir}" includeantruntime="false" debug="true" classpathref="compile.path"/>
    </target>

    <target name="compile-tests" depends="compile" description="Compile tests">
        <mkdir dir="${test.classes.dir}"/>
        <javac srcdir="${test.src.dir}" destdir="${test.classes.dir}" includeantruntime="false" debug="true">
            <classpath>
                <path refid="test.path"/>
                <pathelement path="${classes.dir}"/>
            </classpath>
        </javac>
    </target>

    <!--
    ============
    Test targets
    ============
    -->
    <target name="test" depends="compile-tests" description="Run unit tests">
        <mkdir dir="${test.reports.dir}"/>
        <junit printsummary="yes" haltonfailure="yes">
            <classpath>
                <path refid="test.path"/>
                <pathelement path="${classes.dir}"/>
                <pathelement path="${test.classes.dir}"/>
            </classpath>
            <formatter type="xml"/>
            <batchtest fork="yes" todir="${test.reports.dir}">
                <fileset dir="${test.src.dir}">
                    <include name="**/*Test*.java"/>
                    <exclude name="**/AllTests.java"/>
                </fileset>
            </batchtest>
        </junit>
    </target>

    <!--
    =====================
    Build and run targets
    =====================
    -->
    <target name="build" depends="test" description="Create executable jar archive">
        <ivy:retrieve pattern="${dist.dir}/lib/[artifact]-[revision](-[classifier]).[ext]" conf="runtime"/>

        <manifestclasspath property="jar.classpath" jarfile="${jar.file}">
            <classpath>
                <fileset dir="${dist.dir}/lib" includes="*.jar"/>
            </classpath>
        </manifestclasspath>

        <jar destfile="${jar.file}" basedir="${classes.dir}">
            <manifest>
                <attribute name="Main-Class" value="${jar.main.class}" />
                <attribute name="Class-Path" value="${jar.classpath}" />
            </manifest>
        </jar>
    </target>

    <target name="run" depends="build" description="Run code">
        <java jar="${jar.file}" fork="true"/>
    </target>

    <!--
    =============
    Clean targets
    =============
    -->
    <target name="clean" description="Cleanup build files">
        <delete dir="${build.dir}"/>
    </target>

    <target name="clean-all" depends="clean" description="Additionally purge ivy cache">
        <ivy:cleancache/>
    </target>

</project>

Several items of note:

  • The ivy jar is not shipped by default with ant. The special "bootstrap" target is used to download this into a location which ANT uses for it's plug-ins.
  • The "resolve" target contains ivy tasks for downloading (and caching) dependencies, generating useful reports on these files and creating ANT paths which can be used for compilation and testing.
  • The "build" target contains the ivy "retrieve" task which places the dependencies into a distribution directory. The manifestclasspath can then use these to generate the correct "Class-path" manifest entry for the executable jar file created by this build.
Mark O'Connor
  • 76,015
  • 10
  • 139
  • 185
  • Thanks for such an elaborated description. After some search I found out that I have no option but to choose either Ivy or Maven. Since my project already uses Ant I am thinking using Ivy would be better than shifting to Maven. One very basic question though, How to install ivy plugin into netbeans? – voidMainReturn Jun 17 '13 at 20:03
  • @tejas Run the "bootstrap" target in the example about and that will install the ivy jar so that it can be picked up by ANT. I'm not a netbeans user but I found the following plugin which might be useful for UI integration: http://code.google.com/p/ivybeans/ Finally there is an ivy FAQ on the netbeans wiki: http://wiki.netbeans.org/FaqIvy – Mark O'Connor Jun 17 '13 at 21:56
  • you have shown above how to add ivy.xml. One question is : How to tell ivy about updating that external jar ? – voidMainReturn Jun 17 '13 at 23:37
  • @tejas I don't understand the question. – Mark O'Connor Jun 17 '13 at 23:46
  • Ok, As per my knowledge the main usage of Ivy is to check and fetch the latest versions of the external libraries during build. So where would ivy fetch these latest version from? Is there some change I have to make to the ivy.xml file for this? e.g. : in ant we have ..so is there something similar I have to do in Ivy.xml? – voidMainReturn Jun 17 '13 at 23:56
  • @tejas You're asking the same questions... http://stackoverflow.com/questions/17158456/using-ant-ivy-in-netbeans – Mark O'Connor Jun 18 '13 at 00:13
  • I believe ant pre-dates (came before) maven. – bdrx Feb 16 '21 at 19:35
  • Yes it does. You will find ANT in many legacy builds. It took some time for Maven to gain acceptance. – Mark O'Connor Mar 07 '21 at 10:26
  • I see where you copy *from* `resources.dir` but I don't see where you explicitly populate the `resources.dir` directory? – theyuv May 12 '22 at 12:37
  • The resource directory is in the 'src' directory and contains additional files we want copied onto the java classes directory. The magic bit is in the "resolve" target where the ivy task creates two ANT classpaths populated with jars retrieved from Maven Central repo. Note how classpath references are being used by javac tasks. Hope this helps. To conclude ivy gives ANT a missing capability we now take for granted in tools like Maven and Gradle. – Mark O'Connor May 29 '22 at 09:48
1

As a first advice, I would say that ant is probably not the best tool to do that. Maven is doing that properly (at least if your external libraries are published in a (public) maven repo as SNAPSHOT). Additionally, maven and netbeans works nicely together.

But, if you need to use ant, you should probably take a look at the ant get task. It allows you to download a file if the remote copy is newer that your local copy (with the usetimestamp attribute). So something like this will do the download when required:

<get src="http://some.url/somelib.jar" 
     dest="lib/somelib.jar"
     usetimestamp="true"/>
ben75
  • 29,217
  • 10
  • 88
  • 134
  • Can you give me some pointers about how to migrate my project from Ant to Maven? cause it looks like I have some jars which have to be manually extracted from zip files if I use ant get. – voidMainReturn Jun 17 '13 at 19:54
  • You can unzip with ant: http://ant.apache.org/manual/Tasks/unzip.html There is no simple way to migrate from ant to maven. It's very dependant of the complexity of your current build process. Here is a nice pointer to start with maven: http://books.sonatype.com/mvnex-book/reference/index.html – ben75 Jun 17 '13 at 20:05
  • Hi, I think unzip might help me out here. But I am still confused. Can you take a look at my latest edit to the question and guide me accordingly for that example ? thanks. – voidMainReturn Jun 17 '13 at 20:21