diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java index a41463f409..f6e971328f 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java @@ -16,6 +16,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.Set; @@ -135,6 +136,7 @@ import org.hibernate.boot.spi.InFlightMetadataCollector.EntityTableXref; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.cfg.annotations.CollectionBinder; import org.hibernate.cfg.annotations.EntityBinder; +import org.hibernate.cfg.annotations.HCANNHelper; import org.hibernate.cfg.annotations.MapKeyColumnDelegator; import org.hibernate.cfg.annotations.MapKeyJoinColumnDelegator; import org.hibernate.cfg.annotations.Nullability; @@ -145,7 +147,6 @@ import org.hibernate.cfg.annotations.TableBinder; import org.hibernate.engine.OptimisticLockStyle; import org.hibernate.engine.spi.FilterDefinition; import org.hibernate.id.PersistentIdentifierGenerator; -import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.StringHelper; import org.hibernate.loader.PropertyPath; @@ -2191,6 +2192,16 @@ public final class AnnotationBinder { if ( isId || ( !optional && nullability != Nullability.FORCED_NULL ) ) { //force columns to not null for ( Ejb3Column col : columns ) { + if ( isId && col.isFormula() ) { + throw new CannotForceNonNullableException( + String.format( + Locale.ROOT, + "Identifier property [%s] cannot contain formula mapping [%s]", + HCANNHelper.annotatedElementSignature( property ), + col.getFormulaString() + ) + ); + } col.forceNotNull(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/CannotForceNonNullableException.java b/hibernate-core/src/main/java/org/hibernate/cfg/CannotForceNonNullableException.java new file mode 100644 index 0000000000..b4776caf12 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cfg/CannotForceNonNullableException.java @@ -0,0 +1,24 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.cfg; + +import org.hibernate.AnnotationException; +import org.hibernate.HibernateException; + +/** + * Indicates an internal attempt to mark a column as non-nullable (because its part + * of a PK, etc) but we cannot force that column to be non-nullable. + *

+ * Typically this indicates that the "column" is actually a formula. + * + * @author Steve Ebersole + */ +public class CannotForceNonNullableException extends AnnotationException { + public CannotForceNonNullableException(String message) { + super( message ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3Column.java b/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3Column.java index 14d503f359..78db5c63b3 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3Column.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3Column.java @@ -457,6 +457,12 @@ public class Ejb3Column { } public void forceNotNull() { + if ( mappingColumn == null ) { + throw new CannotForceNonNullableException( + "Cannot perform #forceNotNull because internal org.hibernate.mapping.Column reference is null: " + + "likely a formula" + ); + } mappingColumn.setNullable( false ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/id/AndFormulaTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/id/AndFormulaTest.java index a2d30efb7b..04d17124bc 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/id/AndFormulaTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/id/AndFormulaTest.java @@ -13,13 +13,17 @@ import org.hibernate.annotations.Formula; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.CannotForceNonNullableException; -import org.hibernate.testing.FailureExpected; import org.hibernate.testing.junit4.BaseUnitTestCase; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; +import static org.hamcrest.CoreMatchers.startsWith; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + /** * Originally developed for HHH-9807 - better error message on combination of {@code @Id} + {@code @Formula} * @@ -41,11 +45,16 @@ public class AndFormulaTest extends BaseUnitTestCase { } @Test - @FailureExpected( jiraKey = "HHH-9807" ) public void testBindingEntityWithIdAndFormula() { - new MetadataSources( ssr ) - .addAnnotatedClass( EntityWithIdAndFormula.class ) - .buildMetadata(); + try { + new MetadataSources( ssr ) + .addAnnotatedClass( EntityWithIdAndFormula.class ) + .buildMetadata(); + fail( "Expecting failure from invalid mapping" ); + } + catch (CannotForceNonNullableException e) { + assertThat( e.getMessage(), startsWith( "Identifier property [" ) ); + } } @Entity