jakarta-ee - Weld (CDI) 和 Datanucleus (JPA) 效果不佳,有优雅的解决方法吗?

标签 jakarta-ee jpa cdi datanucleus jboss-weld

...至少,如果“优雅的解决方法”的概念确实有值(value)的话!

以下是一些详细信息:

使用 CDI 和 JPA 时,您经常需要在 JSF 页面之一的 EL 表达式中访问 JPA 管理的 bean 之一,如下所示:

<html xmlns="http://www.w3.org/1999/xhtml" 
      xmlns:h="http://java.sun.com/jsf/html" 
      xmlns:f="http://java.sun.com/jsf/core">
  <h:head>
    <title>An Everyday Facelet</title>
  </h:head>
  <h:body>
    <h1>Behold, a jpa-managed bean property!</h1>
    <h:outputText value="#{exampleEntity.name}" />
  </h:body>
</html>

为了简单起见,我们假设此页面是 HTTP Post 的结果,并且客户端在上一页上输入了 name 属性的值。 bean 本身可以是从生产者方法检索的简单 jpa 实体,如下所示:

@Entity
public class ExampleEntity implements Serializable {
    @Id
    @Column
    private Long entityId;
    @Column
    private String name;

    public ExampleEntity() {
    }

    public void setEntityId(Long entityId) {
        this.entityId = entityId;
    }
    public Long getEntityId() {
        return entityId;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}

// Some method in another class
public class AnotherClass {
    @Produces
    @RequestScoped
    @Named("exampleEntity")
    public ExampleEntity getExampleEntity() {
        return new ExampleEntity();
    }
}

好吧,让我们编译吧。 datanucleus JPA 实现的一个重要方面是有一个后编译步骤。您需要在编译的 jpa 类上运行字节码增强器,所以我们假设我们这样做了。当尝试启动您的 servlet 容器(即 Tomcat、Jetty)时,您将在启动 Weld 时遇到异常(如果您实际上尝试将此 bean 注入(inject)某处,则会出现不止一个异常)。假设我的类位于“testapp”包中,异常(exception)情况如下:

org.jboss.weld.exceptions.UnproxyableResolutionException: WELD-001437 Normal scoped bean class testapp.ExampleEntity is not proxyable because the type is final or it contains a final method public final java.lang.Object testapp.ExampleEntity.jdoGetObjectId() - Managed Bean [class testapp.ExampleEntity] with qualifiers [@Any @Default @Named].

公共(public)最终java.lang.Object jdoGetObjectId()?我既没有定义也没有声明其中之一,好的网络服务器。你肯定搞错了!

事实证明,datanucleus 增强器必须将这个 final方法添加到我编译的类中。如果我不运行网络服务器,它就会正常启动,尽管我认为我的数据实际上不会持久存在。经过一些研究,我在 Weld 文档中找到了问题的解释:http://docs.jboss.org/weld/reference/1.1.5.Final/en-US/html/injection.html#d0e1429

简而言之,命名 bean 似乎不能有 final方法。根据那里的一些建议,我找到了一个可行的解决方案。我为 jpa bean 声明一个接口(interface),并创建一个生成器方法来获取具体类(实际上是 datanucleus 增强类,但 Weld 不知道)。这是附加代码:

public interface ExampleEntity {
    public Long getEntityId();
    public void setEntityId(Long entityId);
    public String getName();
    public void setName(String name);
}

现在,ExampleEntity 纯粹是一个接口(interface),我创建了一个 JPA 管理的实现,无需 CDI 注释

@Entity
public class ExampleEntityImpl implements ExampleEntity, Serializable {
    // Same as the ExampleEntity class above
}

最后,也许在某个 Controller 中,我定义了一个用于获取ExampleEntities的生产者方法

@Named("exampleEntityController")
@RequestScoped
public class ExampleEntityController {

    private ExampleEntity newExampleEntity;

    public ExampleEntityController() {
        newExampleEntity = new ExampleEntityImpl();
    }

    // The producer method
    @Produces
    @RequestScoped
    @Named("exampleEntity")
    public ExampleEntity getExampleEntity() {
        return newExampleEntity;
    }

    // Other stuff, because surely a controller does more than just this, right?
}

而且...这有效。 Web 服务器启动,没有异常(exception)。在该示例 Facelet 中正确检索了名称属性(假设数据已在前一页中输入)。然而,为每个 jpa 管理的 bean 制作一次性接口(interface)和生产者方法是相当多余和丑陋的。有更好的解决方案吗? Datanucleus 是这个项目的要求,所以我不能简单地使用其他东西。如果有一个更“优雅的解决方法”,我想它涉及一种更好的方法让 Weld 让我拥有一个我永远不会在我命名的 bean 中使用的 final方法。

编辑:感谢您的回复/更正,但我正在寻找一种方法来避免为每个 jpa bean 创建接口(interface)。我已经从示例中删除了混合 JPA/CDI 注释,但 Web 服务器仍然抛出相同的异常。不过,我可以看到,无论哪种方式,我都需要一个生产者方法。

最佳答案

您不应为您的实体使用 CDI。

  • 实体由您使用new运算符创建
  • CDI bean 由容器创建,以便它可以处理注入(inject)和初始化

关于jakarta-ee - Weld (CDI) 和 Datanucleus (JPA) 效果不佳,有优雅的解决方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9985031/

相关文章:

java - 检查空变量时出现空指针异常错误

JavaEE和OSGI :How to get BeanManager for certain osgi bundle

使用实体管理器关闭 hibernate session

java - Apache Derby + jpa

mysql - Hibernate 不生成唯一约束

java - 如何以编程方式查找和注入(inject)限定符包含类名的 CDI 托管 bean

java - EJB bean 和 CDI bean 以及注入(inject)

java - 使用 Jax-RS 和 CDI 安排任务

java - 有没有办法通过注释在metro中实现ws-security?

java - 如何获取jar文件父依赖关系?