You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@buildr.apache.org by Ed Smiley <es...@ebrary.com> on 2010/12/02 00:16:38 UTC

Re: Java

Woohoo!

I just tried the following change based on your suggestion that I explicitly
look at the current thread's context class loader:
#old version:
#Java.java.lang.Class.forName(dep.class).asSubclass(Java.java.lang.Class.forName(dep.subclass))

#new version:
Java.java.lang.Class.forName(dep.class, true,
Java.java.lang.Thread.currentThread().getContextClassLoader()).asSubclass(Java.java.lang.Class.forName(dep.subclass))

And the ugly little guy works just great. (whiskey tango foxtrot, but hey)

--Ed

On Tue, Nov 30, 2010 at 1:32 PM, Ed Smiley <es...@ebrary.com> wrote:

> No I haven't.  I'll give it a whirl.
>
>
> On Tue, Nov 30, 2010 at 1:24 PM, Alex Boisvert <al...@gmail.com>wrote:
>
>> Have you tried this?
>>
>> Class.forName("com.mypackage.SomeImpl", true,
>> Thread.currentThread().getContextClassLoader())
>>
>> alex
>>
>> On Tue, Nov 30, 2010 at 11:51 AM, Ed Smiley <es...@ebrary.com> wrote:
>>
>> > First I will explain what I am doing.  (And which used to work.)
>> > If this confuses you, you can skip down below to read the details of the
>> > problem.  That's in section 2.
>> >
>> > I include this information only because it is an order of complexity
>> more
>> > complicated than most of the build programs that I have heard discussed.
>> >  So
>> > the answer "no problem, just rewrite everything" makes me, well, a bit
>> > nervous. :)
>> >
>> > 1.The background is that I have a main application consisting of a
>> number
>> > of
>> > jars and wars with its own build system, and jar classloader.  I then
>> have
>> > a
>> > build system that uses Buildr to create one or more jars which contain
>> > configurations and/or Java code and which are deployed to the main
>> > application. The main application knows how to introspect all the jar
>> files
>> > at startup, so this is highly extensible.
>> >
>> > If they contain only configurations, they have a variety of references
>> to
>> > either main application classes or standard library classes in the main
>> > application.  The main application dependencies are resolved by Buildr
>> by
>> > using a toolkit of Ruby code (libraries it uses for construction of the
>> > configurations) and jar files that is deployed as a Maven repo.  If they
>> > also contain Java code tehmselves, they need to have the references to
>> that
>> > code in their configuration files.  The main application has its own
>> > dependency injection mechanism that looks at these configuration files
>> and
>> > uses its classloader to load these classes.  To make it more
>> interesting, I
>> > also have written a buildr code generator to build the build system.
>>  (Sort
>> > of like a Rails generator.)
>> >
>> > Despite the inherent complexity, this works end to end fine.  The only
>> real
>> > issue is *not* in building or deploying, it is in the built in tests
>> that
>> > the build system manufactures.  By default two basic kinds of tests are
>> > run:
>> > first, the presence of every required configuration file is checked
>> inside
>> > the product jars with rspec; second, every class referenced in the
>> > configuration files is checked using Java.java.lang.Class.forName().
>> >
>> > 2.  The problem is the second test, Class.forName(), it can no longer
>> see
>> > the classes the build system creates.  This is a GREAT feature, and I
>> put a
>> > lot of effort into it, so it would be nice to make it work.  However, I
>> can
>> > function by "turning it off". :((
>> >
>> > Here's a simple example:
>> >
>> > To avoid the readonly nature of the CLASSPATH, very early on I set the
>> > CLASSPATH to INCLUDE the target jars that do no yet exist.  And this
>> used
>> > to
>> > work like a champ....
>> >      FileList[LIBS].each do |lib|
>> >         Java.classpath << lib
>> >      end
>> >      # package products: explicit, they DO NOT EXIST YET
>> >      Java.classpath << "#{RELEASE}/ext-lib/common.jar"
>> >      Java.classpath << "#{RELEASE}/lib/#{GROUP}-#{VERSION_NUMBER}.jar"
>> >      Java.classpath <<
>> > "#{RELEASE}/lib/#{GROUP}-#{vertical}-#{VERSION_NUMBER}.jar"
>> >
>> > RELEASE is just a directory that reassembles the jar products with
>> possibly
>> > designated other jars.  This is a build option.
>> >
>> > I then do tests that come down to the equivalent of
>> >
>> >
>> >
>> Java.java.lang.Class.forName("com.mypackage.SomeImpl").asSubclass(Java.java.lang.Class.forName("com.mypackage.SomeIfc")
>> >
>> > That's the problem in a nutshell!
>> >
>> > Pretty obvious if I specify a type of component, it must both exist, and
>> be
>> > the correct type for the component.  It also means that I will know that
>> > there is a typo in the configuration I will catch it before I deploy my
>> > jars
>> > in the main application.  Unfortunately, now I cannot do that.
>> >
>> > So to test it, all you need to do it have buildr build you a project,
>> add
>> > one class to the source directory, add in the target package jar to the
>> > classpath in a location that it will eventually be in.  Then make a task
>> > that depends on packaging (or packaging and copying to the location you
>> > designate) and that runs the Class.forName check.  My prediction is
>> that,
>> > if
>> > properly constructed, this will work on Linux, on Windows, and on a Mac
>> > with
>> > an earlier JVM, but NOT with the latest Mac JVM (with the header files
>> > restored).
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> > On Mon, Nov 29, 2010 at 6:45 PM, Alex Boisvert <alex.boisvert@gmail.com
>> > >wrote:
>> >
>> > > Can you post a simple example of what you're trying to do?
>> > >
>> > > On Monday, November 29, 2010, Ed Smiley <es...@ebrary.com> wrote:
>> > > > Couldn't get that to work....
>> > > >
>> > > > On Wed, Nov 17, 2010 at 3:54 PM, Ed Smiley <es...@ebrary.com>
>> wrote:
>> > > >
>> > > >> Interesting.
>> > > >>
>> > > >> I saw a post by "Arton", the guy mentioned in the release notes,
>> > > indicating
>> > > >> that the proper way to add a jar to the classpath is using the new
>> > > dynamic
>> > > >> functionality
>> > > >>
>> > > >> Rjb::add_classpath, rather than setting it really early on though
>> > > >> Java.classpath.  I am messing with that approach, currently.
>> > > >>
>> > > >> On Wed, Nov 17, 2010 at 9:50 AM, Alex Boisvert <
>> > alex.boisvert@gmail.com
>> > > >wrote:
>> > > >>
>> > > >>> There were some changes in RJB between 1.2.5 and 1.3.3 related to
>> > > >>> classloading.  In particular, RJB now uses a URLClassLoader
>> instead
>> > of
>> > > the
>> > > >>> JVM's system classloader.
>> > > >>>
>> > > >>> https://github.com/arton/rjb/blob/master/ChangeLog
>> > > >>>
>> > > >>> <https://github.com/arton/rjb/blob/master/ChangeLog>Not sure it
>> > causes
>> > > >>> the
>> > > >>> issue you're seeing but I thought it worth mentioning.
>> > > >>>
>> > > >>> alex
>> > > >>>
>> > > >>>
>> > > >>> On Wed, Nov 17, 2010 at 8:59 AM, Ed Smiley <es...@ebrary.com>
>> > wrote:
>> > > >>>
>> > > >>> > In the aftermath of changing over to getting Buildr to work with
>> > the
>> > > new
>> > > >>> > JVM, I am seeing yet another issue, this one a tad obscure.
>> > > >>> > It's a little complicated to explain so bear with me.
>> > > >>> >
>> > > >>> > In code (that is essentially the same and was working before) I
>> had
>> > a
>> > > >>> step
>> > > >>> > where I set up a Java classpath early on in the build process
>> which
>> > > >>> > included
>> > > >>> > my (not yet existing) package jar file products.  I calculate
>> where
>> > > they
>> > > >>> > would end up and what they would be called to avoid a circular
>> > > >>> dependency
>> > > >>> > on
>> > > >>> > package object, and also to set the classpath for RJB early on
>> (as
>> > it
>> > > >>> lets
>> > > >>> > you set it later, but does not honor the new value).  I then
>> have a
>> > > >>> > validation step where a list of Java classes and their expected
>> > > >>> subclasses
>> > > >>> > are instantiated (using
>> > > >>> >
>> > > >>> >
>> > > >>>
>> > >
>> >
>> Java.java.lang.Class.forName(dep.class).asSubclass(Java.java.lang.Class.forName(dep.subclass))).
>> > > >>> >  As odd as it sounds this worked correctly, and have been using
>> > this
>> > > for
>> > > >>> > the
>> > > >>> > last six weeks until I hit this snag.
>> > > >>> >
>> > > >>> > Now (and I put in debugging to ensure that that classpath is as
>> I
>> > > think
>> > > >>> it
>> > > >>> > is and that the jar file exists before running this check)
>> classes
>> > > that
>> > > >>> are
>> > > >>> > built in my jars are unable to be instantiated by the RJB Java
>> > object
>> > > >>> and I
>> > > >>> > get spurious errors.
>> > > >>> >
>> > > >>> > Any insights?  Has this environment done something to unhinge
>> the
>> > RJB
>> > > >>> > "classpath lifecycle"?  Perhaps something now creating the JVM
>> > > earlier?
>> > > >>> >
>> > > >>>
>> > > >>
>> > > >>
>> > > >
>> > >
>> >
>>
>
>

Re: Java

Posted by Alex Boisvert <al...@gmail.com>.
Glad it worked :)

I really wish Class.forName() with 1 argument was flagged as deprecated so
people would gradually stop using it.   It's been causing trouble ever since
context class loader was introduced (in Java 1.2).

alex


On Wed, Dec 1, 2010 at 3:16 PM, Ed Smiley <es...@ebrary.com> wrote:

> Woohoo!
>
> I just tried the following change based on your suggestion that I
> explicitly
> look at the current thread's context class loader:
> #old version:
>
> #Java.java.lang.Class.forName(dep.class).asSubclass(Java.java.lang.Class.forName(dep.subclass))
>
> #new version:
> Java.java.lang.Class.forName(dep.class, true,
>
> Java.java.lang.Thread.currentThread().getContextClassLoader()).asSubclass(Java.java.lang.Class.forName(dep.subclass))
>
> And the ugly little guy works just great. (whiskey tango foxtrot, but hey)
>
> --Ed
>
> On Tue, Nov 30, 2010 at 1:32 PM, Ed Smiley <es...@ebrary.com> wrote:
>
> > No I haven't.  I'll give it a whirl.
> >
> >
> > On Tue, Nov 30, 2010 at 1:24 PM, Alex Boisvert <alex.boisvert@gmail.com
> >wrote:
> >
> >> Have you tried this?
> >>
> >> Class.forName("com.mypackage.SomeImpl", true,
> >> Thread.currentThread().getContextClassLoader())
> >>
> >> alex
> >>
> >> On Tue, Nov 30, 2010 at 11:51 AM, Ed Smiley <es...@ebrary.com> wrote:
> >>
> >> > First I will explain what I am doing.  (And which used to work.)
> >> > If this confuses you, you can skip down below to read the details of
> the
> >> > problem.  That's in section 2.
> >> >
> >> > I include this information only because it is an order of complexity
> >> more
> >> > complicated than most of the build programs that I have heard
> discussed.
> >> >  So
> >> > the answer "no problem, just rewrite everything" makes me, well, a bit
> >> > nervous. :)
> >> >
> >> > 1.The background is that I have a main application consisting of a
> >> number
> >> > of
> >> > jars and wars with its own build system, and jar classloader.  I then
> >> have
> >> > a
> >> > build system that uses Buildr to create one or more jars which contain
> >> > configurations and/or Java code and which are deployed to the main
> >> > application. The main application knows how to introspect all the jar
> >> files
> >> > at startup, so this is highly extensible.
> >> >
> >> > If they contain only configurations, they have a variety of references
> >> to
> >> > either main application classes or standard library classes in the
> main
> >> > application.  The main application dependencies are resolved by Buildr
> >> by
> >> > using a toolkit of Ruby code (libraries it uses for construction of
> the
> >> > configurations) and jar files that is deployed as a Maven repo.  If
> they
> >> > also contain Java code tehmselves, they need to have the references to
> >> that
> >> > code in their configuration files.  The main application has its own
> >> > dependency injection mechanism that looks at these configuration files
> >> and
> >> > uses its classloader to load these classes.  To make it more
> >> interesting, I
> >> > also have written a buildr code generator to build the build system.
> >>  (Sort
> >> > of like a Rails generator.)
> >> >
> >> > Despite the inherent complexity, this works end to end fine.  The only
> >> real
> >> > issue is *not* in building or deploying, it is in the built in tests
> >> that
> >> > the build system manufactures.  By default two basic kinds of tests
> are
> >> > run:
> >> > first, the presence of every required configuration file is checked
> >> inside
> >> > the product jars with rspec; second, every class referenced in the
> >> > configuration files is checked using Java.java.lang.Class.forName().
> >> >
> >> > 2.  The problem is the second test, Class.forName(), it can no longer
> >> see
> >> > the classes the build system creates.  This is a GREAT feature, and I
> >> put a
> >> > lot of effort into it, so it would be nice to make it work.  However,
> I
> >> can
> >> > function by "turning it off". :((
> >> >
> >> > Here's a simple example:
> >> >
> >> > To avoid the readonly nature of the CLASSPATH, very early on I set the
> >> > CLASSPATH to INCLUDE the target jars that do no yet exist.  And this
> >> used
> >> > to
> >> > work like a champ....
> >> >      FileList[LIBS].each do |lib|
> >> >         Java.classpath << lib
> >> >      end
> >> >      # package products: explicit, they DO NOT EXIST YET
> >> >      Java.classpath << "#{RELEASE}/ext-lib/common.jar"
> >> >      Java.classpath << "#{RELEASE}/lib/#{GROUP}-#{VERSION_NUMBER}.jar"
> >> >      Java.classpath <<
> >> > "#{RELEASE}/lib/#{GROUP}-#{vertical}-#{VERSION_NUMBER}.jar"
> >> >
> >> > RELEASE is just a directory that reassembles the jar products with
> >> possibly
> >> > designated other jars.  This is a build option.
> >> >
> >> > I then do tests that come down to the equivalent of
> >> >
> >> >
> >> >
> >>
> Java.java.lang.Class.forName("com.mypackage.SomeImpl").asSubclass(Java.java.lang.Class.forName("com.mypackage.SomeIfc")
> >> >
> >> > That's the problem in a nutshell!
> >> >
> >> > Pretty obvious if I specify a type of component, it must both exist,
> and
> >> be
> >> > the correct type for the component.  It also means that I will know
> that
> >> > there is a typo in the configuration I will catch it before I deploy
> my
> >> > jars
> >> > in the main application.  Unfortunately, now I cannot do that.
> >> >
> >> > So to test it, all you need to do it have buildr build you a project,
> >> add
> >> > one class to the source directory, add in the target package jar to
> the
> >> > classpath in a location that it will eventually be in.  Then make a
> task
> >> > that depends on packaging (or packaging and copying to the location
> you
> >> > designate) and that runs the Class.forName check.  My prediction is
> >> that,
> >> > if
> >> > properly constructed, this will work on Linux, on Windows, and on a
> Mac
> >> > with
> >> > an earlier JVM, but NOT with the latest Mac JVM (with the header files
> >> > restored).
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >
> >> > On Mon, Nov 29, 2010 at 6:45 PM, Alex Boisvert <
> alex.boisvert@gmail.com
> >> > >wrote:
> >> >
> >> > > Can you post a simple example of what you're trying to do?
> >> > >
> >> > > On Monday, November 29, 2010, Ed Smiley <es...@ebrary.com> wrote:
> >> > > > Couldn't get that to work....
> >> > > >
> >> > > > On Wed, Nov 17, 2010 at 3:54 PM, Ed Smiley <es...@ebrary.com>
> >> wrote:
> >> > > >
> >> > > >> Interesting.
> >> > > >>
> >> > > >> I saw a post by "Arton", the guy mentioned in the release notes,
> >> > > indicating
> >> > > >> that the proper way to add a jar to the classpath is using the
> new
> >> > > dynamic
> >> > > >> functionality
> >> > > >>
> >> > > >> Rjb::add_classpath, rather than setting it really early on though
> >> > > >> Java.classpath.  I am messing with that approach, currently.
> >> > > >>
> >> > > >> On Wed, Nov 17, 2010 at 9:50 AM, Alex Boisvert <
> >> > alex.boisvert@gmail.com
> >> > > >wrote:
> >> > > >>
> >> > > >>> There were some changes in RJB between 1.2.5 and 1.3.3 related
> to
> >> > > >>> classloading.  In particular, RJB now uses a URLClassLoader
> >> instead
> >> > of
> >> > > the
> >> > > >>> JVM's system classloader.
> >> > > >>>
> >> > > >>> https://github.com/arton/rjb/blob/master/ChangeLog
> >> > > >>>
> >> > > >>> <https://github.com/arton/rjb/blob/master/ChangeLog>Not sure it
> >> > causes
> >> > > >>> the
> >> > > >>> issue you're seeing but I thought it worth mentioning.
> >> > > >>>
> >> > > >>> alex
> >> > > >>>
> >> > > >>>
> >> > > >>> On Wed, Nov 17, 2010 at 8:59 AM, Ed Smiley <es...@ebrary.com>
> >> > wrote:
> >> > > >>>
> >> > > >>> > In the aftermath of changing over to getting Buildr to work
> with
> >> > the
> >> > > new
> >> > > >>> > JVM, I am seeing yet another issue, this one a tad obscure.
> >> > > >>> > It's a little complicated to explain so bear with me.
> >> > > >>> >
> >> > > >>> > In code (that is essentially the same and was working before)
> I
> >> had
> >> > a
> >> > > >>> step
> >> > > >>> > where I set up a Java classpath early on in the build process
> >> which
> >> > > >>> > included
> >> > > >>> > my (not yet existing) package jar file products.  I calculate
> >> where
> >> > > they
> >> > > >>> > would end up and what they would be called to avoid a circular
> >> > > >>> dependency
> >> > > >>> > on
> >> > > >>> > package object, and also to set the classpath for RJB early on
> >> (as
> >> > it
> >> > > >>> lets
> >> > > >>> > you set it later, but does not honor the new value).  I then
> >> have a
> >> > > >>> > validation step where a list of Java classes and their
> expected
> >> > > >>> subclasses
> >> > > >>> > are instantiated (using
> >> > > >>> >
> >> > > >>> >
> >> > > >>>
> >> > >
> >> >
> >>
> Java.java.lang.Class.forName(dep.class).asSubclass(Java.java.lang.Class.forName(dep.subclass))).
> >> > > >>> >  As odd as it sounds this worked correctly, and have been
> using
> >> > this
> >> > > for
> >> > > >>> > the
> >> > > >>> > last six weeks until I hit this snag.
> >> > > >>> >
> >> > > >>> > Now (and I put in debugging to ensure that that classpath is
> as
> >> I
> >> > > think
> >> > > >>> it
> >> > > >>> > is and that the jar file exists before running this check)
> >> classes
> >> > > that
> >> > > >>> are
> >> > > >>> > built in my jars are unable to be instantiated by the RJB Java
> >> > object
> >> > > >>> and I
> >> > > >>> > get spurious errors.
> >> > > >>> >
> >> > > >>> > Any insights?  Has this environment done something to unhinge
> >> the
> >> > RJB
> >> > > >>> > "classpath lifecycle"?  Perhaps something now creating the JVM
> >> > > earlier?
> >> > > >>> >
> >> > > >>>
> >> > > >>
> >> > > >>
> >> > > >
> >> > >
> >> >
> >>
> >
> >
>