3

I have several service like that:

@Singleton
public SimpleService {
    ...
}

I have Managed Bean @ViewScoped which should create some complex objects. These objects should execute business-logic. I need to pass these services to this object.

Example of Managed Bean:

@ManagedBean
@ViewScoped
public class ExampleBean {
    @Inject
    private SimpleService simpleService;

    ...
    public void customLogic() {
        // in this method I should create complex object which should have services and some data.
        // current implementation
        ComplexObject object = new ComplexObject(SimpleService simpleService, ...)
    }
}

Services are injected to Managed Bean by @Inject annotation. For creating these objects - I'm using the constructor and pass these services as params. The question is: can I have better solution than passing services in constructor?

TestName
  • 378
  • 2
  • 13
  • In IoC environment, you must separate data from services. You need to have injectable components that `build` your data. – maress Mar 28 '18 at 08:41
  • It is not clear how you are using your injection, could you post that part of the code? – prmottajr Mar 28 '18 at 08:41
  • @maress, thanks, will review my logic for creating injectable components – TestName Mar 28 '18 at 08:52
  • @prmottajr for service injection to Managed Bean, I have this code: ManagedBean public class ManagedBean {Inject SimpleService service;} – TestName Mar 28 '18 at 08:53
  • 1
    @Трубецкой using inject should be enough, that is the point of using CDI, you shouldn't need to pass those objects to the constructor, if you could edit the question and add the code you are using to pass the parameters would help to help. – prmottajr Mar 28 '18 at 08:58
  • @prmottajr, I edited the question – TestName Mar 28 '18 at 09:17

2 Answers2

3

You can:

  • Inject by method:
    private MyService myService;

    @Inject
    public void setMyService(MyService ms) {
        this.myService = ms;
    }
  • Inject by field:
    @Inject
    private MyService myService;   
  • Fetch reference through CDI (not recommended, except in advanced usecases):
    ...
    MyService myService = CDI.current().select(MyService.class).get();
    ...
  • Fetch reference through BeanManager (not recommended, except in advanced usecases or CDI 1.0):
    ...
    BeanManager beanManager = CDI.getBeanManager(); // you can fetch a BeanManager reference by several other methods, I use CDI for simplicity here
    MyService myService = beanManager.getReference(MyService.class);
    ...
  • If your @Singleton annotation is javax.ejb.Singleton and not javax.inject.Singleton, then your bean is actually a EJB and you can also use any mechanism that allows you to access EJB, such as @Resource annotations, or through the JNDI context.

Personally I tend to inject by method as I find it the most flexible option most of the time. In my opinion it is also the most "portable" to other frameworks (e.g: Spring)

Remember that when you use either the CDI.current() or the BeanManager methods to fetch @Dependent beans, you are responsible to manually destroy the fetched bean when you are done with it, so that you do not fall into this CDI-related memory leak. When using CDI.current() it is as easy as saving the Instance reference and invoking it afterwards:

...
Instance<MyService> msInstance = CDI.current().select(MyService.class);
MyService myService = msInstance.get();
...
msInstance.destroy(myService);
...

The BeanManager method is too low-level and should only be used in CDI 1.0 environments (back when the CDI class did not exist yet). You can read the linked StackOverflow question for more details.

gpeche
  • 21,974
  • 5
  • 38
  • 51
  • 1
    Note that when injecting by method, you are not restricted to one parameter methods, you can use a multiple parameter method for injecting several beans at once. – gpeche Mar 28 '18 at 09:03
  • @Трубецкой After editing the question I see my answer is actually a bit offtopic. FYI, prmottajr's answer looks just right. – gpeche Mar 28 '18 at 09:33
2

What you are doing is perfectly fine. You are using the ManagedBean as a bridge to inject the services and then passing the injected variables to a ComplexObject that need the services.

The only restriction that should be considered is, could the ComplexObject class be a ManagedBean itself? That way you could inject everything directly on it, but if it is not possible, you may use the bean for that.

I prefer the inject by field option mentioned because I think it is a little more readable.

prmottajr
  • 1,816
  • 1
  • 13
  • 22