1 2 Previous Next 23 Replies Latest reply on Jan 3, 2010 5:45 AM by meetoblivion

    Dynamic Injection

    meetoblivion

      So I'm not sure if I'm doing this wrong, or if it's just not supported in a clean fashion yet.


      Let's say I have a Foo class.  I also have Bars, which are indirectly created based on a Foo, but, both Foo and Bar need to be created via external producers (as I don't control either class).


      So I define my producer method in my FooMakerBean


      @Produces
      @SomeQualifier(key1="",key2="")
      public Foo produceFoo(InjectionPoint ip) {
      Foo f = new Foo();
      SomeQualifier sq = ip.getAnnotated().getAnnotation(SomeQualifier.class);
      if(key1.equals("Some value")) {
      //do something
      } else {
      //do something else.
      }
      }





      And for Bars, in BarMakerBean




      @Produces
      @SomeOtherQualifier(key="")
      public Bar produceBar(InjectionPoint ip) {
      ...
      }





      Now this is the part where it gets a bit hairy, in my opinion.  I really don't care about Foo's, other than needing a Foo to make a Bar.  From what I can tell, I need to use BeanManager.getReference() to get the Foo.  Every Foo is going to be @ApplicationScoped.  However, in order to get the Foo, the Bar has to know about the Foo, which means that SomeOtherQualifier is going to have to turn into @SomeOtherQualifier(key="",foo=@SomeQualifier(key1="",key2="")).  Would this in fact be the best way to approach dynamic injection in the current state?

        • 1. Re: Dynamic Injection
          gavin.king

          I don't understand your problem. (Your explanation is missing about 3 steps.) Perhaps you just need to use an AnnotationLiteral to instantiate the SomeQualifier instance.

          • 2. Re: Dynamic Injection
            meetoblivion

            I don't think I need to instantiate the SomeQualifier instance.  I'm not sure what 3 steps I'm missing, so that's probably why they're missing.  Basically, for a given Foo, it can help me make a Bar with some reusable business logic, but it's all tied to the Foo instance.  so that means when I @Inject @SomeOtherQualifier(key="",foo=@SomeQualifier(key1="",key2="")) Bar bar; I'm essentially going to have to look up the dynamic Foo instance based on the foo parameter of my SomeOtherQualifier, right?


            Another question, is this going to end up being scoped properly? If my Foo instances are all ApplicationScoped, it's not going to produce a new Foo each time, right?

            • 3. Re: Dynamic Injection
              gavin.king

              So you're telling me you want to have to write @SomeOtherQualifier(key="",foo=@SomeQualifier(key1="",key2="")) at the injection point? I figured you were trying to avoid that. You have a qualifier for one object that embeds the qualifier of another object? That sounds kinda awful. It's not how qualifiers are really mean to be used.



              I'm essentially going to have to look up the dynamic Foo instance based on the foo parameter of my SomeOtherQualifier, right?

              Well, if the generic producer that produces the Bar can't directly inject the Foo because the qualifier of the Foo depends upon the instance of Bar, then you need to do a lookup. Just inject @Any Instance<Foo> into the producer method.


              But since your Foo producer method needs an InjectionPoint, you can't use lookup in this case.


              Look, I think you need to take a step back, actually describe your real requirements (without Foos and Bars) so that I can understand what you're actually trying to achieve.

              • 4. Re: Dynamic Injection
                meetoblivion

                Ok (and it's going to require a bit of knowledge of DNA's APIs).  No, I do not think it's a clean way using the interwoven Qualifiers, but I can't think of any other way to do it.


                You start with an object called JcrConfiguration.  This will be created once, application level, and only one exists.  This is a forget about it object, it needs to exist, but you only need it to pull out other objects.  I want to make this configurable to some level (on start up, it reads an XML file to configure itself, and the path to this XML file is likely to end up in the annotation).  JcrConfiguration has a method start() that creates a JcrEngine object.  The way I see it, I need to wrap the call to this start() in a Producer as I will need the JcrEngine to create javax.jcr.Repository and javax.jcr.Session instances.  In theory, you could have multiple JcrConfiguration/JcrEngines, simply by having them be


                @Inject @NamedJcrEngine("/path/to/my/config.xml") JcrEngine engine1;
                @Inject @NamedJcrEngine("/path/to/another/config.xml") JcrEngine engine2;



                instances of javax.jcr.Repository are going to be dynamic, e.g. the code I'm working on will not be aware of what Repositories will be created, it'll be up to the application that uses this library to determine that.  The complication comes in at this point.  I want my code to be able to produce the Repository without being aware ahead of time what JcrEngine will be needed.  The way I see it, the best way to do this is to have my Repository annotated as:


                @Inject @NamedRepository(name="AuditRepo",engine=@NamedJcrEngine("/path/to/my/config.xml")) Repository repo1Engine1;
                @Inject @NamedRepository(name="ProductRepo",engine=@NamedJcrEngine("/path/to/my/config.xml")) Repository repo2Engine1;
                @Inject @NamedRepository(name="SillyRepo",engine=@NamedJcrEngine("/path/to/another/config.xml")) Repository repo1Engine2;



                Which means that my producer for repositories would need to lookup the JcrEngine for the given engine attribute on the annotation.


                And please let me know if it just sounds way too difficult, as what I'm trying to mimic is how a <bean ref=""/> works in spring, except by making it more dynamic.

                • 5. Re: Dynamic Injection
                  alin.heyoulin.qq.com

                  Right, currently i modify weld code to support spring bean inject(@Autowire). and intergrate spring jpacontainer and transaction(@Transactional).So i can use two framework advantage.


                  I love weld's observer,fireEvent,type safe,decorators....
                  I also love spring's dynamic inject,xml config......

                  • 6. Re: Dynamic Injection
                    asookazian

                    he youlin wrote on Dec 29, 2009 19:55:

                    I also love spring's dynamic inject,xml config......


                    How does Spring do dynamic injection?  via proxies?  I couldn't find anything on this in google...

                    • 7. Re: Dynamic Injection
                      alin.heyoulin.qq.com

                      I can create xml in runtime and create beans by beanfactory. I don't know if this is dynamic injection.

                      • 8. Re: Dynamic Injection
                        gavin.king

                        No, I do not think it's a clean way using the interwoven Qualifiers, but I can't think of any other way to do it.

                        A qualifier is a way of selecting between pre-defined implementations, it's not meant for defining things. You can't just embed your Spring XML bean definition into a qualifier, that's not what it's for. OK, so InjectionPoint lets you push the boundary on this a bit, but not very far.


                        So what you are looking for is a way to define a generic set of inter-related beans. The usual way to define a bean in CDI is to write a Java class or producer method. But that's not the only way. The portable extension SPI let's you read some other metadata source, and create and register a Bean object. The other metadata source could be an XML or properties file, or course, or it could be an annotation on a field, method, class or interface.


                        For these kinds of problems, a portable extension is the right solution. An earlier revision of the spec did have the notion of realization which was designed to address cases like this where you want to define generic producer methods that are inherited by subclasses, but with different qualifiers. But that feature didn't make it (probably a good thing, too).

                        • 9. Re: Dynamic Injection
                          gavin.king

                          he youlin wrote on Dec 29, 2009 20:14:


                          I can create xml in runtime and create beans by beanfactory. I don't know if this is dynamic injection.


                          Yick! How is this not a much uglier solution than CDI's portable extension SPI?

                          • 10. Re: Dynamic Injection
                            gavin.king

                            By these kinds of problems, I mean cases where you want to specify a single item of metadata, and have that result in the creation of multiple beans.

                            • 11. Re: Dynamic Injection
                              alin.heyoulin.qq.com

                              For these kinds of problems, a portable extension is the right solution

                              I'm glad to see it and hope seam3 will do for me.



                              Yick! How is this not a much uglier solution than CDI's portable extension SPI?

                              Yes,this just a example. In my project i don't use like that.



                              By these kinds of problems, I mean cases where you want to specify a single item of metadata

                              Yes,but i really want to reuse some whole function of spring include it's metadata.

                              • 12. Re: Dynamic Injection
                                meetoblivion

                                Hmm.  I kind of get what you're saying.  In this case though, the instances represented by JcrEngine and javax.jcr.Session should belong to different scopes (JcrEngine should be @ApplicationScoped and Session should be @RequestScoped).  At runtime, the JcrEngine should be created when the application gets initialized - e.g. a Singleton bean should have something like @Inject @MyQualifier JcrEngine engine.  I'm not looking to precreate the instances either, they should be created


                                So besides the fact that it looks a bit ugly and that it somewhat borders programming xml/programming annotations, is there a big issue if I use the initial approach?  I really don't get what's going to end up being so different in the code if I use a portable extension vs annotations and producer methods.


                                I assume at some level, I'm still going to have an annotation that's pointing to an properties/xml file, rather than just inferring the configuration based on the annotation, right?

                                • 13. Re: Dynamic Injection
                                  gavin.king

                                  Hmm. I kind of get what you're saying. In this case though, the instances represented by JcrEngine and javax.jcr.Session should belong to different scopes (JcrEngine should be @ApplicationScoped and Session should be @RequestScoped). At runtime, the JcrEngine should be created when the application gets initialized - e.g. a Singleton bean should have something like @Inject @MyQualifier JcrEngine engine. I'm not looking to precreate the instances either, they should be created

                                  Right, that's the point I'm trying to make. You have a bunch of different objects with different lifecycles and different scopes. Even if I was to use Seam2 or Spring XML, I would need multiple bean definitions for every JCR respository. I just don't think that's the right way. Much better to write a portable extension that picks up a single item of metadata defining the repository and creates all the beans relating to that repository.



                                  So besides the fact that it looks a bit ugly and that it somewhat borders programming xml/programming annotations, is there a big issue if I use the initial approach? I really don't get what's going to end up being so different in the code if I use a portable extension vs annotations and producer methods.

                                  Your initial approach just wasn't going to work. It's broken. You just can't use qualifiers like that.

                                  • 14. Re: Dynamic Injection
                                    gavin.king

                                    So I've been bothered for a while by these kinds of problems. I experimented with the realization stuff in the spec, but honestly that didn't quite work out, so we ditched it. I think the problem was that I had my head too much in how existing products like Spring or Seam2 solve the problem with XML, and that was blocking my creativity. Today I came up with a much better, much simpler solution than XML. I don't think we can easily, elegantly implement this as a portable extensions right now (though I think it's possible with some inelegance), but we can do it once I have some new SPI features that are already on the wishlist. Alternatively, perhaps this stuff is cool enough to add to the actual spec in 1.1.


                                    The idea is that you can define a set of generic beans for a specific config annotation like @MessageBus. These beans can inject the configuration, and can inject each other.


                                    @Generic(MessageBus.class)
                                    @ApplicationScoped
                                    class Topic {
                                         @Inject MessageBus config;
                                    }



                                    @Generic(MessageBus.class)
                                    @RequestScoped
                                    class Session {
                                         @Inject Topic topic;
                                         @Inject MessageBus config;
                                    }



                                    You can then add the config annotation to a producer field, together with whatever qualifier annotations you need:


                                    @Produces
                                    @MessageBus(topic="default") 
                                    Topic topic;
                                    
                                    @Produces @Prices 
                                    @MessageBus(topic="prices") 
                                    Topic prices;
                                    
                                    @Produces @Deals 
                                    @MessageBus(topic="deals") 
                                    Topic deals;



                                    And now, finally, we can inject the configured objects:


                                    @Inject Topic topic;
                                    @Inject Session session;
                                    
                                    @Inject @Prices Topic topic;
                                    @Inject @Prices Session session;
                                    
                                    @Inject @Deals Topic topic;
                                    @Inject @Deals Session session;



                                    The trick here is that the @Prices Session gets the @Prices Topic injected, along with @MessageBus(topic="prices") , and the @Deals Session gets the @Deals Topic injected, along with @MessageBus(topic="deals").


                                    WDYT?

                                    1 2 Previous Next