6 Replies Latest reply on Nov 9, 2009 2:31 AM by Nikolay Elenkov

    Annotation processing in Seam

    Arbi Sookazian Master

      How exactly does Seam process the annotations in a Seam component?


      For example:


      @Name("foo")
      public class Foo {
      
          @Begin(join=true, flushMode=FlushModeType.MANUAL)
          public void beginConversation() {
              //do stuff
          }
      
          @End
          public void submit() {
             //do stuff
          }
      
      }



      I noticed there is a org.jboss.seam.util.Reflections class but honestly I am unfamiliar with how annotation processing occurs in Java 5 in general.


      Can someone please shed some light on this?

        • 1. Re: Annotation processing in Seam
          Arbi Sookazian Master

          Well, I found this in wikipedia:



          Processing


          When Java source code is compiled, annotations can be processed by compiler plug-ins called annotation processors. Processors can produce informational messages or create additional Java source files or resources, which in turn may be compiled and processed, but processors cannot modify the annotated code itself. The Java compiler conditionally stores annotation metadata in the class files if the annotation has a RetentionPolicy of CLASS or RUNTIME. Later, the JVM or other programs can look for the metadata to determine how to interact with the program elements or change their behavior.

          so how does this work in a Seam app runtime context?


          • 2. Re: Annotation processing in Seam
            Ingo Jobling Master

            Hi Arbi,


            In a nutshell, Seam generates proxies for components (Java classes annotated with @Name).  Calls to methods on the component are thus intercepted by the proxy, which can then examine the annotations and perform the appropriate processing.


            Regards,
            Ingo

            • 3. Re: Annotation processing in Seam
              Arbi Sookazian Master

              What class(es) do the actuall annotation processing?  I looked in the Seam core packages and there are some Java Reflection API usage.


              I wrote the following class to simulate this:


              @Name("testReflections")
              @Startup
              @Scope(ScopeType.APPLICATION)
              public class TestReflections {
                   
                   @Logger private Log log;
                   
                   @Create
                   public void init(){
                                  
                        getAnnotations("org.jboss.seam.example.booking.BookingListAction");
                        
                   }
                   
                   private void getAnnotations(String myClass) {
                        
                        try {
                             Class clazz = Class.forName(myClass);
                             Method[] methods = clazz.getMethods();
                             java.lang.annotation.Annotation[] annotations = null;
                             for (int i = 0; i < methods.length; i++) {
                                  log.info("methods[i].toString(): "+methods[i].toString());
                                  annotations = methods[i].getAnnotations();
                                  for(int j = 0; j < annotations.length; j++){
                                       java.lang.annotation.Annotation annotation = annotations[j];
                                       log.info("annotation.toString() = "+annotation.toString());
                                  }
                             }
                             log.info("***********************************************************************************");
                        }
                        catch (ClassNotFoundException e) {
                             log.error("error found: ", e);
                        }
                   }
              }



              Output:


              22:43:33,295 INFO  [TestReflections] methods[i].toString(): public void org.jboss.seam.example.booking.BookingListAction.destroy()
              22:43:33,298 INFO  [TestReflections] annotation.toString() = @javax.ejb.Remove(retainIfException=false)
              22:43:33,299 INFO  [TestReflections] methods[i].toString(): public void org.jboss.seam.example.booking.BookingListAction.cancel()
              22:43:33,299 INFO  [TestReflections] methods[i].toString(): public void org.jboss.seam.example.booking.BookingListAction.getBookings()
              22:43:33,301 INFO  [TestReflections] annotation.toString() = @org.jboss.seam.annotations.Factory(value=, autoCreate=false, scope=UNSPECIFIED)
              22:43:33,302 INFO  [TestReflections] annotation.toString() = @org.jboss.seam.annotations.Observer(value=[bookingConfirmed], create=true)
              22:43:33,302 INFO  [TestReflections] methods[i].toString(): public org.jboss.seam.example.booking.Booking org.jboss.seam.example.booking.BookingListAction.getBooking()
              22:43:33,302 INFO  [TestReflections] methods[i].toString(): public native int java.lang.Object.hashCode()
              22:43:33,302 INFO  [TestReflections] methods[i].toString(): public final native java.lang.Class java.lang.Object.getClass()
              22:43:33,302 INFO  [TestReflections] methods[i].toString(): public final void java.lang.Object.wait() throws java.lang.InterruptedException
              22:43:33,302 INFO  [TestReflections] methods[i].toString(): public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
              22:43:33,302 INFO  [TestReflections] methods[i].toString(): public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
              22:43:33,302 INFO  [TestReflections] methods[i].toString(): public boolean java.lang.Object.equals(java.lang.Object)
              22:43:33,302 INFO  [TestReflections] methods[i].toString(): public final native void java.lang.Object.notify()
              22:43:33,302 INFO  [TestReflections] methods[i].toString(): public final native void java.lang.Object.notifyAll()
              22:43:33,303 INFO  [TestReflections] methods[i].toString(): public java.lang.String java.lang.Object.toString()
              22:43:33,303 INFO  [TestReflections] ***********************************************************************************

              • 4. Re: Annotation processing in Seam
                Arbi Sookazian Master

                Ingo Jobling wrote on Jul 26, 2009 00:34:


                Hi Arbi,

                In a nutshell, Seam generates proxies for components (Java classes annotated with @Name).  Calls to methods on the component are thus intercepted by the proxy, which can then examine the annotations and perform the appropriate processing.

                Regards,
                Ingo



                The keyword 'proxy' is not in the index for DAllen or Yuan books.  In the Seam 2.1.2 ref doc the only reference to 'proxy' is in the context of remoting and Spring integration.


                Someone plz shed add'l light on this...

                • 5. Re: Annotation processing in Seam
                  Shervin Asgari Master

                  Hi Arbi. I wondered the same thing, and I looked in the source code and figured it out. I was looking at the RequestParameter annotation.


                  Seam uses reflection to load all annotations, and if for instance the RequestParameter annotation is there, then it know what to perform, in this case using the name of the variable and getting the value from the request. I didn't dig further, but I am pretty sure thats how they intercept and use annotations with Seam.

                  • 6. Re: Annotation processing in Seam
                    Nikolay Elenkov Master

                    Arbi Sookazian wrote on Jul 27, 2009 07:49:


                    What class(es) do the actuall annotation processing?  I looked in the Seam core packages and there are some Java Reflection API usage.



                    As usual, Seam uses interceptors. Annotations are just metatdata for a method or a class, Seam inspects those (using reflection) and decides what to do. So for example, there is a ConverstationIntreceptor (as usual, there are lots of TODO's...):


                          else if ( method.isAnnotationPresent(Begin.class) )
                          {
                             String[] outcomes = method.getAnnotation(Begin.class).ifOutcome();
                             if ( outcomes.length==0 || Arrays.asList(outcomes).contains(result) )
                             {
                                beginConversation( 
                                      method.getAnnotation(Begin.class).nested(), 
                                      getProcessDefinitionName(method) 
                                   );
                                setFlushMode(method); //TODO: what if conversation already exists? Or a nested conversation?
                             }
                          }
                    



                    There is of course BijectionInterceptor, EventInterceptor, etc. Grep the source to find more.