7 Replies Latest reply: Dec 9, 2012 5:31 PM by Rafael Pestano RSS

Automatic Injection based on Stereotype

Rafael Pestano Newbie

Hi everyone,

 

i'd like to know if its possible to automatic inject a field based on the bean type. let me explain:

 

 

given the Hello interface:

 

 

public interface Hello {

    String sayHello();

}

 

, the EnglishHello implementation:

 

 

@English
public class EnglishHello implements Hello{

     public String sayHello(){
          return "Hello World!";
     }

}

 

, the PortugueseHello implementation:

 

@Portuguese
public class PortugueseHello implements Hello{

     public String sayHello(){
          return "Ola mundo!";
     }

}

, the BaseHelloBean

 

public abstract class BaseHelloBean {

     protected Hello hello;//this attribute will be injected by the child class via setter method


    public void setBaseHello(Hello hello){
           this.hello = hello;
     }


}

 

 

, the EnglishHelloBean:

 

@Model
public class EnglishHelloBean extends BaseHelloBean{


@Inject 
public void setHello(@English  Hello hello){ //i want to avoid this method
     super.setBaseHello(hello);
}

}

 

and finaly the PortugueseHelloBean

 

@Model
public class PortugueseHelloBean extends BaseHelloBean{

 @Inject 
 public void setHello(@Portuguese Hello hello){
     super.setBaseHello(hello);
}

}

 

 

What i want to achieve is something like:

 

 

@Model
@Portuguese  
public class PortugueseHelloBean extends BaseHelloBean{

 //the hello implementation is automatically injected based on the stereotype
}

 

So the question is, is it possible? im thinking about an extension which would inspect the classes that have the Portuguese or English Qualifier(actually it should be an annotation @Language(value="english/portuguese") and then inject the appropriated Hello implementation but i dont know how to do that in the extension or in any other place.

 

So thoughts, examples, links are all appreciated, thanks in advance!

  • 1. Re: Automatic Injection based on Stereotype
    Ales Justin Master

    You could modify the injection point of that Port/Eng bean; adding the right qualifier to it.

    Simply grab right annotated type from extension and modify the method or field aka injection point.

  • 2. Re: Automatic Injection based on Stereotype
    Rafael Pestano Newbie

    Thanks for the reply Ales but i really dont know what to do in the extension,

     

     

    public class HelloExtension implements Extension{
    
          void processAnnotatedType(@Observes ProcessAnnotatedType<BaseHelloBean> pat,BeanManager bm) {
                    if(pat.getAnnotatedType().isAnnotationPresent(Portuguese.class)){
                        AnnotatedType<BaseHelloBean> at =  pat.getAnnotatedType();
                        final InjectionTarget<BaseHelloBean> it =  bm.createInjectionTarget(at); 
                        //i have no ideia how to inject the PortugueseHello in the annotatedType
                    }
       }
    
    }
    
    

     

    Also i dont have(i dont want to have) an injectionPoint in the Port/English beans, the idea is to avoid:

     

    @Inject
    public void setHello(@Portuguese Hello hello){ //i want to avoid this method
         super.setBaseHello(hello);
    }

     

    and use:

     

    @Model
    @Portuguese 
    public class PortugueseHelloBean extends BaseHelloBean{

    //the hello implementation is automatically injected based on the stereotype
    }

     

    thus injecting the correct Hello, in the extension, based on the stereotype.

  • 3. Re: Automatic Injection based on Stereotype
    Ales Justin Master

    Something like this:

     

        public void processAnnotatedType(@Observes ProcessAnnotatedType<Child> event) {

            final AnnotatedType<Child> annotatedType = event.getAnnotatedType();

            event.setAnnotatedType(new ForwardingAnnotatedType<Child>() {

                @Override

                public AnnotatedType<Child> delegate() {

                    return annotatedType;

                }

     

                @Override

                public Set<AnnotatedMethod<? super Child>> getMethods() {

                    return super.getMethods(); // fix injection point here

                }

     

     

                @Override

                public Set<AnnotatedField<? super Child>> getFields() {

                    return super.getFields(); // or, fix injection point here

                }

  • 4. Re: Automatic Injection based on Stereotype
    Ales Justin Master

    Child is a test class from my copy/paste example --> in your case you of course need to grab the right HelloBean.

  • 5. Re: Automatic Injection based on Stereotype
    Rafael Pestano Newbie

    thanks for the tips, now i just need to know how to add a qualifier to a field

     

     

     

     if(pat.getAnnotatedType().isAnnotationPresent(Portuguese.class)){
                        final AnnotatedType<BaseHelloBean> at = (AnnotatedType<BaseHelloBean>) pat.getAnnotatedType();
                        
                        ForwardingAnnotatedType<BaseHelloBean> fy = new ForwardingAnnotatedType<BaseHelloBean>() {
    
    
                        @Override
                        public AnnotatedType<BaseHelloBean> delegate() {
                            return at;
                        }
    
    
                        @Override
                        public Set<AnnotatedField<? super BaseHelloBean>> getFields() {
                            
                            return this.modifyHelloField(super.getFields());
                        }
                        
                        private Set<AnnotatedField<? super BaseHelloBean>> modifyHelloField(Set<AnnotatedField<? super BaseHelloBean>> fields){
                            for (AnnotatedField<? super BaseHelloBean> annotatedField : fields) {
                                if(annotatedField.getBaseType().equals(Hello.class)){
                                    //now the question is how to add the qualifier to the field
                                    //annotatedField.getAnnotations().add(new PortugueseImpl());
                                }
                            }
                        }
                                
                        
                    };
                        
               
                        pat.setAnnotatedType(fy);
    
                    }
    
    

     

     

    i've made a fast google search and see that its not simple to add an annotation to a field so i think with CDI its done in a different way, via injection target maybe but i dont know how to do that.

  • 7. Re: Automatic Injection based on Stereotype
    Rafael Pestano Newbie

    Yea that did the trick , thanks for your help Ales.

     

    here is the working extension:

     

     

    public class HelloExtension implements Extension {
        private AnnotatedTypeBuilder<BaseHelloBean> builder = null;
    
    
        void processAnnotatedType(@Observes ProcessAnnotatedType<BaseHelloBean> pat)  {
            final AnnotatedType<BaseHelloBean> at = pat.getAnnotatedType();
            if (pat.getAnnotatedType().isAnnotationPresent(Portuguese.class)) {
                injectLanguage(at, new PortugueseImpl());
            } else if(pat.getAnnotatedType().isAnnotationPresent(English.class)){
                 injectLanguage(at, new EnglishImpl());
            }
            if(builder != null){
                pat.setAnnotatedType(builder.create());
            }
    
    
        }
    
        private void injectLanguage(AnnotatedType<BaseHelloBean> at, AnnotationLiteral language){
             for (AnnotatedField<? super BaseHelloBean> annotatedField : at.getFields()) {
                    if (annotatedField.getBaseType().equals(Hello.class)) {
                        builder = initializeBuilder(builder, at);
                        builder.addToField(annotatedField, language);
                        builder.addToField(annotatedField, new InjectLiteral());
                    }
                }
        }
    
    
        private <X> AnnotatedTypeBuilder<X> initializeBuilder(final AnnotatedTypeBuilder<X> currentBuilder, final AnnotatedType<X> source) {
                return new AnnotatedTypeBuilder<X>().readFromType(source);
    
        }
    }
    
    public class PortugueseImpl extends AnnotationLiteral<Portuguese> implements Portuguese{
    
    }
    
    

     

    and now i can inject the correct Hello based on the stereotype

     

    @Model

    @Portuguese

    public class PortugueseHelloBean extends BaseHelloBean{

     

     

    }

     

    edit: blogged here(in pt_BR): http://rpestano.wordpress.com/2012/03/31/hello-world-cdi-extension/

    source code here: https://github.com/rmpestano/hello-extension