Spring Data MongoDB Cross-Store插件和JPA PrePersist和PreUpdate

时间:2012-08-28 07:59:02

标签: java spring-data spring-data-jpa spring-data-mongodb

我们有一个具有以下设置的应用程序:

Java 6.0 Spring Data JPA 1.1.0.RELEASE Spring Data MongoDB 1.0.2.RELEASE Spring Data MongoDB跨存储1.0.2.RELEASE Hibernate JPA 2.0

我们在此应用程序中有几个使用JPA PrePersist,PreUpdate,PostPersist和PostUpdate注释的类。下面给出一个例子。

@Entity
public class Person
{
    private String password;

    @PrePersist
    @PreUpdate
    public void beforeSave()
    {
        if(!Security.isEncrypted(this.password))
        {
            this.password = Security.encrypt(this.password);
        }
    }
}

只要我们为跨存储插件打开AspectJ编织,Spring应用程序上下文就无法加载错误:

Caused by: javax.persistence.PersistenceException: You can only annotate one callback method with javax.persistence.PrePersist in bean class: org.example.domain.Person
    at org.hibernate.ejb.event.CallbackResolver.resolveCallback(CallbackResolver.java:110)
    at org.hibernate.ejb.event.EntityCallbackHandler.addCallback(EntityCallbackHandler.java:123)
    at org.hibernate.ejb.event.EntityCallbackHandler.add(EntityCallbackHandler.java:61)
    at org.hibernate.ejb.event.JpaIntegrator.integrate(JpaIntegrator.java:151)
    at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:306)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1744)
    at org.hibernate.ejb.EntityManagerFactoryImpl.<init>(EntityManagerFactoryImpl.java:94)
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:905)
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:890)
    at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:74)
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:268)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:310)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1514)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1452)

我发现错误的根本原因是Aspect MongoDocumentBacking将其他PrePersist和PreUpdate方法编织到实体类中。由于类已经有了带有这些注释的方法,因此Hibernate Entity Manager无法验证这些类。

是否有关于如何将跨存储插件用于具有使用JPA注释的现有代码的应用程序的指导?

2 个答案:

答案 0 :(得分:0)

我遇到了与@PreUpdate和@PostLoad相同的问题。

在泉源中有一个错误: https://jira.springsource.org/browse/DATAMONGO-519

他们给出了以下解决方案:

  1. 创建JPA实体事件侦听器类,并将PrePersist,PreUpdate等代码移动到这些侦听器中。
  2. 更改方面以首先搜索实体类是否有任何注释为RelatedDocument的字段。
  3. 如果实体类有一个或多个注释为RelatedDocument的字段,请检查该类是否已经有EventListeners注释。
  4. 如果EventListeners批注已存在,请将跨店事件侦听器添加到列表中。如果没有,请将EventListeners注释添加到类中。
  5. 我将所有注释移动到实体监听器,它立即工作,无需更改任何其他内容。 看看以下链接,似乎只能在实体级别添加同一时间的一个注释,但可以使用实体侦听器添加许多注释:http://docs.jboss.org/hibernate/stable/entitymanager/reference/en/html/listeners.html

    @Entity
    @EntityListeners(ProductEntityListener.class)
    public class Product {
    }
    
    public class ProductEntityListener {
        @PrePersist
        @PreUpdate
        protected void prePersist(Product entity) {
        }
        @PostLoad
        protected void postLoad(Product entity){
        }
    }
    

答案 1 :(得分:0)

我们在这里遇到了同样的问题:

EntityListener 使用泛型参数实现了一个接口。在调试抛出异常的Hibernate代码之后,结果证明在这个侦听器接口中不能使用Generics作为实体类型。删除通用参数后,它可以工作。

原因:在接口中使用泛型参数时,java编译器为实现类(具体类型)创建(例如)一个 postUpdate(...)方法,并为接口创建一个 postUpdate(...)方法(超级型)。 Hibernate检测到那些2,但只需要一个。结果它抛出异常。