【问题标题】:Using CDI instead of @ManagedBean: UnproxyableResolutionException because super class has no no-args constructor使用 CDI 而不是 @ManagedBean: UnproxyableResolutionException 因为超类没有无参数构造函数
【发布时间】:2011-04-19 21:47:12
【问题描述】:

我正在尝试将 CDI 用于我的 JSF/Java EE 应用程序。我有以下类层次结构:

/**
 * base controller class
 * also contains some final methods and an inner enum class declaration
 */
public abstract class AbstractCrudController<K, E> implements Serializable {
  private Class<E> entityClass;

  public AbstractCrudController(Class<E> entityClass) {
    this.entityClass = entityClass;
  }

  // ...
}


import javax.enterprise.context.SessionScoped;
import javax.inject.Named;

@Named
@SessionScoped
public class CategoryController extends AbstractCrudController<Long, Category> implements Serializable {
  public CategoryController() {
    super(Category.class);
  }
  //...
}

当我尝试在 GF 3.1 上部署应用程序时,我收到以下 CDI/Weld 异常:

严重:加载时出现异常 应用程序:WELD-001435 普通范围 bean 班级 com.web.AbstractCrudController 不可代理,因为它没有 无参数构造函数。 org.jboss.weld.exceptions.UnproxyableResolutionException: WELD-001435 普通范围的 bean 类 com.web.AbstractCrudController 不可代理,因为它没有 无参数构造函数。 在 org.jboss.weld.util.Proxies.getUnproxyableClassException(Proxies.java:215) 在 org.jboss.weld.util.Proxies.getUnproxyableTypeException(Proxies.java:166) 在 org.jboss.weld.util.Proxies.getUnproxyableTypesException(Proxies.java:191) 在 org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:134) 在 org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:148) 在 org.jboss.weld.bootstrap.Validator.validateBeans(Validator.java:363) 在 org.jboss.weld.bootstrap.Validator.validateDeployment(Validator.java:349) 在 org.jboss.weld.bootstrap.WeldBootstrap.validateBeans(WeldBootstrap.java:416) 在 org.glassfish.weld.WeldDeployer.event(WeldDeployer.java:178) 在 org.glassfish.kernel.event.EventsImpl.send(EventsImpl.java:128) 在 org.glassfish.internal.data.ApplicationInfo.start(ApplicationInfo.java:265) 在 com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:402) 在 com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:221) 在 org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:351) 在 com.sun.enterprise.v3.admin.CommandRunnerImpl$1.execute(CommandRunnerImpl.java:360) 在 com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:375) 在 com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1072) 在 com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1200(CommandRunnerImpl.java:101) 在 com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1221) 在 com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1210) 在 com.sun.enterprise.v3.admin.AdminAdapter.doCommand(AdminAdapter.java:375) 在 com.sun.enterprise.v3.admin.AdminAdapter.service(AdminAdapter.java:209) 在 com.sun.grizzly.tcp.http11.GrizzlyAdapter.service(GrizzlyAdapter.java:166) 在 com.sun.enterprise.v3.server.HK2Dispatcher.dispath(HK2Dispatcher.java:117) 在 com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:234) 在 com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:824) 在 com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:721) 在 com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1014) 在 com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:220) 在 com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135) 在 com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102) 在 com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88) 在 com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76) 在 com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53) 在 com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57) 在 com.sun.grizzly.ContextTask.run(ContextTask.java:69) 在 com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:530) 在 com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:511) 在 java.lang.Thread.run(Thread.java:637)

即使我向基类添加了一个无参数构造函数,Weld 仍然会抱怨同样的异常,即该类不可代理,因为它具有最终方法。为什么 WELD 强迫我改变我的班级设计?使用 JSF @ManagedBean 注释一切正常。

如果有任何帮助,我将不胜感激。 谢谢, 西奥

【问题讨论】:

    标签: jsf-2 cdi jboss-weld


    【解决方案1】:

    因为接受的答案是正确的但不完整,我想我可以为未来的读者加两分钱。

    OP遇到的问题可以通过两种方式解决:

    1. 通过从方法和类本身中删除 final 关键字
    2. @Singleton@Dependent 伪范围标记这样的“不可代理类”(当然,如果有意义的话)。它会起作用,因为 CDI 不会为伪作用域 bean 创建代理对象。

    在 OP 用例中,建议使用第二种方法恕我直言,因为控制器绝对可以标记为单例。

    希望对某人有所帮助

    【讨论】:

      【解决方案2】:

      我正在从 JSF 托管 bean 迁移到 CDI 托管 bean,我刚刚确认我能够在“扩展”的后代 CDI bean(带有“自定义”@Descendant 限定符)中成功使用super ' 一个祖先 CDI bean(带有 @Default 限定符)。

      具有@Default 限定符的 CDI bean 祖先:

      @Default
      @Named("pf_pointOfContactController")
      @SessionScoped
      public class pf_PointOfContactController implements Serializable {
      

      祖先 bean 有以下内容:

      @PostConstruct
      protected void init() {
      

      带有@Descendant 限定符的 CDI bean 后代:

      @Descendant
      @Named("pf_orderCustomerPointOfContactController")
      @SessionScoped
      public class pf_OrderCustomerPointOfContactController extends pf_PointOfContactController {
      

      后代豆有以下几点:

      @PostConstruct
      public void init(){
          super.init();
      

      我必须添加/使用 super.init(),因为祖先 CDI bean 中的方法引发 NullPointerException,因为祖先 bean 的 @PostConstruct 没有在 CDI @Descendant bean 中执行。

      我已经看到/听到/读到建议在使用 CDI 时使用 @PostConstruct 而不是 Constructor 方法,因此祖先 bean 的构造函数具有“初始化”逻辑,并且在使用 JSF 时会自动调用/执行祖先 bean 的构造函数托管 bean。

      【讨论】:

        【解决方案3】:

        为什么 WELD 强迫我改变我的班级设计?使用 JSF @ManagedBean 注解一切正常。

        嗯,Weld/CDI 的工作方式不同。我的理解是,当您使用注入来获取对 bean 的引用时,您得到的是大多数情况代理对象。这个代理对象对你的 bean 进行子类化并覆盖实现委托的方法。这对 CDI 可以代理的类引入了一些限制。

        CDI 规范是这样写的:

        5.4.1。不可代理的 bean 类型

        某些合法的 bean 类型不能 由容器代理:

        • 没有非私有构造函数的类没有 参数,
        • 声明为 final 或具有 final 方法的类,
        • 原始类型,
        • 和数组类型。

        如果一个注入点的声明 类型不能被代理 容器解析为一个带有 正常范围,容器 自动检测问题并 将其视为部署问题。

        我的建议是使方法成为非最终方法。

        参考文献

        • CDI 规范
          • 第 5.4 节。 “客户代理”
          • 第 5.4.1 节“不可代理的 bean 类型”
          • 第 6.3 节。 "普通作用域和伪作用域"

        【讨论】:

        • CDI 不使用代理的情况有哪些?我认为它应该总是:) (+1)
        • @Bozho 何时使用伪作用域?
        • a,是的,规范说“适用于所有正常范围”
        • 谢谢。 @Bozho 规范说 CDI 不对具有 @Dependent 范围(这是默认范围)的 bean 使用客户端代理。
        • CDI 不会为所有伪作用域 bean 创建代理对象。所以对于@Dependent@Singleton。我真的很欣赏这个功能。
        猜你喜欢
        • 2011-11-24
        • 2019-11-29
        • 1970-01-01
        • 2018-12-13
        • 2015-12-23
        • 2016-06-12
        • 1970-01-01
        • 2013-02-19
        相关资源
        最近更新 更多