Community   SpringSource   Projects    Downloads    Documentation    Forums    Training   Exchange   Blogs

Go Back   Spring Community Forums > Core Spring Projects > Core Container

Reply
 
Thread Tools Display Modes
  #1  
Old Jul 22nd, 2007, 03:45 PM
Vita Rara Vita Rara is offline
Member
 
Join Date: Aug 2006
Location: Troy, NY
Posts: 58
Default Groovy Support Broken with 1.1-beta-2

I am attempting to upgrade to Groovy 1.1 beta into an application that has been using Spring and Groovy 1.0. (I want to be able to use annotations and generics.)

When attempting to use a Groovy bean that bas been instantiated via the lang:groovy method I'm getting the following error:

Code:
     [java] java.lang.IllegalArgumentException: object is not an instance of declaring class
     [java]     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     [java]     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
     [java]     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
     [java]     at java.lang.reflect.Method.invoke(Method.java:585)
     [java]     at org.codehaus.groovy.runtime.metaclass.ReflectionMetaMethod.invoke(ReflectionMetaMethod.java:52)
     [java]     at org.codehaus.groovy.runtime.MetaClassHelper.doMethodInvoke(MetaClassHelper.java:714)
     [java]     at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:583)
     [java]     at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:476)
     [java]     at org.codehaus.groovy.runtime.Invoker.invokePogoMethod(Invoker.java:115)
     [java]     at org.codehaus.groovy.runtime.Invoker.invokeMethod(Invoker.java:81)
     [java]     at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:85)
     [java]     at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:158)
     [java]     at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethod0(ScriptBytecodeAdapter.java:182)
     [java]     at ServiceBeanImpl2.doService(script1185134866212.groovy:13)
     [java]     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     [java]     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
     [java]     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
     [java]     at java.lang.reflect.Method.invoke(Method.java:585)
     [java]     at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:299)
     [java]     at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:172)
     [java]     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:139)
     [java]     at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:127)
     [java]     at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:115)
     [java]     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:161)
     [java]     at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
     [java]     at $Proxy0.doService(Unknown Source)
     [java]     at ServiceConsumerImpl.useService(ServiceConsumerImpl.java:10)
     [java]     at Test.main(Test.java:18)
That stacktrace is from a test that I wrote to demonstrate the issue, but I get basically the same thing in my full application.

The issue seems to be when one Groovy bean attempts to access a service on another groovy bean. (ie. Groovy service bean ---depends_on---> Groovy DAO; or Groovy Struts 2 Action ---depends_on----> Groovy Service bean)

I believe the root of the problem is that each Groovy bean instantiated by Spring has its own classloader.

I have a test application that demonstrates the issue, and also shows the same exact code working in Groovy 1.0. I apologize that the download is on the large side. If I knew how to do dependencies in Ant I'd have done it.

http://mark.mjm.net/~mark/springGroovyTest.tar.gz

To build and run the test simply run ant in the root of the application. In the src-java there is a class Test.java with a main that instantiates a ServiceConsumer, then wires that to a service bean, ServiceBeanImpl2, and calls useService().

The service beans are two Groovy beans, in src-groovy, that are chained by configuration in resources/applicationContext.xml, ServiceBeanImpl2 to ServiceBeanImpl. ServiceBeanImpl2 simply calls the doService() method of ServiceBeanImpl.

In the course of the test I output the class loaders of the Groovy service beans. They each have a different GroovyClassLoader. It is my understanding that this is my design in Spring, but it appears to me to be the root of the issue. If I wire all of my Groovy objects together with Class instances loaded with the same GroovyClassLoader it all works as expected.

Any help on this issue would be greatly appreciated. I've sort of reached the end of what I know about Spring and Groovy.
__________________
Business site: http://www.vitarara.net/
Personal site: http://www.vitarara.org/
Reply With Quote
  #2  
Old Jul 23rd, 2007, 02:40 PM
cltam96 cltam96 is offline
Member
 
Join Date: Jan 2007
Posts: 30
Default

I have tried the testing program and found that if the "refresh-check-delay" attribute is removed, everything works fine. The only difference created by "refresh-check-delay" attribute is that Spring will create a JDK Proxy instead of the plain groovy object for the groovy lang tag. My guess is that the JDK Proxy and Groovy 1.1 has some incompatible behavior which cause the exception. I have check the source code of JdkDynamicAopProxy class under aop/framework package but so far I still cannot locate the source of problem. Hope anyone can help to solve this problem.

Cheers
chris tam
hong kong
Reply With Quote
  #3  
Old Jul 23rd, 2007, 03:08 PM
Vita Rara Vita Rara is offline
Member
 
Join Date: Aug 2006
Location: Troy, NY
Posts: 58
Default

Chris,

I should have emailed you directly. Thanks for digging into this. I just about ran out of mental energy yesterday working on this. I'll take a look at JdkDynamicAopProxy, not that I think I'll get very far, because once we get to Proxies I'm out of my element.

Thanks,

Mark
__________________
Business site: http://www.vitarara.net/
Personal site: http://www.vitarara.org/
Reply With Quote
  #4  
Old Jul 23rd, 2007, 05:05 PM
Vita Rara Vita Rara is offline
Member
 
Join Date: Aug 2006
Location: Troy, NY
Posts: 58
Default

OK, a little more investigation turns up this post over on the Groovy User list:

http://www.nabble.com/using-MOP-to-i....html#a9968363

That test fails under Groovy 1.0, which obviously isn't happening with the existing Spring Groovy support, but it might provide some insight for someone who better understands proxies.

I've also further refined my understanding of what is going on. The error only seems to be thrown when a Groovy object is calling a method on another proxied Groovy object. If you change the Java test to use serviceBean1 the test will success:


Code:
        
try {
            System.out.println ("\nTesting Java implementation of ServiceConsumer with only one service bean with Spring.");
            ServiceConsumer sc = new ServiceConsumerImpl ();
            sc.setServiceBean ((ServiceBean ) c.getBean ("serviceBean1") );
            sc.useService ();
        } catch (Exception e) {
            // System.out.println ("\nFAILURE: Testing Java implementation of ServiceConsumer with Spring.");
            e.printStackTrace ();
        } finally {
            Thread.sleep (1000);
        }
So, the issue seems to be some interaction between the JdkDynamicAopProxy and the Groovy method calling mechanism in Groovy 1.1.
__________________
Business site: http://www.vitarara.net/
Personal site: http://www.vitarara.org/
Reply With Quote
  #5  
Old Jul 23rd, 2007, 06:13 PM
Vita Rara Vita Rara is offline
Member
 
Join Date: Aug 2006
Location: Troy, NY
Posts: 58
Default

I think this is a Groovy issue, and not a Spring issue. I have simplified the test, removing all dependencies on Spring. Please see:

http://mark.mjm.net/~mark/GroovyProxyTest.tar.gz

The issue seems to be with a groovy object calling a proxied Groovy object.

Mark
__________________
Business site: http://www.vitarara.net/
Personal site: http://www.vitarara.org/
Reply With Quote
  #6  
Old Jul 24th, 2007, 12:48 AM
cltam96 cltam96 is offline
Member
 
Join Date: Jan 2007
Posts: 30
Default

Thanks for your information.

cheers
chris tam
hong kong
Reply With Quote
  #7  
Old Jul 25th, 2007, 04:17 AM
zjumty zjumty is offline
Junior Member
 
Join Date: Jul 2007
Location: Shanghai, China
Posts: 2
Default I got the some problem!

I got the some problem in my project. and I found that use TransactionProxyFactoryBean can make it working.

Code:
    <bean id="txProxyTemplate" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="transactionManager" ref="transactionManager" />
        <property name="transactionAttributes">
            <props>
                <prop key="add*">PROPAGATION_REQUIRED</prop>
                <prop key="delete*">PROPAGATION_REQUIRED</prop>
                <prop key="*">PROPAGATION_REQUIRED, readOnly</prop>
            </props>
        </property>
    </bean>

    <lang:groovy id="fooServiceBean" refresh-check-delay="1000" script-source="classpath:/com/legendapl/cms/author/service/FooService.groovy">
    </lang:groovy>

    
    <bean id="fooService" parent="txProxyTemplate">
        <property name="target" ref="fooServiceBean" />
        <property name="proxyInterfaces">
            <list>
                <value>com.legendapl.cms.author.service.spi.IFooService</value>
            </list>
        </property>
    </bean>
But, this is not the style in spring2.0!

is there better solution for this problem?
Reply With Quote
  #8  
Old Jul 25th, 2007, 11:42 AM
Vita Rara Vita Rara is offline
Member
 
Join Date: Aug 2006
Location: Troy, NY
Posts: 58
Default

No quick solution yet. There's a conversation going on over on the Groovy-dev list:

http://www.nabble.com/JDK-Style-Prox...tf4137792.html

I've isolated the issue down to the use of proxies where a GroovyBean -calls-a-method-on-> Proxied(GroovyBean).

This works in Groovy 1.0. Just so you know.
__________________
Business site: http://www.vitarara.net/
Personal site: http://www.vitarara.org/
Reply With Quote
  #9  
Old Jul 25th, 2007, 12:39 PM
Vita Rara Vita Rara is offline
Member
 
Join Date: Aug 2006
Location: Troy, NY
Posts: 58
Default

Do you by chance know what AopProxy implementation is used to manufacture the proxy object using the TransactionProxyFactoryBean methodology?

There are four of them in org.springframwork.aop.framework: Cglib2AopProxy, DefaultAopProxyFactory, JdkDynamicAopProxy, and ProxyFactory.

It is my suspicion that it likely uses Cglib2AopProxy, but I'd like to know for sure.

Mark
__________________
Business site: http://www.vitarara.net/
Personal site: http://www.vitarara.org/
Reply With Quote
  #10  
Old Jul 28th, 2007, 06:14 PM
Vita Rara Vita Rara is offline
Member
 
Join Date: Aug 2006
Location: Troy, NY
Posts: 58
Default

I have created a patch for Groovy-1.1-beta-3-SNAPSHOT that fixes the JDK dynamic proxy issue. It has not been applied to the SVN trunk yet. You can retrieve the patch from:

http://jira.codehaus.org/browse/GROOVY-2006

Mark
__________________
Business site: http://www.vitarara.net/
Personal site: http://www.vitarara.org/
Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -5. The time now is 11:26 PM.


Contegix provides first-class managed hosting and partial sponsorship of these forums.

Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.