You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot 3升级后Hibernate Envers与Hypersistence Utils适配问题求助

Spring Boot 3.1.2升级后Hibernate Envers结合hypersistence-utils的JSON类型空指针问题

问题场景

将Spring Boot从2.7.14升级至3.1.2后,操作Oracle数据库时触发Hibernate空指针异常,H2环境下正常。异常栈核心信息如下:

Caused by: org.hibernate.HibernateException: Unable to perform beforeTransactionCompletion callback: Cannot read the array length because "array" is null
at org.hibernate.engine.spi.ActionQueue$BeforeTransactionCompletionProcessQueue.beforeTransactionCompletion(ActionQueue.java:1016)
...
Caused by: java.lang.NullPointerException: Cannot read the array length because "array" is null
at java.base/java.util.Arrays.stream(Arrays.java:5428)
at io.hypersistence.utils.hibernate.type.util.ParameterTypeUtils.getAnnotations(ParameterTypeUtils.java:76)
at io.hypersistence.utils.hibernate.type.util.ParameterTypeUtils.getAnnotationOrNull(ParameterTypeUtils.java:53)
at io.hypersistence.utils.hibernate.type.util.ParameterTypeUtils.getColumnType(ParameterTypeUtils.java:90)
at io.hypersistence.utils.hibernate.type.json.internal.JsonJdbcTypeDescriptor.resolveJdbcTypeDescriptor(JsonJdbcTypeDescriptor.java:90)

经调试确认,问题出在Hibernate Envers生成的审计实体处理@Type(JsonType.class)注解时,因无法获取有效注解信息导致空指针。

环境配置

  • 数据库:Oracle Database 19c Enterprise Edition(19.14.0.0.0)
    JDBC依赖:
    <dependency>
        <groupId>com.oracle.database.jdbc</groupId>
        <artifactId>ojdbc8</artifactId>
        <version>21.1.0.0</version>
        <scope>runtime</scope>
    </dependency>
    
  • Hibernate:6.2.6.Final(Spring Boot管理),使用Hibernate Envers审计
    依赖:
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-envers</artifactId>
        <version>6.2.6.Final</version>
    </dependency>
    
  • JSON类型映射:使用hypersistence-utils的JsonType映射CUSTOMER_LOCALIZED_FULLNAME列
    依赖:
    <dependency>
        <groupId>io.hypersistence</groupId>
        <artifactId>hypersistence-utils-hibernate-62</artifactId>
        <version>3.5.1</version>
    </dependency>
    

相关代码与表结构

数据库表结构

CREATE TABLE CCS_CUSTOMER_DETAILS
(
    CUSTOMER_NUMBER                 VARCHAR2(9)  NOT NULL
        CONSTRAINT CCS_CUSTOMER_DETAILS_PK
            PRIMARY KEY,
    CUSTOMER_EGN                    VARCHAR2(10) NOT NULL
        CONSTRAINT CCS_CUSTOMER_DETAILS_EGN_UNIQUE
            UNIQUE,
    CUSTOMER_IS_AGREED_TO_USE_OF_DATA NUMBER(1, 0) NOT NULL,
    CUSTOMER_LOCALIZED_FULLNAME              VARCHAR2(4000) NOT NULL
        CONSTRAINT LOCALIZED_FULLNAME_IS_JSON
            CHECK (CUSTOMER_LOCALIZED_FULLNAME IS JSON),
    DRIVING_LICENSE_NUMBER          VARCHAR2(9),
    DRIVING_LICENSE_EXPIRATION_DATE DATE,
    CUSTOMER_STATUS              SMALLINT  NOT NULL,
    CREATED_ON                   TIMESTAMP NOT NULL,
    LAST_UPDATED_ON              TIMESTAMP NOT NULL
);

CREATE TABLE CCS_AUDIT_REVISIONS_INFO
(
    REVISION_NUMBER      NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY
        CONSTRAINT CCS_SUBSCRIPTION_SERVICES_PK
            PRIMARY KEY,
    REVISION_TIMESTAMP  NUMBER
);

CREATE TABLE CCS_CUSTOMER_DETAILS_AUDIT_LOG
(
    REVISION_NUMBER_START           NUMBER       NOT NULL,
    REVISION_NUMBER_END             NUMBER,
    REVISION_TYPE                   SMALLINT,
    CUSTOMER_NUMBER                 VARCHAR2(9),
    CUSTOMER_IS_AGREED_TO_USE_OF_DATA NUMBER(1, 0),
    CUSTOMER_LOCALIZED_FULLNAME     VARCHAR2(4000),
    CUSTOMER_EGN                    VARCHAR2(10),
    DRIVING_LICENSE_NUMBER          VARCHAR2(9),
    DRIVING_LICENSE_EXPIRATION_DATE DATE,
    CUSTOMER_STATUS              SMALLINT,
    CREATED_ON                   TIMESTAMP,
    LAST_UPDATED_ON              TIMESTAMP,
    CONSTRAINT CCS_AUDIT_REVISIONS_INFO_START_FK
        FOREIGN KEY (REVISION_NUMBER_START) REFERENCES CCS_AUDIT_REVISIONS_INFO,
    CONSTRAINT CCS_AUDIT_REVISIONS_INFO_END_FK
        FOREIGN KEY (REVISION_NUMBER_END) REFERENCES CCS_AUDIT_REVISIONS_INFO,
    CONSTRAINT CCS_CUSTOMER_DETAILS_AUDIT_LOG_PK
        PRIMARY KEY (CUSTOMER_NUMBER, REVISION_NUMBER_START)
);

JPA实体代码

@Getter
@Setter
@Entity
@Audited
@Table(name = "CCS_CUSTOMER_DETAILS")
public class CustomerDetailsEntity {

    @Id
    @Column(name = "CUSTOMER_NUMBER", nullable = false)
    private String customerNumber;

    @Column(name = "CUSTOMER_EGN", unique = true, nullable = false)
    private String egn;

    @Column(name = "DRIVING_LICENSE_NUMBER", unique = true, nullable = false)
    private String drivingLicenseNumber;

    @Column(name = "DRIVING_LICENSE_EXPIRATION_DATE", nullable = false)
    private LocalDate drivingLicenseExpirationDate;

    @Column(name = "CUSTOMER_IS_AGREED_TO_USE_OF_DATA", nullable = false)
    private boolean agreedToUseOfData;

    @Type(JsonType.class)
    @Column(name = "CUSTOMER_LOCALIZED_FULLNAME", nullable = false)
    private Map<Alphabet, FullName> localizedFullName;

    @Enumerated
    @Column(name = "CUSTOMER_STATUS", nullable = false)
    private Status status;

    @CreationTimestamp
    @Column(name = "CREATED_ON", updatable = false)
    private LocalDateTime createdOn;

    @UpdateTimestamp
    @Column(name = "LAST_UPDATED_ON")
    private LocalDateTime lastUpdatedOn;
}

@Getter
@Setter
@Entity
@RevisionEntity
@Table(name = "CCS_AUDIT_REVISIONS_INFO")
public class RevisionInfoEntity {

    @Id
    @GeneratedValue(strategy = IDENTITY)
    @RevisionNumber
    @Column(name = "REVISION_NUMBER")
    private long id;

    @RevisionTimestamp
    @Column(name = "REVISION_TIMESTAMP")
    private long timestamp;
}

解决方案

1. 升级hypersistence-utils版本

当前3.5.1版本存在Hibernate 6.2兼容问题,升级至3.6.0及以上稳定版,该版本修复了Envers审计实体处理自定义类型时的注解空指针问题。

修改依赖:

<dependency>
    <groupId>io.hypersistence</groupId>
    <artifactId>hypersistence-utils-hibernate-62</artifactId>
    <version>3.6.0</version>
</dependency>

2. 显式指定JSON列的JdbcType

在实体类的JSON字段上添加@JdbcType注解,明确指定对应JDBC类型,避免Envers生成审计实体时无法识别类型:

@Type(JsonType.class)
@JdbcType(VarcharJdbcType.class) // 对应Oracle的VARCHAR2类型
@Column(name = "CUSTOMER_LOCALIZED_FULLNAME", nullable = false)
private Map<Alphabet, FullName> localizedFullName;

3. 配置Hibernate Envers的类型映射

在application.yml中添加Envers配置,确保自定义类型注解能被复制到审计实体:

spring:
  jpa:
    properties:
      org:
        hibernate:
          envers:
            replicate_annotations: true

4. 升级Oracle JDBC驱动版本

将ojdbc8升级至与Oracle 19c匹配的稳定版(如21.9.0.0),避免驱动与Hibernate 6.2的兼容性问题:

<dependency>
    <groupId>com.oracle.database.jdbc</groupId>
    <artifactId>ojdbc8</artifactId>
    <version>21.9.0.0</version>
    <scope>runtime</scope>
</dependency>

内容的提问来源于stack exchange,提问作者eHayik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 16:55:57