8 Replies Latest reply on Oct 21, 2005 8:56 AM by dunks80

    Invocation running on wrong field

    dunks80 Newbie

      I have an interceptor and a customer annotation I use to bind the pointcut for the interceptor. Runs great in JBoss AS 4.0.3 with load time weaving. I try to test the same aspectized class using the directions for standalone loadtime weaving from the jboss-aop documentation and a strange thing happen. The Invocation is running against the wrong field. My annotation is marked as a Field level target. When I debug through the interceptor I see that the invocation is running not on the field I annotated but on another non-annotated field in the class. If I debug the same code while running it in JBoss AS the invocation runs against the correct field. Has anyone had any experience with this before?

        • 1. Re: Invocation running on wrong field
          dunks80 Newbie

          Using jboss-aop 1.3.1

          After some more debugging through the jboss-aop source I think I know what's going on but I 'm not 100% certain why, or if it's my fault or if it's a bug. Keep in mind this only happens when I run the class using standalone aop (both precompiled and loadtime) with the following jvm args

          -Djboss.aop.verbose=true
          -Djboss.aop.prune=true
          -Djboss.aop.optimized=true
          -Djboss.aop.include=com.tura
          -Djboss.aop.exclude=org,com,bsh,net,antlr
          -Djboss.aop.class.path=/home/gdunkle/workspace/insight-core/
          -javaagent:/usr/local/jboss/server/dev/deploy/jboss-aop.deployer/jboss-aop-jdk50.jar
          


          as said before eveything works fine when using loadtime weaving in JBoss AS 4.0.3.

          Ok so debuging through the code it seems that when the class is being advised the field access transformer believes that there are only three fields in my class and that the annotated field is number 1 in the array of fields...this is correct except for one detail. My class extends from another class which also has a field. So when I look as the final invocation class being invoked by my test in the debugger the advised fields array has a length of 4. The inherited field is in the 0 slot pushing the annotated field up from the 1 slot (which is where the advised class believes it to be) to the 2 slot. So when I call invocation.resolveAnnotation(MyAnnotaion.class) it resolves to a null annotation because it's looking at the wrong field. I'm going to continue to dig into this but I think it's a possible bug unless I'm somehow running this incorrectly.

          • 2. Re: Invocation running on wrong field
            dunks80 Newbie

            Ok I'm pretty sure this is a bug. I've checked out the code in question from both jboss-head and jboss-aop and it's the same in both places here's where i think i'm seeing the problem....
            line 89 in org.jboss.aop.instrument.FieldAccessTransformer

             // Public --------------------------------------------------------
            
             protected void buildFieldWrappers(CtClass clazz, ClassAdvisor advisor) throws NotFoundException, CannotCompileException
             {
             List fields = Instrumentor.getAdvisableFields(clazz);
            
             int fieldIndex = fieldOffset(clazz.getSuperclass());
             JoinpointClassification[] classificationGet = classifyFieldGet(clazz, advisor);
             JoinpointClassification[] classificationSet = classifyFieldSet(clazz, advisor);
             Iterator it = fields.iterator();
             boolean skipFieldInterception = true;
             for (int index = 0; it.hasNext(); index++, fieldIndex++)
             {
             CtField field = (CtField) it.next();
            
             if (!isPrepared(classificationGet[index]) && !isPrepared(classificationSet[index]))
             {
             continue;
             }
            
             if (!javassist.Modifier.isPrivate(field.getModifiers()))
             {
             skipFieldInterception = false;
             }
            
             Shouldn't we be passing field index instead of index? --> doBuildFieldWrappers(clazz, field, index, classificationGet[index], classificationSet[index]);
             }
            
             if (skipFieldInterception)
             {
             advisor.getManager().skipFieldAccess(clazz.getName());
             }
             else
             {
             advisor.getManager().addFieldInterceptionMarker(clazz.getName());
             }
            
             }


            The call to doBuildFieldWrappers goes to org.jboss.aop.instrument.OptimizedFieldAccessTransformer which has a method signature like this
            protected void doBuildFieldWrappers(CtClass clazz, CtField field, int fieldIndex,JoinpointClassification classificationGet, JoinpointClassification classificationSet) throws NotFoundException, CannotCompileException
            


            So i'm pretty sure the third argument should be the fieldIndex which takes into account inherited field offset instead of just index. I"m going to file a bug in Jira and see what happens.

            • 3. Re: Invocation running on wrong field
              Kabir Khan Master

              Thanks for the fix. I've added it along with a test to jboss-head. However, in the 1.3.x branch I could not get it to fail?

              Can you please take a look at the testcase I've used to see if I am missing anything? It is under aop/src/resources/test/regression/jboss-aop.xml, and src/test/org/jboss/test/aop/regression/inheritedfield.

              • 4. Re: Invocation running on wrong field
                dunks80 Newbie

                I'm having a hard time building jboss-head right now so i'm not of much help.

                Your fix fixed my problem...i just checked out aop from jboss-head replaces the old aop libraries my test was using with the new ones. debugged through the code and it's now invoking on the correct field. I looked over you test case and couldn't figure out why it would fail in 1.3.x branch. My interceptor was failing specifically when I was looking for the annotation of a field. here is a look at the invoke method of my interceptor

                public Object invoke(Invocation invocation) throws Throwable
                 {
                 System.out.print("Invocation : " + invocation.getTargetObject());
                 //was failing here because it was looking at the wrong field (index instead of fieldIndex) to resolve the annotation
                Service serviceProvider = (Service) invocation.resolveAnnotation(Service.class);
                 Object serviceObject = null;
                 if (serviceProvider != null)
                 {
                 ServiceLookup SERVICE = new DefaultServiceLookup(serviceProvider.lookup(), serviceProvider.cache(), serviceProvider.lookupType());
                 serviceObject = ServiceLocator.lookupService(SERVICE);
                 }
                 invocation.invokeNext();
                 return serviceObject;
                 }


                perhaps a testcase which tries to retrieve an annotated field would help?

                • 5. Re: Invocation running on wrong field
                  dunks80 Newbie

                  So oddly enough my test now works with the patched jboss-aop-jdk50.jar but if i replace the old jboss-aop-jdk50.jar sitting in my jboss-aop.deployer folder on my server and run the class that my test was testing things don't work. Perhaps I can't just do a drop in replacement of jboss-aop-jdk50.jar? It's no big deal right now because what wasn't working prior to the patch runs standalone and so i can just point it's classpath to the patched jar. Meanwhile my interceptor always worked when running on the JBoss server with loadtime weaving. Question though, would we see the fixed jboss-aop released with jboss 4.0.4? Thanks

                  • 6. Re: Invocation running on wrong field
                    Kabir Khan Master

                     

                    "dunks" wrote:
                    So oddly enough my test now works with the patched jboss-aop-jdk50.jar but if i replace the old jboss-aop-jdk50.jar sitting in my jboss-aop.deployer folder on my server and run the class that my test was testing things don't work. Perhaps I can't just do a drop in replacement of jboss-aop-jdk50.jar? It's no big deal right now because what wasn't working prior to the patch runs standalone and so i can just point it's classpath to the patched jar. Meanwhile my interceptor always worked when running on the JBoss server with loadtime weaving.

                    You've got me confused :-)

                    "dunks" wrote:

                    Question though, would we see the fixed jboss-aop released with jboss 4.0.4? Thanks

                    Definitely

                    • 7. Re: Invocation running on wrong field
                      Kabir Khan Master

                      Can you please provide a scaled down version of what broke it for you with 1.3.1, so I can fix this in the 1.3 branch? You can send it to me directly.

                      Thanks

                      • 8. Re: Invocation running on wrong field
                        dunks80 Newbie

                        Sorry about the confusing post I'll try to explain again. My interceptor and custom annotation are basically used for injection (looking up object in jndi). The interceptor always worked in JBoss 4.0.3 with load time weaving. So In other words I could annotate my classes and when running in the container my interceptor would be correctly invoked on the annotated fields.

                        I also unit test those classes which have annotated fields outside the server environment. I accomplished this using standalone aop and embeddable ejb. That is when I found the bug.

                        Your fix (changing index to fieldIndex in the call to doBuildFieldWrappers) fixed my problem in my testing environment. I pulled your fix from jboss-head built the new jjars and placed them in my classpath. The interceptor now invokes on the correctly annotated field.

                        What I was trying to convey in my last post was that for the sake of consistency I felt I should use the same jboss-aop-jdk50.jar both for testing and for running on the server. So I took the jar I had created from the latest code in jboss-head and overwrote the existing jboss-aop-jdk50.jar in my server's jboss-aop.deployer folder. When I did this however my interceptor failed to work in the container and gave no indication as to why. I had already spent alot of time on the problem and felt that since I had a jar that would allow me to test the annotated classes outside the container and since the annotated classes always worked inside the standard container I would just not worry about using the same jar for both standalone testing and running in the container. I hope that makes more sense.

                        Ok so a scaled down version of what initially broke could be something like this...

                        Annotation...

                        @Target( { ElementType.FIELD })
                        public @interface MyAnnotation
                        {
                        
                        }
                        
                        


                        Interceptor...
                        @InterceptorDef(scope = Scope.PER_VM)
                        @Bind(pointcut = "get(* *->@MyAnnotation)")
                        public class MyInterceptor implements Interceptor
                        {
                        
                         /**
                         * returns the name of the interceptor...I just use the fully qualified
                         * classname
                         */
                         public String getName()
                         {
                         return MyInterceptor.class.getName();
                         }
                        
                         /**
                         * Interceptor invocation. Uses the values of the annotation to determine
                         * what service to lookup and set.
                         */
                         public Object invoke(Invocation invocation) throws Throwable
                         {
                         System.out.print("Invocation : " + invocation.getTargetObject());
                         MyAnnotation myAnnotation = (MyAnnotation) invocation.resolveAnnotation(Service.class);
                         Object serviceObject = null;
                         if myAnnotation != null)
                         {
                         System.out.print("Found an annotation!");
                         }
                         invocation.invokeNext();
                         return serviceObject;
                         }
                        }
                        


                        Class the uses the interceptor...
                        public class MyClass implements Serializable
                        {
                        
                        
                        
                         @MyAnnotation
                        
                         private SomeOtherClass annotatedField
                        
                        
                         public BackingBean()
                        
                         {
                        
                         super();
                        
                         }
                        
                         public void doSomething()
                         {
                         annotatedField.someCall();
                         }
                        }
                        


                        A test
                        public class Test
                        {
                         @org.testng.annotations.Test
                         public void testDoSomething()throws Exception
                         {
                         MyClass myClass=new MyClass();
                         myClass.doSomething();
                         }
                        }
                        


                        I hope that helps you out