5 Replies Latest reply on Feb 9, 2018 5:13 AM by Ondra Chaloupka

    How rule injection to abstract classes works

    Ondra Chaloupka Expert

      Hi adinn,

       

      If you have time, I wonder about this: I tried to inject a rule at the abstract class but it does work strangely a bit.

       

      I have here three cases where a class extends an abstract class.

       

      In first case when abstract method defines `abstract method` and implementation is provided by the child class

      (see in case at byteman-abstract-class-location-test/src/main/java/org/jboss/btm/abstractmethod at master · ochaloup/byteman-abstract-cl… ) then rule bound at the abstract class is not invoked when call of the impl class happens. I do understand here that there is no code in the abstract class itself, this sounds fine to me.

      The testing rule is at: byteman-abstract-class-location-test/AbstractTest.java at master · ochaloup/byteman-abstract-class-location-test · GitHu…

       

      But if I have abstract class which implements behaviour and it's called from child class with `super.method(...)` call

      (see in case at byteman-abstract-class-location-test/src/main/java/org/jboss/btm/callsuper at master · ochaloup/byteman-abstract-class-l… ) then rule bound at the abstract class is not invoked even the method of the abstract class is invoked by `super.method` call of the child class.

      The testing rule is at: byteman-abstract-class-location-test/AbstractTest.java at master · ochaloup/byteman-abstract-class-location-test · GitHu…

       

      I do a small check how it's if I run some other method than overriden in the child with rule bound at the abstract class

      (see in case at byteman-abstract-class-location-test/src/main/java/org/jboss/btm/callingnonabstract at master · ochaloup/byteman-abstrac… ) and that works fine.

      The testing rule is at: byteman-abstract-class-location-test/AbstractTest.java at master · ochaloup/byteman-abstract-class-location-test · GitHu…

       

      Thank you

      Ondra

        • 1. Re: How rule injection to abstract classes works
          Andrew Dinn Master

          Oooh, that's an interesting outcome. I'll take a look as soon as I get a chance!

           

          regards,

           

           

          Andrew Dinn

          • 2. Re: How rule injection to abstract classes works
            Andrew Dinn Master

            Hi Ondra,

             

            I looked at your tests and I don't think Byteman is doing anything wrong or unexpected either for the abstractmethod test or the callSuper tests.

             

            Firstly, lets look at the abstract method question. As you say, for test abstractmethod the rule does not trigger because there is no method for it to be injected into. If you switch on verbose trace you can see this

             

              retransforming org.jboss.btm.abstractmethod.AbstractGreetingsProcessorAbstractMethod

             

            However, you don't see any messages about triggers because there is no method to inject into.

             

            What you also don't see is a TypeWarning saying that the rule failed to be injected. That is perhaps an issue as it ought to be flagged when a retransform is scheduled for a class mentioned in some rule but injection of that rule never happens. I am not quite sure why and will investigate that further.

             

            As for the super call test that is doing what I would expect and I don't understand why you think it should do anything different. I changed your rules slightly to make it clearer what is happening and to show which rules are being executed. The problem is that your rule produces the same side effect in the parent and child implementation. I modified the action to this

             

                targetLocation = "AT ENTRY",

                action = "$1 = $1 + \" \" + $CLASS")

             

            n.b. $CLASS is a special var that names the class into which the rule has been injected. When I run this the test fails (of course) but the errors are as follows

             

            Failed tests:   abstractmethod(org.jboss.btm.test.AbstractTest): expected:<"[goodbye]"> but was:<"[hello]">

              callsuper(org.jboss.btm.test.AbstractTest): expected:<"[goodbye]"> but was:<"[hello org.jboss.btm.callsuper.AbstractGreetingsProcessorCallSuper]">

              callsuperInheritInheritanceRule(org.jboss.btm.test.AbstractTest): expected:<"[goodbye]"> but was:<"[hello org.jboss.btm.callsuper.GreetingsProcessorCallSuper org.jboss.btm.callsuper.AbstractGreetingsProcessorCallSuper]">

             

            As you can see in the first test -- where you inject only into the parent class -- the argument is modified by appending the parent class name.  By contrast, in the second test the argument is modified in the child class by appending the child class name and then again in the parent class by appending the parent class name· This is what is expected.

             

            One other thing. Your rules specify overriding injection using

             

              targetClass = "^AbstractGreetingsProcessorAbstractMethod"

             

             

            That happens to work but it is an anti-pattern and may be rejected in future. What you are supposed to specify is

             

              targetClass = "^AbstractGreetingsProcessorAbstractMethod",

              isOverriding = true

             

            regards,

             

             

            Andrew Dinn

             

            • 3. Re: How rule injection to abstract classes works
              Ondra Chaloupka Expert

              HI adinn

               

              many thanks for the clarification and sorry for my ignorance if you consider so I can see the point now just I was kind of blind when playing with it. And thank you for pointing to $CLASS variable. I haven't recognized the existence. I can see it's pretty handy for rule debugging.

               

              Have a nice day

              Ondra

              • 4. Re: How rule injection to abstract classes works
                Andrew Dinn Master

                Hi Ondra,

                 

                ochaloup  wrote:

                 

                many thanks for the clarification and sorry for my ignorance if you consider so I can see the point now just I was kind of blind when playing with it. And thank you for pointing to $CLASS variable. I haven't recognized the existence. I can see it's pretty handy for rule debugging.

                 

                There is nothing wrong or ignorant about asking questions :-)

                 

                The special vars $CLASS and $METHOD were added as part of the SystemTap integration. I think they are mentioned somewhere in the Programmer's Guide but if not they ought to be.

                 

                While we are here I'll just note that $CLASS is really useful when using overriding rules. I initially wrote the action as

                 

                    action = "$1 = $1 + \" \" + $0.getClass().getName()")

                 

                but of course that appends the same string in both super- and subclass. $CLASS refers to the name of the class that owns the method into which the rule has been injected. So, when the rule is triggered when executing the subclass method it identifies the name of the subclass and when it is triggered from the superclass method it identifies the name of the superclass.

                 

                That's quite a useful feature. For example, this condition will ensure that a rule injected using overriding only fires at the outermost injection point

                 

                  condition = "$0.getClass().getName() == $CLASS"

                 

                regards,

                 

                 

                Andrew Dinn

                • 5. Re: How rule injection to abstract classes works
                  Ondra Chaloupka Expert

                  I see, sure ;)

                  ah, ok, that's nice trick (condition = "$0.getClass().getName() == $CLASS"). Thanks!