CDI:由于多重继承和泛型抽象导致的属性注入问题
Posted
技术标签:
【中文标题】CDI:由于多重继承和泛型抽象导致的属性注入问题【英文标题】:CDI: Property injection issue due to multiple inheritance and Generics abstraction 【发布时间】:2012-01-24 22:10:14 【问题描述】:我们使用 CDI 进行依赖注入。我们需要实现一个通用类,LazyAccountDataModel,它将被所有数据表 bean 使用/注入(如下面的 DataTableBean 中)。通用的 LazyAccountDataModel 需要根据注入它的数据表 bean 来处理特定类型的外观。我尝试使用泛型作为一种方法来确定在 LazyAccountDataModel 中使用哪个外观,如下所示,但它引发了以下异常:
@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<IAccount, IAccountFacade>] 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<IAccount, IAccountFacade>] 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)
我们的问题与以下帖子非常相似:CDI producer method for data model。 谁能提供关于我们如何注入 LazyAccountDataModel 并指定需要使用哪个外观的指针?
一种可能的解决方案是将特定外观类型与 LazyAccountDataModel 一起注入,然后显式设置外观类型。但是,这不是一个干净的解决方案:
@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;
另一种解决方案可能是使用上下文生成器,例如:http://blog.frankel.ch/further-into-cdi 但这似乎不适用于 2 深的抽象层。通过在上下文 XML 中指定嵌套属性,这个用例可以很容易地在 Spring 中实现。任何人都可以提供有关如何在 CDI 中完成此操作的任何意见吗?任何帮助将不胜感激。
谢谢。
【问题讨论】:
【参考方案1】:根据 Pete Muir(如果您使用 Weld)的说法,这是一个错误。更多信息请访问CDI events and generics
【讨论】:
感谢您抽出宝贵时间阅读我们的问题并做出回应。【参考方案2】:乍一看,你为什么要使用@Named 限定符?如果你在一个类上使用过它,那么你需要在注入点有,否则它不会解决依赖关系。
第二个是根据我的经验,我可以说 CDI 不喜欢泛型,并且不确定你能否让它像那样工作。但是,如果您要执行以下操作,那么它可能会起作用: 将此作为接口:
LazyAccountDataModel<DO extends IDomainObject, FACADE extends IPersistableFacade<DO>>
并创建一个实现的类:
LazyAccountDataModel<IAccount, IAccountFacade>
然后你可以像你的例子一样注入。 我怀疑这部分是否会起作用:
@EJB (@Named doesn't work here due to WELD bug GLASSFISH-16186 which is not-optimal)
private FACADE facade;
【讨论】:
以上是关于CDI:由于多重继承和泛型抽象导致的属性注入问题的主要内容,如果未能解决你的问题,请参考以下文章