11 Replies Latest reply on Jul 8, 2013 9:15 AM by Pete Muir

    A basic query on CDI Extension

    job75 Newbie

      Hi

      I'm new to CDI/Weld. I'm trying to use CDI to ingrate legacy application services with new set of services. Things that I did so far

       

      Created custom Qualifiers and a producer method and used the same to inject legacy Java services to new Java class

      Now client uses the following annaotation

          @Inject  @MyService

           SomeService someSvc;

       

      My custom Producer method creates an instance of SomeServiceImpl class.

      public @Produces  @MyService  SomeServiceI createSomeService(InjectionPoint injectionPoint){...}

       

      The SomeServiceImpl class generated by the producer in turn contain some set of  CDI annoatations. e.g

      public class SomeServiceImpl implements SomeServiceI  {

        @Inject  @TestSvc

          TestI test;

       

      }

      Question is, how do I make the  SomeServiceImpl (generated by my producer method) also to go through the same CDI life cycle so that it gets intitilaized properly with right set of dependency injections. Any example  will help. Thanks a lot

        • 1. Re: A basic query on CDI Extension
          Radim Hanus Expert

          not sure if I understood well but I guess you need to use right scope(s)

          for instance you may define the producer along with a session scope annotation to ensure that in a http session you always use the same instance:

           

          public @Produces @SessionScoped @MyService SomeServiceI createSomeService(InjectionPoint injectionPoint){...}

          • 2. Re: A basic query on CDI Extension
            job75 Newbie

            thanks Radim for the answer.  The above stuff works. But the issue is(or my question was), if I use producer method for creating SomeServiceImpl(impl returned by my producer method 'createSomeService'), the depency injections specifed within  SomeServiceImpl class is not getting evaluated, they get evaluated if I dont have any producer emthod. For e.g

                TestI test; is not getting injected in the below code.

            public class SomeServiceImpl implements SomeServiceI  {

              @Inject  @TestSvc

                TestI test;

             

            }

            • 3. Re: A basic query on CDI Extension
              Martin Kouba Master

              Hi job75,

               

              there's one thing I don't understand. SomeServiceImpl is a legacy code but still contains CDI annotations (@Inject, qualifiers, ...)? In any case it's up to the producer to fully initialize the produced object (note that interceptors and decorators are not applied to the return value as well). With regard to your use case (as I understand it) - I think you could use a portable extension and BeforeBeanDiscovery.addAnnotatedType()... see for example https://github.com/mojavelinux/cdi-extension-showcase/blob/master/src/main/java/com/acme/importbeans/RegisterBeanFromNonBeanClassExtension.java (replace SecureRandom.class with SomeServiceImpl.class).

              • 4. Re: A basic query on CDI Extension
                job75 Newbie

                Thanks Martin for your response. The above thing didnt really work for me. I can work around this if I call the following things from my producer method - however I wanted to get thing thing done by framework if ther is a way.

                 

                AnnotatedType<SomeServiceImpl> type = beanManager.createAnnotatedType(SomeServiceImpl.class);

                  InjectionTarget<SomeServiceImpl> it = beanManager.createInjectionTarget(type);

                  CreationalContext ctx = beanManager.createCreationalContext(null);

                  it.inject( someServiceImpl, ctx);  //call initializer methods and perform field injection

                  it.postConstruct(testI);

                • 5. Re: A basic query on CDI Extension
                  Martin Kouba Master

                  Hm, what exactly "didn't really work" means? I think your workaround will not work correctly - for instance injected dependent instances will not be destroyed properly (@PreDestroy callbacks and disposer methods will not be invoked). See also CDI 1.1: http://docs.jboss.org/cdi/spec/1.1/cdi-spec.html#bm_obtain_unmanaged_instance and javax.enterprise.inject.spi.Unmanaged javadoc...

                  1 of 1 people found this helpful
                  • 6. Re: A basic query on CDI Extension
                    job75 Newbie

                    >>Hm, what exactly "didn't really work" means?

                    It didn't work for me. The SomeServiceImpl didn't get its CDI enabled variables initialized. btw, all works if I remove my custom producer method( as usual ). Not sure if I missing some basics. Any sample is available?

                    • 7. Re: A basic query on CDI Extension
                      Marko Lukša Apprentice

                      If you create the instance yourself (with new SomeServiceImpl()) - even if you do it inside a producer method - CDI will never just magically inject things into your instance. You either have to let CDI create the instance for you or you must create an injection target (as you did in one of your previous comments).  One way of having CDI create the instance for you, is through a CDI extension, as Martin mentioned.

                      1 of 1 people found this helpful
                      • 8. Re: A basic query on CDI Extension
                        job75 Newbie

                        >One way of having CDI create the instance for you, is through a CDI extension, as Martin mentioned.

                        I've tried that, didn't work for me.

                         

                        I'm attaching a sample JSF web application(a maven project built using Netbeans 7.3.1) where the issue is replicated.  I could be missing some basics(for sure)

                        https://adf-samples.googlecode.com/files/cdi-testcase.zip

                         

                        In this sample, the index.xhtml uses IndexPageBean. When you click the button on this page it invokes IndexPageBean::btnClicked(). This method inturn invokes  MyServiceImpl::doCheck()  MyServiceImpl is injected through my producer class(MyServiceProducer).  MyServiceImpl  has SomeModularServiceI as memeber variable which fails to get intiailized through CDI if I use my own producer.

                        Tried the Martin's suggestion of using Extension to add AnnotatedType, doesnot seems working for me(or I missed something here). Can anyone please help

                        • 9. Re: A basic query on CDI Extension
                          Marko Lukša Apprentice

                          Job, it's really not clear what you are trying to achieve. What do you actually need the producer method for? Do you want it to return a specific implementation of MyService, while you actually have many implementations available at runtime? Is this why you want to create the instance yourself?

                           

                          In cdi-testcase.zip your producer is creating a new instance of MyServiceImpl. As I said before, CDI will not inject anything into it. You have to let CDI create the instance for you. You do this by either putting MyServiceImpl into a bean archive (add beans.xml to the jar the class is in) or by calling BeforeBeanDiscovery.addAnnotatedType() if you can't put the class into a bean archive.

                          • 10. Re: A basic query on CDI Extension
                            job75 Newbie

                            >What do you actually need the producer method for?

                            Thanks Mark for the reply. Yes , It's bid odd case. In fact, I'm trying out a POC. In real life case, MyServiceImpl could be a pooled object managed by the continer(it's custom managed object and its not based on any standard technolgoy such as EJB + CDI doesnot know aout the traget plactform in this case). So I cannot let CDI simply to create a new intance of MyServiceImpl, rather my producer method may have logic to look up from the pool(this logic is missing in the sample to keep it simple).  So I'm juts seeing whether MyServiceImpl can also have CDI enabled memeber varibale(i.e  introducing CDI for injecting thing in my legacy MyServiceImpl).  In a nutshell , I need control on injecting MyServiceImpl instnaces, and at the sametime, would like know whther MyServiceImpl can have 'normal' CDI enebaled memeber variables (whose linjections are normal and straight forward and can be managed by CDI).  If this is not acheivable, probably I can change my approach( ie. having CDI annotated variables as members in MyServiceImpl )




                            • 11. Re: A basic query on CDI Extension
                              Pete Muir Master

                              In CDI 1.0

                               

                               

                              AnnotatedType<SomeServiceImpl> type = beanManager.createAnnotatedType(SomeServiceImpl.class);

                                InjectionTarget<SomeServiceImpl> it = beanManager.createInjectionTarget(type);

                                CreationalContext ctx = beanManager.createCreationalContext(null);

                                it.inject( someServiceImpl, ctx);  //call initializer methods and perform field injection

                                it.postConstruct(testI);

                               

                              is your best approach.

                               

                              In CDI 1.1, you can use the more concise version that Martin linked to - http://docs.jboss.org/cdi/spec/1.1/cdi-spec.html#bm_obtain_unmanaged_instance