当前位置: 首页 > 知识库问答 >
问题:

Hibernate与Bean验证API结合时不遵循JPA规范?

贺卜霸
2023-03-14

这个问题是这个问题的后续:JPA约束违反vs回滚

我做了一些关于JPA和验证API(JSR-303)组合的测试。

我在JPA规范(第101-102页)中发现了以下内容:

默认情况下,默认Bean验证组(默认组)将在预持久性和预更新生命周期验证事件时进行验证

...

如果validate方法返回的ConstraintViolation对象集不是空的,则持久性提供程序必须抛出javax。验证。ConstraintViolationException包含对返回的ConstraintViolation对象集的引用,并且必须将事务标记为回滚。

我设置了以下测试:

  • 作为JSR-303实现的HibernateValidator
  • 2持久性提供者Hibernate和Eclipse链接
  • 一个实体NameNotNullBackDefaultGeneratedStrategy,其ID是用默认策略生成的(@Generated)和@NotNull String name
  • 另一个实体NameNotNullBackTableGeneratedStrategy,其ID是用表策略生成的(@TableGenerated)和@NotNull String name
  • 测试尝试将每个实体的一个实例保留为空的name
  • 预期的结果是持久化方法抛出的javax.validation.ConstraintViolationExcture和标记为rollback的事务(即这些假设基于本文引用的JPA规范)。

结果是:

  • 使用eclipse link作为提供者:
    • 坚持方法抛出一个javax.validation.ConstraintViolationExc0019的两个实体。
    • 在这两种情况下,事务仅标记为回滚
    • 持久抛出一个javax.validation.ConstraintViolationExc0019的实体NameNotNullBackDefaultGeneratedStrategy事务标记为只回滚
    • 坚持不抛出任何异常的实体NameNotNullBackTableGeneratedStrategy事务没有标记为只回滚
    • 提交NameNotNullBackTableGeneratedStrategy失败与Rollback Exc0019

    问题是:

    • 这真的违反了JPA规范吗?或者我错过了一些表生成策略的特殊情况?
    • 如果它是违规:是否有任何现有的错误报告与之相关?

    以下是我的测试代码:

    package com.example.jpa.validator;
    import org.junit.Assert;
    import org.junit.Test;
    import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;
    import javax.persistence.EntityTransaction;
    import javax.persistence.Persistence;
    import javax.persistence.RollbackException;
    
    public class ConstraintViolationExceptionTest {
    
        @Test
        public void testHibernateDefaultStrategy() {  // Success
            testPersistWithNullName("pu-hibernate",new NameNotNullWithDefaultGeneratedStrategy());
        }
    
        @Test
        public void testHibernateTableStrategy() {
            testPersistWithNullName("pu-hibernate",new NameNotNullWithTableGeneratedStrategy());
            //this test fail with :
            //java.lang.AssertionError: Expecting a javax.validation.ConstraintViolationException, but persist() succeed !
        }
    
        @Test
        public void testEclipseLinkDefaultStrategy() {  // Success
            testPersistWithNullName("pu-eclipselink",new NameNotNullWithDefaultGeneratedStrategy());
        }
    
        @Test
        public void testEclipseLinkTableStrategy() {  // Success
            testPersistWithNullName("pu-eclipselink",new NameNotNullWithTableGeneratedStrategy());
        }
    
        private void testPersistWithNullName(String persistenceUnitName, Object entity){
            EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnitName);
            EntityManager entityManager = emf.createEntityManager();
            try {
                final EntityTransaction transaction = entityManager.getTransaction();
                transaction.begin();
                try {
                    try {
                        entityManager.persist(entity);
                        Assert.fail("Expecting a javax.validation.ConstraintViolationException, but persist() succeed !");
                    } catch (javax.validation.ConstraintViolationException cve) {
                        //That's expected
                        Assert.assertTrue("According JPA specs transaction must be flagged as rollback only",transaction.getRollbackOnly());
                    } catch (Exception e) {
                        Assert.assertTrue("According JPA specs transaction must be flagged as rollback only",transaction.getRollbackOnly());
                        e.printStackTrace();
                        Assert.fail("Expecting a javax.validation.ConstraintViolationException, but got " + e.getClass());
                    }
                    transaction.commit();
                    Assert.fail("persisted with null name !!!");
                } catch (RollbackException e) {
                    //That's expected
                }  catch (Exception e) {
                    e.printStackTrace();
                    Assert.fail("Unexpected exception :"+e.getMessage());
                }
            } finally {
                entityManager.close();
            }
        }
    }
    

    实体

    默认策略

    package com.example.jpa.validator;
    
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    import javax.validation.constraints.NotNull;
    
    @Entity
    public class NameNotNullWithDefaultGeneratedStrategy {
    
        @Id @GeneratedValue private Long id;
        @NotNull public String name;
        public NameNotNullWithDefaultGeneratedStrategy() {}
    }
    

    表策略:

    package com.example.jpa.validator;
    
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.TableGenerator;
    import javax.validation.constraints.NotNull;
    
    @Entity
    public class NameNotNullWithTableGeneratedStrategy {
    
        @GeneratedValue(strategy = GenerationType.TABLE,
            generator = "NAME_MUST_NOT_BE_NULL_ID_GENERATOR")
        @TableGenerator(name = "NAME_MUST_NOT_BE_NULL_ID_GENERATOR")
        @Id @NotNull private Long id;
        @NotNull public String name;
        public NameNotNullWithTableGeneratedStrategy() {}
    }
    

    坚持。xml

        <?xml version="1.0" encoding="UTF-8"?>
        <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
            <persistence-unit name="pu-hibernate" transaction-type="RESOURCE_LOCAL">
                <provider>org.hibernate.ejb.HibernatePersistence</provider>
                <class>com.example.jpa.validator.NameNotNullWithTableGeneratedStrategy</class>
                <class>com.example.jpa.validator.NameNotNullWithDefaultGeneratedStrategy</class>
                <properties>
                    <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
                    <property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:test_mem_hibernate"/>
                    <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
                    <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
                </properties>
            </persistence-unit>
            <persistence-unit name="pu-eclipselink" transaction-type="RESOURCE_LOCAL">
                <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
                <class>com.example.jpa.validator.NameNotNullWithTableGeneratedStrategy</class>
                <class>com.example.jpa.validator.NameNotNullWithDefaultGeneratedStrategy</class>
                <properties>
                    <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
                    <property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:test_mem"/>
                    <property name="eclipselink.ddl-generation" value="create-tables"/>
                    <property name="eclipselink.target-database" value="org.eclipse.persistence.platform.database.H2Platform"/>
                </properties>
            </persistence-unit>
        </persistence>
    

    pom。xml

        <?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>
    
            <groupId>com.example</groupId>
            <artifactId>com.example.jpa.validator</artifactId>
            <version>1.0-SNAPSHOT</version>
            <properties>
                <hibernate.version>4.2.0.CR1</hibernate.version>
                <hibernate-validator.version>4.3.1.Final</hibernate-validator.version>
                <junit.version>4.11</junit.version>
                <h2.version>1.3.170</h2.version>
            </properties>
    
            <dependencies>
                <dependency>
                    <groupId>org.hibernate</groupId>
                    <artifactId>hibernate-validator</artifactId>
                    <version>${hibernate-validator.version}</version>
                </dependency>
                <dependency>
                    <groupId>com.h2database</groupId>
                    <artifactId>h2</artifactId>
                    <version>${h2.version}</version>
                    <scope>test</scope>
                </dependency>
                <dependency>
                    <groupId>junit</groupId>
                    <artifactId>junit</artifactId>
                    <scope>test</scope>
                    <version>${junit.version}</version>
                </dependency>
    
                <dependency>
                    <groupId>org.hibernate</groupId>
                    <artifactId>hibernate-core</artifactId>
                    <version>${hibernate.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.hibernate</groupId>
                    <artifactId>hibernate-entitymanager</artifactId>
                    <version>${hibernate.version}</version>
                </dependency>
    
                <dependency>
                    <groupId>org.eclipse.persistence</groupId>
                    <artifactId>org.eclipse.persistence.jpa</artifactId>
                    <version>2.4.0</version>
                </dependency>
                <dependency>
                    <groupId>org.eclipse.persistence</groupId>
                    <artifactId>javax.persistence</artifactId>
                    <version>2.0.0</version>
                </dependency>
            </dependencies>
    
            <repositories>
                <repository>
                    <url>http://download.eclipse.org/rt/eclipselink/maven.repo/</url>
                    <id>eclipselink</id>
                    <layout>default</layout>
                    <name>Repository for library EclipseLink (JPA 2.0)</name>
                </repository>
            </repositories>
        </project>
    

共有1个答案

富勇军
2023-03-14

我为此提交了一份错误报告:https://hibernate.onjira.com/browse/HHH-8028

 类似资料:
  • 问题内容: 这个问题是该问题的后续解决方案:JPAConstraintViolation与回滚 我对JPA和验证API(JSR-303)的组合进行了一些测试。 我在JPA规范中找到了以下内容(第101-102页): 默认情况下,默认Bean验证组(默认组)将在持久化和更新前生命周期验证事件时进行验证 … 如果validate方法返回的ConstraintViolation对象集不为空,则持久性提供

  • 我尝试将JSF与Bean验证结合使用。基本上,一切正常,验证工作如预期,我得到了正确的消息,但我的Glassfish控制台上有一个例外: 如果我使用自定义约束和预定义约束,则会发生此异常。 这是我的示例代码。 示例实体: 自定义约束: 自定义验证器: 样品控制器: jsf页面示例: MyEntityFacade仅从实体管理器进行持久化调用。 如前所述,应用程序运行良好,正确的消息已显示,但我希望在

  • 但是,当我执行以下测试时,不会引发验证异常: 当保存一个已经持久化的对象时,我如何使验证器触发器?最好是通过Java配置。 我的验证依赖项:

  • 环境 Glassfish 3.1.2内置Hibernate-Validator 4.2。

  • 我现在把这两者搞混了。我知道Hibernate Validator6是Bean验证2.0规范的参考实现。它支持分组、错误消息国际化、自定义方法验证等。问题是Spring5支持这些特性还是我只剩下Hibernate Validator6了? 网上所有的参考例子都建议使用Hibernate验证器,没有什么关于Spring验证的发现,请建议或指向其他链接。

  • 我试图在我的项目中使用Hibernate验证器,但它不起作用。在以下行: 我得到以下例外情况: 我发现这个问题似乎与我的问题很相似。他将他的解决方案描述为 我想我的问题也是一样的。在http://hibernate.org/validator/documentation/getting-start/it上说: 这会传递地引入对Bean验证API的依赖关系(javax.Validation:vali