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

Spring Boot 2使用hibernate-jpamodelgen时的重复注解问题

Spring Boot 2 + hibernate-jpamodelgen: 热重启时出现重复@NotNull注解错误

问题背景

我有一个基于Spring Boot 2.0.2.RELEASE(也在2.0.0.RELEASE中复现)的简单应用,使用hibernate-jpamodelgen生成JPA元模型。完整的Maven POM如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
</parent>
<groupId>gov.idaho.isp</groupId>
<artifactId>SpringBootJpaModelGenIssue</artifactId>
<version>0.1</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<tomcat.version>9.0.5</tomcat.version>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
</dependency>
</dependencies>
</project>

应用包含一个简单实体Widget,其中name字段带有@NotNull校验注解:

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.NotNull;

@Entity
public class Widget implements Serializable {

@Id
@GeneratedValue
private Long id;

@NotNull
private String name;
// 省略getter/setter等方法
}

当运行应用并修改这个实体类后,应用无法成功重启,抛出以下错误:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.cfg.beanvalidation.IntegrationException: Error activating Bean Validation integration

最终根因是:

Caused by: java.lang.annotation.AnnotationFormatError: Duplicate annotation for class: interface javax.validation.constraints.NotNull: @javax.validation.constraints.NotNull(message={javax.validation.constraints.NotNull.message}, groups=[], payload=[])

移除hibernate-jpamodelgen依赖后,重启错误消失。请问这是已知问题吗?


专家解答

你遇到的这个问题确实是Spring Boot 2.x早期版本与hibernate-jpamodelgen结合使用时的已知兼容性问题,核心冲突点在于Spring Boot DevTools的热重启机制和JPA元模型生成的交互逻辑。

问题本质

Spring Boot DevTools的自动重启功能会在检测到类文件变化时,重新加载相关类。而hibernate-jpamodelgen会在编译时生成JPA元模型类(默认存放在target/generated-sources/annotations目录下),这些生成的类会引用原始实体类的注解信息。当热重启触发时,DevTools会同时重新加载原始实体类和生成的元模型类,导致Bean Validation注解(如@NotNull)被重复注册到类元数据中,最终触发AnnotationFormatError。

解决办法

这里有几个实用的解决方案,你可以根据开发需求选择:

  1. 排除元模型目录的热重启监控
    在application.properties中添加配置,让DevTools忽略元模型生成目录的变化,避免重复加载:
spring.devtools.restart.exclude=target/generated-sources/**
  1. 限定hibernate-jpamodelgen的依赖范围
    将hibernate-jpamodelgen的依赖范围设置为provided,这样它仅在编译阶段用于生成元模型,运行时(包括热重启)不会被加载,从根源避免冲突:
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-jpamodelgen</artifactId>
    <scope>provided</scope>
</dependency>
  1. 禁用DevTools自动重启
    如果你的开发流程不需要热重启功能,可以直接关闭该特性:
spring.devtools.restart.enabled=false

版本修复说明

这个问题在Spring Boot 2.1.x及后续版本中得到了优化,同时Hibernate后续版本的hibernate-jpamodelgen也调整了注解处理逻辑,减少了类加载冲突的概率。如果项目允许升级版本,这也是一个长期的解决方案。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:25:13