Announcement Announcement Module
Collapse
No announcement yet.
AOP with Groovy beans Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • 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.

  • #2
    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

    Comment


    • #3
      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, 03:43 PM.

      Comment


      • #4
        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

        Comment


        • #5
          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>
          <aopointcut 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, 08:49 AM.

          Comment


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

            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

            Comment


            • #7
              Hi Mark, Chris, all

              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

              Comment


              • #8
                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

                Comment


                • #9
                  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, 01:59 PM.

                  Comment


                  • #10
                    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

                    Comment


                    • #11
                      Dear All

                      Juergen Hoeller has already fixed the AOP and Groovy bean problem. The fix will be available in the next snapshot of spring 2.0.3. The current snapshot build.121-20070301 does not contain the fix. Janos problem should be solved with the fix. Please refer to the following link about the problem and fix:
                      AspectJExpressionPointcut throws ReflectionWorldException. Thanks for Juergen help.

                      cheers
                      chris tam
                      xenium

                      Comment


                      • #12
                        I posted the following on the JIRA issue. If anyone else has an answer I'd really like to know.

                        Juergen,

                        You say, "After all, AOP advice for scripted objects is not supposed to match against the target class in the first place... " I'm new to Spring and AOP. Does this mean that you can't use AOP to wrap a scripted bean in a transaction?

                        In my particular case all of my scripted service beans implement an interface, written in Java and compiled ahead of time. I use the interfaces in my aop:config entry in my xml file. Will my Groovy beans be wrapped in a transaction?

                        Thanks,

                        Mark

                        Comment


                        • #13
                          Dear Mark

                          You can use AOP with any scripted bean in transaction. I have already tested Juergen fix to use declarative transaction on Groovy scripted bean. The Groovy scripted bean can insert, update and delete. Also it can commit or rollback.

                          The problem is in the AspectJExpressionPointcut java file. Within this java file, it use the AspectJ weaver to check all beans and its methods whether the methods should be pointcut or not. But AspectJ is not used in actually pointcut the method. If you want to know the detail, you need to read the AspectJExpressionPointcut java file.

                          cheers
                          chris tam
                          xenium

                          Comment


                          • #14
                            I updated to the CVS head for Spring. As soon as I add a lang:groovy bean I get the following error:

                            Code:
                            Embedded error: Configuration problem: Unable to locate NamespaceHandler for namespace [http://www.springframework.org/schema/lang]
                            Offending resource: class path resource [applicationContext.xml]
                            Code:
                            [ERROR] 12:17:49,858 [org.springframework.web.context.ContextLoader : 200] : Context initialization failed
                            org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unable to locate NamespaceHandler for namespace [http://www.springframework.org/schema/lang]
                            Offending resource: class path resource [applicationContext.xml]
                            
                                    at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68)
                                    at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:85)
                                    at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:80)
                                    at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.error(BeanDefinitionParserDelegate.java:261)
                                    at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1106)
                                    at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1099)
                            I think I got this error when I tried to patch 2.0.3 with the scripted bean scope patch, that was why I fell back to 2.0.2. I can use 2.0.2 with a lang:groovy statement in my applicationContext.xml file without issue, other than the AOP exceptions.

                            Mark

                            Comment


                            • #15
                              Dear Mark

                              I had encountered "Unable to locate NamespaceHandler..." problem when I try to create my own namespace. If the content of the META-INF\spring.handlers has some problems, the "Unable to locate NamespaceHandler..." problem will appear.
                              Using my own case as an example, I have the following definition in my META-INF\spring.handlers:
                              Code:
                              http\://www.alchian.org/schema/xlang=org.alchian.springx.scripting.config.XLangNamespaceHandler.java
                              The above definition will trigger the Unable to locate NamespaceHandler..." problem because I have misspelled "XLangNamespaceHandler" to "XLangNamespaceHandler.java". The correct definition should be:
                              Code:
                              http\://www.alchian.org/schema/xlang=org.alchian.springx.scripting.config.XLangNamespaceHandler
                              cheers
                              chris tam
                              xenium

                              Comment

                              Working...
                              X