Bug 47003

Summary: Add to ant lib classpath from within project file
Product: Ant Reporter: Martin von Gagern <Martin.vGagern>
Component: Optional TasksAssignee: Ant Notifications List <notifications>
Status: NEW ---    
Severity: enhancement Keywords: PatchAvailable
Priority: P2    
Version: 1.7.1   
Target Milestone: ---   
Hardware: PC   
OS: Linux   
Attachments: Imrpove <classloader> task, always provide core loader

Description Martin von Gagern 2009-04-08 14:25:32 UTC
I'm trying to write ant build files that only require developers to have ant core installed, and resolve any optional tasks through ivy. For some tasks that works fairly well by <taskdef>ing them with a proper nested classpath argument. At least in the case of <junitreport>, however, this approach fails when trying to format the combined report, due to missing TraXLiaison. I just filed bug #47002 about this.

On the whole, a cleaner solution would be preferable, though. I would imagine some expandable class loader within ant itself. Then there could be some task which adds a given resource collection to the internal ant classpath, making it available whenever an UnknownElement is instantiated or a task is executed.

This way, I could declare all optional tasks in ivy, could tell ivy to retrieve them, then could ant to add them to its classpath, and start using the tasks without any need to redefine tasks or specify bulky classpaths. Especially now that ivy is an official ant project, I would consider such scenarios very useful.
Comment 1 Stefan Bodewig 2009-04-09 06:09:35 UTC
I think you are looking for the (undocumented) classloader task.
Comment 2 Martin von Gagern 2009-04-09 09:56:29 UTC
Created attachment 23476 [details]
Imrpove <classloader> task, always provide core loader

(In reply to comment #1)
> I think you are looking for the (undocumented) classloader task.

Almost, but not quite. <classloader> is a good first step, because it allows modification of an existing class loader, in theory even the core class loader.

It fails to achieve this, though, because it identified the core task loader using a reference name not used anywhere else. ComponentHelper.initTasks() comes before <classloader> is executed, and already fixes the association between standard tasks and the core class loader in use at that moment. Furthermore, when started from the command line, ant by default has null as its core class loader.

The attached patch addresses those issues. Firstly it changes Main.runBuild to always provide an AntClassLoader as the core loader, so there will always be a loader to which additional path elements can be added.

Secondly it changes the behaviour of the classloader task when name is omitted or specified as "ant.coreLoader". In that case, the loader is not looked up by reference, but instead the core loader of the project is used. This avoids having to register a reference to this loader anywhere else.

I've tested using this simple build file:

<project default="demo">
  <target name="demo" description="Demonstrate bug 47003">
    <echo message="$${ant-junit.jar}='${ant-junit.jar}'"/>
    <classloader classpath="${ant-junit.jar}"/>
    <junit/>
  </target>
</project>

I had only ant.jar inside ant.library.dir, but had ant-junit.jar point at that optional task. Before my patch, the build failed because of a missing JUnitTask. With the patch applied, it failed due to missing junit.jar, emitting an error message specific to a correctly loaded <junit> task.
Comment 3 Jesse Glick 2010-01-18 09:51:27 UTC
My preference would be for fixes to particular tasks (such as bug #47002) to ensure that any necessary libraries can be supplied using a regular <classpath> element. Injecting JARs into the main Ant classpath has at least two disadvantages:

1. It breaks modularity for large builds, parts of which may have different expectations about library versions and so on.

2. It will likely not work when Ant is run in an embedded environment. In particular, Main is not used at all when run from NetBeans and possibly other containers.
Comment 4 Martin von Gagern 2010-06-01 12:45:44 UTC
(In reply to comment #3)
> My preference would be for fixes to particular tasks (such as bug #47002) to
> ensure that any necessary libraries can be supplied using a regular
> <classpath> element.

I agree that this should be an option, for cases where tweaking the main class path are either impossible or a worse alternative. But one approach doesn't precluse the other; if we can have both ways to address the issue, why not expose them both to developers in a fairly usable way, and let them decide what works best for them?

> Injecting JARs into the main Ant classpath has at least two
> disadvantages:
> 
> 1. It breaks modularity for large builds, parts of which may have different
> expectations about library versions and so on.

In my experience, many large projects tend to ship a shell script and batch file which builds a class path to be passed to the java vm running ant, in order to ensure that all required things are available on the ant class path and able to cooperate smoothly. So in those cases, having a single target in build.xml replace the two shell scripts certainly is a benefit.

In cases where you really and truly need different library versions on the classpath for different tasks, then there should be a <classpath> element to configure this, but I consider this a rare case so developers shouldn't be forced to juggle class paths for those 98% of projects that can work quite well with a single homogenous classpath.

> 2. It will likely not work when Ant is run in an embedded environment. In
> particular, Main is not used at all when run from NetBeans and possibly other
> containers.

Good point. Do you know of some unique entry point suitable for this classpath manipulation?

I'm willing to improve my patch further, but I'd like to know if this whole approach has a chance of landing in ant core one day, before I invest any more of my free time into coding improvements. Seeing that even the simpler bug #47002 has been open for well over a year without so much as a comment, I feel a bit pessimistic there.