Этот вопрос является продолжением этого: JPA ConstraintViolation vs Rollback
Я провел некоторый тест на предмет сочетания JPA и API проверки (JSR-303).
Я нашел следующее в спецификациях JPA (стр. 101-102):
По умолчанию группа проверки компонентов по умолчанию (группа По умолчанию) будет проверяться после события предварительной проверки жизненного цикла до и после обновления
...
Если набор объектов ConstraintViolation, возвращаемых методом validate, не является пустым, поставщик сохраняемости должен выдать исключение javax.validation.ConstraintViolationException, содержащее ссылку на возвращенный набор объектов ConstraintViolation, и должен пометить транзакцию для отката.
Я настроил следующий тест:
NameNotNullWithDefaultGeneratedStrategy
с идентификатор, сгенерированный с помощью стратегии по умолчанию (@Generated
) и столбца @NotNull String name
NameNotNullWithTableGeneratedStrategy
с идентификатором, сгенерированным с помощью стратегии таблицы (@TableGenerated
) и столбца @NotNull String name
persist
один экземпляр каждого объекта с нулевым name
. javax.validation.ConstraintViolationException
, генерируемый методом persist, и транзакция, помеченная как rollback only
(т.е. эти предположения основаны на спецификации JPA, приведенной в этом посте). Результаты:
persist
выбрасывает javax.validation.ConstraintViolationException
для обоих объектов. rollback only
в обоих случаях persist
выбрасывает javax.validation.ConstraintViolationException
для сущности NameNotNullWithDefaultGeneratedStrategy
] + транзакция, помеченная как rollback only
persist
, не выдает никаких исключений для сущности NameNotNullWithTableGeneratedStrategy
+ транзакция не помечена как rollback only
commit
] для NameNotNullWithTableGeneratedStrategy
не удается с RollbackException
Вопросы:
Вот код для Мой тест:
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() {}
}
Persistence.xml
org.hibernate.ejb.HibernatePersistence
com.example.jpa.validator.NameNotNullWithTableGeneratedStrategy
com.example.jpa.validator.NameNotNullWithDefaultGeneratedStrategy
org.eclipse.persistence.jpa.PersistenceProvider
com.example.jpa.validator.NameNotNullWithTableGeneratedStrategy
com.example.jpa.validator.NameNotNullWithDefaultGeneratedStrategy
Pom.xml
4.0.0
com.example
com.example.jpa.validator
1.0-SNAPSHOT
4.2.0.CR1
4.3.1.Final
4.11
1.3.170
org.hibernate
hibernate-validator
${hibernate-validator.version}
com.h2database
h2
${h2.version}
test
junit
junit
test
${junit.version}
org.hibernate
hibernate-core
${hibernate.version}
org.hibernate
hibernate-entitymanager
${hibernate.version}
org.eclipse.persistence
org.eclipse.persistence.jpa
2.4.0
org.eclipse.persistence
javax.persistence
2.0.0
http://download.eclipse.org/rt/eclipselink/maven.repo/
eclipselink
default
Repository for library EclipseLink (JPA 2.0)