I'm using the Restlet framework [1] but I'll try to make that a
non-factor. I'm using Groovy 1.5.6 on an Intel Mac with Mac OS X
10.5.4, using Apple's 1.5.0_13-119 JVM.
My problem, essentially, is that I've got a Java class which knows the
name of a Groovy class, and it's trying to instantiate it with
Class.forName(), and I'm getting a ClassNotFoundException:
java.lang.ClassNotFoundException: com.arc90.slices.resources.AssignmentsResource
at org.codehaus.groovy.tools.RootLoader.findClass(RootLoader.java:146)
at java.lang.ClassLoader.loadClass(ClassLoader.java:316)
at org.codehaus.groovy.tools.RootLoader.loadClass(RootLoader.java:118)
at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:374)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:164)
at org.restlet.ext.wadl.WadlApplication.attachResource(WadlApplication.java:267)
And here's line 267 of WadlApplication.java:
final Class targetClass =
Class.forName(currentResource.getIdentifier());
currentResource.getIdentifier() just returns a string containing the
fully qualified name of a Groovy class.
I have no trouble instantiating the same class by name from within my
Groovy code, so I'm fairly certain that I don't have any obvious
classpath problems.
My basic question is: is there a way to effect class loading for
regular Java classes, so they can find Groovy classes when using
Class.forName()?
I'm beginning to suspect not, because Class.forName(name) doesn't even
work from within a Groovy script; I need to use Class.forName(name,
initialize, loader) and pass in the current class's loader.
If that's the answer, then I'm thinking what I'll want to do is modify
the Restlet class so I can pass a ClassLoader into it. Does that make
sense?
Thank you!!
--
Avi Flax » Lead Technologist » Partner » Arc90 » http://arc90.com
Hi, make sure that this bug
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4971254
is not the source of your problem.
---------------------------------------------------------------------
To unsubscribe from this list, please visit:
http://xircles.codehaus.org/manage_email
Class#forName(String) works if Class#forName(String) is able to choose a
class loader that knows the class you are trying to load. Don't ask me
how Class#forName(String) chooses a class loader, because that is "Black
Art of the VM".... and it has problems in Groovy. Basically you go
better when you use the forName call that takes a class loader. Then
this class loader will be used and you can ensure that it knows the
class you want to load. As I see from the trace you have a loader that
is a child to RootLoader.. I suspect none of them knows the Groovy
class, because I think in that case we would see a GroovyClassLoader
somewhere in the trace.
> I'm beginning to suspect not, because Class.forName(name) doesn't even
> work from within a Groovy script; I need to use Class.forName(name,
> initialize, loader) and pass in the current class's loader.
yes
> If that's the answer, then I'm thinking what I'll want to do is modify
> the Restlet class so I can pass a ClassLoader into it. Does that make
> sense?
possibly ;) If you want to call Groovy scripts created at runtime from
within your restlet and you know only the name... then a classloader
will surely help. on the other hand.. you have the name... you have the
script, isn't it possible to transport the class instead of the name?
bye blackdrag
--
Jochen "blackdrag" Theodorou
The Groovy Project Tech Lead (http://groovy.codehaus.org)
http://blackdragsview.blogspot.com/
http://www.g2one.com/
> Hi, make sure that this bug
>
> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4971254
>
> is not the source of your problem.
Thanks Jürgen, I modified the Java source to use the more verbose form
of Class.forName(), and the behavior is still the same. So I don't
think this is it.
> Class#forName(String) works if Class#forName(String) is able to choose a
> class loader that knows the class you are trying to load. Don't ask me how
> Class#forName(String) chooses a class loader, because that is "Black Art of
> the VM".... and it has problems in Groovy. Basically you go better when you
> use the forName call that takes a class loader. Then this class loader will
> be used and you can ensure that it knows the class you want to load. As I
> see from the trace you have a loader that is a child to RootLoader.. I
> suspect none of them knows the Groovy class, because I think in that case we
> would see a GroovyClassLoader somewhere in the trace.
Thanks Jochen. This is a little frustrating for me; I'd hoped that
Groovy and Java would get along better than this. The way I see it, in
my JVM I've defined classes, and they should be able to refer to each
other by name!
>> If that's the answer, then I'm thinking what I'll want to do is modify
>> the Restlet class so I can pass a ClassLoader into it. Does that make
>> sense?
>
> possibly ;) If you want to call Groovy scripts created at runtime from
> within your restlet and you know only the name... then a classloader will
> surely help. on the other hand.. you have the name... you have the script,
> isn't it possible to transport the class instead of the name?
Unfortunately, no, that won't work in this case, the Java class will
have to instantiate the Groovy class by name. I'm poking around in the
Java class now to see if I can pass in a specific ClassLoader, but
it's looking like it might be a pain.
What I *really* want to be able to do is somehow tell the system's
root ClassLoader to be aware of Groovy classes. Is that possible
somehow?
Thanks!
> ...I'm thinking what I'll want to do is modify
> the Restlet class so I can pass a ClassLoader into it...
OK, I've tried this approach and it does work. And I might be able to
get this change committed to Restlet, so I'll probably be OK in this
case.
But it's troubling to think that, in general, Java classes won't be
able to find my Groovy classes, unless I can make sure that I can
specify the ClassLoader to use. And I'm sure there will be plenty of
cases where I can't change the Java class. And even when I can, it
could be quite a hassle.
So does anyone know whether there's a way to get the JVM's root/system
ClassLoaders to find Groovy classes?
One way to make this very easy is to use Spring. For example, I had no problem to run Groovy scripts as Quartz jobs, and Quartz knows nothing about Groovy.
>> So does anyone know whether there's a way to get the JVM's root/system
>> ClassLoaders to find Groovy classes?
>
> One way to make this very easy is to use Spring. For example, I had no problem to run
> Groovy scripts as Quartz jobs, and Quartz knows nothing about Groovy.
OK, well, I'm not using Spring right now -- but maybe someone knows
how Spring does this?
don't get that wrong, they do play nicely together, but you are working
in a multi class loader architecture, so things are not so easy anymore
even if you would use only Java classes. Or to say it in a different
way: you could have the exact same problem with only Java code.
For example... Say there is a loader R with two children A and B. Let's
say we have a class names X loaded by B. If I now try to load X through
R or A, then it will fail. I need to load X through B or a child of B.
So if you have one loader per web application and then create another
loader for the Groovy scripts, which is a child to that loader or a
sibling, then any class loading attempts through the per web application
won't work for Groovy scripts.
>>> If that's the answer, then I'm thinking what I'll want to do is modify
>>> the Restlet class so I can pass a ClassLoader into it. Does that make
>>> sense?
>> possibly ;) If you want to call Groovy scripts created at runtime from
>> within your restlet and you know only the name... then a classloader will
>> surely help. on the other hand.. you have the name... you have the script,
>> isn't it possible to transport the class instead of the name?
>
> Unfortunately, no, that won't work in this case, the Java class will
> have to instantiate the Groovy class by name. I'm poking around in the
> Java class now to see if I can pass in a specific ClassLoader, but
> it's looking like it might be a pain.
>
> What I *really* want to be able to do is somehow tell the system's
> root ClassLoader to be aware of Groovy classes. Is that possible
> somehow?
before I answer that I need to know more about your classloader setup.
For example I saw RootLoader, but does Restlet use that by default? If
it is possible to put your own classloader somewhere there in between,
then maybe I know of a wayto solve the problem easily. The next thing I
would need to know.. why do you need to load a class by using
Class#forName at all? There is always the possibility to use the name
directly or to use a static structure that allows you access.
precompile them, like you do with Java