7 Replies Latest reply on Dec 9, 2012 5:31 PM by kwintesencja

    Automatic Injection based on Stereotype

    kwintesencja

      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
          alesj

          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
            kwintesencja

            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
              alesj

              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

                          }

              1 of 1 people found this helpful
              • 4. Re: Automatic Injection based on Stereotype
                alesj

                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
                  kwintesencja

                  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.

                  • 6. Re: Automatic Injection based on Stereotype
                    kwintesencja
                    • 7. Re: Automatic Injection based on Stereotype
                      kwintesencja

                      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