ant-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jacob Kjome <h...@visi.com>
Subject Re: ant and classloading
Date Tue, 17 Oct 2006 16:30:43 GMT
Quoting Peter Reilly <peter.kitt.reilly@gmail.com>:

> On 10/17/06, Jacob Kjome <hoju@visi.com> wrote:
> >
> > Very interesting stuff.  I will definitely use your tasks for my own
> > build files.  It would be very nice if your tasks were added to
> > Ant-1.7.  Any luck with that so far?
> >
> > I actually did come up with a solution to my problem, though.  I need
> > to be able to add path elements on the fly via the task to the
> > current classloader, but make sure it gets cleaned up immediately
> > thereafter so subsequent uses of the same classloader have no
> > remnants of any changes.  I wrote the following....
> >
> >          AntClassLoader xmlcLoader = null;
> >          String origClasspath = null;
> >          try {
> >              // Add the user-defined resource path to the current
> > classloader so
> >              // that XCatalog and DTD resources can be found by XMLC during
> >              // compilation.  Store the original classpath so it can be
> reset.
> >              // This avoids pollution of the classpath outside of the
> current
> >              // <xmlc/> task invocation.
> >              xmlcLoader = (AntClassLoader) getClass().getClassLoader();
> >              origClasspath = xmlcLoader.getClasspath();
> >              xmlcLoader.addPathElement(getResourcePath().toString());
> >
> >              ....
> >              ....
> >
> >              Class clazz = Class.forName(xmlcClassName, true, xmlcLoader);
> >
> >              ....
> >              ....
> >
> >          } catch (Exception x) {
> >              throw new BuildException(x);
> >          } finally {
> >              if (xmlcLoader != null && origClasspath != null) {
> >                  // Restore the original classpath to avoid leaking
> > user-defined
> >                  // resource path information outside the current
> invocation of
> >                  // the <xmlc/> task.
> >                  xmlcLoader.setClassPath(new Path(getProject(),
> > origClasspath));
> >              }
> >          }
> >
> > Anyone see a problem with this?
> The  "xmlcLoader = (AntClassLoader) getClass().getClassLoader();"
> may not always be correct - your class may be in $ANT_HOME/lib
> or in ~/.ant/lib,
> in this case the classloader will be a URLClassLoader.
>
> Peter

Hmm... On the one hand, it is unlikely that anyone would put my task (<xmlc/>)
in either of these lib directories because it would require all the task's
dependencies to be put there as well.  And since all the tasks dependencies are
required at runtime as well, it would make much more sense to keep them as part
of the project and just include them in the taskdef's classpath as needed.

That said, what could be done to account for the classloader not being an
instance of AntClassLoader and still implement the behavior that I want?  I
suppose I could reflect on the protected URLClassLoader.addURL(URL) method to
add any new classpath entries and restore the original URL's by repopulating
the result of the second call to getURLs() with the URLs obtained from the
first call to getURLs().

Is there another less hacky approach to this or is this my only option to get
the behavior I desire while being compatible with all possible task
installation scenarios?


Jake

> >
> > Jake
> >
> > At 03:41 PM 10/16/2006, you wrote:
> >  >maybe <classloaderreport> [1] can help you with diagnostics.
> >  >
> >  >rainer
> >  >
> >  >[1] http://enitsys.sourceforge.net/ant-classloadertask/
> >  >
> >  >
> >  >
> >  >> -----Original Message-----
> >  >> From: Jacob Kjome [mailto:hoju@visi.com]
> >  >> Sent: Monday, October 16, 2006 10:24 PM
> >  >> To: Ant Users List
> >  >> Subject: Re: ant and classloading
> >  >>
> >  >>
> >  >> Quoting Peter Reilly <peter.kitt.reilly@gmail.com>:
> >  >>
> >  >> > On 10/16/06, Jacob Kjome <hoju@visi.com> wrote:
> >  >> > >
> >  >> > > I'm not sure this is 100% an Ant question, but it is within
the
> >  >> > > context of
> >  >> > Ant.
> >  >> > >
> >  >> > > In my Ant task, I'm loading up a class using Class.forName()
and
> >  >> > > pass in a classloader that I would have expected to be
> >  >> assigned as
> >  >> > > the classloader for the class.  That doesn't seem to be
> >  >> the case.
> >  >> > > Here's what I'm doing..
> >  >> > >
> >  >> > >
> >  >> > > AntClassLoader customLoader = new
> >  >> > > AntClassLoader(getClass().getClassLoader(), true);
> >  >> > > customLoader.setClassPath(getResourcePath());
> >  >> > >
> >  >> > > Class clazz = Class.forName(clazzName, true, customLoader);
> >  >> > >
> >  >> > >
> >  >> >
> >  >> System.out.println(customLoader.getResource("org/myorganizatio
> >  >> n/resources/my.dtd"));
> >  >> > >
> >  >> >
> >  >> System.out.println(clazz.getClassLoader().getResource("org/myo
> >  >rganization/resources/my.dtd"));
> >  >> > >
> >  >> > >
> >  >> > > The DTD resource is found in the first case using the custom
> >  >> > > classloader where the user configured the resourcePath
> >  >> attribute of
> >  >> > > the task, but in the second case when I use the
> >  >> classloader of the
> >  >> > > class that I just loaded by passing in the custom
> >  >> classloader I just
> >  >> > > get "null".  The point of this is that the class I am
> >  >> loading needs
> >  >> > > to look up user-defined resources on the classpath.  With the
> >  >> > > System.out lines, I am just testing what my loaded class
> >  >> needs to do
> >  >> > > further down the line.
> >  >> > >
> >  >> > > Shouldn't the classloader of the class I just loaded be a
> >  >> reference
> >  >> > > to that which I passed into Class.forName()?
> >  >> >
> >  >> > No, Java uses a delegated classloader model. Normally, classloaders
> >  >> > search up the hierarchy, starting at the base classloader
> >  >> to load a
> >  >> > class. The reason for this is that classes are not the same unless
> >  >> > they are loaded from the same classloader. To take a simple
> >  >> case one
> >  >> > would want java.lang.Object to be the same no matter how it
> >  >> is loaded.
> >  >> >
> >  >>
> >  >> So, is there a way to add some more classpath information to
> >  >> the base classloader that loaded the task?  I have no ability
> >  >> to pass a classloader to the code that attempts to load
> >  >> configured resources.  The classloader that loads the class
> >  >> needs to make this user-defined classpath available.
> >  >>
> >  >> Come to think of it, can I just cast the classloader to an
> >  >> AntClassLoader and add the path to it using
> >  >> addPathElement(String)?  I guess I didn't try that yesterday,
> >  >> but I'll try it tonight.
> >  >>
> >  >> Of course, it seems like that might cause side effects for
> >  >> later calls to the same task where an added path element from
> >  >> one task use would be available for another.
> >  >>
> >  >> What other way is there?  Would I need to fork a new process
> >  >> and define the classpath from the get-go for each call?  I'd
> >  >> like to use something less heavyweight, but not have side effects.
> >  >>
> >  >> Jake
> >  >>
> >  >> >
> >  >> > > This is probably more
> >  >> > > of a general classloading question than an Ant question, but
I'm
> >  >> > > guessing others have had to deal with that here.  I must
> >  >> be making a
> >  >> > > bad assumption, but it seems like something like this should
be
> >  >> > > possible.
> >  >> > >
> >  >> > > My only workaround right now is to add the extra classpath
> >  >> > > information to the Task definition classpath.  However,
> >  >> that is not
> >  >> > > intuitive for task users and a pretty ugly hack.  Is
> >  >> there any way
> >  >> > > to do this?  I've run into and solved many classloading issues
in
> >  >> > > the past, but I've never had to deal with this
> >  >> specifically.  I have
> >  >> > > to imagine someone has solved this problem already.  Care
> >  >> to share
> >  >> > > the
> >  >> > solution?
> >  >> > >
> >  >> > >
> >  >> > > Jake
> >  >> > >
> >  >> > >
> >  >> > >
> >  >> --------------------------------------------------------------------
> >  >> > > -
> >  >> > > 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
> >  >> >
> >  >>
> >  >>
> >  >>
> >  >>
> >  >> ---------------------------------------------------------------------
> >  >> 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
> >
> >
> > ---------------------------------------------------------------------
> > 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
>




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


Mime
View raw message