3 Replies Latest reply on Jul 31, 2012 6:48 PM by atomicknight

    Simulating guice's Assisted Injection

    wz2b

      I want to do something like Guice's assisted injection with CDI, but

      I'd prefer to not have to add CDI extensions to do it, because that

      makes deployment quite messy.  I have tried a few things, but can't quite seem to find a pattern that works.


      Here's a simple example.  I have an object MyDaoObject that is a Data

      Access Object. There are multiple databases, and it has to

      choose the correct one.  I want to construct the object via injection.


      public class MyDaoObject implements MyDaoObject {

              private String dbid;


              @Singleton

              public static class Factory {


                      @Inject @New

                      Instance<MyDaoObject> cdiFactory;


                      public MyDaoObject get( String dbid ) {

                              MyDaoObject dao = cdiFactory.get();

                              dao.dbid = dbid;

                              return dao;

                      }

              }

      }




      When I try to construct one of these, the using class does something like:

          @Inject MyDaoObject.Factory fact;

          ...

          MyDaoObject = fact.get( "db12345678" );



      What happens though is that two MaintDaoObjects get created.  One is

      prepared properly (dbid is set), the other is not.


      So this apparently is not a good pattern.


      Next I tried to reverse the pattern: have the Factory be the outer

      class, and the MyDaoObject be a nested (non-static) class within.

      This also failed, because CDI was unable to find the inner class.


      I'm now not entirely sure what's the best pattern here.  I'm leaning

      toward having MyDaoObject have a .setDbid() method that only allows it

      to be set once (yuck!)   I essentially want that field to be immutable

      once the object is created.



      What's the best pattern to approximate assisted injection without CDI

      extensions?


      --Chris

        • 1. Re: Simulating guice's Assisted Injection
          atomicknight

          Well, your example doesn't seem to really merit assisted injection (since it doesn't have any dependencies), but the basic template used by Guice is the following (Guice annotations noted in comments):

           

          {code}public class Foo {

            private final BarService barService;

            private final Baz baz;

           

            /*@Inject*/

            private Foo( BarService barService, /*@Assisted*/ Baz baz ) {

              this.barService = barService;

              this.baz = baz;

            }

           

            // Foo methods

           

            @Singleton

            public static class Factory {

              @Inject private BarService barService; // Or use constructor injection

           

              public Foo create( Baz baz ) {

                return new Foo( barService, baz );

              }

            }

          }{code}

           

          And then you use it like this:

           

          {code}public class Qux {

            @Inject private Foo.Factory fooFactory;

           

            public void doit( Baz baz ) {

              Foo foo = fooFactory.create( baz );

            }

          }{code}

          • 2. Re: Simulating guice's Assisted Injection
            wz2b

            Yeah, it was just an example .. the real class being created (in place of your example "Foo") has other stuff injected into it - a logger, a few database handlers, and so forth.  It's more than I really want to pass on the constructor, though if that's the only way maybe I have to.

             

            If I create an object with new, is there some way I can, after the fact, tell CDI to inject members?

            • 3. Re: Simulating guice's Assisted Injection
              atomicknight

              Christopher Piggott wrote:

               

              Yeah, it was just an example .. the real class being created (in place of your example "Foo") has other stuff injected into it - a logger, a few database handlers, and so forth.  It's more than I really want to pass on the constructor, though if that's the only way maybe I have to.

               

              If you're shooting for complete immutability, the constructor route is really the only way to go. Given that the constructor is encapsulated within the class, I don't see anything particularly distasteful about having lots of parameters.

               

              Christopher Piggott wrote:

               

              If I create an object with new, is there some way I can, after the fact, tell CDI to inject members?

               

              Not really - the CDI model is based on the idea of resolving dependencies just once at startup. Though depending on your particular use case, you could potentially chain/compose a number of these factories to achieve something similar (e.g. with [non-CDI] decorators).