4 Replies Latest reply on Oct 16, 2019 5:28 AM by adinn

    Intercept java.lang.Class#getAnnotation

    fercoli

      Hi all,

       

      I'm trying to use Byteman to check whether annotations are read.

      This is my rule:

       

      RULE check annotation is not read at runtime
      CLASS java.lang.Class
      METHOD getAnnotation
      IF true
      DO THROW new org.hibernate.session.runtime.check.CheckForbiddenAPIException("Reading annotation");
      ENDRULE

       

      But it seems not working. I tried also:

       

      RULE check annotation is not read at runtime
      INTERFACE ^AnnotatedElement
      METHOD getAnnotation
      IF true
      DO THROW new org.hibernate.session.runtime.check.CheckForbiddenAPIException("Reading annotation");
      ENDRULE

       

      with or without the `^` prefix.

      Is it supposed to work? If so, what is my mistake?

       

      Many thanks in advance.

       

      By the way I'm using Byteman to do nice stuff, see https://github.com/hibernate/hibernate-orm/pull/3040

        • 1. Re: Intercept java.lang.Class#getAnnotation
          y.rodiere

          From the documentation (Byteman Programmer’s Guide, 4.0.8, Oct 14, 2019):

           

          The Byteman agent will not normally transform any classes in package java.lang and will never transform classes in package org.jboss.byteman, the byteman package itself (it is possible to remove the first of these restrictions by setting a System property, but you need to be really sure you know what you are doing – see below for details).

           

          org.jboss.byteman.transform.all

          When this system property is set, then the agent will allow rules to be injected into methods of classes in the java.lang hierarchy. Note that this will require the Byteman jar to be installed in the bootstrap classpath using the boot: option to the -javaagent JVM command line argument.

          1 of 1 people found this helpful
          • 2. Re: Intercept java.lang.Class#getAnnotation
            adinn

            Hi Fabio,

             

            Thanks for reporting your problem.

            fercoli  wrote:

             

            I'm trying to use Byteman to check whether annotations are read.

            This is my rule:

            RULE check annotation is not read at runtime
            CLASS java.lang.Class
            METHOD getAnnotation
            IF true
            DO THROW new org.hibernate.session.runtime.check.CheckForbiddenAPIException("Reading annotation")
            ENDRULE

            But it seems not working.

             

            There are several things going on here. I think this most likely a classloader issue (yeah, I know it doesn't look like it but ... I'll explain :-)

             

            You are trying to inject code into a method of java.lang.Class which is loaded by the bootstrap loader. The first issue is that Byteman does not normally inject into java.lang classes or indeed into any bootstrap classes. If you are using BMUnit then you don't have to worry because it configures Byteman to allow injection into bootstrap classes including java.lang classes. If you are loading Byteman form the command line using -javaagent or at runtime using bminstall then you need to configure two things. Firstly, you need to ensure the Byteman agent code is installed into the bootstrap loader. Second, you need to ensure that transformation of java.lang classes is enabled.

             

            On the command line you need to use an extra agent option and an extra property define

             

            java -javaagent:$BYTEMAN_HOME/lib/byteman.jar=script:/path/to/myscript.btm,boot:$BYTEMAN_HOME/lib/byteman.jar \
                -Dorg.jboss.byteman.transform.all MyAppClass arg1 arg2 ...

             

            or equivalently

             

            bmjava.sh -b -s /path/to/myscript.btm -Dorg.jboss.byteman.transform.all MyAppClass arg1 arg2

             

            When using bminstall you need to use an extra option and an extra property define

             

            bminstall.sh -b -Dorg.jboss.byteman.transform.all 

             

            However, that still won't fix things whether you are using Byteman from the command line or via BMUnit.

             

            Asecond problem is that the code you are injecting makes a reference to class CheckForbiddenAPIException which -- I assume -- is loaded by the system loader. I say 'I assume' because I am assuming you have placed this class in a hibernate jar located on the classpath. The problem is that from the point of view of the target class it is not possible to resolve the reference to CheckForbiddenAPIException.

             

            If you run your test with -Dorg.jboss.byteman.verbose set on the command line you ought to see a TypeCheck error being notified when Byteman considers your rule for injection. Alternatively, run the offline type checker on your rule script

             

            bmcheck.sh -cp /path/to/hibernate.jar myscript.btm

             

            and see what it says.

             

            There is a third problem that would probably bite you even if you could deal with the class resolution issue. You are trying to throw a Hibernate exception from method Class.getAnnotation. However, Clas does not declare CheckForbbiddenAPIException as a checked exception. Byteman will not inject THROW code into a method unless the exception is either i) a checked exception declared by themethod in its exception signature or ii) a RuntimeException or subclass of RuntimeException. The exception signature is part of the method's type contract with clients that Byteman will not break.

             

            If you change your rule to throw a RuntimeException I think that will work. However, I'm not sure what you are going to do to catch the exception!

             

            I tried also:

            RULE check annotation is not read at runtime
            INTERFACE ^AnnotatedElement
            METHOD getAnnotation
            IF true
            DO THROW new org.hibernate.session.runtime.check.CheckForbiddenAPIException("Reading annotation");
            ENDRULE

            with or without the `^` prefix.

            Is it supposed to work? If so, what is my mistake?

             

            This is going to suffer the same problems, both class resolution and exception type contract.

             

            By the way I'm using Byteman to do nice stuff, see https://github.com/hibernate/hibernate-orm/pull/3040

             

            Oh very good. Thanks for using Byteman and I hope you find a way to get it to do what you for this use case. If you tel me more about what you want to achieve maybe I can provide some advice (alternatively, you can ask Sanne who is one of my power users).

             

            regards,

             

             

            Andrew Dinn

            1 of 1 people found this helpful
            • 3. Re: Intercept java.lang.Class#getAnnotation
              fercoli

              Hi and nice to meet you Andrew.

              Thanks for the extensive response and the very interesting explanation.

              Sanne is the supervisor of the activity

               

              Yes, as you guessed, we're using the `BMUnit` library and `CheckForbiddenAPIException` extends directly `RuntimeException`, as suggested in the documentation.

               

              So it seems that by simply setting the `org.jboss.byteman.transform.all` system to` true`, the rule works very well.

              You can find another commit on the same pull request: https://github.com/hibernate/hibernate-orm/pull/3040.

              It just added the new rule and the property.

               

              Using Byteman we have detected many stuff, the ones we wanted to detect!

              So thank you and your team.

               

              Have a great day

              Fabio

              • 4. Re: Intercept java.lang.Class#getAnnotation
                adinn

                Hi Fabio,

                 

                Good to see you got this working!

                 

                regards,

                 

                 

                Andrew Dinn