I'm working in very big java project, consisting of many smaller maven modules and one web module which is maintained using ant. Now, I need to access in my web module projects written in maven modules. Is it possible to somehow add maven modules to ant project?
I have tried to make jar files from maven modules and simple add them to ant project, but I received errors ClassNotFoundException and NoClassDefFoundError.
You can integrate maven dependencies with Apache Ant by using Maven Ant Tasks.
Use a Maven repository manager like Nexus, Artifactory or Archiva to store jars built by your Maven project.
The Apache ivy plugin for ANT can then be used to pull these as dependencies (Ivy can also be used to store jars in a Maven repo but that is another question).
Example
├── build.xml
├── ivysettings.xml
└── target
└── WEB-INF
└── lib
├── log4j-1.2.17.jar
├── slf4j-api-1.7.5.jar
└── slf4j-log4j12-1.7.5.jar
build.xml
<project name="demo" default="resolve" xmlns:ivy="antlib:org.apache.ivy.ant">
<property name="build.dir" location="target"/>
<available classname="org.apache.ivy.Main" property="ivy.installed"/>
<target name="resolve" depends="install-ivy" description="Use ivy to resolve classpaths">
<ivy:retrieve pattern="${build.dir}/WEB-INF/lib/[artifact]-[revision].[ext]">
<dependency org="org.slf4j" name="slf4j-api" rev="1.7.5" conf="default"/>
<dependency org="org.slf4j" name="slf4j-log4j12" rev="1.7.5" conf="default"/>
</ivy:retrieve>
</target>
<target name="install-ivy" unless="ivy.installed">
<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.4.0/ivy-2.4.0.jar"/>
<fail message="Ivy installed run build again"/>
</target>
<target name="clean">
<delete dir="${build.dir}"/>
</target>
<target name="clean-all" depends="clean">
<ivy:cleancache/>
</target>
</project>
Notes:
The "install-ivy" target is optional and my recommended way to ensure the ivy plugin jar is installed on your build server
The ivy retrieve task is used to resolve dependencies and place them within the project space
The ivy cleancache task purges the local ivy cache.
ivysettings.xml
<ivysettings>
<settings defaultResolver="my-resolvers"/>
<resolvers>
<chain name="my-resolvers" returnFirst="true">
<ibiblio name="central" m2compatible="true"/>
<ibiblio name="myrepo" root="http://mavenrepo/path/to/repo" m2compatible="true"/>
</chain>
</resolvers>
</ivysettings>
Note:
The ivy configuration file is optional and this example demonstrates how both Maven Central and a local Maven repository can be used as a source of dependencies.
Related
I have a project where we store a local copy of some client API jars. These jars may or may not be the same as the final run-time versions used by the client. When I build the project locally for testing, I want to use the local copies of the jars. However, when I'm on-site with the client, I want to look at an external location from my project and check if the client updated jars are available. If they are we use them, if not we fall back on our local copies.
I have found a way to conditionally build a file-set containing the given jars, but I can't figure out how to get the file-set into my classpath.
Below is the script I have generated so far. I do not have access to the ant-contrib IF statements, so this is the only way I've found to conditionally build the file-set.
<condition property="externalFileExists">
<available file="[path to external file]"/>
</condition>
<target name="buildExternalFileset" if="externalFileExists">
<fileset id="fileset" includes="[path to external library]"/>
</target>
<target name="buildInternalFileset" unless="externalFileExists">
<fileset id="fileset" includes="[path to internal library]"/>
</target>
<target name="buildFileset depends="buildExternalFileset, buildInternalFileSet>
</target>
Once I have this file-set built, how do I include it in the classpath?
<path id="classpath">
<!-- other filesets -->
<!-- line that includes the conditional fileset by ID -->
</path>
According to the documentation for path-like structures you can include a path within another path, but I don't see an example for including an external file-set. Perhaps I've answered my question - - should I be building paths instead of file-sets? Additionally, file-set documentation doesn't actually include the option to add IDs, do they work?
If anyone has a better way to do this I'd be more than happy to hear about it!
I would suggest using a dependency manager rather than try and building your own.
Apache ivy is able to download dependencies from configured locations. It also caches downloaded files removing the need to store them locally if they are universally available from Maven Central.
Example
This project has an ivy settings file that pulls dependencies from either the local "lib" directory or from Maven central.
├── build.xml
├── ivysettings.xml
├── ivy.xml
└── lib
├── hamcrest-core-1.3.jar
├── junit-4.11.jar
├── log4j-1.2.17.jar
├── slf4j-api-1.7.5.jar
└── slf4j-log4j12-1.7.5.jar
build.xml
<project name="demo" default="resolve" xmlns:ivy="antlib:org.apache.ivy.ant">
<property name="build.dir" location="target"/>
<available classname="org.apache.ivy.Main" property="ivy.installed"/>
<target name="install-ivy" unless="ivy.installed">
<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.4.0/ivy-2.4.0.jar"/>
<fail message="Ivy installed run build again"/>
</target>
<target name="resolve" depends="install-ivy" description="Use ivy to resolve classpaths">
<ivy:resolve/>
<ivy:report todir='${build.dir}/ivy-reports' graph='false' xml='false'/>
<ivy:cachepath pathid="compile.path" conf="compile"/>
<ivy:cachepath pathid="test.path" conf="test"/>
</target>
<target name="clean">
<delete dir="${build.dir}"/>
</target>
<target name="clean-all" depends="clean">
<ivy:cleancache/>
</target>
</project>
Notes:
Ivy does not come bundled with ANT. The "install-ivy" task ensures it gets installed on the first ant run
The "cachepath" tasks will create classpaths for use in your javac, junit and java tasks.
The "report" and "cleancache" tasks are useful additional tasks.
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:
Uses configurations to keep dependencies separated. Note how this is used by the "cachepath" tasks to control dependency classpaths
ivysettings.xml
<ivysettings>
<settings defaultResolver="my-resolvers"/>
<resolvers>
<chain name="my-resolvers" returnFirst="true">
<filesystem name="local-lib">
<artifact pattern="${ivy.settings.dir}/lib/[artifact]-[revision].[ext]"/>
</filesystem>
<ibiblio name="central" m2compatible="true"/>
</chain>
</resolvers>
</ivysettings>
Notes:
This file is optional. By default Ivy will retrieve from Maven Central
The special chain resolver controls which source of dependencies is used. In this case the local "lib" directory is favoured over Maven Cental.
I'm not very familiar with ant, but how about a build configuration on ant ?
Try this site for a tutorial on how to do it: http://ant.apache.org/easyant/history/trunk/howto/BuildConfigurations.html
Try something like this
<classpath>
<fileset dir="[external-path1]">
<include name="**/*.jar"/>
</fileset>
<fileset dir="[external-path2]">
<include name="**/*.jar"/>
</fileset>
<fileset dir="[external-path3]">
<include name="**/*.jar"/>
</fileset>
</classpath>
found here
https://ant.apache.org/manual/using.html#path
So, since I've been unable to find a way to resolve our dependency issues by including everything from external sources I've turned to Eclipse / IvyDE for ant / Ivy integration.
With that said, I normally include a lib like this:
<dependency org="org.jsoup" name="jsoup" rev="1.6.3"/>
However what if I want to look at something in our own intranet?
Example, if the folder holding the jar is somewhere like this:
https://prdsvn01.company.intra.net/repo/libName/
and I want to include lib.jar into my folder.
I've been relatively unable to find ivysettings.xml in this implementation of eclipse, nor am I confident that I'd be able to get it right if I could.
Could someone help me with this?
The following ivy settings file:
<ivysettings>
<settings defaultResolver="central"/>
<resolvers>
<ibiblio name="central" m2compatible="true"/>
<url name="my-repo">
<artifact pattern="http://myserver/myrepo/[organisation]/[artifact]/[revision]/[artifact].[ext]"/>
</url>
</resolvers>
<modules>
<module organisation="org.mycompany" resolver="my-repo"/>
</modules>
</ivysettings>
Is configured to retrieve artifacts from Maven Central by default, and local artifacts from a HTTP server.
Update
ivy.xml
Nothing special in the ivy file. Just declare the dependencies and which configuration to associate them with:
<configurations>
<conf name="compile" description="Required to compile application"/>
</configurations>
<dependencies>
<!-- compile dependencies -->
<dependency org="org.slf4j" name="slf4j-api" rev="1.6.4" conf="compile->default"/>
<dependency org="org.mycompany" name="my-module" rev="1.0" conf="compile->default"/>
</dependencies>
Note:
It's ivy best practice to use configurations.
build.xml
<target name="resolve" dependencies="Resolve build dependencies">
<ivy:resolve/>
<ivy:report todir='build/reports' graph='false' xml='false'/>
<ivy:cachepath pathid="compile.path" conf="compile"/>
..
</target>
Notes:
The ivycachepath task transforms an ivy configuration into a populated ANT classpath. Very useful.
The ivy report task tells you the jars on the classpath(s)
Ivy resolve build output
All the magic is in the settings file. Running the build produces the following:
[ivy:resolve] found org.slf4j#slf4j-api;1.6.4 in central
[ivy:resolve] found org.mycompany#my-module;1.0 in my-repo
..
[ivy:resolve] downloading http://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.6.4/slf4j-api-1.6.4.jar ...
..
[ivy:resolve] downloading http://myserver/myrepo/org.mycompany/my-module/1.0/my-module.jar ...
Notes:
The my-repo resolver is used for modules with a "org.mycompany" groupId.
Everything else comes from the default resolver, Maven Central.
I have a ivy.xml - https://gist.github.com/1898060
I also have the jar file related to this ivy.xml.
What i need is a mechanism to import this project to my maven repo and use it in my maven project.
SO basically if i am able to convert the ivy.xml to pom.xml , i might be able to get it work.
Is there some mechanism through which i can achieve this.
I am looking for something like a maven plugin to accomplish this task.
I know that there are ways we can edit the ivy.xml and build.xml to achieve this but then i dont want to do it , as the project is in a private repo.
What you really need to do is publish the jars built by ANT project into your Maven repository.
ant -Dproject.version=0.9.0-local-20120211095554 clean publish
I know you don't want to change the ANT build, but creating an extra "publish" target will properly integrate your ANT and Maven projects.
The two jar artifacts, published by your modified ANT build, could be consumed normally as follows:
<dependency>
<groupId>com.opengamma</groupId>
<artifactId>og-analytics</artifactId>
<version>0.9.0-local-20120211095554</version>
</dependency>
<dependency>
<groupId>com.opengamma</groupId>
<artifactId>og-analytics</artifactId>
<version>0.9.0-local-20120211095554</version>
<classifier>sources</classifier>
</dependency>
Modifications to your ANT build
ivy.xml
Main changes are to your publications section:
<ivy-module version="2.0" xmlns:e="http://ant.apache.org/ivy/extra">
<info organisation="com.opengamma" module="og-analytics"/>
<publications>
<artifact name="og-analytics" type="jar"/>
<artifact name="og-analytics" type="pom"/>
<artifact name="og-analytics" type="jar" e:classifier="sources"/>
</publications>
<dependencies>
<dependency name="og-util" rev="0.9.0-local-20120211095525" revConstraint="latest.integration"/>
<dependency org="org.jfree" name="jfreechart" rev="1.0.13"/>
<dependency org="cern" name="colt" rev="1.2.0"/>
<dependency org="cern" name="parallelcolt" rev="0.9.1"/>
<dependency org="latexlet" name="latexlet" rev="1.11"/>
<dependency org="org.apache.commons" name="commons-math" rev="2.1"/>
<dependency org="it.dexy" name="json-doclet" rev="0.3.1"/>
<dependency org="org.json" name="simple" rev="1.1"/>
<exclude org="org.junit"/>
</dependencies>
</ivy-module>
Notes:
The ANT project will now publish 3 files, jar, sources jar and the Maven POM
In Maven source jars have a "classifier" attributes that is set to "sources" (Not source). To facilitate this we're adding an ivy extra attribute.
No need for version and status information in the info tag header. This will be added by the publication step.
build.xml
<target name="prepare" description="Generate POM">
<fail message="Unset property: project.version" unless="project.version"/>
<ivy:deliver deliverpattern="${build.dir}/ivy.xml" pubrevision="${project.version}" status="release"/>
<ivy:makepom ivyfile="${build.dir}/ivy.xml" pomfile="${build.dir}/${ivy.module}.pom"/>
</target>
<target name="publish" depends="build,prepare" description="Upload to Nexus">
<ivy:publish resolver="nexus-deploy" pubrevision="${project.version}" overwrite="true" publishivy="false" >
<artifacts pattern="${build.dir}/[artifact](-[classifier]).[ext]"/>
</ivy:publish>
</target>
Notes:
The deliver task is optional, but recommended in case your ivy file contains dynamic revisions, such as "latest.release" or "latest.integration".
The makepoms task has powerful support for convert ivy configurations into Maven scopes. Does not apply in your case, but an incentive to learn more about ivy :-)
The publish task uses a specified pattern to find files specified in ivy's publications section.
ivysettings.xml
This is where you configure the location of the repositories and credentials to be used by publish build target.
<ivysettings>
<settings defaultResolver="nexus-central"/>
<credentials host="somehost" realm="Sonatype Nexus Repository Manager" username="????" passwd="????"/>
<resolvers>
<ibiblio name="nexus-central" root="http://somehost/nexus/content/repositories/central/" m2compatible="true"/>
<ibiblio name="nexus-deploy" root="http://somehost/nexus/content/repositories/repo" m2compatible="true"/>
</resolvers>
</ivysettings>
Notes:
Ivy downloads use the configured default resolver nexus-central.
The ivy publish task pushes to the Nexus repository called nexus-deploy
The security realm in this example matches Nexus Maven. Would be different for other repo managers.
Apache Ant itself provides a task to do this - makepom. Always helps to consult the documentation!
We recently started using ant-ivy for a java webapp and the journey has been good so far. I have specified transitive='false' for all dependencies and listed log4j version 1.2.16 as a dependency. I have to use a recent version of log4j as I rely on an enhanced pattern layout.
Main problem - when the project is built, there are multiple versions of log4j in the ivy-lib folder. When looking at the package explorer in Eclipse, I see the right version and seems like it downloads only 1.2.16 from ivycachepath.
Any pointers? Do I need to remove each dependency individually and see which one brings older versions?
Thanks for the help.
I've included an example ant build which downloads log4j as a dependency, into a local directory called "lib".
$ ant
$ find lib
lib
lib/log4j-1.2.16.jar
As you can see only one version of the jar is present. Hope this helps in diagnosing your issue.
build.xml
<project xmlns:ivy="antlib:org.apache.ivy.ant" name="hello-ivy" default="retrieve">
<property name="lib.dir" location="lib"/>
<property name="report.dir" location="report"/>
<target name="retrieve" description="Retrieve dependencies locally">
<ivy:retrieve pattern="${lib.dir}/[artifact]-[revision](-[classifier]).[ext]"/>
<ivy:report todir="${report.dir}" graph="false"/>
</target>
<target name="clean" description="Remove build directories">
<delete dir="${lib.dir}"/>
<delete dir="${report.dir}"/>
</target>
<target name="clean-all" depends="clean" description="clean ivy cache">
<ivy:cleancache />
</target>
</project>
ivy.xml
<ivy-module version="2.0">
<info organisation="org.demo" module="demo"/>
<configurations defaultconfmapping="compile->default">
<conf name="compile" description="jars used for compilation"/>
</configurations>
<dependencies>
<dependency org="log4j" name="log4j" rev="1.2.16"/>
</dependencies>
</ivy-module>
I'm trying to set up my ant build so that the targets which run Ivy functions are completely separated from the ones that the continuous build and most developers run. I want one target to download updated dependencies, which I'll check in. Other targets will set up their classpath by including *.jar from the relevant directory.
I have two configurations:
<configurations>
<conf name="compile" />
<conf name="test" />
</configurations>
I have some dependencies:
<dependency
org="my.org"
name="some-lib"
rev="latest.release"
conf="compile->default" />
<dependency
org="my.org"
name="some-test-lib"
rev="latest.release"
conf="test->default" />
And I download those dependencies and their transitive dependencies using ivy:retrieve:
<ivy:retrieve
pattern="lib/[conf]/[type]/[artifact]-[revision].[ext]"
sync="true"
file="ivy.xml" />
The problem is that I'm seeing some duplicates jars between the compile and the test directories, which come from transitive dependencies. Since I want to check in all these jars and use them for creating classpaths, I'd like to avoid duplicates. Is this possible?
lib/compile/jar/some-lib-1.0.jar
lib/compile/jar/slf4j-api-1.5.11.jar
lib/test/jar/some-test-lib-1.0.jar
lib/test/jar/junit-4.7.jar
lib/test/jar/slf4j-api-1.5.11.jar
This is not duplication, each configuration is a separate set of jars and the ivy restrieve task is faithly creating each set....
Perhaps it would make more sense to create the classpaths directly, rather than populating a local lib directory.
Here's a snippet of my ANT build files:
<target name="get-dependencies">
<ivy:resolve/>
<ivy:cachepath pathid="compile.path" conf="compile" />
<ivy:cachepath pathid="test.path" conf="test" />
</target>
<target name="compile" depends="get-dependencies">
<javac srcdir="src" destdir="build/classes" classpathref="compile.path"/>
</target>
I normally only use the ivy retrieve task when I need to create a local copy of a set of jars, for example assembling a web app's directory:
<ivy:retrieve pattern="build/WEB_INF/lib/[artifact].[ext]" conf="runtime"/>
Update
Another alternative is to instruct ivy to exclude the slf4j module when downloading transient dependencies, as follows:
<dependency org="my.org" name="some-lib" rev="latest.release" conf="compile->default">
<exclude module="slf4j-api"/>
</dependency>
<dependency org="my.org" name="some-test-lib" rev="latest.release" conf="test->default">
<exclude module="slf4j-api"/>
</dependency>
If I can do this through Ivy directly, that would be best. For now I've solved the problem by just deleting duplicates using ant.
Try the following. Your test should extend compile
<dependency
org="my.org"
name="some-test-lib"
rev="latest.release"
conf="**test->compile**" />
If i am right IVY should find that test extends compile and would download slf4j only once.