You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@ant.apache.org by Rainer Noack <ra...@noacks.net> on 2005/09/01 00:52:18 UTC

RE: custom classloader for a task

Hi Jochen,

unfortunately, the displayed delegation hierarchy is typically not correct.
oata.AntClassLoader allways returns the System Classloader (class
sun.misc.Launcher$AppClassLoader) as its
parent.
See http://issues.apache.org/bugzilla/show_bug.cgi?id=35436
 
If you run ant from it's shell script you will have typically the following
delegation hierarchy:
* class org.apache.tools.ant.AntClassLoader (loads a task explicitely
defined by taskdef, contains the jars/dirs defined in taskdefs classpath
argument)
* class java.net.URLClassLoader   (created by Launcher, Classloader of
oata.Project, default tasks and most of the other ant stuff; typically
contains your classpath, the jars in $ANT_HOME/lib and the jdk's tools.jar)
* class sun.misc.Launcher$AppClassLoader (known as System-, Application- or
User- Classloader, that only loads the oata.launch.* classes, normally only
contains ant-launcher.jar)
* class sun.misc.Launcher$ExtClassLoader (Extension classloader, typically
contains the jars in $JRE_HOME/lib/ext)
* null (bootstrap classloader for all the jdk stuff, typically contains the
jars in $JRE_HOME/lib resp. $JDK_HOME/lib)

To find out the delegation hierarchy in maven you have to change your code
to something like this (not clean but should work, assumed your task extends
oata.Task):

public void execute() throws BuildException {
    ClassLoader loader = this.getClass().getClassLoader();
    if (loader instanceof AntClassLoader) {
        System.out.println(loader.getClass());
        loader = getProject().getCoreloader();
        if (loader == null)
            loader = Project.class.getClassLoader();
    }
    while (loader!=null) {
        System.out.println(loader.getClass());
        loader = loader.getParent();
    }
}

In the next weeks, I will publish a new patch (and a ready-to-use trial
version) for the proposed <classloader> and <classloaderreport> task (see
http://issues.apache.org/bugzilla/show_bug.cgi?id=28228) that gives a more
common 
solution for this problem.

Once knowing the environment's delegation hierarchy you have to decide
whether it is really possible to create a consistent second delegation
hierarchy for the conflicting jars or not. (This could be done by the
proposed <classloader> task).

However, if you want to run your task in very different environments (in
terms of classloading), I think forking is the cleanest solution. (BTW,
forking of compile tasks is IMHO mostly allways the best solution).

Cheers

Rainer

> -----Original Message-----
> From: Jochen Theodorou [mailto:blackdrag@gmx.org] 
> Sent: Tuesday, August 30, 2005 10:49 AM
> To: Ant Users List
> Subject: Re: custom classloader for a task
> 
> 
> Conor MacNeill schrieb:
> 
> > 
> > Jochen Theodorou wrote:
> > 
> >>Hi all,
> >>
> >>Te problem I have is a little complex but I hope you can help me. 
> >>Groovy has an ant task to compile groovy classes and a task to use 
> >>groovy from within ant see 
> http://groovy.codehaus.org/Groovy+Ant+Task 
> >>for details. But in some enviroments such as in maven with certain 
> >>plugins we have conflicting jars. I mean jars of a 
> different version 
> >>than needed by groovy. For example antlr or asm.
> >>
> >>Our current workaround for the compile task (groovyc) is to 
> fork the 
> >>VM. But this can't be the solution? I mean isn't there a 
> possibility 
> >>to load a task through a custom classloader? It's no 
> problem for me to 
> >>write such a loader, but where to wire it in? I know about the 
> >>loaderref attribute, but as far as I understand this 
> attribute is for 
> >>reusing a classloader. A normal classloader can't be used since a 
> >>normal classloader looks for a class first in the parent and if the 
> >>parent knows the conflicting jar/class then we have the 
> same problem 
> >>as before.
> > 
> > Since you are passing a classpath to the taskdef above, Ant will 
> > create a classloader to load this task's classes. What classes this 
> > classloader can see will depend on the classloader hierarchy under 
> > Maven. I have no idea what that will be.
> 
> classloader hirarchy for the task class without loaderref:
> 
> class org.apache.tools.ant.AntClassLoader
> class sun.misc.Launcher$AppClassLoader
> class sun.misc.Launcher$ExtClassLoader
> 
> printed by a task:
> 
>      public void execute() throws BuildException {
>          ClassLoader loader = this.getClass().getClassLoader();
>          while (loader!=null) {
>              System.out.println(loader.getClass());
>              loader = loader.getParent();
>          }
>      }
> 
> so it seems maven does not change the hirarchy...
> 
> > It is possible to specify a reverseloader="true" attribute 
> on an Ant 
> > taskdef. It is highly deprecated, unsupported, bad things 
> happen, etc. 
> > It will cause the classloader to consult it's jars first, 
> before those 
> > of its parent.
> 
> well, reverseloader=true might be the thing I am searching for, and a 
> test shows it works then... But these deprecated warnings are 
> annoying. 
> No way to work around this problem?
> 
> >>I heard that when you do loaderref="root" in a maven 
> project you get 
> >>the ant-loader, but that will be no help if the normal classpath 
> >>contains a conflicting jar for another task. Maybe someone 
> can explain 
> >>me if a classpath from a taskdef is added to the loader reffered by 
> >>loaderref. If so the ant-loader will be polluted too.
> > 
> > No, this does not happen - loaderref and classpath are exclusive, I 
> > think.
> 
> my tests are showing that with a loaderref I hae a different 
> AntClassLoader, than the normal Classloader, but I have still the 
> conflicting jar. When I enable reverseloader, then it's ok. 
> So the new 
> Loader has to share some classpath parts with the normal antloader 
> somewhere, because I am sure the sun.misc.Launcher does not caontain 
> that jar.
> 
> by blackdrag
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
> For additional commands, e-mail: user-help@ant.apache.org
> 


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


Re: custom classloader for a task

Posted by Jochen Theodorou <bl...@gmx.org>.
first, thx for all your help from everyone. To solve my problem I wrote 
a task that will store a laoder reference for the usage by my taskdef. 
That classloader does try to load all classes by himself instead 
delegating these classes to the parent as a normal classloader would do. 
To avoid duplicate definitions of ant classes, these classes are 
excluded. This works nicely here. Of course this is not the most clean 
solution, but better than nothing.

see
http://cvs.groovy.codehaus.org/viewrep/groovy/groovy/groovy-core/src/main/org/codehaus/groovy/tools/RootLoader.java
http://cvs.groovy.codehaus.org/viewrep/groovy/groovy/groovy-core/src/main/org/codehaus/groovy/ant/RootLoaderRef.java

for details

bye blackdrag


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