1 Reply Latest reply on Jan 25, 2012 2:14 PM by gkari.gurpreet.ari.frequentis.com

    CDI: Property injection issue due to multiple inheritance and Generics abstraction

    gkari.gurpreet.ari.frequentis.com

      We use CDI for Dependency Injection. We need to implement a generic class, LazyAccountDataModel which will be used/injected by all data table beans (like in DataTableBean below). The generic LazyAccountDataModel needs to deal with a specific type of facade depending on the data table bean injecting it. I tried using Generics as an approach to determine which facade to use in the LazyAccountDataModel as follows but it throws the following exception:



      @Named
      @RequestScoped
      public class DataTableBean
      {
          @Inject
          private LazyAccountDataModel<IAccount, IAccountFacade> lazyModel;
      }
      
      @Named
      @RequestScoped
      public class LazyAccountDataModel<DO extends IDomainObject, FACADE extends
      IPersistableFacade<DO>> extends LazyDataModel<DO>
      {
          @EJB (@Named doesn't work here due to WELD bug GLASSFISH-16186 which is not-optimal)
          private FACADE facade;
      
          private List<DO> datasource;
      
          @Override
          public List<DO> load(int first, int pageSize, String sortField, SortOrder 
              sortOrder, Map<String, String> filters)
          {
          setRowCount((int) facade.findTotalCount());
      
          // do more work on specific facade derivation (IAccountFacade in this case)
      
          return datasource;
          }
      }
      
      public interface IAccountFacade extends IPersistableFacade<IAccount>
      {
          public void logIn(String userName);
      }
      
      public interface IPersistableFacade<DO extends IDomainObject> extends IFacade<DO>
      {
          void create(DO domainData);
      
          List<DO> getAll();
      
          long findTotalCount();
      }
      
      SEVERE: Exception while loading the app : WELD-001408 Unsatisfied dependencies for type [LazyAccountDataModel] with qualifiers [@Default] at injection point [[field] @Inject private view.dashDOard.DataTableBean.lazyModel] org.jDOss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied dependencies for type [LazyAccountDataModel] with qualifiers [@Default] at injection point [[field] @Inject private view.dashboard.DataTableBean.lazyModel] at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:270) at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:106) at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:129) at org.jboss.weld.bootstrap.Validator.validateBeans(Validator.java:351) at org.jboss.weld.bootstrap.Validator.validateDeployment(Validator.java:336) at org.jboss.weld.bootstrap.WeldDOotstrap.validateBeans(WeldDOotstrap.java:396) at org.glassfish.weld.WeldDeployer.event(WeldDeployer.java:190) at org.glassfish.kernel.event.EventsImpl.send(EventsImpl.java:128) at org.glassfish.internal.data.ApplicationInfo.start(ApplicationInfo.java:306) at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:462) at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:240) at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:382) at com.sun.enterprise.v3.admin.CommandRunnerImpl$1.execute(CommandRunnerImpl.java:355) at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:370) at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1064) at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1200(CommandRunnerImpl.java:96) at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1244) at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1232) at com.sun.enterprise.v3.admin.AdminAdapter.doCommand(AdminAdapter.java:459) at com.sun.enterprise.v3.admin.AdminAdapter.service(AdminAdapter.java:209) at com.sun.grizzly.tcp.http11.GrizzlyAdapter.service(GrizzlyAdapter.java:168) at com.sun.enterprise.v3.server.HK2Dispatcher.dispath(HK2Dispatcher.java:117) at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:238) at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:828) at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:725) at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1019) at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225) at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137) at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104) at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90) at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79) at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54) at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59) at com.sun.grizzly.ContextTask.run(ContextTask.java:71) at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532) at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513) at java.lang.Thread.run(Thread.java:662)





      Our problem is quite similar to the following post: CDI producer method for data model. Can anyone provide pointers on how we can inject LazyAccountDataModel and specify to it which facade needs to be used?


      One possible solution would be to inject the specific facade type along with the LazyAccountDataModel and then set the facade type explicitly. However, this is not a clean solution:




      @Named
      @RequestScoped
      public class DataTableBean
      {
          @EJB
          private IAccountFacade facade;
      
          @Inject
          private LazyAccountDataModel<IAccount> lazyModel;
      
      @PostConstruct
      public void init()
      {
          // would rather this stayed decoupled/handled by IoC framework
          lazyModel.setfacade(facade);
      }
      
      
      @Named
      @RequestScoped
      public class LazyAccountDataModel<DO extends IDomainObject> extends LazyDataModel<DO>
      {
          private IPersistableFacade<DO> facade;
      
          private List<DO> datasource;
      
          @Override
          public List<DO> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, String> filters)
          {
                  setRowCount((int) facade.findTotalCount());
      
               // do more work on specific facade derivation (IAccountFacade in this     case)
              return datasource;
          }
      
          public void setfacade(IPersistableBusinessObjectfacade<DO> facade)
          {
              this.facade = facade;
          }
      }





      Another solution may be to use contextual producers like: http://blog.frankel.ch/further-into-cdi But this doesn't seem to work for 2-deep layers of abstraction. This use case would be easily implemented in Spring by specifying nested properties in the context XML. Can anyone provide any inputs on how this can be done in CDI? Any help would be appreciated.


      Thanks.

        • 1. Re: CDI: Property injection issue due to multiple inheritance and Generics abstraction
          gkari.gurpreet.ari.frequentis.com

          Gurpreet Ari wrote on Jan 25, 2012 13:58:


          We use CDI for Dependency Injection. We need to implement a generic class, LazyAccountDataModel which will be used/injected by all data table beans (like in DataTableBean below). The generic LazyAccountDataModel needs to deal with a specific type of facade depending on the data table bean injecting it. I tried using Generics as an approach to determine which facade to use in the LazyAccountDataModel as follows but it throws the following exception:


          @Named
          @RequestScoped
          public class DataTableBean
          {
              @Inject
              private LazyAccountDataModel<IAccount, IAccountFacade> lazyModel;
          }
          
          @Named
          @RequestScoped
          public class LazyAccountDataModel<DO extends IDomainObject, FACADE extends
          IPersistableFacade<DO>> extends LazyDataModel<DO>
          {
              @EJB (@Named doesn't work here due to WELD bug GLASSFISH-16186 which is not-optimal)
              private FACADE facade;
          
              private List<DO> datasource;
          
              @Override
              public List<DO> load(int first, int pageSize, String sortField, SortOrder 
                  sortOrder, Map<String, String> filters)
              {
              setRowCount((int) facade.findTotalCount());
          
              // do more work on specific facade derivation (IAccountFacade in this case)
          
              return datasource;
              }
          }
          
          public interface IAccountFacade extends IPersistableFacade<IAccount>
          {
              public void logIn(String userName);
          }
          
          public interface IPersistableFacade<DO extends IDomainObject> extends IFacade<DO>
          {
              void create(DO domainData);
          
              List<DO> getAll();
          
              long findTotalCount();
          }
          
          SEVERE: Exception while loading the app : WELD-001408 Unsatisfied dependencies for type [LazyAccountDataModel] with qualifiers [@Default] at injection point [[field] @Inject private view.dashDOard.DataTableBean.lazyModel] org.jDOss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied dependencies for type [LazyAccountDataModel] with qualifiers [@Default] at injection point [[field] @Inject private view.dashboard.DataTableBean.lazyModel] at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:270) at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:106) at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:129) at org.jboss.weld.bootstrap.Validator.validateBeans(Validator.java:351) at org.jboss.weld.bootstrap.Validator.validateDeployment(Validator.java:336) at org.jboss.weld.bootstrap.WeldDOotstrap.validateBeans(WeldDOotstrap.java:396) at org.glassfish.weld.WeldDeployer.event(WeldDeployer.java:190) at org.glassfish.kernel.event.EventsImpl.send(EventsImpl.java:128) at org.glassfish.internal.data.ApplicationInfo.start(ApplicationInfo.java:306) at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:462) at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:240) at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:382) at com.sun.enterprise.v3.admin.CommandRunnerImpl$1.execute(CommandRunnerImpl.java:355) at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:370) at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1064) at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1200(CommandRunnerImpl.java:96) at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1244) at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1232) at com.sun.enterprise.v3.admin.AdminAdapter.doCommand(AdminAdapter.java:459) at com.sun.enterprise.v3.admin.AdminAdapter.service(AdminAdapter.java:209) at com.sun.grizzly.tcp.http11.GrizzlyAdapter.service(GrizzlyAdapter.java:168) at com.sun.enterprise.v3.server.HK2Dispatcher.dispath(HK2Dispatcher.java:117) at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:238) at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:828) at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:725) at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1019) at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225) at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137) at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104) at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90) at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79) at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54) at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59) at com.sun.grizzly.ContextTask.run(ContextTask.java:71) at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532) at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513) at java.lang.Thread.run(Thread.java:662)





          Our problem is quite similar to the following post: My Link. Can anyone provide pointers on how we can inject LazyAccountDataModel and specify to it which facade needs to be used?

          One possible solution would be to inject the specific facade type along with the LazyAccountDataModel and then set the facade type explicitly. However, this is not a clean solution:



          @Named
          @RequestScoped
          public class DataTableBean
          {
              @EJB
              private IAccountFacade facade;
          
              @Inject
              private LazyAccountDataModel<IAccount> lazyModel;
          
          @PostConstruct
          public void init()
          {
              // would rather this stayed decoupled/handled by IoC framework
              lazyModel.setfacade(facade);
          }
          
          
          @Named
          @RequestScoped
          public class LazyAccountDataModel<DO extends IDomainObject> extends LazyDataModel<DO>
          {
              private IPersistableFacade<DO> facade;
          
              private List<DO> datasource;
          
              @Override
              public List<DO> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, String> filters)
              {
                      setRowCount((int) facade.findTotalCount());
          
                   // do more work on specific facade derivation (IAccountFacade in this     case)
                  return datasource;
              }
          
              public void setfacade(IPersistableBusinessObjectfacade<DO> facade)
              {
                  this.facade = facade;
              }
          }





          Another solution may be to use contextual producers like: My Link But this doesn't seem to work for 2-deep layers of abstraction. This use case would be easily implemented in Spring by specifying nested properties in the context XML. Can anyone provide any inputs on how this can be done in CDI? Any help would be appreciated.

          Thanks.


          Click HELP for text formatting instructions. Then edit this text and check the preview.