与Bean验证API结合使用时,Hibernate不遵循JPA规范? [英] Hibernate not following JPA specifications when combined with Bean Validation API?

查看:180
本文介绍了与Bean验证API结合使用时,Hibernate不遵循JPA规范?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题跟随这个问题: JPA约束违规vs回滚



我对JPA和验证API(JSR-303)的组合进行了一些测试。



JPA规范(第101-102页):

lockquote
默认情况下,默认的Bean验证组(默认组)在预留持续时间和更新前的生命周期验证事件中进行验证。

...



由validate方法返回的ConstraintViolation对象不为空,则持久性提供程序必须抛出包含对返回的ConstraintViolation对象集的引用的javax.validation.ConstraintViolationException,并且必须标记tr


我设置了以下测试:


  • HibernateValidator作为JSR-303实现

  • 2 PersistenceProvider Hibernate和EclipseLink
  • 一个实体 NameNotNullWithDefaultGeneratedStrategy @Generated )和 @NotNull字符串名称
  • >
  • 另一个实体 NameNotNullWithTableGeneratedStrategy ,其中包含使用表策略( @TableGenerated )和 @NotNull字符串名称
  • 测试尝试 persist 每个实例实体的空值名称

  • 预期的结果是 javax.validation.ConstraintViolationException 由persist方法抛出,标记为仅回滚的事务这些假设是基于本文中引用的JPA规范)。

    $ b 结果如下:


    • 以eclipse link作为提供者:


      • persist 方法为这两个实体抛出 javax.validation.ConstraintViolationException
      • 事务被标记为 rollback只有在这两种情况下


    • 以hibernate作为提供者:


      • persist 为实体抛出一个 javax.validation.ConstraintViolationException NameNotNullWithDefaultGeneratedStrategy +标记为仅回滚的交易

      • persist 不要为实体 NameNotNullWithTableGeneratedStrategy +事务未标记仅回滚 >

      • commit 用于 NameNotNullWithTableGeneratedStrategy 失败,并且 RollbackException




    问题是:


    • 是否真的违反了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(){//成功
    testPersistWithNullName(pu-hibernate,new NameNotNullWithDefaultGeneratedStrategy( ));
    }

    @Test
    public void testHibernateTableStrategy(){
    testPersistWithNullName(pu-hibernate,new NameNotNullWithTableGeneratedStrategy());
    //此测试失败:
    //java.lang.AssertionError:期望javax.validation.ConstraintViolationException,但persist()成功!

    $ b @Test
    public void testEclipseLinkDefaultStrategy(){//成功
    testPersistWithNullName(pu-eclipselink,new NameNotNullWithDefaultGeneratedStrategy());

    $ b @Test
    public void testEclipseLinkTableStrategy(){//成功
    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();
    尝试{
    尝试{
    entityManager.persist(entity);
    Assert.fail(期待javax.validation.ConstraintViolationException,但persist()成功!);
    } catch(javax.validation.ConstraintViolationException cve){
    //预计
    Assert.assertTrue(根据JPA规范事务必须被标记为只回滚,transaction.getRollbackOnly()) ;
    catch(Exception e){
    Assert.assertTrue(根据JPA规范事务必须标记为只回滚,transaction.getRollbackOnly());
    e.printStackTrace();
    Assert.fail(期望得到一个javax.validation.ConstraintViolationException,但得到了+ e.getClass());
    }
    transaction.commit();
    Assert.fail(持续使用null name !!!);
    } catch(RollbackException e){
    //这就是所期望的
    } catch(Exception e){
    e.printStackTrace();
    Assert.fail(Unexpected exception:+ e.getMessage());
    }
    } finally {
    entityManager.close();





    实体




    $ b $



    默认策略

      package com.example.jpa 。验证器; 

    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私人长ID;
    @NotNull public String name;
    public NameNotNullWithTableGeneratedStrategy(){}
    }

    持久性。 xml

     <?xml version =1.0encoding =UTF-8?> 
    < persistence version =2.0xmlns =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-hibernatetransaction-type =RESOURCE_LOCAL>
    < provider> org.hibernate.ejb.HibernatePersistence< / provider>
    < class> com.example.jpa.validator.NameNotNullWithTableGeneratedStrategy< / class>
    < class> com.example.jpa.validator.NameNotNullWithDefaultGeneratedStrategy< / class>
    <属性>
    < property name =javax.persistence.jdbc.drivervalue =org.h2.Driver/>
    < property name =javax.persistence.jdbc.urlvalue =jdbc:h2:mem:test_mem_hibernate/>
    < property name =hibernate.hbm2ddl.autovalue =create-drop/>
    < property name =hibernate.dialectvalue =org.hibernate.dialect.H2Dialect/>
    < / properties>
    < / persistence-unit>
    < persistence-unit name =pu-eclipselinktransaction-type =RESOURCE_LOCAL>
    < provider> org.eclipse.persistence.jpa.PersistenceProvider< / provider>
    < class> com.example.jpa.validator.NameNotNullWithTableGeneratedStrategy< / class>
    < class> com.example.jpa.validator.NameNotNullWithDefaultGeneratedStrategy< / class>
    <属性>
    < property name =javax.persistence.jdbc.drivervalue =org.h2.Driver/>
    < property name =javax.persistence.jdbc.urlvalue =jdbc:h2:mem:test_mem/>
    < property name =eclipselink.ddl-generationvalue =create-tables/>
    < property name =eclipselink.target-databasevalue =org.eclipse.persistence.platform.database.H2Platform/>
    < / properties>
    < / persistence-unit>
    < /余辉>

    pom.xml

     <?xml version =1.0encoding =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>
    <属性>
    < 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>

    <依赖关系>
    < dependency>
    < groupId> org.hibernate< / groupId>
    < artifactId> hibernate-validator< / artifactId>
    < version> $ {hibernate-validator.version}< / version>
    < /依赖关系>
    < dependency>
    < groupId> com.h2database< / groupId>
    < artifactId> h2< / artifactId>
    < version> $ {h2.version}< / version>
    < scope> test< / scope>
    < /依赖关系>
    < dependency>
    < groupId> junit< / groupId>
    < artifactId> junit< / artifactId>
    < scope> test< / scope>
    < version> $ {junit.version}< / version>
    < /依赖关系>

    < dependency>
    < groupId> org.hibernate< / groupId>
    < artifactId> hibernate-core< / artifactId>
    < version> $ {hibernate.version}< / version>
    < /依赖关系>
    < dependency>
    < groupId> org.hibernate< / groupId>
    < artifactId> hibernate-entitymanager< / artifactId>
    < version> $ {hibernate.version}< / version>
    < /依赖关系>

    < dependency>
    < groupId> org.eclipse.persistence< / groupId>
    < artifactId> org.eclipse.persistence.jpa< / artifactId>
    < version> 2.4.0< / version>
    < /依赖关系>
    < dependency>
    < groupId> org.eclipse.persistence< / groupId>
    < artifactId> javax.persistence< / artifactId>
    < version> 2.0.0< / version>
    < /依赖关系>
    < /依赖关系>

    < repositories>
    < repository>
    < url> http://download.eclipse.org/rt/eclipselink/maven.repo/< / url>
    < id> eclipselink< / id>
    < layout>预设< / layout>
    < name>库EclipseLink库(JPA 2.0)< / name>
    < / repository>
    < / repositories>
    < / project>


    解决方案

    =https://hibernate.onjira.com/browse/HHH-8028 =nofollow> https://hibernate.onjira.com/browse/HHH-8028


    This question is a follow up to this one : JPA ConstraintViolation vs Rollback

    I did some test about combination of JPA and validation API (JSR-303).

    I found the following in JPA specifications (page 101-102):

    By default, the default Bean Validation group (the group Default) will be validated upon the pre-persist and pre-update lifecycle validation events

    ...

    If the set of ConstraintViolation objects returned by the validate method is not empty, the persistence provider must throw the javax.validation.ConstraintViolationException containing a reference to the returned set of ConstraintViolation objects, and must mark the transaction for rollback.

    I setup the following test:

    • HibernateValidator as JSR-303 implementation
    • 2 PersistenceProvider Hibernate and EclipseLink
    • one entity NameNotNullWithDefaultGeneratedStrategy with an id generated with default strategy (@Generated) and @NotNull String name column
    • another entity NameNotNullWithTableGeneratedStrategy with an id generated with table strategy (@TableGenerated) and @NotNull String name column
    • the test try to persist one instance of each entity with a null name.
    • the expected results are a javax.validation.ConstraintViolationException thrown by the persist method and the transaction marked as rollback only (i.e. those assumptions are based on JPA specification quoted in this post).

    The results are :

    • with eclipse link as a provider :
      • the persist method throws a javax.validation.ConstraintViolationException for both entities.
      • the transaction is marked as rollback only in both cases
    • with hibernate as a provider :
      • persist throws a javax.validation.ConstraintViolationException for entity NameNotNullWithDefaultGeneratedStrategy + transaction marked as rollback only
      • persist don't throw any exception for entity NameNotNullWithTableGeneratedStrategy + transaction not flagged as rollback only
      • commit for NameNotNullWithTableGeneratedStrategy fails with a RollbackException

    The questions are :

    • is it really a violation of JPA specifications ? or I am missing something with particular case of table generated strategy ?
    • in case it is a violation: is there any existing bug report related to it ?

    Here is the code for my test:

    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();
            }
        }
    }
    

    The entities

    Default strategy

    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() {}
    }
    

    Table stategy:

    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() {}
    }
    

    The persistence.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>
    

    The 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>
    

    解决方案

    I filed a bug report for this : https://hibernate.onjira.com/browse/HHH-8028

    这篇关于与Bean验证API结合使用时,Hibernate不遵循JPA规范?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆