ant-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Nicolas Lalevée <nicolas.lale...@hibnet.org>
Subject Re: controlling ClassLoader when programmatically invoking Ant
Date Sat, 21 Jul 2012 13:10:35 GMT
Hi Mitch,

Le 21 juil. 2012 à 07:37, Mitch Gitman a écrit :

> Technically, this message is better suited for the ant-user list, but I'm
> thinking I'm more apt to get an answer on this list. (I'm also thinking
> this is the better place for me to cash in some chits for my having
> submitted patches for three Ivy issues I mentioned recently on this list.
> Subject: "extends and buildlist on 2.3.0-rc1....")

I am intended to give it a look very soon, I have seen all the activity you have done, I don't
want to waste it :)

> Here's my problem. I'm trying to do a JUnit test of some Ivy functionality
> (actually, relating to the aforementioned Ivy bugs) by programmatically
> creating and executing an Ant Project object. Everything runs just fine.
> I'm able to execute targets and even tie in a BuildListener and a
> BuildLogger to tap into output and error and check if the build failed.
> 
> The problem is, everything works a little too well. Take a look at the
> following example build.xml:
> <project xmlns:ivy="antlib:org.apache.ivy.ant" name="resolve-test"
> default="build">
> 
>    <target name="build">
>    <ivy:settings file="ivysettings.xml" />
>    <ivy:resolve ... />
>    </target>
> </project>
> 
> I've abbreviated the ivy:resolve call, but take it from me that everything
> works, including running the test directly from within an IDE. It
> shouldn't. Nowhere am I specifying the classpath containing the JAR for Ivy
> itself. Nowhere am I even doing the taskdef for Ivy.

In fact, just by writing xmlns:ivy="antlib:org.apache.ivy.ant", Ant does a lookup for the
Ivy tasks. It will look for org/apache/ivy/ant/antlib.xml in the classpath, derived from the
uri definition of the xmlns.
So I guess that in your IDE, it works since you have Ivy in your classpath.

> And in fact, if I run this build.xml straight from the command line, it
> fails like you would expect:
> Problem: failed to create task or type antlib:org.apache.ivy.ant:settings
> ...

This means that the Ivy jar is neither in the Ant classpath ($ANT_HOME/lib/), nor in your
ant user lib directory ($HOME/.ant/lib).

> I can only think that the key method I want to take advantage of is this in
> Project:
>    public void setCoreLoader(ClassLoader coreLoader) {
>        this.coreLoader = coreLoader;
>    }
> 
> What's interesting is that the command-line entry point for Ant in
> org.apache.tools.ant.Main ends up passing null to setCoreLoader, in which
> case "the parent classloader should be used," according to the method's
> Javadoc. At this point, I go take a look at the scripts that launch Ant and
> my eyes get blurry. But I believe what I want to do is manually construct a
> ClassLoader as if I were running "java -cp ..." with the contents of Ant's
> lib directory. (I'm showing my ignorance of ClassLoaders here, I realize.)
> Perhaps someone can point me to an elegant way to accomplish that.

On the command line, the jvm is given only the ant-launcher.jar, it will be the content of
the system classloader.
Then in org.apache.tools.ant.launch.Launcher.run(String[]), we can see the ant Main class
is loaded and launched with this classloader:
new URLClassLoader(jars, Launcher.class.getClassLoader());
The system is the parent, the jars listed from $ANT_HOME/lib/, $HOME/.ant/lib and other jars
from the jvm (tools.jar for instance) will be the content of that classloader. This last classloader
will be the parent classloader of the Project instance.

Now in your IDE, you launch your unit test with every jar listed in your classpath, so every
thing is already available in the system classlaoder. And that system classloader is the parent
classloader of the Project instance. So lookups works.
So if you want thing to not work, you'll have to build indeed an URLClassloader, just like
org.apache.tools.ant.launch.Launcher.run does. But without any parent classlaoder, otherwise
you end up again with the full classpath of your project in the IDE.

But If I were you, I wouldn't bother trying to mimic Ant classloading in a unit test. The
important thing is to be sure that you run against the expected version of Ant and Ivy. And
relying on the content of a $HOME/.ant/lib is quite unsafe.

Nicolas


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org


Mime
View raw message