8 Replies Latest reply on Oct 25, 2010 2:10 AM by glammy

    Inject a List of objects in CDI (Weld)

    glammy

      Let's say I have an interface called SocialNetworkService, and three implementations - TwitterService, FacebookService and FriendFeedService.


      Now I want, whenever my managed bean (or whatever web component) receives a message, to share it in all social networks. I tried:


      @Inject
      private List<SocialNetworkService> socialNetworkServices;


      But it didn't work. (Also tried to the @Any qualifier - same result)


      So, is there a way to inject a list of all (or some) implementations of an interface?


      I know the rule that a given injection point should not have more than one possible bean.
      I guess I can achieve that by making a producer that produces the list, and using Instance<SocialNetworkService>, but that seems like too much for this task.

        • 1. Re: Inject a List of objects in CDI (Weld)
          ljnelson

          Ooh!  Ooh!  One I can answer!


          Look at http://download.oracle.com/javaee/6/api/javax/enterprise/inject/Instance.html and notice that it is also an Iterable (left angle bracket) T (right angle bracket).


          Best,
          Laird

          • 2. Re: Inject a List of objects in CDI (Weld)
            glammy

            I mentioned in my question that I'm aware of this option, but it seems like too much effort to me. (not that it will take me hours, but it is tedious to write a method to do that)

            • 3. Re: Inject a List of objects in CDI (Weld)
              ljnelson

              No need for the producer, just the injection.


              So:




              @Inject
              private Iterable<SocialNetworkService> services;
              



              ...should do it.


              Best,

              Laird

              • 4. Re: Inject a List of objects in CDI (Weld)
                glammy

                It doesn't work.


                But indeed you are right, that Instance is also Iterable. When I defined it as Instance<SocialNetworkService>, it worked. Thanks.

                • 5. Re: Inject a List of objects in CDI (Weld)
                  glammy

                  Just to note something I forgot - you need the @Any annotation in the injection point, otherwise it doesn't get filled.

                  • 6. Re: Inject a List of objects in CDI (Weld)
                    meetoblivion

                    There is no way to automatically generate a list of implementations, you may be able to pull it out of the BeanManager, depending on how they're implemented, you may be able to pull them out via qualifiers.  the easiest way I can think of would be something like




                    public class SocialBean {
                    @Inject TwitterService twitter;
                    @Inject FacebookService facebook;
                    @Inject FriendFeedService friendFeed;
                    
                    @Produces
                    public List<SocialNetworkService> produceSocialNetworkServces() {
                    List l = new ArrayList();
                    l.add(twitter;
                    l.add(facebook);
                    l.add(friendFeed);
                    return l;
                    }
                    
                    }



                    however, it seems like you're trying to work around the framework.  It seems to me that it would be better to simply fire off events that need to be sent.  take a look at this example:



                    public class TwitterEvent {
                    private SocialNetworkStatus status;
                    //getter and setter, constructor with field
                    }





                    in the place where you want to notify of the event.




                    @Inject Event<TwitterEvent> eventHandler;
                    ...
                    eventHandler.fire(new TwitterEvent(status));



                    Then in your TwitterService you would really just need




                    @Stateless
                    public class TwitterService {
                    public void handleTwitter(@Observes TwitterEvent event) {
                    ....
                    }
                    }



                    • 7. Re: Inject a List of objects in CDI (Weld)
                      glammy

                      I already got it working the way I want with Liard's suggestion. And no, I'm not working around the framework. I want to give all implementations of a given interface a chance to act on some input, with as little code as possible.


                      The event mechanism could be used, but I'd need a generic MessageEvent, observed by all services. But that would be again lots of code

                      • 8. Re: Inject a List of objects in CDI (Weld)
                        glammy

                        Well, not that much code actually - but a redundant intermediate object - the MessageEvent