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

时间:2022-09-11 16:23:12

We have an application with the following set up:

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

Java 6.0 Spring Data JPA 1.1.0.RELEASE Spring Data MongoDB 1.0.2.RELEASE Spring Data MongoDB Cross-Store 1.0.2.RELEASE Hibernate JPA 2.0

Java 6.0 Spring Data JPA 1.1.0.RELEASE Spring Data MongoDB 1.0.2.RELEASE Spring Data MongoDB Cross-Store 1.0.2.RELEASE Hibernate JPA 2.0

We have several classes in this application that use the JPA PrePersist, PreUpdate, PostPersist and PostUpdate annotations. An example is given below.

我们在此应用程序中有几个使用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);
        }
    }
}

As soon as we turn on AspectJ weaving for the cross-store plugin, the Spring application context fails to load with the error:

一旦我们为跨存储插件打开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)

I have found out that the root cause for the error is that the Aspect MongoDocumentBacking weaves additional PrePersist and PreUpdate methods into entity classes. Since the classes already have methods with these annotations, Hibernate Entity Manager fails to validate these classes.

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

Is there any guidance on how the cross-store plugin should be used with applications that have existing code that use JPA annotations?

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

2 个解决方案

#1


0  

I was facing the same issue with @PreUpdate and @PostLoad.

我在使用@PreUpdate和@PostLoad时遇到了同样的问题。

There is a bug opened in springsource about this: https://jira.springsource.org/browse/DATAMONGO-519

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

They have given the solution below:

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

  1. Create JPA entity event listener classes and move PrePersist, PreUpdate, etc. code into these listeners.
  2. 创建JPA实体事件侦听器类,并将PrePersist,PreUpdate等代码移动到这些侦听器中。

  3. Change the aspects to first search whether an entity class has any field annotated as RelatedDocument.
  4. 更改方面以首先搜索实体类是否具有注释为RelatedDocument的任何字段。

  5. If an entity class has one or more fields annotated as RelatedDocument, check whether the class already has EventListeners annotation.
  6. 如果实体类具有一个或多个注释为RelatedDocument的字段,请检查该类是否已具有EventListeners注释。

  7. If the EventListeners annotation is already present, add cross-store event listeners to the list. If not, add the EventListeners annotation to the class.
  8. 如果EventListeners批注已存在,请将跨店事件侦听器添加到列表中。如果没有,请将EventListeners注释添加到类中。

I moved all my annotations to an entity listener and it worked straight away, no need to change anything else. Have a look at the following link, it seems that only one annotation of the same time can be added at the entity level, but many can be added using entity listeners: http://docs.jboss.org/hibernate/stable/entitymanager/reference/en/html/listeners.html

我将所有注释移动到实体监听器,它立即工作,无需更改任何其他内容。看看以下链接,似乎只能在实体级别添加同一个注释,但可以使用实体监听器添加许多注释: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){
    }
}

#2


0  

We had the same issue here:

我们在这里有同样的问题:

an EntityListener implemented an Interface with a generic parameter. After debugging the Hibernate code that threw the exception it turned out that it is not possible to use Generics in this listener interface for the entity type. After removing the generic parameter it worked.

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

Reason: When using a generic parameter in the interface the java compiler creates (for example) one postUpdate(...)-method for the implementing class (concrete type) and one for the interface (super type). Hibernate detects those 2, but expects only one. As a consequence it throws the exception.

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

#1


0  

I was facing the same issue with @PreUpdate and @PostLoad.

我在使用@PreUpdate和@PostLoad时遇到了同样的问题。

There is a bug opened in springsource about this: https://jira.springsource.org/browse/DATAMONGO-519

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

They have given the solution below:

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

  1. Create JPA entity event listener classes and move PrePersist, PreUpdate, etc. code into these listeners.
  2. 创建JPA实体事件侦听器类,并将PrePersist,PreUpdate等代码移动到这些侦听器中。

  3. Change the aspects to first search whether an entity class has any field annotated as RelatedDocument.
  4. 更改方面以首先搜索实体类是否具有注释为RelatedDocument的任何字段。

  5. If an entity class has one or more fields annotated as RelatedDocument, check whether the class already has EventListeners annotation.
  6. 如果实体类具有一个或多个注释为RelatedDocument的字段,请检查该类是否已具有EventListeners注释。

  7. If the EventListeners annotation is already present, add cross-store event listeners to the list. If not, add the EventListeners annotation to the class.
  8. 如果EventListeners批注已存在,请将跨店事件侦听器添加到列表中。如果没有,请将EventListeners注释添加到类中。

I moved all my annotations to an entity listener and it worked straight away, no need to change anything else. Have a look at the following link, it seems that only one annotation of the same time can be added at the entity level, but many can be added using entity listeners: http://docs.jboss.org/hibernate/stable/entitymanager/reference/en/html/listeners.html

我将所有注释移动到实体监听器,它立即工作,无需更改任何其他内容。看看以下链接,似乎只能在实体级别添加同一个注释,但可以使用实体监听器添加许多注释: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){
    }
}

#2


0  

We had the same issue here:

我们在这里有同样的问题:

an EntityListener implemented an Interface with a generic parameter. After debugging the Hibernate code that threw the exception it turned out that it is not possible to use Generics in this listener interface for the entity type. After removing the generic parameter it worked.

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

Reason: When using a generic parameter in the interface the java compiler creates (for example) one postUpdate(...)-method for the implementing class (concrete type) and one for the interface (super type). Hibernate detects those 2, but expects only one. As a consequence it throws the exception.

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