Search code examples
javaproxyseam

Losing Class Custom Annotation For Proxy Classes


I am using Seam to inject beans to my controller using @In annotation. The injected class has a custom annotation, when calling injectedClass.getClass().getAnnotation(annotationClass) it returns null.

When debug I found that Seam passes a proxy instance so getClass() returns InjectedClass_$$_javassist_seam_5 which doesn't have my custom annotation.

How I can get my custom annotation from the proxy class?

Here's how my classes look like:

@CustomAnnotation(value="myvalue")
@Name("myAnnotatedClass")
public class MyAnnotatedClass extends SuperClass {...}

@Scope(ScopeType.SESSION)
@Name("myController")
public class MyController {
     @In("#{myAnnotatedClass}")
     private MyAnnotatedClass myAnnotatedClass;

     public void actionMethod(){
         //call another class which call myAnnotatedClass.getClass().getAnnotation(CustomAnnotation.class)
         //then do some reflection for MyAnnotatedClass fields 
     }
}

Solution

  • Good question.

    When you call a method by using Seam, it is intercepted by a proxy. And this one enables @In or @Out-jection. But There is an exception to this rule: it does not work when you call an internal method

    So try this code

    @Name
    public class Service {
    
        @In
        private MyAnnotatedClass myAnnotatedClass;
    
    
        public void myInterceptedMethod() {
            // internal method bypass interceptor
            // So @In or @Out-jection is not enabled
            internalMethod();
        }
    
        private void internalMethod() {
            System.out.println(myAnnotatedClass.getClass().getAnnotation(annotationClass));
        }
    
    }
    

    Added to original answer

    You want to retrieve an annotation from your bean. But, because of method interceptor, myAnnotatedClass.getClass() returns a proxy object, not the bean class itself.

    For each bean class, Seam creates a Component definition, in which is stored in the application context. The name of the attribute follows this pattern: component name plus .component. So if you have a bean like this one

    @Name("myBean")
    public class MyBean {
    
    }
    

    Its Componet definition is stored in the attribute myBean.component

    So inside your method, you can use

    Component myBeanComponentDefinition = (Component) Context.getApplicationContext().get("myBean.component");
    

    Now you can call

    myBeanComponentDefinition.getBeanClass().getAnnotation(CustomAnnotation.class);
    

    regards,