0

Currently, I have everything working with one injection of my CDI bean, but I need about 6 to 10 separate instances(?) depending on my inputs. (Ideally, I would like to be able to inject a dynamic number of the same CDI beans depending on how many I need.)

Unfortunately, I need to have the beans injected since the class depends on another CDI bean. (See the 2.CDI bean class below)

  1. Clients class
@ApplicationScoped
public class Clients {
   Publisher pub;
   Subscriber sub;
   @Inject
   ListenerBean listener;

   public void init(){
      pub = new Publisher();
      sub = new Subscriber(listener);
   }
}
  1. CDI bean class
@Dependent
public class ListenerBean{
   @Inject
   private eventHandler h;

   public void onMessage(Msg msg){
      h.doesSomething();
   }
}

The functionality I'm looking for, but not sure what's available out there. I haven't found anyone looking to accomplish the same thing.

for(Subscriber s: listOfSubscribers){
   @Inject
   ListenerBean l;
   s = new Subscriber(l);
}

// The only thing I can do right now is
@Inject
ListenerBean listener1;
@Inject
ListenerBean listener2;
@Inject
ListenerBean listener3;
@Inject
ListenerBean listener4;

Edit: The listeners do need to be identifiable. (Calls a setter after injection.) Probably not the best practice but not sure how else to implement this-

  • The listeners will listen to different topics (declared by the respective consumer)
  • Each listener must handle their messages based off of the topic
@Inject
ListenerBean listener1;
listener1.setTopic("TopicA");
dko
  • 197
  • 8
  • Can't you inject `List`? – chrylis -cautiouslyoptimistic- Oct 18 '21 at 20:48
  • 1
    I believe that, if `ListenerBean` is `@Dependent` and you inject an `Instance listenerInstance`, then every time you do `listenerInstance.get()` you get a fresh copy. Make sure to dispose of the instances you get, once you are done with them. – Nikos Paraskevopoulos Oct 18 '21 at 21:22
  • This sounds like a classic example to use the standard `Event` and `@Observes` instead. – mtj Oct 20 '21 at 05:57
  • @chrylis-cautiouslyoptimistic- That's not a thing... see [post 4009388](https://stackoverflow.com/questions/4009388/inject-list-of-objects-in-cdi-weld) – dko Oct 20 '21 at 14:27
  • @NikosParaskevopoulos thank you! I will try this – dko Oct 20 '21 at 14:28
  • @mtj Would this work the same way as Instance? Like `Event e` and `e.fire(Bean)` is respective to `Instance i` and `i.get()` ? I'm trying to understand from [docs here](https://docs.jboss.org/weld/reference/2.4.0.CR1/en-US/html/events.html) – dko Oct 20 '21 at 14:38
  • @dko See the answer for an explanation – mtj Oct 22 '21 at 07:01

2 Answers2

2

If you need to inject several different instances of a @Dependent scoped bean, you could do it via programmatic lookup - in other words via Instance<T>.

Every bean resolution for a @Dependent bean via Instance will result in a new bean instance created. Following code illustrates that:

@Inject Instance<ListenerBean> instance;

public void createMultipleBeanInstances() {
  // bean1 and bean2 are two different instances because the bean is @Dependent
  // you can OFC do this in a cycle and generate as many as you like
  ListenerBean bean1 = instance.get(); 
  ListenerBean bean2 = instance.get();
}

Just note that dependent beans you create via programmatic lookup have their lifecycle bound to the Instance object meaning they will exist so long as does the Instance. Given that you @Inject Instance into the bean, it will be destroyed along with the bean it was injected into.

Siliarus
  • 6,393
  • 1
  • 14
  • 30
  • thank you so much, and for the example too!! Yes, I want the *different* instances injected as you described, I will see if this works for me – dko Oct 20 '21 at 14:41
  • this is partially working for me. But if I want the ListenerBean to inject separately-- The class should be `@Dependent` scoped, right? I edited my original post to include a detail that I missed. -- I need to set a value in the ListenerBeans. But I'm not sure if `@Dependent` is the correct scope for the Listener – dko Oct 26 '21 at 21:40
  • Not sure I understand your issue. They are identifiable and you can still do `bean1.setTopic("someTopic")`. As for scope, only you can know which scope fits your scenario. However, if by `Listener` you mean a CDI observer, than note that `@Dependent` scope will mean a *separate* bean instance will be created to observe fired events and will be destroyed afterwards. – Siliarus Oct 27 '21 at 11:14
  • Actually, it was a separate issue. This solution, worked!! Thank you so much :) – dko Oct 27 '21 at 17:45
1

Explanation following my comment. I might be misunderstanding your question though.

First of all, your code looks basically like the implementation of a multicaster: you inject several objects which all implement a common interface to call the same method.

I think, that in trying to inject the various receiver objects, you basically have an X-Y-problem: does the emitter really need to know the receivers, or is it enough, that the event reaches the targets?

If I am right with the assumption, that your emitter does not really need to know the subscribers, you can simply use the Event standard mechanism:

First, define a message (which can carry additional information, but this is not specifically necessary, you just need a class):

public class MyMessage {
     // if needed, add some fields
}

Then, in your emitter, inject the corresponding event type, and use it to fire the message:

@Inject
private Event<MyMessage> myEvent;  // note: type is message, not the bean

...

myEvent.fire(new MyMessage()); // to broadcast the message to everyone who is interested

In your subscribers, just @Observe the message:

public void theMethodWeWantCalled(@Observes MyMessage messageObject) {
    // do things here
}

That's it: no need to couple emitter and subscriber.

mtj
  • 3,381
  • 19
  • 30
  • thanks, this makes more sense. Unfortunately, I think the emitter does need to know the receivers? Since I still need them to have a field set :( See the edit I just made on my post. – dko Oct 26 '21 at 14:34