diff --git a/hibernate-core/src/main/java/org/hibernate/boot/beanvalidation/TypeSafeActivator.java b/hibernate-core/src/main/java/org/hibernate/boot/beanvalidation/TypeSafeActivator.java index e07bd7a32cb1..5b67043bd287 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/beanvalidation/TypeSafeActivator.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/beanvalidation/TypeSafeActivator.java @@ -16,6 +16,7 @@ import java.util.Set; import java.util.StringTokenizer; +import jakarta.validation.NoProviderFoundException; import jakarta.validation.constraints.Digits; import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Min; @@ -97,14 +98,24 @@ public static void activate(ActivationContext context) { catch (IntegrationException e) { final Set validationModes = context.getValidationModes(); if ( validationModes.contains( ValidationMode.CALLBACK ) ) { - throw new IntegrationException( "Bean Validation provider was not available, but 'callback' validation was requested", e ); + throw new IntegrationException( "Jakarta Validation provider was not available, but 'callback' validation mode was requested", e ); } else if ( validationModes.contains( ValidationMode.DDL ) ) { - throw new IntegrationException( "Bean Validation provider was not available, but 'ddl' validation was requested", e ); + throw new IntegrationException( "Jakarta Validation provider was not available, but 'ddl' validation mode was requested", e ); } else { - LOG.debug( "Unable to acquire Bean Validation ValidatorFactory, skipping activation" ); - return; + if ( e.getCause() != null && e.getCause() instanceof NoProviderFoundException ) { + // all good, we are looking at the ValidationMode.AUTO, and there are no providers available. + // Hence, we just don't enable the Jakarta Validation integration: + LOG.debug( "Unable to acquire Jakarta Validation ValidatorFactory, skipping activation" ); + return; + } + else { + // There is a Jakarta Validation provider, but it failed to bootstrap the factory for some reason, + // we should fail and let the user deal with it: + throw e; + + } } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/BeanValidationAutoTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/BeanValidationAutoTest.java index e2e0c2265bb7..a47e994b5d94 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/BeanValidationAutoTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/BeanValidationAutoTest.java @@ -4,54 +4,42 @@ */ package org.hibernate.orm.test.annotations.beanvalidation; -import java.math.BigDecimal; import jakarta.validation.ConstraintViolationException; +import org.hibernate.cfg.ValidationSettings; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.Setting; +import org.junit.jupiter.api.Test; -import org.hibernate.boot.beanvalidation.ValidationMode; -import org.junit.Test; - -import org.hibernate.Session; -import org.hibernate.Transaction; -import org.hibernate.cfg.Configuration; - -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import java.math.BigDecimal; -import static org.hibernate.cfg.ValidationSettings.JAKARTA_VALIDATION_MODE; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.fail; /** * @author Emmanuel Bernard */ -public class BeanValidationAutoTest extends BaseCoreFunctionalTestCase { +@ServiceRegistry( + settings = @Setting(name = ValidationSettings.JAKARTA_VALIDATION_MODE, value = "AUTO") +) +@DomainModel(annotatedClasses = CupHolder.class) +@SessionFactory +class BeanValidationAutoTest { @Test - public void testListeners() { - CupHolder ch = new CupHolder(); - ch.setRadius( new BigDecimal( "12" ) ); - Session s = openSession(); - Transaction tx = s.beginTransaction(); - try { - s.persist( ch ); - s.flush(); - fail( "invalid object should not be persisted" ); - } - catch ( ConstraintViolationException e ) { - assertEquals( 1, e.getConstraintViolations().size() ); - } - tx.rollback(); - s.close(); - } - - @Override - protected void configure(Configuration cfg) { - super.configure( cfg ); - cfg.setProperty( JAKARTA_VALIDATION_MODE, ValidationMode.AUTO ); - } - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { - CupHolder.class - }; + void testListeners(SessionFactoryScope scope) { + scope.inTransaction( s -> { + CupHolder ch = new CupHolder(); + ch.setRadius( new BigDecimal( "12" ) ); + try { + s.persist( ch ); + s.flush(); + fail( "invalid object should not be persisted" ); + } + catch (ConstraintViolationException e) { + assertThat( e.getConstraintViolations() ).hasSize( 1 ); + } + } ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/BeanValidationDisabledTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/BeanValidationDisabledTest.java index 3ab2833b06cf..0b2a5a800b42 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/BeanValidationDisabledTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/BeanValidationDisabledTest.java @@ -4,59 +4,53 @@ */ package org.hibernate.orm.test.annotations.beanvalidation; -import java.math.BigDecimal; -import java.util.Map; import jakarta.validation.ConstraintViolationException; - -import org.hibernate.Session; -import org.hibernate.Transaction; +import org.hibernate.cfg.ValidationSettings; import org.hibernate.mapping.Column; import org.hibernate.mapping.PersistentClass; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.Setting; +import org.junit.jupiter.api.Test; -import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; -import org.junit.Test; +import java.math.BigDecimal; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; /** * @author Emmanuel Bernard */ -public class BeanValidationDisabledTest extends BaseNonConfigCoreFunctionalTestCase { +@ServiceRegistry( + settings = @Setting(name = ValidationSettings.JAKARTA_VALIDATION_MODE, value = "none") +) +@DomainModel(annotatedClasses = { + Address.class, + CupHolder.class +}) +@SessionFactory +class BeanValidationDisabledTest { @Test - public void testListeners() { - CupHolder ch = new CupHolder(); - ch.setRadius( new BigDecimal( "12" ) ); - Session s = openSession(); - Transaction tx = s.beginTransaction(); - try { - s.persist( ch ); - s.flush(); - } - catch ( ConstraintViolationException e ) { - fail( "invalid object should not be validated" ); - } - tx.rollback(); - s.close(); + void testListeners(SessionFactoryScope scope) { + scope.inTransaction( s -> { + CupHolder ch = new CupHolder(); + ch.setRadius( new BigDecimal( "12" ) ); + try { + s.persist( ch ); + s.flush(); + } + catch (ConstraintViolationException e) { + fail( "invalid object should not be validated" ); + } + } ); } @Test - public void testDDLDisabled() { - PersistentClass classMapping = metadata().getEntityBinding( Address.class.getName() ); + void testDDLDisabled(SessionFactoryScope scope) { + PersistentClass classMapping = scope.getMetadataImplementor().getEntityBinding( Address.class.getName() ); Column countryColumn = (Column) classMapping.getProperty( "country" ).getSelectables().get( 0 ); - assertTrue( "DDL constraints are applied", countryColumn.isNullable() ); - } - - @Override - protected void addSettings(Map settings) { - settings.put( "jakarta.persistence.validation.mode", "none" ); - } - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { - Address.class, - CupHolder.class - }; + assertTrue( countryColumn.isNullable(), "DDL constraints are applied" ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/BeanValidationGroupsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/BeanValidationGroupsTest.java index 7d34d64dd8db..e228cb101fb9 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/BeanValidationGroupsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/BeanValidationGroupsTest.java @@ -4,91 +4,77 @@ */ package org.hibernate.orm.test.annotations.beanvalidation; -import java.lang.annotation.Annotation; -import java.math.BigDecimal; import jakarta.validation.ConstraintViolationException; import jakarta.validation.constraints.NotNull; -import jakarta.validation.groups.Default; - -import org.junit.Test; - -import org.hibernate.Session; import org.hibernate.Transaction; -import org.hibernate.cfg.Configuration; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.hibernate.boot.beanvalidation.BeanValidationIntegrator; +import org.hibernate.cfg.ValidationSettings; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.Setting; +import org.junit.jupiter.api.Test; + +import java.lang.annotation.Annotation; +import java.math.BigDecimal; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.fail; /** * @author Emmanuel Bernard */ -public class BeanValidationGroupsTest extends BaseCoreFunctionalTestCase { - @Test - public void testListeners() { - CupHolder ch = new CupHolder(); - ch.setRadius( new BigDecimal( "12" ) ); - Session s = openSession(); - Transaction tx = s.beginTransaction(); - try { - s.persist( ch ); - s.flush(); - } - catch ( ConstraintViolationException e ) { - fail( "invalid object should not be validated" ); - } - try { - ch.setRadius( null ); - s.flush(); - } - catch ( ConstraintViolationException e ) { - fail( "invalid object should not be validated" ); - } - try { - s.remove( ch ); - s.flush(); - fail( "invalid object should not be persisted" ); - } - catch ( ConstraintViolationException e ) { - assertEquals( 1, e.getConstraintViolations().size() ); - // TODO - seems this explicit case is necessary with JDK 5 (at least on Mac). With Java 6 there is no problem - Annotation annotation = e.getConstraintViolations() - .iterator() - .next() - .getConstraintDescriptor() - .getAnnotation(); - assertEquals( - NotNull.class, - annotation.annotationType() - ); - } - tx.rollback(); - s.close(); - } +@ServiceRegistry(settings = { + @Setting(name = ValidationSettings.JAKARTA_PERSIST_VALIDATION_GROUP, value = ""), + @Setting(name = ValidationSettings.JAKARTA_UPDATE_VALIDATION_GROUP, value = ""), + @Setting(name = ValidationSettings.JAKARTA_REMOVE_VALIDATION_GROUP, + value = "jakarta.validation.groups.Default, org.hibernate.orm.test.annotations.beanvalidation.Strict"), + @Setting(name = BeanValidationIntegrator.APPLY_CONSTRAINTS, value = "false"), + @Setting(name = ValidationSettings.JAKARTA_VALIDATION_MODE, value = "auto"), +}) +@DomainModel(annotatedClasses = { + CupHolder.class +}) +@SessionFactory +class BeanValidationGroupsTest { - @Override - protected void configure(Configuration cfg) { - super.configure( cfg ); - cfg.setProperty( - "javax.persistence.validation.group.pre-persist", - "" - ); - cfg.setProperty( - "javax.persistence.validation.group.pre-update", - "" - ); - cfg.setProperty( - "javax.persistence.validation.group.pre-remove", - Default.class.getName() + ", " + Strict.class.getName() - ); - cfg.setProperty( "hibernate.validator.apply_to_ddl", "false" ); - cfg.setProperty( "jakarta.persistence.validation.mode", "auto" ); - } - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { - CupHolder.class - }; + @Test + void testListeners(SessionFactoryScope scope) { + scope.inSession( s -> { + CupHolder ch = new CupHolder(); + ch.setRadius( new BigDecimal( "12" ) ); + Transaction tx = s.beginTransaction(); + try { + s.persist( ch ); + s.flush(); + } + catch (ConstraintViolationException e) { + fail( "invalid object should not be validated" ); + } + try { + ch.setRadius( null ); + s.flush(); + } + catch (ConstraintViolationException e) { + fail( "invalid object should not be validated" ); + } + try { + s.remove( ch ); + s.flush(); + fail( "invalid object should not be persisted" ); + } + catch (ConstraintViolationException e) { + assertThat( e.getConstraintViolations() ).hasSize( 1 ); + // TODO - seems this explicit case is necessary with JDK 5 (at least on Mac). With Java 6 there is no problem + Annotation annotation = e.getConstraintViolations() + .iterator() + .next() + .getConstraintDescriptor() + .getAnnotation(); + assertThat( annotation.annotationType() ).isEqualTo( NotNull.class ); + } + tx.rollback(); + } ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/BeanValidationProvidedFactoryTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/BeanValidationProvidedFactoryTest.java index ba56c985b3ef..4ea3e86bb5f6 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/BeanValidationProvidedFactoryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/BeanValidationProvidedFactoryTest.java @@ -4,73 +4,74 @@ */ package org.hibernate.orm.test.annotations.beanvalidation; -import java.math.BigDecimal; -import java.util.Locale; import jakarta.validation.ConstraintViolationException; import jakarta.validation.MessageInterpolator; import jakarta.validation.Validation; import jakarta.validation.ValidatorFactory; - -import org.hibernate.boot.beanvalidation.ValidationMode; -import org.junit.Test; - -import org.hibernate.Session; import org.hibernate.Transaction; -import org.hibernate.cfg.Configuration; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.hibernate.cfg.ValidationSettings; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.Setting; +import org.hibernate.testing.orm.junit.SettingProvider; +import org.junit.jupiter.api.Test; -import static org.hibernate.cfg.ValidationSettings.JAKARTA_VALIDATION_FACTORY; -import static org.hibernate.cfg.ValidationSettings.JAKARTA_VALIDATION_MODE; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import java.math.BigDecimal; +import java.util.Locale; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.fail; /** * @author Emmanuel Bernard */ -public class BeanValidationProvidedFactoryTest extends BaseCoreFunctionalTestCase { +@ServiceRegistry( + settings = @Setting(name = ValidationSettings.JAKARTA_VALIDATION_MODE, value = "auto"), + settingProviders = @SettingProvider(settingName = ValidationSettings.JAKARTA_VALIDATION_FACTORY, + provider = BeanValidationProvidedFactoryTest.ValidatorFactoryProvider.class) +) +@DomainModel(annotatedClasses = { + CupHolder.class +}) +@SessionFactory +class BeanValidationProvidedFactoryTest { @Test - public void testListeners() { - CupHolder ch = new CupHolder(); - ch.setRadius( new BigDecimal( "12" ) ); - Session s = openSession(); - Transaction tx = s.beginTransaction(); - try { - s.persist( ch ); - s.flush(); - fail( "invalid object should not be persisted" ); - } - catch ( ConstraintViolationException e ) { - assertEquals( 1, e.getConstraintViolations().size() ); - assertEquals( "Oops", e.getConstraintViolations().iterator().next().getMessage() ); - } - tx.rollback(); - s.close(); - } - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { - CupHolder.class - }; + void testListeners(SessionFactoryScope scope) { + scope.inSession( s -> { + CupHolder ch = new CupHolder(); + ch.setRadius( new BigDecimal( "12" ) ); + Transaction tx = s.beginTransaction(); + try { + s.persist( ch ); + s.flush(); + fail( "invalid object should not be persisted" ); + } + catch (ConstraintViolationException e) { + assertThat( e.getConstraintViolations() ).hasSize( 1 ); + assertThat( e.getConstraintViolations().iterator().next().getMessage() ).isEqualTo( "Oops" ); + } + tx.rollback(); + } ); } - @Override - protected void configure(Configuration cfg) { - super.configure( cfg ); - final MessageInterpolator messageInterpolator = new MessageInterpolator() { + public static class ValidatorFactoryProvider implements SettingProvider.Provider { + @Override + public ValidatorFactory getSetting() { + final MessageInterpolator messageInterpolator = new MessageInterpolator() { - public String interpolate(String s, Context context) { - return "Oops"; - } + public String interpolate(String s, Context context) { + return "Oops"; + } - public String interpolate(String s, Context context, Locale locale) { - return interpolate( s, context ); - } - }; - final jakarta.validation.Configuration configuration = Validation.byDefaultProvider().configure(); - configuration.messageInterpolator( messageInterpolator ); - ValidatorFactory vf = configuration.buildValidatorFactory(); - cfg.getProperties().put( JAKARTA_VALIDATION_FACTORY, vf ); - cfg.setProperty( JAKARTA_VALIDATION_MODE, ValidationMode.AUTO ); + public String interpolate(String s, Context context, Locale locale) { + return interpolate( s, context ); + } + }; + final jakarta.validation.Configuration configuration = Validation.byDefaultProvider().configure(); + configuration.messageInterpolator( messageInterpolator ); + return configuration.buildValidatorFactory(); + } } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/DDLTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/DDLTest.java index 2c08ec8ab587..4b02fa628d5c 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/DDLTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/DDLTest.java @@ -4,18 +4,23 @@ */ package org.hibernate.orm.test.annotations.beanvalidation; -import java.util.Map; - +import org.hibernate.cfg.ValidationSettings; import org.hibernate.mapping.Column; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; -import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; -import org.junit.Test; +import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableMutationStrategy; +import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableMutationStrategy; +import org.hibernate.query.sqm.mutation.internal.temptable.PersistentTableStrategy; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.Setting; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; /** * Test verifying that DDL constraints get applied when Bean Validation / Hibernate Validator are enabled. @@ -23,121 +28,136 @@ * @author Emmanuel Bernard * @author Hardy Ferentschik */ -public class DDLTest extends BaseNonConfigCoreFunctionalTestCase { +@ServiceRegistry(settings = { + @Setting(name = ValidationSettings.JAKARTA_VALIDATION_MODE, value = "DDL"), + @Setting(name = PersistentTableStrategy.DROP_ID_TABLES, value = "true"), + @Setting(name = GlobalTemporaryTableMutationStrategy.DROP_ID_TABLES, value = "true"), + @Setting(name = LocalTemporaryTableMutationStrategy.DROP_ID_TABLES, value = "true") +}) +@DomainModel(annotatedClasses = { + Address.class, + Tv.class, + TvOwner.class, + Rock.class +}) +@SessionFactory +class DDLTest { + + @BeforeAll + static void beforeAll(SessionFactoryScope scope) { + // we want to get the SF built before we inspect the boot metamodel, + // if we don't -- the integrators won't get applied, and hence DDL validation mode will not be applied either: + scope.getSessionFactory(); + } + @Test - public void testBasicDDL() { - PersistentClass classMapping = metadata().getEntityBinding( Address.class.getName() ); - Column stateColumn = classMapping.getProperty( "state" ).getColumns().get(0); - assertEquals( stateColumn.getLength(), (Long) 3L ); - Column zipColumn = classMapping.getProperty( "zip" ).getColumns().get(0); - assertEquals( zipColumn.getLength(), (Long) 5L ); - assertFalse( zipColumn.isNullable() ); + void testBasicDDL(SessionFactoryScope scope) { + PersistentClass classMapping = scope.getMetadataImplementor().getEntityBinding( Address.class.getName() ); + Column stateColumn = classMapping.getProperty( "state" ).getColumns().get( 0 ); + assertThat( stateColumn.getLength() ).isEqualTo( 3L ); + Column zipColumn = classMapping.getProperty( "zip" ).getColumns().get( 0 ); + assertThat( zipColumn.getLength() ).isEqualTo( 5L ); + assertThat( zipColumn.isNullable() ).isFalse(); } @Test - public void testNotNullDDL() { - PersistentClass classMapping = metadata().getEntityBinding( Address.class.getName() ); - Column stateColumn = classMapping.getProperty( "state" ).getColumns().get(0); - assertFalse("Validator annotations are applied on state as it is @NotNull", stateColumn.isNullable()); - - Column line1Column = classMapping.getProperty( "line1" ).getColumns().get(0); - assertFalse("Validator annotations are applied on line1 as it is @NotEmpty", line1Column.isNullable()); - - Column line2Column = classMapping.getProperty( "line2" ).getColumns().get(0); - assertFalse("Validator annotations are applied on line2 as it is @NotBlank", line2Column.isNullable()); - - Column line3Column = classMapping.getProperty( "line3" ).getColumns().get(0); - assertTrue( - "Validator composition of type OR should result in line3 being nullable", - line3Column.isNullable()); - - Column line4Column = classMapping.getProperty( "line4" ).getColumns().get(0); - assertFalse( - "Validator composition of type OR should result in line4 being not-null", - line4Column.isNullable()); - - Column line5Column = classMapping.getProperty( "line5" ).getColumns().get(0); - assertFalse( - "Validator composition of type AND should result in line5 being not-null", - line5Column.isNullable()); - - Column line6Column = classMapping.getProperty( "line6" ).getColumns().get(0); - assertFalse( - "Validator composition of type AND should result in line6 being not-null", - line6Column.isNullable()); - - Column line7Column = classMapping.getProperty( "line7" ).getColumns().get(0); - assertTrue( - "Validator composition of type OR should result in line7 being nullable", - line7Column.isNullable()); + void testNotNullDDL(SessionFactoryScope scope) { + PersistentClass classMapping = scope.getMetadataImplementor().getEntityBinding( Address.class.getName() ); + Column stateColumn = classMapping.getProperty( "state" ).getColumns().get( 0 ); + assertThat( stateColumn.isNullable() ) + .as( "Validator annotations are applied on state as it is @NotNull" ) + .isFalse(); + + Column line1Column = classMapping.getProperty( "line1" ).getColumns().get( 0 ); + assertThat( line1Column.isNullable() ) + .as( "Validator annotations are applied on line1 as it is @NotEmpty" ) + .isFalse(); + + Column line2Column = classMapping.getProperty( "line2" ).getColumns().get( 0 ); + assertThat( line2Column.isNullable() ) + .as( "Validator annotations are applied on line2 as it is @NotBlank" ) + .isFalse(); + + Column line3Column = classMapping.getProperty( "line3" ).getColumns().get( 0 ); + assertThat( line3Column.isNullable() ) + .as( "Validator composition of type OR should result in line3 being nullable" ) + .isTrue(); + + Column line4Column = classMapping.getProperty( "line4" ).getColumns().get( 0 ); + assertThat( line4Column.isNullable() ) + .as( "Validator composition of type OR should result in line4 being not-null" ) + .isFalse(); + + Column line5Column = classMapping.getProperty( "line5" ).getColumns().get( 0 ); + assertThat( line5Column.isNullable() ) + .as( "Validator composition of type AND should result in line5 being not-null" ) + .isFalse(); + + Column line6Column = classMapping.getProperty( "line6" ).getColumns().get( 0 ); + assertThat( line6Column.isNullable() ) + .as( "Validator composition of type AND should result in line6 being not-null" ) + .isFalse(); + + Column line7Column = classMapping.getProperty( "line7" ).getColumns().get( 0 ); + assertThat( line7Column.isNullable() ) + .as( "Validator composition of type OR should result in line7 being nullable" ) + .isTrue(); Column line8Column = classMapping.getProperty( "line8" ).getColumns().get( 0 ); - assertFalse( - "Validator should result in line8 being not-null", - line8Column.isNullable()); + assertThat( line8Column.isNullable() ) + .as( "Validator should result in line8 being not-null" ) + .isFalse(); Column line9Column = classMapping.getProperty( "line9" ).getColumns().get( 0 ); - assertTrue( - "Validator should result in line9 being nullable", - line9Column.isNullable()); + assertThat( line9Column.isNullable() ).as( "Validator should result in line9 being nullable" ) + .isTrue(); } @Test - public void testApplyOnIdColumn() { - PersistentClass classMapping = metadata().getEntityBinding( Tv.class.getName() ); - Column serialColumn = classMapping.getIdentifierProperty().getColumns().get(0); - assertEquals( "Validator annotation not applied on ids", (Long) 2L, serialColumn.getLength() ); + void testApplyOnIdColumn(SessionFactoryScope scope) { + PersistentClass classMapping = scope.getMetadataImplementor().getEntityBinding( Tv.class.getName() ); + Column serialColumn = classMapping.getIdentifierProperty().getColumns().get( 0 ); + assertThat( serialColumn.getLength() ).as( "Validator annotation not applied on ids" ).isEqualTo( 2L ); } @Test - public void testLengthConstraint() { - PersistentClass classMapping = metadata().getEntityBinding( Tv.class.getName() ); - Column modelColumn = classMapping.getProperty( "model" ).getColumns().get(0); - assertEquals( modelColumn.getLength(), (Long) 5L ); + void testLengthConstraint(SessionFactoryScope scope) { + PersistentClass classMapping = scope.getMetadataImplementor().getEntityBinding( Tv.class.getName() ); + Column modelColumn = classMapping.getProperty( "model" ).getColumns().get( 0 ); + assertThat( modelColumn.getLength() ).isEqualTo( 5L ); } @Test - public void testApplyOnManyToOne() { - PersistentClass classMapping = metadata().getEntityBinding( TvOwner.class.getName() ); - Column serialColumn = classMapping.getProperty( "tv" ).getColumns().get(0); - assertEquals( "Validator annotations not applied on associations", false, serialColumn.isNullable() ); + void testApplyOnManyToOne(SessionFactoryScope scope) { + PersistentClass classMapping = scope.getMetadataImplementor().getEntityBinding( TvOwner.class.getName() ); + Column serialColumn = classMapping.getProperty( "tv" ).getColumns().get( 0 ); + assertThat( serialColumn.isNullable() ) + .as( "Validator annotations not applied on associations" ) + .isFalse(); } @Test - public void testSingleTableAvoidNotNull() { - PersistentClass classMapping = metadata().getEntityBinding( Rock.class.getName() ); - Column serialColumn = classMapping.getProperty( "bit" ).getColumns().get(0); - assertTrue( "Notnull should not be applied on single tables", serialColumn.isNullable() ); + void testSingleTableAvoidNotNull(SessionFactoryScope scope) { + PersistentClass classMapping = scope.getMetadataImplementor().getEntityBinding( Rock.class.getName() ); + Column serialColumn = classMapping.getProperty( "bit" ).getColumns().get( 0 ); + assertThat( serialColumn.isNullable() ) + .as( "Notnull should not be applied on single tables" ) + .isTrue(); } @Test - public void testNotNullOnlyAppliedIfEmbeddedIsNotNullItself() { - PersistentClass classMapping = metadata().getEntityBinding( Tv.class.getName() ); + void testNotNullOnlyAppliedIfEmbeddedIsNotNullItself(SessionFactoryScope scope) { + PersistentClass classMapping = scope.getMetadataImplementor().getEntityBinding( Tv.class.getName() ); Property property = classMapping.getProperty( "tuner.frequency" ); - Column serialColumn = property.getColumns().get(0); - assertEquals( - "Validator annotations are applied on tuner as it is @NotNull", false, serialColumn.isNullable() - ); + Column serialColumn = property.getColumns().get( 0 ); + assertThat( serialColumn.isNullable() ) + .as( "Validator annotations are applied on tuner as it is @NotNull" ) + .isFalse(); property = classMapping.getProperty( "recorder.time" ); - serialColumn = property.getColumns().get(0); - assertEquals( - "Validator annotations are applied on tuner as it is @NotNull", true, serialColumn.isNullable() - ); - } - - @Override - protected void addSettings(Map settings) { - settings.put( "jakarta.persistence.validation.mode", "ddl" ); - } - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { - Address.class, - Tv.class, - TvOwner.class, - Rock.class - }; + serialColumn = property.getColumns().get( 0 ); + assertThat( serialColumn.isNullable() ) + .as( "Validator annotations are applied on tuner as it is @NotNull" ) + .isTrue(); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/DDLWithoutCallbackTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/DDLWithoutCallbackTest.java index 240f1d27766a..3b6f1ad5e8d0 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/DDLWithoutCallbackTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/DDLWithoutCallbackTest.java @@ -5,100 +5,103 @@ package org.hibernate.orm.test.annotations.beanvalidation; import java.math.BigDecimal; -import java.util.Map; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.PersistenceException; import jakarta.validation.ConstraintViolationException; +import org.hibernate.cfg.ValidationSettings; import org.hibernate.mapping.Column; import org.hibernate.mapping.PersistentClass; -import org.hibernate.testing.DialectChecks; -import org.hibernate.testing.RequiresDialectFeature; -import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; -import org.junit.Test; - -import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.fail; +import org.hibernate.testing.orm.junit.DialectFeatureChecks; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.RequiresDialectFeature; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.Setting; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hibernate.testing.orm.junit.DialectContext.getDialect; +import static org.junit.jupiter.api.Assertions.fail; /** * @author Vladimir Klyushnikov * @author Hardy Ferentschik */ -public class DDLWithoutCallbackTest extends BaseNonConfigCoreFunctionalTestCase { - - @Override - protected void addSettings(Map settings) { - settings.put( "jakarta.persistence.validation.mode", "ddl" ); - } - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { - Address.class, - CupHolder.class, - MinMax.class, - RangeEntity.class - }; - } - - @Override - protected boolean isCleanupTestDataRequired() { - return true; +@ServiceRegistry( + settings = @Setting(name = ValidationSettings.JAKARTA_VALIDATION_MODE, value = "ddl") +) +@DomainModel(annotatedClasses = { + Address.class, + CupHolder.class, + MinMax.class, + DDLWithoutCallbackTest.RangeEntity.class +}) +@SessionFactory +class DDLWithoutCallbackTest { + + @BeforeAll + static void beforeAll(SessionFactoryScope scope) { + // we want to get the SF built before we inspect the boot metamodel, + // if we don't -- the integrators won't get applied, and hence DDL validation mode will not be applied either: + scope.getSessionFactory(); } @Test - @RequiresDialectFeature(DialectChecks.SupportsColumnCheck.class) - public void testListeners() { + @RequiresDialectFeature(feature = DialectFeatureChecks.SupportsColumnCheck.class) + void testListeners(SessionFactoryScope scope) { CupHolder ch = new CupHolder(); ch.setRadius( new BigDecimal( "12" ) ); - assertDatabaseConstraintViolationThrown( ch ); + assertDatabaseConstraintViolationThrown( scope, ch ); } @Test - @RequiresDialectFeature(DialectChecks.SupportsColumnCheck.class) - public void testMinAndMaxChecksGetApplied() { + @RequiresDialectFeature(feature = DialectFeatureChecks.SupportsColumnCheck.class) + public void testMinAndMaxChecksGetApplied(SessionFactoryScope scope) { MinMax minMax = new MinMax( 1 ); - assertDatabaseConstraintViolationThrown( minMax ); + assertDatabaseConstraintViolationThrown( scope, minMax ); minMax = new MinMax( 11 ); - assertDatabaseConstraintViolationThrown( minMax ); + assertDatabaseConstraintViolationThrown( scope, minMax ); final MinMax validMinMax = new MinMax( 5 ); - doInHibernate( this::sessionFactory, session -> { - session.persist( validMinMax ); + scope.inTransaction( s -> { + s.persist( validMinMax ); } ); } @Test - @RequiresDialectFeature(DialectChecks.SupportsColumnCheck.class) - public void testRangeChecksGetApplied() { + @RequiresDialectFeature(feature = DialectFeatureChecks.SupportsColumnCheck.class) + public void testRangeChecksGetApplied(SessionFactoryScope scope) { RangeEntity range = new RangeEntity( 1 ); - assertDatabaseConstraintViolationThrown( range ); + assertDatabaseConstraintViolationThrown( scope, range ); range = new RangeEntity( 11 ); - assertDatabaseConstraintViolationThrown( range ); + assertDatabaseConstraintViolationThrown( scope, range ); RangeEntity validRange = new RangeEntity( 5 ); - doInHibernate( this::sessionFactory, session -> { - session.persist( validRange ); + scope.inTransaction( s -> { + s.persist( validRange ); } ); } @Test - public void testDDLEnabled() { - PersistentClass classMapping = metadata().getEntityBinding( Address.class.getName() ); + public void testDDLEnabled(SessionFactoryScope scope) { + PersistentClass classMapping = scope.getMetadataImplementor().getEntityBinding( Address.class.getName() ); Column countryColumn = (Column) classMapping.getProperty( "country" ).getSelectables().get( 0 ); - assertFalse( "DDL constraints are not applied", countryColumn.isNullable() ); + assertThat( countryColumn.isNullable() ).as( "DDL constraints are not applied" ).isFalse(); } - private void assertDatabaseConstraintViolationThrown(Object o) { - doInHibernate( this::sessionFactory, session -> { + private void assertDatabaseConstraintViolationThrown(SessionFactoryScope scope, Object o) { + scope.inTransaction( session -> { try { session.persist( o ); session.flush(); @@ -122,6 +125,11 @@ else if ( cause instanceof org.hibernate.exception.ConstraintViolationException } ); } + @AfterEach + void dropTestData(SessionFactoryScope sessions) { + sessions.dropData(); + } + @Entity(name = "RangeEntity") public static class RangeEntity { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/HibernateTraversableResolverTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/HibernateTraversableResolverTest.java index 59eda9fb633b..1372b2812430 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/HibernateTraversableResolverTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/HibernateTraversableResolverTest.java @@ -8,203 +8,175 @@ import jakarta.validation.ConstraintViolation; import jakarta.validation.ConstraintViolationException; -import org.hibernate.boot.beanvalidation.ValidationMode; -import org.junit.Test; +import org.hibernate.cfg.ValidationSettings; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.Setting; -import org.hibernate.Session; -import org.hibernate.Transaction; -import org.hibernate.cfg.Configuration; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.fail; -import static org.hibernate.cfg.ValidationSettings.JAKARTA_VALIDATION_MODE; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; /** * @author Emmanuel Bernard */ -public class HibernateTraversableResolverTest extends BaseCoreFunctionalTestCase { +@ServiceRegistry( + settings = @Setting(name = ValidationSettings.JAKARTA_VALIDATION_MODE, value = "AUTO") +) +@DomainModel(annotatedClasses = { + Button.class, + Color.class, + Display.class, + DisplayConnector.class, + PowerSupply.class, + Screen.class +}) +@SessionFactory +class HibernateTraversableResolverTest { @Test - public void testNonLazyAssocFieldWithConstraintsFailureExpected() { - Session s = openSession(); - Transaction tx = s.beginTransaction(); - - Screen screen = new Screen(); - screen.setPowerSupply( null ); - try { - s.persist( screen ); - s.flush(); - fail( "@NotNull on a non lazy association is not evaluated" ); - } - catch ( ConstraintViolationException e ) { - assertEquals( 1, e.getConstraintViolations().size() ); - } - - tx.rollback(); - s.close(); + void testNonLazyAssocFieldWithConstraintsFailureExpected(SessionFactoryScope scope) { + scope.inTransaction( s -> { + Screen screen = new Screen(); + screen.setPowerSupply( null ); + try { + s.persist( screen ); + s.flush(); + fail( "@NotNull on a non lazy association is not evaluated" ); + } + catch (ConstraintViolationException e) { + assertThat( e.getConstraintViolations() ).hasSize( 1 ); + } + } ); } @Test - public void testEmbedded() { - Session s = openSession(); - Transaction tx = s.beginTransaction(); - - Screen screen = new Screen(); - PowerSupply ps = new PowerSupply(); - screen.setPowerSupply( ps ); - Button button = new Button(); - button.setName( null ); - button.setSize( 3 ); - screen.setStopButton( button ); - try { - s.persist( screen ); - s.flush(); - fail( "@NotNull on embedded property is not evaluated" ); - } - catch ( ConstraintViolationException e ) { - assertEquals( 1, e.getConstraintViolations().size() ); - ConstraintViolation cv = e.getConstraintViolations().iterator().next(); - assertEquals( Screen.class, cv.getRootBeanClass() ); - // toString works since hibernate validator's Path implementation works accordingly. Should do a Path comparison though - assertEquals( "stopButton.name", cv.getPropertyPath().toString() ); - } - - tx.rollback(); - s.close(); + void testEmbedded(SessionFactoryScope scope) { + scope.inTransaction( s -> { + Screen screen = new Screen(); + PowerSupply ps = new PowerSupply(); + screen.setPowerSupply( ps ); + Button button = new Button(); + button.setName( null ); + button.setSize( 3 ); + screen.setStopButton( button ); + try { + s.persist( screen ); + s.flush(); + fail( "@NotNull on embedded property is not evaluated" ); + } + catch (ConstraintViolationException e) { + assertThat( e.getConstraintViolations() ).hasSize( 1 ); + ConstraintViolation cv = e.getConstraintViolations().iterator().next(); + assertThat( cv.getRootBeanClass() ).isEqualTo( Screen.class ); + // toString works since hibernate validator's Path implementation works accordingly. Should do a Path comparison though + assertThat( cv.getPropertyPath().toString() ).isEqualTo( "stopButton.name" ); + } + + } ); } @Test - public void testToOneAssocNotValidated() { - Session s = openSession(); - Transaction tx = s.beginTransaction(); - - Screen screen = new Screen(); - PowerSupply ps = new PowerSupply(); - ps.setPosition( "1" ); - ps.setPower( new BigDecimal( 350 ) ); - screen.setPowerSupply( ps ); - try { - s.persist( screen ); - s.flush(); - fail( "Associated objects should not be validated" ); - } - catch ( ConstraintViolationException e ) { - assertEquals( 1, e.getConstraintViolations().size() ); - final ConstraintViolation constraintViolation = e.getConstraintViolations().iterator().next(); - assertEquals( PowerSupply.class, constraintViolation.getRootBeanClass() ); - } - - tx.rollback(); - s.close(); + void testToOneAssocNotValidated(SessionFactoryScope scope) { + scope.inTransaction( s -> { + Screen screen = new Screen(); + PowerSupply ps = new PowerSupply(); + ps.setPosition( "1" ); + ps.setPower( new BigDecimal( 350 ) ); + screen.setPowerSupply( ps ); + try { + s.persist( screen ); + s.flush(); + fail( "Associated objects should not be validated" ); + } + catch (ConstraintViolationException e) { + assertThat( e.getConstraintViolations() ).hasSize( 1 ); + final ConstraintViolation constraintViolation = e.getConstraintViolations().iterator().next(); + assertThat( constraintViolation.getRootBeanClass() ).isEqualTo( PowerSupply.class ); + } + } ); } @Test - public void testCollectionAssocNotValidated() { - Session s = openSession(); - Transaction tx = s.beginTransaction(); - - Screen screen = new Screen(); - screen.setStopButton( new Button() ); - screen.getStopButton().setName( "STOOOOOP" ); - PowerSupply ps = new PowerSupply(); - screen.setPowerSupply( ps ); - Color c = new Color(); - c.setName( "Blue" ); - s.persist( c ); - c.setName( null ); - screen.getDisplayColors().add( c ); - try { - s.persist( screen ); - s.flush(); - fail( "Associated objects should not be validated" ); - } - catch ( ConstraintViolationException e ) { - assertEquals( 1, e.getConstraintViolations().size() ); - final ConstraintViolation constraintViolation = e.getConstraintViolations().iterator().next(); - assertEquals( Color.class, constraintViolation.getRootBeanClass() ); - } - - tx.rollback(); - s.close(); + void testCollectionAssocNotValidated(SessionFactoryScope scope) { + scope.inTransaction( s -> { + Screen screen = new Screen(); + screen.setStopButton( new Button() ); + screen.getStopButton().setName( "STOOOOOP" ); + PowerSupply ps = new PowerSupply(); + screen.setPowerSupply( ps ); + Color c = new Color(); + c.setName( "Blue" ); + s.persist( c ); + c.setName( null ); + screen.getDisplayColors().add( c ); + try { + s.persist( screen ); + s.flush(); + fail( "Associated objects should not be validated" ); + } + catch (ConstraintViolationException e) { + assertThat( e.getConstraintViolations() ).hasSize( 1 ); + final ConstraintViolation constraintViolation = e.getConstraintViolations().iterator().next(); + assertThat( constraintViolation.getRootBeanClass() ).isEqualTo( Color.class ); + } + } ); } @Test - public void testEmbeddedCollection() { - Session s = openSession(); - Transaction tx = s.beginTransaction(); - - Screen screen = new Screen(); - PowerSupply ps = new PowerSupply(); - screen.setPowerSupply( ps ); - DisplayConnector conn = new DisplayConnector(); - conn.setNumber( 0 ); - screen.getConnectors().add( conn ); - try { - s.persist( screen ); - s.flush(); - fail( "Collection of embedded objects should be validated" ); - } - catch ( ConstraintViolationException e ) { - assertEquals( 1, e.getConstraintViolations().size() ); - final ConstraintViolation constraintViolation = e.getConstraintViolations().iterator().next(); - assertEquals( Screen.class, constraintViolation.getRootBeanClass() ); - // toString works since hibernate validator's Path implementation works accordingly. Should do a Path comparison though - assertEquals( "connectors[].number", constraintViolation.getPropertyPath().toString() ); - } - - tx.rollback(); - s.close(); + void testEmbeddedCollection(SessionFactoryScope scope) { + scope.inTransaction( s -> { + Screen screen = new Screen(); + PowerSupply ps = new PowerSupply(); + screen.setPowerSupply( ps ); + DisplayConnector conn = new DisplayConnector(); + conn.setNumber( 0 ); + screen.getConnectors().add( conn ); + try { + s.persist( screen ); + s.flush(); + fail( "Collection of embedded objects should be validated" ); + } + catch (ConstraintViolationException e) { + assertThat( e.getConstraintViolations() ).hasSize( 1 ); + final ConstraintViolation constraintViolation = e.getConstraintViolations().iterator().next(); + assertThat( constraintViolation.getRootBeanClass() ).isEqualTo( Screen.class ); + // toString works since hibernate validator's Path implementation works accordingly. Should do a Path comparison though + assertThat( constraintViolation.getPropertyPath().toString() ).isEqualTo( "connectors[].number" ); + } + }); } @Test - public void testAssocInEmbeddedNotValidated() { - Session s = openSession(); - Transaction tx = s.beginTransaction(); - - Screen screen = new Screen(); - screen.setStopButton( new Button() ); - screen.getStopButton().setName( "STOOOOOP" ); - PowerSupply ps = new PowerSupply(); - screen.setPowerSupply( ps ); - DisplayConnector conn = new DisplayConnector(); - conn.setNumber( 1 ); - screen.getConnectors().add( conn ); - final Display display = new Display(); - display.setBrand( "dell" ); - conn.setDisplay( display ); - s.persist( display ); - s.flush(); - try { - display.setBrand( null ); - s.persist( screen ); + void testAssocInEmbeddedNotValidated(SessionFactoryScope scope) { + scope.inTransaction( s -> { + Screen screen = new Screen(); + screen.setStopButton( new Button() ); + screen.getStopButton().setName( "STOOOOOP" ); + PowerSupply ps = new PowerSupply(); + screen.setPowerSupply( ps ); + DisplayConnector conn = new DisplayConnector(); + conn.setNumber( 1 ); + screen.getConnectors().add( conn ); + final Display display = new Display(); + display.setBrand( "dell" ); + conn.setDisplay( display ); + s.persist( display ); s.flush(); - fail( "Collection of embedded objects should be validated" ); - } - catch ( ConstraintViolationException e ) { - assertEquals( 1, e.getConstraintViolations().size() ); - final ConstraintViolation constraintViolation = e.getConstraintViolations().iterator().next(); - assertEquals( Display.class, constraintViolation.getRootBeanClass() ); - } - - tx.rollback(); - s.close(); - } - - @Override - protected void configure(Configuration cfg) { - super.configure( cfg ); - cfg.setProperty( JAKARTA_VALIDATION_MODE, ValidationMode.AUTO ); - } - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { - Button.class, - Color.class, - Display.class, - DisplayConnector.class, - PowerSupply.class, - Screen.class - }; + try { + display.setBrand( null ); + s.persist( screen ); + s.flush(); + fail( "Collection of embedded objects should be validated" ); + } + catch (ConstraintViolationException e) { + assertThat( e.getConstraintViolations() ).hasSize( 1 ); + final ConstraintViolation constraintViolation = e.getConstraintViolations().iterator().next(); + assertThat( constraintViolation.getRootBeanClass() ).isEqualTo( Display.class ); + } + } ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/MergeNotNullCollectionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/MergeNotNullCollectionTest.java index a96ad6cc12f4..2a8ccabe1aa1 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/MergeNotNullCollectionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/MergeNotNullCollectionTest.java @@ -15,36 +15,31 @@ import jakarta.validation.ConstraintViolationException; import jakarta.validation.constraints.NotNull; -import org.hibernate.Session; -import org.hibernate.Transaction; -import org.hibernate.boot.beanvalidation.ValidationMode; -import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.ValidationSettings; +import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.junit.Test; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.Setting; +import org.junit.jupiter.api.Test; -import static org.hibernate.cfg.ValidationSettings.JAKARTA_VALIDATION_MODE; +import static org.assertj.core.api.Assertions.assertThatThrownBy; /** * @author Ryan Emerson */ +@ServiceRegistry( + settings = @Setting(name = ValidationSettings.JAKARTA_VALIDATION_MODE, value = "AUTO") +) +@DomainModel(annotatedClasses = {MergeNotNullCollectionTest.Parent.class, MergeNotNullCollectionTest.Child.class}) +@SessionFactory @JiraKey( value = "HHH-9979") -public class MergeNotNullCollectionTest extends BaseCoreFunctionalTestCase { - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] {Parent.class, Child.class}; - } - - @Override - protected void configure(Configuration cfg) { - super.configure( cfg ); - cfg.setProperty( JAKARTA_VALIDATION_MODE, ValidationMode.AUTO ); - } +public class MergeNotNullCollectionTest { @Test - public void testOneToManyNotNullCollection() { + void testOneToManyNotNullCollection(SessionFactoryScope scope) { Parent parent = new Parent(); parent.id = 1L; Child child = new Child(); @@ -56,35 +51,18 @@ public void testOneToManyNotNullCollection() { child.setParent( parent ); parent.setChildren( children ); - Session s = openSession(); - Transaction t = s.beginTransaction(); - parent = (Parent) s.merge( parent ); - t.commit(); - s.close(); - - s = openSession(); - t = s.beginTransaction(); - s.remove( parent ); - t.commit(); - s.close(); + Parent p = scope.fromTransaction( s -> s.merge( parent ) ); + + scope.inTransaction( s -> s.remove( p ) ); } - @Test(expected = ConstraintViolationException.class) - public void testOneToManyNullCollection() { + @Test + void testOneToManyNullCollection(SessionFactoryScope scope) { Parent parent = new Parent(); parent.id = 1L; - Session s = openSession(); - Transaction t = s.beginTransaction(); - parent = (Parent) s.merge( parent ); - t.commit(); - s.close(); - - s = openSession(); - t = s.beginTransaction(); - s.remove( parent ); - t.commit(); - s.close(); + assertThatThrownBy( () -> scope.fromTransaction( s -> s.merge( parent ) ) ) + .isInstanceOf( ConstraintViolationException.class ); } @Entity diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/MergeNotNullCollectionUsingIdentityTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/MergeNotNullCollectionUsingIdentityTest.java index 1c718d58b8b2..6c853e3049fd 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/MergeNotNullCollectionUsingIdentityTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/MergeNotNullCollectionUsingIdentityTest.java @@ -17,83 +17,59 @@ import jakarta.validation.ConstraintViolationException; import jakarta.validation.constraints.NotNull; -import org.hibernate.boot.beanvalidation.ValidationMode; -import org.junit.Test; - -import org.hibernate.Session; -import org.hibernate.Transaction; -import org.hibernate.cfg.Configuration; -import org.hibernate.testing.DialectChecks; -import org.hibernate.testing.FailureExpected; -import org.hibernate.testing.RequiresDialectFeature; +import org.hibernate.cfg.ValidationSettings; +import org.hibernate.testing.orm.junit.DialectFeatureChecks; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.Setting; + +import org.hibernate.testing.orm.junit.FailureExpected; +import org.hibernate.testing.orm.junit.RequiresDialectFeature; import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.jupiter.api.Test; -import static org.hibernate.cfg.ValidationSettings.JAKARTA_VALIDATION_MODE; +import static org.assertj.core.api.Assertions.assertThatThrownBy; /** * @author Ryan Emerson */ -@RequiresDialectFeature( value = { - DialectChecks.SupportsIdentityColumns.class, - DialectChecks.SupportsNoColumnInsert.class -}, jiraKey = "HHH-9979") +@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsIdentityColumns.class, jiraKey = "HHH-9979") +@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsNoColumnInsert.class, jiraKey = "HHH-9979") +@ServiceRegistry( + settings = @Setting(name = ValidationSettings.JAKARTA_VALIDATION_MODE, value = "AUTO") +) +@DomainModel(annotatedClasses = {MergeNotNullCollectionUsingIdentityTest.Parent.class, MergeNotNullCollectionUsingIdentityTest.Child.class}) +@SessionFactory @JiraKey( value = "HHH-9979") -public class MergeNotNullCollectionUsingIdentityTest extends BaseCoreFunctionalTestCase { - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] {Parent.class, Child.class}; - } - - @Override - protected void configure(Configuration cfg) { - super.configure( cfg ); - cfg.setProperty( JAKARTA_VALIDATION_MODE, ValidationMode.AUTO ); - } +class MergeNotNullCollectionUsingIdentityTest { @Test @FailureExpected(jiraKey = "HHH-9979") - public void testOneToManyNotNullCollection() { + void testOneToManyNotNullCollection(SessionFactoryScope scope) { Parent parent = new Parent(); Child child = new Child(); - List children = new ArrayList(); + List children = new ArrayList<>(); children.add( child ); child.setParent( parent ); parent.setChildren( children ); - Session s = openSession(); - Transaction t = s.beginTransaction(); - parent = (Parent) s.merge( parent ); - t.commit(); - s.close(); - - s = openSession(); - t = s.beginTransaction(); - s.remove( parent ); - t.commit(); - s.close(); + Parent p = scope.fromTransaction( s -> s.merge( parent ) ); + + scope.inTransaction( s -> s.remove( p ) ); } - @Test(expected = ConstraintViolationException.class) - public void testOneToManyNullCollection() { + @Test + void testOneToManyNullCollection(SessionFactoryScope scope) { Parent parent = new Parent(); Child child = new Child(); child.setParent( parent ); - Session s = openSession(); - Transaction t = s.beginTransaction(); - parent = (Parent) s.merge( parent ); - t.commit(); - s.close(); - - s = openSession(); - t = s.beginTransaction(); - s.remove( parent ); - t.commit(); - s.close(); + assertThatThrownBy( () -> scope.fromTransaction( s -> s.merge( parent ) ) ) + .isInstanceOf( ConstraintViolationException.class ); } @Entity diff --git a/migration-guide.adoc b/migration-guide.adoc index 47a598f07ed8..4df9f419b8b6 100644 --- a/migration-guide.adoc +++ b/migration-guide.adoc @@ -538,6 +538,17 @@ Also, a key subgraph now always refers to a `Map` key, and never to an entity id We encourage migration to the use of the new JPA-standard operations. +[[validator-integration-validation-mode]] +== Behaviour change for `ValidationMode.AUTO` + +Hibernate ORM will not silently ignore issues with the `ValidatorFactory` configuration anymore when an auto validation mode is chosen. +In the past, with `ValidationMode.AUTO` enabled, Hibernate ORM would translate the validation mode to `ValidationMode.NONE`, +either when there were no providers available or when a provider was available, +but creating an instance of the validator factory resulted in an exception. +From now on, `ValidationMode.AUTO` will only be translated to `ValidationMode.NONE` when there are no validation providers available, +and in the case when the validation provider is available and an exception is encountered while creating an instance of the `ValidatorFactory` +this exception will be propagated to the user. + == Deprecations * `@Comment` is deprecated in favor of the JPA 3.2 `comment` members @@ -617,4 +628,4 @@ We encourage migration to the use of the new JPA-standard operations. == Todos (dev) * Look for `todo (jpa 3.2)` comments -* Look for `todo (7.0)` comments \ No newline at end of file +* Look for `todo (7.0)` comments