diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/AggregatedIdentifierMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/AggregatedIdentifierMapping.java new file mode 100644 index 0000000000..f995b80afd --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/AggregatedIdentifierMapping.java @@ -0,0 +1,20 @@ +/* + * 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 http://www.gnu.org/licenses/lgpl-2.1.html. + */ +package org.hibernate.metamodel.mapping; + +import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping; + +/** + * An "aggregated" composite identifier, which is another way to say that the + * identifier is represented as an {@linkplain jakarta.persistence.EmbeddedId embeddable}. + * + * @see jakarta.persistence.EmbeddedId + * + * @author Steve Ebersole + */ +public interface AggregatedIdentifierMapping extends SingleAttributeIdentifierMapping { +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/BasicEntityIdentifierMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/BasicEntityIdentifierMapping.java index ceae81e67b..58b06c4b6b 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/BasicEntityIdentifierMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/BasicEntityIdentifierMapping.java @@ -9,7 +9,7 @@ package org.hibernate.metamodel.mapping; import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping; /** - * Mapping for a simple identifier + * Mapping for a simple, single-column identifier * * @author Steve Ebersole */ diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityIdentifierMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityIdentifierMapping.java index d3e4985d18..e70ef8dfba 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityIdentifierMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityIdentifierMapping.java @@ -11,12 +11,17 @@ import org.hibernate.engine.internal.ForeignKeys; import org.hibernate.engine.spi.IdentifierValue; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; + /** * Describes the mapping of an entity's identifier. * - * @see jakarta.persistence.Id - * @see jakarta.persistence.EmbeddedId + * @see Id + * @see EmbeddedId + * @see Nature */ public interface EntityIdentifierMapping extends ValuedModelPart { @@ -40,20 +45,23 @@ public interface EntityIdentifierMapping extends ValuedModelPart { /** * The strategy for distinguishing between detached and transient * state based on the identifier mapping + * + * @see EntityVersionMapping#getUnsavedStrategy() */ IdentifierValue getUnsavedStrategy(); /** + * Instantiate an instance of the identifier. * - * - * @return the entity identifier value - * - * @deprecated Use {@link #getIdentifier(Object)} + * @apiNote This is really only valid on {@linkplain CompositeIdentifierMapping composite identifiers} */ - @Deprecated - Object getIdentifier(Object entity, SharedSessionContractImplementor session); + Object instantiate(); + /** + * Extract the identifier from an instance of the entity + */ Object getIdentifier(Object entity); + /** * Return the identifier of the persistent or transient object, or throw * an exception if the instance is "unsaved" @@ -97,24 +105,39 @@ public interface EntityIdentifierMapping extends ValuedModelPart { return id; } + /** + * Inject an identifier value into an instance of the entity + */ void setIdentifier(Object entity, Object id, SharedSessionContractImplementor session); - Object instantiate(); - + /** + * The style of identifier used. + */ enum Nature { /** - * Single column id + * Simple, single-column identifier. + * + * @see Id + * @see BasicEntityIdentifierMapping */ SIMPLE, /** - * @see jakarta.persistence.EmbeddedId + * An "aggregated" composite identifier, which is another way to say that the + * identifier is represented as an {@linkplain EmbeddedId embeddable}. + * + * @see EmbeddedId + * @see AggregatedIdentifierMapping */ COMPOSITE, /** - * Composite identifier defined with multiple {@link jakarta.persistence.Id} - * mappings. Often used in conjunction with an {@link jakarta.persistence.IdClass} + * Composite identifier defined with multiple {@link Id} + * mappings. Often used in conjunction with an {@link IdClass} + * + * @see Id + * @see IdClass + * @see NonAggregatedIdentifierMapping */ VIRTUAL } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityVersionMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityVersionMapping.java index 5d63ada177..7e7a70a37d 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityVersionMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityVersionMapping.java @@ -8,7 +8,6 @@ package org.hibernate.metamodel.mapping; import org.hibernate.engine.spi.VersionValue; import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping; -import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.VersionJavaType; /** @@ -24,7 +23,9 @@ public interface EntityVersionMapping extends BasicValuedModelPart { /** * The strategy for distinguishing between detached and transient - * state based on the version mapping + * state based on the version mapping. + * + * @see EntityIdentifierMapping#getUnsavedStrategy() */ VersionValue getUnsavedStrategy(); @@ -35,4 +36,9 @@ public interface EntityVersionMapping extends BasicValuedModelPart { default VersionJavaType getExpressibleJavaType() { return (VersionJavaType) getMappedType().getMappedJavaType(); } + + @Override + default AttributeMapping asAttributeMapping() { + return getVersionAttribute(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/NonAggregatedIdentifierMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/NonAggregatedIdentifierMapping.java index 7cc6284336..9e25ff54e8 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/NonAggregatedIdentifierMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/NonAggregatedIdentifierMapping.java @@ -16,7 +16,7 @@ import org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable; /** * A "non-aggregated" composite identifier, which means that the entity itself * does not define a singular representation of its identifier like an - * {@link jakarta.persistence.EmbeddedId} does. + * {@linkplain AggregatedIdentifierMapping aggregated mapping} does. * * An IdClass can be used to provide a simple, singular representation of the * identifier for easier reference in API calls. JPA requires using an IdClass @@ -73,6 +73,7 @@ public interface NonAggregatedIdentifierMapping extends CompositeIdentifierMappi * Convenience method to iterate the attributes for this mapper's representation */ default void forEachAttribute(IndexedConsumer consumer) { + //noinspection unchecked,rawtypes getEmbeddedPart().getEmbeddableTypeDescriptor().forEachAttributeMapping( (IndexedConsumer) consumer ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java index 64b786fd54..340a109d89 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java @@ -47,6 +47,10 @@ import org.hibernate.type.BasicType; import org.hibernate.type.descriptor.java.JavaType; /** + * Mapping of a simple identifier + * + * @see jakarta.persistence.Id + * * @author Andrea Boriero */ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMapping, FetchOptions { @@ -96,6 +100,7 @@ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMa this.attributeName = attributeName; this.rootTable = rootTable; this.pkColumnName = pkColumnName; + //noinspection unchecked this.idType = (BasicType) idType; this.entityPersister = entityPersister; @@ -142,15 +147,6 @@ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMa return unsavedStrategy; } - @Override - public Object getIdentifier(Object entity, SharedSessionContractImplementor session) { - final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( entity ); - if ( lazyInitializer != null ) { - return lazyInitializer.getIdentifier(); - } - return propertyAccess.getGetter().get( entity ); - } - @Override public Object getIdentifier(Object entity) { final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( entity ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedIdentifierMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedIdentifierMappingImpl.java index b41f035249..c0081f7d51 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedIdentifierMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedIdentifierMappingImpl.java @@ -10,6 +10,7 @@ import java.util.function.BiConsumer; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.metamodel.internal.AbstractCompositeIdentifierMapping; +import org.hibernate.metamodel.mapping.AggregatedIdentifierMapping; import org.hibernate.metamodel.mapping.EmbeddableMappingType; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.JdbcMapping; @@ -29,7 +30,7 @@ import org.hibernate.sql.results.graph.Fetchable; */ public class EmbeddedIdentifierMappingImpl extends AbstractCompositeIdentifierMapping - implements SingleAttributeIdentifierMapping { + implements AggregatedIdentifierMapping { private final String name; private final EmbeddableMappingType embeddableDescriptor; private final PropertyAccess propertyAccess; @@ -83,15 +84,6 @@ public class EmbeddedIdentifierMappingImpl getEmbeddableTypeDescriptor().applySqlSelections( navigablePath, tableGroup, creationState, selectionConsumer ); } - @Override - public Object getIdentifier(Object entity, SharedSessionContractImplementor session) { - final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( entity ); - if ( lazyInitializer != null ) { - return lazyInitializer.getIdentifier(); - } - return propertyAccess.getGetter().get( entity ); - } - @Override public Object getIdentifier(Object entity) { final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( entity ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/InverseNonAggregatedIdentifierMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/InverseNonAggregatedIdentifierMapping.java index 54dce4c5eb..5749529203 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/InverseNonAggregatedIdentifierMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/InverseNonAggregatedIdentifierMapping.java @@ -178,11 +178,6 @@ public class InverseNonAggregatedIdentifierMapping extends EmbeddedAttributeMapp return super.toSqlExpression( tableGroup, clause, walker, sqlAstCreationState ); } - @Override - public Object getIdentifier(Object entity, SharedSessionContractImplementor session) { - return getIdentifier( entity ); - } - @Override public Object getIdentifier(Object entity) { if ( hasContainingClass() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MappingModelCreationHelper.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MappingModelCreationHelper.java index 1b7481e0dc..e6fb73ad7f 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MappingModelCreationHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MappingModelCreationHelper.java @@ -64,7 +64,6 @@ import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.ManagedMappingType; import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.ModelPartContainer; -import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping; import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.metamodel.mapping.PropertyBasedMapping; import org.hibernate.metamodel.mapping.SelectableMapping; @@ -1386,12 +1385,12 @@ public class MappingModelCreationHelper { SelectableMappings selectableMappings, MappingModelCreationProcess creationProcess) { final EmbeddableMappingType embeddableTypeDescriptor = modelPart.getEmbeddableTypeDescriptor(); - if ( modelPart instanceof NonAggregatedIdentifierMapping ) { + if ( modelPart instanceof org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping ) { return new InverseNonAggregatedIdentifierMapping( keyDeclaringType, declaringTableGroupProducer, selectableMappings, - (NonAggregatedIdentifierMapping) modelPart, + (org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping) modelPart, embeddableTypeDescriptor, creationProcess ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/NonAggregatedIdentifierMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/NonAggregatedIdentifierMappingImpl.java index 272ce66516..046410d434 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/NonAggregatedIdentifierMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/NonAggregatedIdentifierMappingImpl.java @@ -107,13 +107,6 @@ public class NonAggregatedIdentifierMappingImpl extends AbstractCompositeIdentif } } - /** - * The entity whose identifier this mapping is the inverse of - */ - public EntityPersister getIdentifiedEntityDescriptor() { - return entityDescriptor; - } - @Override public EmbeddableMappingType getMappedType() { return virtualIdEmbeddable; @@ -209,11 +202,6 @@ public class NonAggregatedIdentifierMappingImpl extends AbstractCompositeIdentif return null; } - @Override - public Object getIdentifier(Object entity, SharedSessionContractImplementor session) { - return getIdentifier( entity ); - } - @Override public Object getIdentifier(Object entity) { if ( hasContainingClass() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleBasicEntityIdentifierMapping.java b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleBasicEntityIdentifierMapping.java index 6e750871b7..40288b078a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleBasicEntityIdentifierMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleBasicEntityIdentifierMapping.java @@ -43,11 +43,6 @@ public class AnonymousTupleBasicEntityIdentifierMapping return delegate.getUnsavedStrategy(); } - @Override - public Object getIdentifier(Object entity, SharedSessionContractImplementor session) { - return delegate.getIdentifier( entity, session ); - } - @Override public Object getIdentifier(Object entity) { return delegate.getIdentifier( entity ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEmbeddedEntityIdentifierMapping.java b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEmbeddedEntityIdentifierMapping.java index f19ce941a0..7f24733b69 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEmbeddedEntityIdentifierMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEmbeddedEntityIdentifierMapping.java @@ -13,7 +13,6 @@ import org.hibernate.engine.spi.IdentifierValue; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.metamodel.mapping.CompositeIdentifierMapping; import org.hibernate.metamodel.mapping.EmbeddableMappingType; -import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart; import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping; import org.hibernate.metamodel.model.domain.DomainType; @@ -37,7 +36,7 @@ public class AnonymousTupleEmbeddedEntityIdentifierMapping extends AnonymousTupl modelParts, domainType, componentName, - (EmbeddableValuedModelPart) delegate, + delegate, -1 ); this.delegate = delegate; @@ -53,11 +52,6 @@ public class AnonymousTupleEmbeddedEntityIdentifierMapping extends AnonymousTupl return delegate.getUnsavedStrategy(); } - @Override - public Object getIdentifier(Object entity, SharedSessionContractImplementor session) { - return delegate.getIdentifier( entity, session ); - } - @Override public Object getIdentifier(Object entity) { return delegate.getIdentifier( entity ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleNonAggregatedEntityIdentifierMapping.java b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleNonAggregatedEntityIdentifierMapping.java index 392594b727..951114badf 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleNonAggregatedEntityIdentifierMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleNonAggregatedEntityIdentifierMapping.java @@ -59,11 +59,6 @@ public class AnonymousTupleNonAggregatedEntityIdentifierMapping extends Anonymou return delegate.getUnsavedStrategy(); } - @Override - public Object getIdentifier(Object entity, SharedSessionContractImplementor session) { - return delegate.getIdentifier( entity, session ); - } - @Override public Object getIdentifier(Object entity) { return delegate.getIdentifier( entity ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java index d89c8b8b55..349cf6850c 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java @@ -5073,10 +5073,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base final EntityIdentifierMapping identifierMapping = entityValuedModelPart.getEntityMappingType() .getIdentifierMapping(); associationKeyPart = identifierMapping; - associationKey = identifierMapping.getIdentifier( - literal.getLiteralValue(), - null - ); + associationKey = identifierMapping.getIdentifier( literal.getLiteralValue() ); } if ( associationKeyPart instanceof BasicValuedMapping ) { return new QueryLiteral<>( diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/MappingModelAccessTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/MappingModelAccessTests.java new file mode 100644 index 0000000000..8afc08cd33 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/MappingModelAccessTests.java @@ -0,0 +1,131 @@ +/* + * 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 http://www.gnu.org/licenses/lgpl-2.1.html. + */ +package org.hibernate.orm.test.mapping; + +import java.time.Instant; + +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.metamodel.MappingMetamodel; +import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; +import org.hibernate.metamodel.mapping.EntityIdentifierMapping; +import org.hibernate.metamodel.mapping.EntityMappingType; +import org.hibernate.metamodel.mapping.EntityVersionMapping; +import org.hibernate.metamodel.spi.MappingMetamodelImplementor; + +import org.hibernate.testing.orm.domain.StandardDomainModel; +import org.hibernate.testing.orm.domain.retail.CardPayment; +import org.hibernate.testing.orm.domain.retail.CashPayment; +import org.hibernate.testing.orm.domain.retail.DomesticVendor; +import org.hibernate.testing.orm.domain.retail.ForeignVendor; +import org.hibernate.testing.orm.domain.retail.Payment; +import org.hibernate.testing.orm.domain.retail.Product; +import org.hibernate.testing.orm.domain.retail.Vendor; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests access to {@link MappingMetamodel} as API and SPI contracts + * + * @author Steve Ebersole + */ +@DomainModel(standardModels = StandardDomainModel.RETAIL) +@SessionFactory(exportSchema = false) +public class MappingModelAccessTests { + @Test + public void testUnwrapAccess(SessionFactoryScope scope) { + final SessionFactoryImplementor sf = scope.getSessionFactory(); + + final MappingMetamodel mappingMetamodel = sf.unwrap( MappingMetamodel.class ); + assertThat( mappingMetamodel ).isNotNull(); + + final MappingMetamodelImplementor mappingMetamodelImplementor = sf.unwrap( MappingMetamodelImplementor.class ); + assertThat( mappingMetamodelImplementor ).isSameAs( mappingMetamodel ); + } + + @Test + void testEntityMappingAccess(SessionFactoryScope scope) { + final SessionFactoryImplementor sf = scope.getSessionFactory(); + final MappingMetamodel mappingMetamodel = sf.unwrap( MappingMetamodel.class ); + + final EntityMappingType productMapping = mappingMetamodel.getEntityDescriptor( Product.class ); + assertThat( productMapping ).isNotNull(); + + final EntityIdentifierMapping productIdMapping = productMapping.getIdentifierMapping(); + assertThat( productIdMapping ).isNotNull(); + assertThat( productIdMapping.getJavaType().getJavaTypeClass() ).isEqualTo( Integer.class ); + + final EntityVersionMapping productVersionMapping = productMapping.getVersionMapping(); + assertThat( productVersionMapping ).isNotNull(); + assertThat( productVersionMapping.getVersionAttribute().getAttributeName() ).isEqualTo( "version" ); + assertThat( productVersionMapping.getVersionAttribute().getJavaType().getJavaTypeClass() ).isEqualTo( Instant.class ); + assertThat( productVersionMapping.asAttributeMapping() ).isSameAs( productVersionMapping.getVersionAttribute() ); + } + + @Test + void testJoinedSubclassInheritance(SessionFactoryScope scope) { + final SessionFactoryImplementor sf = scope.getSessionFactory(); + final MappingMetamodel mappingMetamodel = sf.unwrap( MappingMetamodel.class ); + + final EntityMappingType paymentMapping = mappingMetamodel.getEntityDescriptor( Payment.class ); + final EntityMappingType cardPaymentMapping = mappingMetamodel.getEntityDescriptor( CardPayment.class ); + final EntityMappingType cashPaymentMapping = mappingMetamodel.getEntityDescriptor( CashPayment.class ); + + final EntityDiscriminatorMapping discriminatorMapping = paymentMapping.getDiscriminatorMapping(); + assertThat( discriminatorMapping ) + .isSameAs( cardPaymentMapping.getDiscriminatorMapping() ) + .isSameAs( cashPaymentMapping.getDiscriminatorMapping() ); + + assertThat( discriminatorMapping.isPhysical() ).isFalse(); + assertThat( discriminatorMapping.isVirtual() ).isTrue(); + assertThat( discriminatorMapping.getJavaType().getJavaTypeClass() ).isEqualTo( Class.class ); + assertThat( discriminatorMapping.getJdbcMapping().getJavaTypeDescriptor().getJavaTypeClass() ).isEqualTo( Class.class ); + assertThat( discriminatorMapping.getJdbcMapping().getJdbcJavaType().getJavaTypeClass() ).isEqualTo( Integer.class ); + + assertThat( paymentMapping.getDiscriminatorValue() ).isEqualTo( 0 ); + assertThat( cashPaymentMapping.getDiscriminatorValue() ).isEqualTo( 1 ); + assertThat( cardPaymentMapping.getDiscriminatorValue() ).isEqualTo( 2 ); + + assertThat( discriminatorMapping.resolveDiscriminatorValue( 0 ).getIndicatedEntity() ).isEqualTo( paymentMapping ); + assertThat( discriminatorMapping.resolveDiscriminatorValue( 1 ).getIndicatedEntity() ).isEqualTo( cashPaymentMapping ); + assertThat( discriminatorMapping.resolveDiscriminatorValue( 2 ).getIndicatedEntity() ).isEqualTo( cardPaymentMapping ); + assertThat( discriminatorMapping.resolveDiscriminatorValue( 3 ) ).isNull(); + } + + @Test + void testSingleTableInheritance(SessionFactoryScope scope) { + final SessionFactoryImplementor sf = scope.getSessionFactory(); + final MappingMetamodel mappingMetamodel = sf.unwrap( MappingMetamodel.class ); + + final EntityMappingType vendorMapping = mappingMetamodel.getEntityDescriptor( Vendor.class ); + final EntityMappingType domesticVendorMapping = mappingMetamodel.getEntityDescriptor( DomesticVendor.class ); + final EntityMappingType foreignVendorMapping = mappingMetamodel.getEntityDescriptor( ForeignVendor.class ); + + final EntityDiscriminatorMapping discriminatorMapping = vendorMapping.getDiscriminatorMapping(); + assertThat( discriminatorMapping ) + .isSameAs( domesticVendorMapping.getDiscriminatorMapping() ) + .isSameAs( foreignVendorMapping.getDiscriminatorMapping() ); + + assertThat( discriminatorMapping.isPhysical() ).isTrue(); + assertThat( discriminatorMapping.isVirtual() ).isTrue(); + assertThat( discriminatorMapping.getJavaType().getJavaTypeClass() ).isEqualTo( Class.class ); + assertThat( discriminatorMapping.getJdbcMapping().getJavaTypeDescriptor().getJavaTypeClass() ).isEqualTo( Class.class ); + assertThat( discriminatorMapping.getJdbcMapping().getJdbcJavaType().getJavaTypeClass() ).isEqualTo( String.class ); + + assertThat( vendorMapping.getDiscriminatorValue() ).isEqualTo( "Vendor" ); + assertThat( domesticVendorMapping.getDiscriminatorValue() ).isEqualTo( "domestic" ); + assertThat( foreignVendorMapping.getDiscriminatorValue() ).isEqualTo( "foreign" ); + + assertThat( discriminatorMapping.resolveDiscriminatorValue( "Vendor" ).getIndicatedEntity() ).isEqualTo( vendorMapping ); + assertThat( discriminatorMapping.resolveDiscriminatorValue( "domestic" ).getIndicatedEntity() ).isEqualTo( domesticVendorMapping ); + assertThat( discriminatorMapping.resolveDiscriminatorValue( "foreign" ).getIndicatedEntity() ).isEqualTo( foreignVendorMapping ); + assertThat( discriminatorMapping.resolveDiscriminatorValue( "invalid" ) ).isNull(); + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/retail/Product.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/retail/Product.java index 9ac0a5cf57..8d223eaf51 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/retail/Product.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/retail/Product.java @@ -6,14 +6,20 @@ */ package org.hibernate.testing.orm.domain.retail; +import java.time.Instant; import java.util.UUID; import javax.money.MonetaryAmount; + +import org.hibernate.annotations.CurrentTimestamp; +import org.hibernate.annotations.NaturalId; + +import jakarta.persistence.Access; +import jakarta.persistence.AccessType; import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; - -import org.hibernate.annotations.NaturalId; +import jakarta.persistence.Version; /** * @author Steve Ebersole @@ -27,6 +33,11 @@ public class Product { private MonetaryAmount currentSellPrice; + @Access( AccessType.FIELD ) + @Version + @CurrentTimestamp + private Instant version; + public Product() { }