diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java b/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java index 8844440831..d9f8b65ec9 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java @@ -264,6 +264,17 @@ public class SimpleValue implements KeyValue { private IdentifierGenerator identifierGenerator; + /** + * Returns the cached identifierGenerator. + * + * @return IdentifierGenerator null if + * {@link #createIdentifierGenerator(IdentifierGeneratorFactory, Dialect, String, String, RootClass)} was never + * completed. + */ + public IdentifierGenerator getIdentifierGenerator() { + return identifierGenerator; + } + @Override public IdentifierGenerator createIdentifierGenerator( IdentifierGeneratorFactory identifierGeneratorFactory, diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java index 3d137219d0..7cae6edda8 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java @@ -26,8 +26,10 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.id.Assigned; import org.hibernate.loader.PropertyPath; import org.hibernate.mapping.Component; +import org.hibernate.mapping.KeyValue; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; +import org.hibernate.mapping.SimpleValue; import org.hibernate.metamodel.spi.MetamodelImplementor; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.property.access.spi.Getter; @@ -168,11 +170,13 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer { } else { identifierMapperType = (CompositeType) mapper.getType(); + KeyValue identifier = mappingInfo.getIdentifier(); mappedIdentifierValueMarshaller = buildMappedIdentifierValueMarshaller( getEntityName(), getFactory(), (ComponentType) entityMetamodel.getIdentifierProperty().getType(), - (ComponentType) identifierMapperType + (ComponentType) identifierMapperType, + identifier ); } } @@ -274,7 +278,8 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer { String entityName, SessionFactoryImplementor sessionFactory, ComponentType mappedIdClassComponentType, - ComponentType virtualIdComponent) { + ComponentType virtualIdComponent, + KeyValue identifier) { // so basically at this point we know we have a "mapped" composite identifier // which is an awful way to say that the identifier is represented differently // in the entity and in the identifier value. The incoming value should @@ -302,7 +307,8 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer { entityName, sessionFactory, virtualIdComponent, - mappedIdClassComponentType + mappedIdClassComponentType, + identifier ); } @@ -341,28 +347,40 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer { private final SessionFactoryImplementor sessionFactory; private final ComponentType virtualIdComponent; private final ComponentType mappedIdentifierType; + private final KeyValue identifier; private IncrediblySillyJpaMapsIdMappedIdentifierValueMarshaller( String entityName, SessionFactoryImplementor sessionFactory, ComponentType virtualIdComponent, - ComponentType mappedIdentifierType) { + ComponentType mappedIdentifierType, + KeyValue identifier) { this.sessionFactory = sessionFactory; this.entityName = entityName; this.virtualIdComponent = virtualIdComponent; this.mappedIdentifierType = mappedIdentifierType; + this.identifier = identifier; } @Override public Object getIdentifier(Object entity, EntityMode entityMode, SharedSessionContractImplementor session) { final Object id = mappedIdentifierType.instantiate( entityMode ); final Object[] propertyValues = virtualIdComponent.getPropertyValues( entity, entityMode ); + final String[] names = virtualIdComponent.getPropertyNames(); final Type[] subTypes = virtualIdComponent.getSubtypes(); final Type[] copierSubTypes = mappedIdentifierType.getSubtypes(); final int length = subTypes.length; for ( int i = 0; i < length; i++ ) { if ( propertyValues[i] == null ) { - throw new HibernateException( "No part of a composite identifier may be null" ); + try { + final String name = names[i]; + final Property p = ((Component) identifier).getProperty(name); + final SimpleValue v = (SimpleValue) p.getValue(); + if ( v.getIdentifierGenerator() == null ) throw new NullPointerException("No IdentifierGenerator found for property "+name); + } + catch (Throwable t) { + throw new HibernateException( "No part of a composite identifier may be null", t ); + } } //JPA 2 @MapsId + @IdClass points to the pk of the entity if ( subTypes[i].isAssociationType() && !copierSubTypes[i].isAssociationType() ) { diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/cid/CompositeIdFkGeneratedValueIdentityTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/cid/CompositeIdFkGeneratedValueIdentityTest.java index e0bc612c4b..e50d016c6d 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/cid/CompositeIdFkGeneratedValueIdentityTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/cid/CompositeIdFkGeneratedValueIdentityTest.java @@ -45,7 +45,6 @@ import org.junit.Test; public class CompositeIdFkGeneratedValueIdentityTest extends BaseCoreFunctionalTestCase { @Test - @FailureExpected(jiraKey = "HHH-10956", message = "javax.persistence.PersistenceException: org.hibernate.HibernateException: No part of a composite identifier may be null") public void testCompositePkWithIdentityAndFKBySequence() throws Exception { doInHibernate( this::sessionFactory, session -> { HeadS head = new HeadS(); @@ -75,7 +74,6 @@ public class CompositeIdFkGeneratedValueIdentityTest extends BaseCoreFunctionalT } @Test - @FailureExpected(jiraKey = "HHH-10956", message = "javax.persistence.PersistenceException: org.hibernate.HibernateException: No part of a composite identifier may be null") public void testCompositePkWithIdentityAndFKByTable() throws Exception { doInHibernate( this::sessionFactory, session -> { HeadT head = new HeadT(); @@ -90,7 +88,6 @@ public class CompositeIdFkGeneratedValueIdentityTest extends BaseCoreFunctionalT } @Test - @FailureExpected(jiraKey = "HHH-10956", message = "javax.persistence.PersistenceException: org.hibernate.HibernateException: No part of a composite identifier may be null") public void testCompositePkWithIdentityAndFKByAuto() throws Exception { doInHibernate( this::sessionFactory, session -> { HeadA head = new HeadA();