Search code examples
javajakarta-eedependency-injectioncdi

CDI Nested Producers Issue


I am new to CDI and I have an issue which is a bit hard to explain but lets give it a try. I would like to have a cdi producer which produces a request scoped instance of a class called RequestData like here for example (its pseudo-code):

 public class MyBean {
  private RequestData dataHolder;

  @Produces
  @RequestScoped
  public RequestData getData() {
   return dataHolder;
  }
}

I know that this cdi producer produces an instance which "lives" in wildfly application server as long as the request context is there (as long the request lasts, lets call it request-singleton instance thingy)

Now I would like to have that RequestData class includes futher cdi producers. Like in this example (again java pseudo-code):

public class RequestData {
 private Something1 param1;
 private Something2 param2;
 ...

 @Produces
 public Something1 getParam1(){
  return param1;
 }

 @Produces
 public Something2 getParam2(){
  ...
 }
}

The final question of my issue is how can I force param1 and param2 to be produced from the request-singleton instance in MyBean (what java code / annotations or whatever do I need)?

To sum up MyBean produces RequestData and RequestData is alive the whole request time and futhermore it shall produce param1, param2.

Here some example of a class injecting param1

public class Stuff{

 @Inject
 public void startup(Something1 param1){
 // param1 shall come from MyBean.getData().getParam1()
 }
}

Any ideas how to achive this? How to have cdi engine do the MyBean.getData().getParam1() for param1?


Solution

  • This is the wrong approach. CDI is a very powerful injection framework. How you use it for injection depends on how much you understand it.

    For this case, it is far easier to use Instance lazy injection as follows:

    @ApplicationScoped //No need to be request scope, CDI is quite smart
    public class RequestContextProvider {
    
       @Inject
       private HttpServletRequest servletRequest;
    
       @Produces
       @Dependent //Make dependent if it can be null, if you are sure it cannot be, just declare it as RequestScoped
       public SomethingData createSomethingData(InjectionPoint ip) {
           String requestParam = servletRequest.getParameter("something-data");
           if(requestParam == null) {
               return null;
           }
    
           return initSomethingData(requestParam);
       }
    
    }
    

    The usage will look something like this:

    @RequestScoped //Or whichever scope
    public class StuffService {
    
       @Inject
       private Instance<SomethingData> somethingData;
    
       public void doStuff() {
           //You need to take care here, that the somethingData.get() may return null
           somethingData.get().soSomething();
       }
    }