Details
-
Bug
-
Status: Closed
-
Major
-
Resolution: Fixed
-
1.0-JSR-1
-
None
Description
- Alan <alan-groovy-user@engrm.com> [2005-06-03 14:57]:
>> * Alan <alan-groovy-user@engrm.com> [2005-05-21 12:31]:
>>> > * Christof Vollrath <christof@taobits.net> [2005-05-20 15:13]:
>>>> > > I had the same problem while developping GvTags (www.gvtags.org).
>>>> > > I solved it by writing a proxy object for HttpServletRequest in Java,
>>>> > > which accesses HttpServletRequest and is included in my application,
>>>> > > so that it can be accessed by Groovy.
>>>> > > This is much better then turning bytecode compilation off.
>>>> > > But I would be happy if you find a solution without the need for
>>>> > > a proxy object.
>>> > The following is a bunch of guessing. Not wild guesses, I don't
>>> > think, reasonable guesses, but I've not read through the source
>>> > code for Groovy nor Tomcat. I claim no experience, nor
>>> > authority.
>>> >
>>> > The Groovy ClassLoader (this is a guess) gets a copy of the class
>>> > file as a stream, using the ClassLoader().getResource() method.
>>> > It then runs it through ASM to generate bytecode for a proxy
>>> > object that supports the GroovyObject interface.
>>> >
>>> > Tomcat has a special class loader (guessing) to support the
>>> > class loading requirements of web applications, each web
>>> > application can have it's own class path. The servlet class
>>> > loader and the Tomcat application class loader share an instance
>>> > of the interface HttpServletRequest (and friends), but the
>>> > implementation is not available as a class file to the servlet
>>> > class loader. Only the class in memory.
>>> >
>>> > The easy solution was to put a set of proxy classes in place,
>>> > since their bytecode will be avaialable to the servlet class
>>> > loader. This makes the problem go away. It is very easy to do. I
>>> > knocked out all the proxy objects using Eclipse's refactoring
>>> > tricks. It would be a nice to have for the Groovy servlet. We
>>> > could add a switch to use reflection or use proxies. It is
>>> > better than turning bytecode compilation off.
>>> > Then to go without the proxy object requires looking at the class
>>> > loader implementation in Tomcat. The class file is probably
>>> > available through the parent class loader. However the parent
>>> > class loader is probably protected by Java security. For all I
>>> > know, Groovy might already make the attempt to search the parent
>>> > class loader, but backs off quietly on a security exception.
>>> > Including the Tomcat jars in a web application archive is a
>>> > non-starter. A very broken solution.
>>> > Another solution might be to create a GroovyObject around the
>>> > interface, so that the Groovy code:
>>> > HttpSession session = request.getSession()
>>> > Would create a GroovyObject that wraps the HttpSession
>>> > interface, rather than the actual implementation. This is what I
>>> > expected to happen when I added the explicit casts.
>> This last part here, am I on the right track?
I'm thinking that you'd want to have the nice features of
Groovy's full reflection when you can have them.
---- In Java ----
import com.fubar.Foo;
import com.fubar.Bar;
import com.fubar.Fubar;
Foo foo = new Fubar();
Bar bar = (Bar) foo;
bar.bar();
---- In Groovy ----
import com.fubar.Foo;
import com.fubar.Fubar;
Foo foo = new Fubar()
foo.bar()
Thus, the current design, where the GroovyObject is devined from
the bytecode of the class file is probably correct.
The ideas I had before about casts being explicit, probably not
so hot, unless there is a way in groovy of specifying any.
def doFoo(foo)
{ foo.bar() }def doFoo(Foo foo)
{ foo.bar() // Exception raised. } Otherwise, I'd imagine that it is done in the class loader,
which could fall back to reflection if the bytecode for the
underlying object could not be found. And by falling back to
refelction, I'd imagine that it would only use reflection to
enumerate the interfaces and base classes, and create a
GroovyObject that implements as many as are available.