3 Replies Latest reply on Nov 8, 2010 3:33 PM by Andrew Dinn

    Cannot invoke method of parameter objects $1, $2,....

    duc trung tran Newbie

      Hello,

       

      I have a rule like this :

       

      RULE a_rule
      CLASS MyClass
      METHOD myMethod(Object)
      IF TRUE
      DO traceln("invoke method on parameter " + $1.otherMethod())
      ENDRULE

       

      The parameter object ($1) is alwyas of type OtherClass (which has otherMethod method) at runtime. But i have a error message "Cannot invoke otherMethod of java.lang.Object..."

       

      Is this a bug or not implemented feature?

       

      Thanks for your help!

        • 1. Re: Cannot invoke method of parameter objects $1, $2,....
          Andrew Dinn Master

          Hi,

           

          It'snice  to see that you are trying to use Byteman.

          duc trung tran wrote:


          I have a rule like this :

           

          RULE a_rule
          CLASS MyClass
          METHOD myMethod(Object)
          IF TRUE
          DO traceln("invoke method on parameter " + $1.otherMethod())
          ENDRULE

           

          The parameter object ($1) is alwyas of type OtherClass (which has otherMethod method) at runtime. But i have a error message "Cannot invoke otherMethod of java.lang.Object..."

           

          Is this a bug or not implemented feature?

           

          Could you please provide the definition of your method? Does the method declaration specify that the parametr is of type Obejct or OtherClass?

           

          In this rule the method appears to have one argument of type Object.  So, when Byteman tries to typecheck the rule it can only assume that $1 is an instance of Object. When it sees the call $1.otherMethod() it will only typecheck the rule if the declared type, Object, has a method called otherMethod. Obviously this fails so the rule is not type correct. This is just the same as when javac compiles java code. Like javac, Byteman performs strict type checking.

           

          Of course, when the rule gets executed $1 may actually be an instance of OtherClass. But Byteman has to be able to type check the rule using the declared argument type not the type found at execute-time when the rule fired. If it used the execute-time type then it would have to type check the rule every time it was triggered  and this would make the rule engine much slower. It would also make it impossible to compile the rule  code to bytecode.

          • 2. Re: Cannot invoke method of parameter objects $1, $2,....
            duc trung tran Newbie

            Hi,

             

            Thanks for your rapid and detailed answer. It's really a cool tool Byteman .

             

            I tried to cast $1 to OtherClass in the BIND clause but it does not work either.  I have to implement custom helper for that?

             

            On the other hand, i would like to know if it's possible to capture private nested class or static initialization?

             

            Thanks

            • 3. Re: Cannot invoke method of parameter objects $1, $2,....
              Andrew Dinn Master

              duc trung tran wrote:

               

              Thanks for your rapid and detailed answer. It's really a cool tool Byteman .

               

              Thanks very much.

               

              duc trung tran wrote:

              I tried to cast $1 to OtherClass in the BIND clause but it does not work either.  I have to implement custom helper for that?

              I have been thinking about adding casting to rules. It's a little tricky but it is possible. One of  the hardest tasks is to get my rule garmmar to parse casts and not treat them as parse errors -- I know  that sounds silly but it is actually really tricky to do it and also retain good error reporting. So far most people have been able to use Byteman fairly effectively without using casts but I would be  interested to see some good use cases which would justify adding it to the language.

               

              Yes, you are right that it is possibekl to  add your own helper class to do the cast. For example,  you could define the following helper:

               

              package org.my;
              import org.jboss.byteman.rule.helper.Helper;
              import org.other.OtherClass;
              public Class MyHelper  extends Helper
              {
                  public OtherClass asOtherClass(Object object)
                  {
                      if (object instanceof OtherClass) {
                          return (OtherClass) object;
                  }
                  return null;
              }
              

               

              Then your rule could be redefined as follows

               

              RULE a_rule
              CLASS MyClass
              METHOD myMethod(Object)
              HELPER org.my.MyHelper
              BIND otherClassObject = asOtherClass($1)
              IF TRUE
              DO traceln("invoke method on parameter " + otherClassObject.otherMethod())
              ENDRULE
              

               

              duc trung tran wrote:

               

              On the other hand, i would like to know if it's possible to capture private nested class or static initialization?

               

              If you want to attach a rule to a method fo a nested class then you need to refer to the nested class usiing the internal JVM name format whihc uses a $ as rthe separator between the outer class and the inner class name

               

              RULE b_rule
              CLASS MyClass$NestedClass

              METHOD myOtherMethod(Object)

              . . .

               

              It is also possible to attach rules to classinitialiser methods using the internal name for a class initializer method, <clinit> e.g.

               

              RULE c_rule
              CLASS SomeClass

              METHOD <clinit>

              . . .

               

              However, in order  to make this work you need to be sure that you install the rule before SomeClass is loaded. If you install the rule after SomeClassis loaded then the <clinit> method will already have run and your rule will not get called. The best way to achieve this is to install the rule on the JVM command line i.e. if the rule  is contained in a script file /path/to/myrules.txt then run your code using the bmjava script in theinstall  bindirectory as follows:

               

              bmjava.sh -s /path/to/myrules.txt -classpath <myclasspath> org.my.MyMainClass
              

               

              If you cannot use bmjava.sh and have to run using the java command directly then you need to pass the script using the javaagent oiption to  the java command e.g.

               

              java -javaagent:${BYTEMAN_HOME}/lib/byteman.jar=script:/path/to/myrules.txt \
                       -classpath <myclasspath> org.my.MyMainClass