Spring Boot 迁移Hibernate 6

xzlaal3s  于 2022-12-23  发布在  Spring
关注(0)|答案(1)|浏览(187)

我尝试将SpringBoot应用程序迁移到SpringBoot 3。SpringBoot 3使用Hibernate 6。我的应用程序由于以下错误而拒绝启动

Caused by: java.lang.NullPointerException: Cannot invoke "java.util.Map.get(Object)" because the return value of "java.util.Map.get(Object)" is null
at org.hibernate.envers.configuration.internal.metadata.AuditMetadataGenerator.addJoins(AuditMetadataGenerator.java:206)
at org.hibernate.envers.configuration.internal.metadata.AuditMetadataGenerator.generateSecondPass(AuditMetadataGenerator.java:409)
at org.hibernate.envers.configuration.internal.EntitiesConfigurator.configure(EntitiesConfigurator.java:86)
at org.hibernate.envers.boot.internal.EnversServiceImpl.initialize(EnversServiceImpl.java:129)
at org.hibernate.envers.boot.internal.AdditionalJaxbMappingProducerImpl.produceAdditionalMappings(AdditionalJaxbMappingProducerImpl.java:92)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:329)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1350)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1421)
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:66)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:376)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:396)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:352)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1797)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1747)
... 110 common frames omitted

在深入研究Envers代码后,发现问题位于org.hibernate.envers.configuration.internal.metadata.AuditMetadaGenerator类中。
在第337行,有一个条件允许在first pass的envers期间引用一个审计类。

if ( entity.isJoinAware() ) {
        final JoinAwarePersistentEntity joinAwareEntity = (JoinAwarePersistentEntity) entity;
        createJoins( persistentClass, joinAwareEntity, auditingData );
        addJoins( persistentClass, propertyMapper, auditingData, persistentClass.getEntityName(), mappingData, true );
}

private void createJoins(PersistentClass persistentClass, JoinAwarePersistentEntity entity, ClassAuditingData auditingData) {
    final Iterator<org.hibernate.mapping.Join> joins = persistentClass.getJoinIterator();
    final Map<org.hibernate.mapping.Join, Join> joinElements = new HashMap<>();
    entityJoins.put( persistentClass.getEntityName(), joinElements );
    ....

这是在second pass行206期间被调用的列表。

while ( joins.hasNext() ) {
        final org.hibernate.mapping.Join join = joins.next();
        final Join entityJoin = entityJoins.get( entityName ).get( join );

这里entityJoins.get(entityName)返回我的一个实体的null
此实体已正确标注@Audited,并从另一个实体扩展,如下所示:

@Entity
@Table(name = "a")
@Audited
@DiscriminatorValue("DISCRIMINATOR")
public class A extends B {
   //...
}

@Entity
@Table(name = "b")
@Inheritance(strategy = InheritanceType.JOINED)
@Audited
public abstract class B {
   //...
}

在我的理解中,使用InheritanceType.JOINED的值指定Inheritance会使envers创建一个JoinedSubclassPersistentEntity,该JoinedSubclassPersistentEntity本身继承自PersistentEntity
这个PersistentEntity有一个方法:

public boolean isJoinAware() {
    return false;
}

它会被它的子进程(如RootPersistentEntity)覆盖,方法是:

@Override
public boolean isJoinAware() {
    return true;
}

JoinedSubclassPersistentEntity不是使用Joined继承策略时生成的类,它不会进行此覆盖。
这导致我的实体没有被添加到first pass,但仍然由second pass处理。
所以问题是?这是Envers的一个bug吗?我可以在@Audited类中使用Joined继承策略吗?
它在hib5.6中运行良好。
[编辑]:我设法用一个简单的测试类重现了这个错误:

@Entity
@Audited
@DiscriminatorValue("OPTION")
public class Child extends Parent{

    private String propA;

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinTable(name = "recursive_children_child", joinColumns = {@JoinColumn(name = "child_id", nullable = false, updatable = false)}, inverseJoinColumns = {@JoinColumn(name = "recursive_id", nullable = false, updatable = false)})
    @NotAudited
    @OrderBy("propA DESC")
    private List<Child> children = new ArrayList<>();

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinTable(name = "recursive_children_child", joinColumns = {@JoinColumn(name = "recursive_id")}, inverseJoinColumns = {@JoinColumn(name = "child_id")})
    @NotAudited
    private Child recursiveChild;
    public Child(String propA) {
        this.propA = propA;
    }

    public Child() {

    }

    public String getPropA() {
        return propA;
    }

    public void setPropA(String propA) {
        this.propA = propA;
    }
}

问题似乎与Child类中的递归关系有关。尽管存在@Audited注解,但Ember仍尝试审计关系。
链接到重现错误的项目=〉https://github.com/scandinave/envers6-migration-bug

6qfn3psc

6qfn3psc1#

通过阅读Jakarta持久性规范,我终于发现了这个问题。
JoinTable注解用于实体关联的Map。JoinTable注解在关联的拥有方指定
在我的项目中,关联的两边都有一个@JoinTable注解,这在Hibernate 6之前是有效的,但现在不行了,我只需要删除不需要的@JoinTable就可以解决这个错误。

相关问题