2013-02-20 10 views
9

Questa domanda è il seguito di questa: JPA ConstraintViolation vs RollbackHibernate non segue le specifiche JPA se combinato con l'API di convalida Bean?

Ho eseguito alcuni test sulla combinazione di JPA e API di convalida (JSR-303).

ho trovato quanto segue in JPA specifications (pag 101-102):

Per impostazione predefinita, il gruppo Bean Validation di default (il gruppo predefinito) verrà convalidato sul persistere-pre e pre-aggiornamento validazione del ciclo di vita eventi

...

Se l'insieme di ConstraintViolation oggetti restituiti dalla metodo validate non è vuoto, il provider di persistenza deve gettare il javax.validation.ConstraintViolationException contenente un riferimento all'insieme restituito di ConstraintV oggetti di iolation e deve contrassegnare la transazione per il rollback.

I installa il seguente test:

  • HibernateValidator come JSR-303 attuazione
  • 2 PersistenceProvider Sospensione e EclipseLink
  • un'entità NameNotNullWithDefaultGeneratedStrategy con un id generato con la strategia di default (@Generated) e @NotNull String name colonna
  • un'altra entità NameNotNullWithTableGeneratedStrategy con un ID generato con strategia tabella (@TableGenerated) e @NotNull String name colonna
  • test cercare di persist un'istanza di ciascuna entità con un nullo name.
  • i risultati attesi sono un javax.validation.ConstraintViolationException generato dal metodo persist e la transazione contrassegnata come rollback only (ovvero, tali ipotesi sono basate sulle specifiche JPA citate in questo post).

I risultati sono:

  • con il collegamento eclissi come fornitore:
    • il metodo persist getta una javax.validation.ConstraintViolationException per entrambe le entità.
    • la transazione viene contrassegnata come rollback only in entrambi i casi
  • con Hibernate come provider:
    • persist tiri un javax.validation.ConstraintViolationException per l'entità NameNotNullWithDefaultGeneratedStrategy + transazione contrassegnata come rollback only
    • persist Non gettare alcun eccezione per l'entità NameNotNullWithTableGeneratedStrategy + transazione non contrassegnata come rollback only
    • .515.053.691,36321 milioni
    • commit per NameNotNullWithTableGeneratedStrategy fallisce con un RollbackException

Le domande sono:

  • è davvero una violazione di specifiche JPA? o mi manca qualcosa con particolare caso di strategia generata da una tabella?
  • nel caso in cui si tratti di una violazione: esiste una segnalazione di bug esistente ad essa correlata?

Qui è il codice per la mia prova:

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

Le entità

strategia di default

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

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

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

Il 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

Cosa succede con @Column (nullable = false) insieme a @NotNull? –

+0

Ho provato con '@Column (nullable = false)': stesso risultato – ben75

+1

Realmente non capisco perché la strategia di generazione influenzi la convalida in questo caso, comunque aprirò sicuramente una segnalazione di bug come hai già configurato un testcase riproducibile (bene , dopo aver rimosso la parte di eclipselink) contro il validatore di ibernazione. –

risposta

Problemi correlati