Page 1 of 2 12 LastLast
Results 1 to 10 of 20

Thread: AOP with Groovy beans

  1. #1
    Join Date
    Dec 2005
    Location
    California
    Posts
    63

    Default AOP with Groovy beans

    Hi
    In a standard web application in applicationContext.xml I have the following:

    Code:
      <lang:groovy id="vinGenerator" script-source="/WEB-INF/scripts/groovy/VINBuildQuery.groovy">
    	    ..properties here
      </lang:groovy>
    When I start up I am getting the following error:
    Code:
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'vinGenerator': BeanPostProcessor before instantiation of bean failed; nested exception is org.aspectj.weaver.reflect.ReflectionWorld$ReflectionWorldException: warning can't determine implemented interfaces of missing type groovy.VINBuildQuery
     [Xlint:cantFindType]
    Caused by: 
    org.aspectj.weaver.reflect.ReflectionWorld$ReflectionWorldException: warning can't determine implemented interfaces of missing type groovy.VINBuildQuery
     [Xlint:cantFindType]
    	at org.aspectj.weaver.reflect.ReflectionWorld$ExceptionBasedMessageHandler.handleMessage(ReflectionWorld.java:163)
    	at org.aspectj.weaver.Lint$Kind.signal(Lint.java:287)
    	at org.aspectj.weaver.MissingResolvedTypeWithKnownSignature.raiseCantFindType(MissingResolvedTypeWithKnownSignature.java:198)
    	at org.aspectj.weaver.MissingResolvedTypeWithKnownSignature.getDeclaredInterfaces(MissingResolvedTypeWithKnownSignature.java:76)
    	at org.aspectj.weaver.ResolvedType.getDirectSupertypes(ResolvedType.java:65)
    	at org.aspectj.weaver.JoinPointSignatureIterator.findSignaturesFromSupertypes(JoinPointSignatureIterator.java:164)
    	at org.aspectj.weaver.JoinPointSignatureIterator.hasNext(JoinPointSignatureIterator.java:69)
    	at org.aspectj.weaver.patterns.SignaturePattern.matches(SignaturePattern.java:287)
    This is obviously happening because I have
    Code:
    <aop:aspectj-autoproxy/>
    When I move this Groovy bean into my dvc-servlet.xml (the standard context required by Spring MVC), this problem does not happen because I do not have AOP there.
    My question is how to turn off the inspection of this bean in applicationContext.xml so I do not have to move it out?

    Thanks.
    Janos

  2. #2

    Default

    Do your Groovy bean implement any java interface? It seems that your Groovy bean does not implement any java interface. If your Groovy bean does not implement any java interface, there will be a lot of problem.

    cheers
    chris tam
    xenium

  3. #3
    Join Date
    Aug 2006
    Location
    Troy, NY
    Posts
    58

    Default

    I'm getting this same error, "warning can't determine implemented interfaces of missing type..."

    My groovy classes implements LOTS of interfaces. They descend from com.opensymphony.xworks.ActionSupport which implements six interfaces. I think this is a remanifestation of a very old bug in AspectJ (https://bugs.eclipse.org/bugs/show_bug.cgi?id=116305#c1) because if I add a single letter to my pointcut expression the issue disappears.

    I have emailed the AspectJ mailing list to see if I can get some advice on this issue.

    Mark
    Last edited by Vita Rara; Feb 24th, 2007 at 02:43 PM.

  4. #4
    Join Date
    Aug 2006
    Location
    Troy, NY
    Posts
    58

    Default

    I've done a bit more research on this issue.

    I did the following:

    • Created a GroovyClassLoader
    • Created an ApplicationContext and set its classloader to the GroovyClassLoader
    • Refreshed my applicationContext


    By doing this it seems to have the effect of making the Groovy classes visible to the AspectJ pointcut.

    I can instantiate a Groovy bean, and then hand it to the applicationContext to wire its dependencies, which works.

    It almost seems like the class loaders that load scripts needs to be parents of the context class loader. The current method creates classloaders that are children of the applicationContext's loader, and therefore siblings to each other. Therefore it would seem like you couldn't use declarative transactions with a scripted bean. Is this right?

    It seems to me like the classloader configuration when using AOP with scripted beans is as follows:

    Code:
                      Root Class Loader
                        |            |  
     AspectJ Class Loader      Script class loader per scripted bean definition
    Is this right?

    Thanks,

    Mark

  5. #5

    Default

    Dear Janos and Mark

    I am sorry and feel shameful that I had misunderstood Janos problem and wrote the silly comment. About the AspectJ and Groovy problem, Mark comment is correct and I have encountered the same problem in my current company project. I had tried a workaround in my current company project that "SEEMS" to work in my case but I am not sure that it works or not in other cases. My workaround is to create 2 application context xml files. In context xml file 1, I have defined all the domain objects and groovy scripts. For example: applicaionContext1.xml

    <bean id="dataSource" ...
    ...
    </bean>
    ...
    <!-- Hibernate -->
    <bean id="sessionFactory" ...
    </bean>
    ...
    <bean id="txManager" class="org.springframework.orm.hibernate3.Hibernat eTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
    </bean>
    ...
    <tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
    <tx:method name="get*" read-only="true"/>
    <tx:method name="*"/>
    </tx:attributes>
    </tx:advice>
    ...
    <bean id="Person" class="org.test.Person" scope="prototype">
    <property name="name" value="Unknown"/>
    </bean>
    <bean id="PersonDAO" class="org.test.PersonDAOImpl" scope="prototype">
    <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    <lang:groovy id="PersonService"
    script-source="classpath:org/test/GroovyPersonService.groovy"
    script-scope="prototype">
    ...
    </lang:groovy>
    ...

    Please note that "script-scope" attribute only work if apply Mark patch to spring.
    The GroovyPersonService.groovy file contains all the methods which are pointcut by AspectJ and it implements a Personservice interface.

    In the context xml file 2, I have ONLY defined the aop pointcut and nothing else. For example: applicaionContext2.xml
    ...
    <aop:config>
    <aop:pointcut id="PersonServiceOperation" expression="execution(*
    org.test.PersonService.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="PersonServiceOperation"/>
    </aop:config>
    ...

    In my java program,
    ...
    // need to create 2 ApplicationContext objects
    ApplicationContext context1 = new ClassPathXmlApplicationContext(
    new String[] {"applicaionContext1.xml"});

    // Note: context1 must pass to create context2
    ApplicationContext context2 = new ClassPathXmlApplicationContext(
    new String[] {"applicaionContext2.xml"}, context1);

    Person p = (Person)context2.getBean("Person") ;
    p.setName("testing") ;

    PersonService srv = (Personservice)context2.getBean("PersonService") ;
    srv.insertPerson(person) ;
    ...

    I don't know whether it can help Janos to solve his problem. I can only say that it works in my project. Please give it a try and If there is any problem, please let me know so that I can avoid it in my project. Thanks Mark and Janos for their help.

    cheers
    chris tam
    xenium
    Last edited by cltam96; Feb 25th, 2007 at 07:49 AM.

  6. #6
    Join Date
    Aug 2006
    Location
    Troy, NY
    Posts
    58

    Default

    This is long, my apologies, but if you're interested in using scripted beans please read it.

    Quote Originally Posted by cltam96 View Post
    About the AspectJ and Groovy problem, Mark comment is correct and I have encountered the same problem in my current company project.
    So, basically the scripting support in Spring is pretty useless. Yes you can instantiate a bean from a script, but it can't participate in any aspects or in transactions.

    Is the scripting support in Spring a proof of concept? Are there any plans to address this issue? Or is the problem so fundamental due to the need for a class loader for each language that there is no way to effectively do this?

    Issues I see with the scripting support:

    • Each scripted bean has its own class loader, which is a child of the context class loader, and can specify independently if it wants dynamic reloading, and the delay in checking for a change in the script.
    • AspectJ seems to have its own class loader that is a child of the Spring class loader.
    • Due to the single class loader per scripted bean, if you have a scripted bean that depends on a second scripted class, it would seem that the second class would be loaded and compiled multiple times if it was a dependency of multiple scripted beans.
    • Currently scripted beans only support singleton scope. (There is a patch for this on JIRA to support singleton and prototype scope.)


    I'm sure there are other issues I'm not thinking of right now. Basically a scripted bean doesn't fit naturally into the Spring universe. It's different and really can't be used in place of a compiled bean. (I say that because I have encountered absolutely no issues using beans written in Groovy and compiled ahead of time with Spring. Spring just uses them like any other Java sourced bean.)

    I had tried a workaround in my current company project that "SEEMS" to work in my case but I am not sure that it works or not in other cases. My workaround is to create 2 application context xml files. In context xml file 1, I have defined all the domain objects and groovy scripts. For example: applicaionContext1.xml

    *big snip*

    Please note that "script-scope" attribute only work if apply Mark patch to spring.

    The GroovyPersonService.groovy file contains all the methods which are pointcut by AspectJ and it implements a Personservice interface.

    In the context xml file 2, I have ONLY defined the aop pointcut and nothing else. For example: applicaionContext2.xml
    ...
    <aop:config>
    <aopointcut id="PersonServiceOperation" expression="execution(*
    org.test.PersonService.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="PersonServiceOperation"/>
    </aop:config>
    ...

    In my java program,
    ...
    *snip*
    ...

    I don't know whether it can help Janos to solve his problem. I can only say that it works in my project. Please give it a try and If there is any problem, please let me know so that I can avoid it in my project. Thanks Mark and Janos for their help.
    Chris I'm not sure I see how this would work. Please correct me if my understanding is wrong.

    • You have two contexts, 2 is the parent of 1.
    • All beans are defined in 1.
    • AOP pointcut is defined in 2.


    Context 2 should have 3 class loaders a parent that belongs to the context, and a child that belongs to AspectJ, and a child that belongs to Context 1. So, effectively Context 1 and its descendant class loaders are siblings of AspectsJ's. How would this work? The AspectJ class loader still shouldn't be able to see the Groovy classes instantiated down in Context 1.

    I ask all of this because I'm really just trying to understand what is going on in hopes of finding a solution.

    To someone on the Spring scripting team:

    Are the problems we have encountered using AOP support with scripted beans fundamental to the way scripting is implemented in Spring? Or are we doing something wrong?

    If these problems are fundamental, would it make sense to mark the scripting support in Spring experimental until these issues can be addressed and scripted beans can be more closely integrated with Spring so they can be used in a natural manner in place of traditional compiled beans?

    I have some ideas to address what I think is the issue, but I'm not sure that this is fundamental, or are we just doing something wrong in our configurations.

    Thanks,

    Mark

  7. #7
    Join Date
    Oct 2004
    Location
    Fareham, England
    Posts
    313

    Default

    Hi Mark, Chris, all

    Quote Originally Posted by Vita Rara View Post
    Are the problems we have encountered using AOP support with scripted beans fundamental to the way scripting is implemented in Spring? Or are we doing something wrong?
    The issues that you are encountering with regard to the scripting support in Spring are not fundamental ones. I will address these issues to your satisfaction in the coming weeks... you guys are hitting these issues because you are the ones actually using the scripting support in anger as it were... in the runup to the Spring 2.0 release there were, insofar as I can remember, no bug reports related to the scripting support when said scripting support was still in 'beta-mode' (as it were). You guys are now banging on the code (quite rightly too), and issues that I daresay should have been spotted in the development phase were not.

    Okay, so where to from here? I'll have a thorough review of the issues that Chris has brought up (I have one or maybe two JRuby-related issues on the Spring JIRA). As soon as they are dealt with (or at the same time), I will address the issue that you are encountering. The timeframe for me personally looking into these issues and fixing them is 2 weeks (a project I have been working on finishes next week, and that will free up my time and allow me to focus on my Spring commitments).

    If you have any ideas/comments about the scripting support, fire them into this thread.

    Cheers
    Rick

  8. #8
    Join Date
    Aug 2006
    Location
    Troy, NY
    Posts
    58

    Default

    Hi Rick,

    First, I'm not angry at anyone. I love Spring. (As much as I can love something intangible like a framework. I sure know I don't love EJB though. ) I also greatly appreciate your support, and willingness to address these issues.

    I'm relatively new to Spring. We started using it in-house about six months ago. I've dug into the org.springframework.scripting package and had a look around. I did the "script-scope" patch with coaching from Chris Tam, which is attached to SPR-3161. (http://opensource.atlassian.com/proj...rowse/SPR-3161)

    If you could answer a few questions that would be great.

    Does every scripted bean have its own class loader?

    Does AspectJ have its own class loader?

    Does Spring have a class loader that can consult its child class loaders when it and its parents can not fulfill a request on behalf of one of its children?

    Two ideas:

    Might it make sense to be able to configure a class loader for each scripting language as a bean?

    If you are having issues with sibling class loaders might it make sense to have a class loader that can consult the siblings of its children on behalf of its children?

    Discussion:

    Configuring class loader beans per context: This bean would then be used to instantiate beans for that language. This would allow a global policy for reloads, etc. (Kind of like if you name your transaction manager by convention it just gets picked up by name and injected appropriately.)

    Myself, I'm just working with Groovy. It would be nice to just configure the GroovyClassLoader once, and have it shared between the Groovy beans in my context.

    Rick, again thanks for your help. I'm quite excited about the possibilities that are created with Spring's support for scripted languages and dynamic reloading. (I envision a day when I can start Jetty and just work on files, save and reload in my browser with minimal need for restarts. To see what I'm trying to do: http://www.vitarara.org/cms/node/98 )

    Thanks,

    Mark

  9. #9

    Default

    Dear Mark,

    I am sorry that my comment may be confusing. The workaround that I suggest is being used in my current project. It seems that my workaround works from day to day for a month. I have write some junit tests on it and I need to run my junit test many times each date and the groovy script work well with the AspectJ everytime. I have even tested the rollback case. I intentionally throw a RuntimeException in my Groovy script to force the transaction rollback in my junit test. The result is also fine. So I am sure that my solution is empirically workable for my case as describe in above comment.

    About the classloader problem, I have not go deep into the problem. so I can only tell what I know so far.

    There are two contexts, 1 is the parent of 2.
    All beans are defined in 1.
    AOP pointcut is defined in 2.


    Before you create context2, you need to create context1. All the beans and groovy script are loaded when create context1.

    The tricky point is when create the context 2, you need to pass the context1 to create context2. If you don't pass context1 to create context2, my workaround will not work.

    Context1 classloader will become the parent classloader of context2 classloader. AspectJ use context2 classloader parent, which is context1 classloader, to find the Groovy script with its java interface and pointcut it.

    I hope that my explanation will not confuse you. May be you can try my workaround and you will find that the classloader structure is different when you use context1 to create context2 like this:

    // context1 classloader will become the parent of context2 classloader
    ApplicationContext context2 = new ClassPathXmlApplicationContext(
    new String[] {"applicaionContext2.xml"}, context1);

    About the GroovyClassLoader problem, I agree with you that there should be only one GroovyClassLoader because I have also encounter a problem in my program which is due to multiple GroovyClassloader but I have workaround it again.

    But personally I know Rick Evan is working very hard to solve all the dynamic language problem and there are many bugs already assigned to him. Some are created by me. I think he may need 36 hr per day in order to fix all these bugs.

    Thanks
    chris tam
    xenium
    Last edited by cltam96; Feb 25th, 2007 at 12:59 PM.

  10. #10

    Default

    Dear Mark

    As a side note, not all script bean have its own classloader. Both beanshell and JRuby have different loading strategy.

    Thanks
    chris tam
    xenium

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •