diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/AnyDiscriminator.java b/hibernate-core/src/main/java/org/hibernate/annotations/AnyDiscriminator.java index afc6b38c0210..e772221a0029 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/AnyDiscriminator.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/AnyDiscriminator.java @@ -54,4 +54,10 @@ * @since 7.0 */ AnyDiscriminatorValueStrategy valueStrategy() default AUTO; + + /** + * Whether the entity's short-name should be used as the discriminator value + * (as opposed to its full-name) in the case of implicit value mapping. + */ + boolean implicitEntityShortName() default false; } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnyBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnyBinder.java index 8199e10fe011..af5feed10cda 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnyBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnyBinder.java @@ -111,6 +111,7 @@ private static void bindAny( final AnyDiscriminator anyDiscriminator = property.getDirectAnnotationUsage( AnyDiscriminator.class ); if ( anyDiscriminator != null ) { value.setDiscriminatorValueStrategy( anyDiscriminator.valueStrategy() ); + value.setImplicitEntityShortName( anyDiscriminator.implicitEntityShortName() ); } final PropertyBinder binder = new PropertyBinder(); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/AnyDiscriminatorAnnotation.java b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/AnyDiscriminatorAnnotation.java index 12404277da4d..daaf7d759d90 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/AnyDiscriminatorAnnotation.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/AnyDiscriminatorAnnotation.java @@ -16,6 +16,7 @@ public class AnyDiscriminatorAnnotation implements AnyDiscriminator { private jakarta.persistence.DiscriminatorType value; private AnyDiscriminatorValueStrategy valueStrategy; + private boolean implicitEntityShortName; /** * Used in creating dynamic annotation instances (e.g. from XML) @@ -23,6 +24,7 @@ public class AnyDiscriminatorAnnotation implements AnyDiscriminator { public AnyDiscriminatorAnnotation(SourceModelBuildingContext modelContext) { this.value = jakarta.persistence.DiscriminatorType.STRING; this.valueStrategy = AnyDiscriminatorValueStrategy.AUTO; + this.implicitEntityShortName = false; } /** @@ -31,6 +33,7 @@ public AnyDiscriminatorAnnotation(SourceModelBuildingContext modelContext) { public AnyDiscriminatorAnnotation(AnyDiscriminator annotation, SourceModelBuildingContext modelContext) { this.value = annotation.value(); this.valueStrategy = annotation.valueStrategy(); + this.implicitEntityShortName = annotation.implicitEntityShortName(); } /** @@ -38,6 +41,8 @@ public AnyDiscriminatorAnnotation(AnyDiscriminator annotation, SourceModelBuildi */ public AnyDiscriminatorAnnotation(Map attributeValues, SourceModelBuildingContext modelContext) { this.value = (jakarta.persistence.DiscriminatorType) attributeValues.get( "value" ); + this.valueStrategy = (AnyDiscriminatorValueStrategy) attributeValues.get( "valueStrategy" ); + this.implicitEntityShortName = (boolean) attributeValues.get( "implicitEntityShortName" ); } @Override @@ -63,5 +68,12 @@ public void valueStrategy(AnyDiscriminatorValueStrategy valueStrategy) { this.valueStrategy = valueStrategy; } + @Override + public boolean implicitEntityShortName() { + return implicitEntityShortName; + } + public void implicitEntityShortName(boolean implicitEntityShortName) { + this.implicitEntityShortName = implicitEntityShortName; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Any.java b/hibernate-core/src/main/java/org/hibernate/mapping/Any.java index 60d01794e793..ff54cbde2881 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Any.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Any.java @@ -4,19 +4,19 @@ */ package org.hibernate.mapping; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.function.Consumer; - import org.hibernate.Incubating; import org.hibernate.MappingException; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.type.AnyDiscriminatorValueStrategy; import org.hibernate.type.AnyType; -import org.hibernate.type.Type; import org.hibernate.type.MappingContext; +import org.hibernate.type.Type; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.function.Consumer; /** * A mapping model object representing a {@linkplain org.hibernate.annotations.Any polymorphic association} @@ -36,6 +36,7 @@ public class Any extends SimpleValue { // common private Map metaValueToEntityNameMap; private AnyDiscriminatorValueStrategy discriminatorValueStrategy = AnyDiscriminatorValueStrategy.AUTO; + private boolean implicitEntityShortName = false; private boolean lazy = true; private AnyType resolvedType; @@ -132,25 +133,24 @@ public void setIdentifierType(String identifierType) { } /** - * Current strategy for interpreting {@linkplain org.hibernate.annotations.AnyDiscriminatorValue} definitions, - * especially in terms of implicit, explicit and potentially missing values. + * Set the strategy for interpreting {@linkplain org.hibernate.annotations.AnyDiscriminatorValue} + * definitions in terms of implicit, explicit and potentially missing values. * * @since 7.0 */ @Incubating - public AnyDiscriminatorValueStrategy getDiscriminatorValueStrategy() { - return discriminatorValueStrategy; + public void setDiscriminatorValueStrategy(AnyDiscriminatorValueStrategy discriminatorValueStrategy) { + this.discriminatorValueStrategy = discriminatorValueStrategy; } /** - * Set the strategy + * Set whether to use the entity's short-name for implicit discriminator value mappings * - * @see #getDiscriminatorValueStrategy * @since 7.0 */ @Incubating - public void setDiscriminatorValueStrategy(AnyDiscriminatorValueStrategy discriminatorValueStrategy) { - this.discriminatorValueStrategy = discriminatorValueStrategy; + public void setImplicitEntityShortName(boolean implicitEntityShortName) { + this.implicitEntityShortName = implicitEntityShortName; } @Override @@ -176,6 +176,7 @@ public AnyType getType() throws MappingException { discriminatorType, identifierType, discriminatorValueStrategy, + implicitEntityShortName, metaValueToEntityNameMap, isLazy(), getBuildingContext() diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/MappingHelper.java b/hibernate-core/src/main/java/org/hibernate/mapping/MappingHelper.java index 77e5a0364f07..2cfe8a6e0f7c 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/MappingHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/MappingHelper.java @@ -129,17 +129,26 @@ public static AnyType anyMapping( Map explicitValeMappings, boolean lazy, MetadataBuildingContext buildingContext) { - return anyMapping( discriminatorType, identifierType, AnyDiscriminatorValueStrategy.AUTO, explicitValeMappings, lazy, buildingContext ); + return anyMapping( + discriminatorType, + identifierType, + AnyDiscriminatorValueStrategy.AUTO, + false, + explicitValeMappings, + lazy, + buildingContext + ); } public static AnyType anyMapping( Type discriminatorType, Type identifierType, AnyDiscriminatorValueStrategy discriminatorValueStrategy, + boolean implicitEntityShortName, Map explicitValeMappings, boolean lazy, MetadataBuildingContext buildingContext) { - final MetaType metaType = new MetaType( discriminatorType, discriminatorValueStrategy, explicitValeMappings ); + final MetaType metaType = new MetaType( discriminatorType, discriminatorValueStrategy, implicitEntityShortName, explicitValeMappings ); return new AnyType( buildingContext.getBootstrapContext().getTypeConfiguration(), metaType, identifierType, lazy ); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/DiscriminatorConverter.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/DiscriminatorConverter.java index 312c331eb987..c7f1951bd709 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/DiscriminatorConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/DiscriminatorConverter.java @@ -90,7 +90,7 @@ public R toRelationalValue(O domainForm) { return (R) discriminatorValueDetails.getValue(); } - public abstract DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object relationalForm); + public abstract DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object relationalValue); public abstract DiscriminatorValueDetails getDetailsForEntityName(String entityName); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableDiscriminatorConverter.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableDiscriminatorConverter.java index d16a4be2a2db..b60eb3acb270 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableDiscriminatorConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableDiscriminatorConverter.java @@ -86,13 +86,13 @@ public O toDomainValue(R relationalForm) { } @Override - public EmbeddableDiscriminatorValueDetailsImpl getDetailsForDiscriminatorValue(Object value) { - final EmbeddableDiscriminatorValueDetailsImpl valueMatch = discriminatorValueToDetailsMap.get( value ); + public EmbeddableDiscriminatorValueDetailsImpl getDetailsForDiscriminatorValue(Object relationalValue) { + final EmbeddableDiscriminatorValueDetailsImpl valueMatch = discriminatorValueToDetailsMap.get( relationalValue ); if ( valueMatch != null ) { return valueMatch; } - throw new HibernateException( "Unrecognized discriminator value: " + value ); + throw new HibernateException( "Unrecognized discriminator value: " + relationalValue ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyDiscriminatorPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyDiscriminatorPart.java index 3556bbf835bd..12a3027182f2 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyDiscriminatorPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyDiscriminatorPart.java @@ -85,6 +85,7 @@ public AnyDiscriminatorPart( BasicType underlyingJdbcMapping, Map valueToEntityNameMap, AnyDiscriminatorValueStrategy valueStrategy, + boolean implicitEntityShortName, MappingMetamodelImplementor mappingMetamodel) { this.navigableRole = partRole; this.declaringType = declaringType; @@ -106,6 +107,7 @@ public AnyDiscriminatorPart( underlyingJdbcMapping, valueToEntityNameMap, valueStrategy, + implicitEntityShortName, mappingMetamodel ); } @@ -115,6 +117,7 @@ public AnyDiscriminatorPart( BasicType underlyingJdbcMapping, Map valueToEntityNameMap, AnyDiscriminatorValueStrategy valueStrategy, + boolean implicitEntityShortName, MappingMetamodelImplementor mappingMetamodel) { if ( valueStrategy == AnyDiscriminatorValueStrategy.AUTO ) { if ( valueToEntityNameMap == null || valueToEntityNameMap.isEmpty() ) { @@ -132,6 +135,7 @@ public AnyDiscriminatorPart( ClassJavaType.INSTANCE, underlyingJdbcMapping.getJavaTypeDescriptor(), valueToEntityNameMap, + implicitEntityShortName, mappingMetamodel ); case EXPLICIT -> new ExplicitDiscriminatorConverter<>( @@ -146,6 +150,7 @@ public AnyDiscriminatorPart( ClassJavaType.INSTANCE, underlyingJdbcMapping.getJavaTypeDescriptor(), valueToEntityNameMap, + implicitEntityShortName, mappingMetamodel ); }; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationMapping.java index 1b788e0db99e..43c444355d4e 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationMapping.java @@ -90,6 +90,7 @@ public static DiscriminatedAssociationMapping from( (BasicType) metaType.getBaseType(), metaType.getDiscriminatorValuesToEntityNameMap(), metaType.getValueStrategy(), + metaType.isImplicitEntityShortName(), creationProcess.getCreationContext().getSessionFactory().getMappingMetamodel() ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ExplicitDiscriminatorConverter.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ExplicitDiscriminatorConverter.java index 7cd3ab5f04e1..f2d2f909a994 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ExplicitDiscriminatorConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ExplicitDiscriminatorConverter.java @@ -54,7 +54,8 @@ public ExplicitDiscriminatorConverter( this.detailsByEntityName = CollectionHelper.concurrentMap( explicitValueMappings.size() ); explicitValueMappings.forEach( (value, entityName) -> { - final EntityPersister entityDescriptor = mappingMetamodel.getEntityDescriptor( entityName ); + final String importedEntityName = mappingMetamodel.getImportedName( entityName ); + final EntityPersister entityDescriptor = mappingMetamodel.getEntityDescriptor( importedEntityName ); final DiscriminatorValueDetails details = new DiscriminatorValueDetailsImpl( value, entityDescriptor ); detailsByValue.put( value, details ); detailsByEntityName.put( entityDescriptor.getEntityName(), details ); @@ -75,12 +76,12 @@ public Map getDetailsByEntityName() { } @Override - public DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object relationalForm) { - if ( relationalForm == null ) { + public DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object relationalValue) { + if ( relationalValue == null ) { return detailsByValue.get( NULL_DISCRIMINATOR ); } - final DiscriminatorValueDetails existing = detailsByValue.get( relationalForm ); + final DiscriminatorValueDetails existing = detailsByValue.get( relationalValue ); if ( existing != null ) { // an explicit or previously-resolved mapping return existing; @@ -91,16 +92,16 @@ public DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object relation return notNullMatch; } - if ( relationalForm.getClass().isEnum() ) { + if ( relationalValue.getClass().isEnum() ) { final Object enumValue; if ( getRelationalJavaType() instanceof StringJavaType ) { - enumValue = ( (Enum) relationalForm ).name(); + enumValue = ( (Enum) relationalValue).name(); } else if ( getRelationalJavaType() instanceof CharacterJavaType ) { - enumValue = ( (Enum) relationalForm ).name().charAt( 0 ); + enumValue = ( (Enum) relationalValue).name().charAt( 0 ); } else { - enumValue = ( (Enum) relationalForm ).ordinal(); + enumValue = ( (Enum) relationalValue).ordinal(); } final DiscriminatorValueDetails enumMatch = detailsByValue.get( enumValue ); if ( enumMatch != null ) { @@ -112,7 +113,7 @@ else if ( getRelationalJavaType() instanceof CharacterJavaType ) { ROOT, "Unknown discriminator value (%s) : %s", discriminatorRole, - relationalForm + relationalValue ) ); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ImplicitDiscriminatorConverter.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ImplicitDiscriminatorConverter.java index cf0c5ee0f048..9323c7421a32 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ImplicitDiscriminatorConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ImplicitDiscriminatorConverter.java @@ -26,6 +26,7 @@ */ public class ImplicitDiscriminatorConverter extends DiscriminatorConverter { private final NavigableRole discriminatorRole; + private final boolean implicitEntityShortName; private final MappingMetamodelImplementor mappingMetamodel; private final Map detailsByValue; private final Map detailsByEntityName; @@ -35,9 +36,11 @@ public ImplicitDiscriminatorConverter( JavaType domainJavaType, JavaType relationalJavaType, Map explicitValueMappings, + boolean implicitEntityShortName, MappingMetamodelImplementor mappingMetamodel) { super( discriminatorRole.getFullPath(), domainJavaType, relationalJavaType ); this.discriminatorRole = discriminatorRole; + this.implicitEntityShortName = implicitEntityShortName; this.mappingMetamodel = mappingMetamodel; if ( CollectionHelper.isNotEmpty( explicitValueMappings ) ) { @@ -66,22 +69,47 @@ public Map getDetailsByEntityName() { } @Override - public DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object value) { - if ( value instanceof String incoming ) { - final DiscriminatorValueDetails existingDetails = detailsByValue.get( incoming ); - if ( existingDetails != null ) { - return existingDetails; + public DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object relationalValue) { + // entity-name : org.hibernate.Thing + // short-name : Thing + + // in the case of full entity-name handling, we'd have + // detailsByValue["org.hibernate.Thing", DiscriminatorValueDetails( "org.hibernate.Thing", ... )] + // detailsByEntityName["org.hibernate.Thing", DiscriminatorValueDetails( "org.hibernate.Thing", ... )] + + // in the case of short-name "Thing", we'd have + // detailsByValue["Thing", DiscriminatorValueDetails( "Thing", ... )] + // detailsByEntityName["org.hibernate.Thing", DiscriminatorValueDetails( "Thing", ... )] + + final DiscriminatorValueDetails existing = detailsByValue.get( relationalValue ); + if ( existing != null ) { + return existing; + } + + if ( relationalValue instanceof String incoming ) { + final EntityPersister persister; + if ( implicitEntityShortName ) { + // incoming - "Thing" + // importedName - "org.hibernate.Thing" + final String importedName = mappingMetamodel.getImportedName( incoming ); + persister = mappingMetamodel.findEntityDescriptor( importedName ); + } + else { + // incoming - "org.hibernate.Thing" + // importedName - "org.hibernate.Thing" + persister = mappingMetamodel.findEntityDescriptor( incoming ); } - final EntityPersister persister = mappingMetamodel.findEntityDescriptor( incoming ); + if ( persister != null ) { return register( incoming, persister ); } } + throw new HibernateException( String.format( ROOT, - "Unrecognized discriminator value (%s): %s", + "Unrecognized discriminator relationalValue (%s): %s", discriminatorRole.getFullPath(), - value + relationalValue ) ); } @@ -94,14 +122,19 @@ private DiscriminatorValueDetails register(Object value, EntityPersister entityD @Override public DiscriminatorValueDetails getDetailsForEntityName(String entityName) { + // entityName - "org.hibernate.Thing" + final DiscriminatorValueDetails existingDetails = detailsByEntityName.get( entityName ); if ( existingDetails != null ) { return existingDetails; } + final EntityPersister persister = mappingMetamodel.findEntityDescriptor( entityName ); if ( persister!= null ) { - return register( persister.getEntityName(), persister ); + final String implicitValue = implicitEntityShortName ? persister.getImportedName() : persister.getEntityName(); + return register( implicitValue, persister ); } + throw new HibernateException( String.format( ROOT, "Unrecognized entity name (%s): %s", diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MixedDiscriminatorConverter.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MixedDiscriminatorConverter.java index c4c9d99c8f6c..5d57114e64cf 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MixedDiscriminatorConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MixedDiscriminatorConverter.java @@ -32,6 +32,7 @@ public class MixedDiscriminatorConverter extends DiscriminatorConverter detailsByValue; private final Map detailsByEntityName; + private final boolean implicitEntityShortName; private final MappingMetamodelImplementor mappingMetamodel; public MixedDiscriminatorConverter( @@ -39,15 +40,17 @@ public MixedDiscriminatorConverter( JavaType domainJavaType, JavaType relationalJavaType, Map explicitValueMappings, + boolean implicitEntityShortName, MappingMetamodelImplementor mappingMetamodel) { super( discriminatorRole.getFullPath(), domainJavaType, relationalJavaType ); this.discriminatorRole = discriminatorRole; + this.implicitEntityShortName = implicitEntityShortName; this.mappingMetamodel = mappingMetamodel; this.detailsByValue = CollectionHelper.concurrentMap( explicitValueMappings.size() ); this.detailsByEntityName = CollectionHelper.concurrentMap( explicitValueMappings.size() ); explicitValueMappings.forEach( (value,entityName) -> { - String importedEntityName = mappingMetamodel.getImportedName( entityName ); + final String importedEntityName = mappingMetamodel.getImportedName( entityName ); final EntityPersister entityDescriptor = mappingMetamodel.getEntityDescriptor( importedEntityName ); register( value, entityDescriptor ); } ); @@ -74,32 +77,26 @@ public Map getDetailsByEntityName() { } @Override - public DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object relationalForm) { - if ( relationalForm == null ) { + public DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object relationalValue) { + if ( relationalValue == null ) { return detailsByValue.get( NULL_DISCRIMINATOR ); } - final DiscriminatorValueDetails existing = detailsByValue.get( relationalForm ); + final DiscriminatorValueDetails existing = detailsByValue.get( relationalValue ); if ( existing != null ) { - // an explicit or previously-resolved mapping return existing; } - final DiscriminatorValueDetails notNullMatch = detailsByValue.get( NOT_NULL_DISCRIMINATOR ); - if ( notNullMatch != null ) { - return notNullMatch; - } - - if ( relationalForm.getClass().isEnum() ) { + if ( relationalValue.getClass().isEnum() ) { final Object enumValue; if ( getRelationalJavaType() instanceof StringJavaType ) { - enumValue = ( (Enum) relationalForm ).name(); + enumValue = ( (Enum) relationalValue ).name(); } else if ( getRelationalJavaType() instanceof CharacterJavaType ) { - enumValue = ( (Enum) relationalForm ).name().charAt( 0 ); + enumValue = ( (Enum) relationalValue ).name().charAt( 0 ); } else { - enumValue = ( (Enum) relationalForm ).ordinal(); + enumValue = ( (Enum) relationalValue ).ordinal(); } final DiscriminatorValueDetails enumMatch = detailsByValue.get( enumValue ); if ( enumMatch != null ) { @@ -107,15 +104,27 @@ else if ( getRelationalJavaType() instanceof CharacterJavaType ) { } } - if ( relationalForm instanceof String assumedEntityName ) { - // Assume the relational form is the entity name - final EntityPersister persister = mappingMetamodel.findEntityDescriptor( assumedEntityName ); + if ( relationalValue instanceof String assumedEntityName ) { + final EntityPersister persister; + if ( implicitEntityShortName ) { + final String importedName = mappingMetamodel.getImportedName( assumedEntityName ); + persister = mappingMetamodel.findEntityDescriptor( importedName ); + } + else { + persister = mappingMetamodel.findEntityDescriptor( assumedEntityName ); + } + if ( persister != null ) { return register( assumedEntityName, persister ); } } - throw new HibernateException( "Cannot interpret discriminator value (" + discriminatorRole + ") : " + relationalForm ); + final DiscriminatorValueDetails notNullMatch = detailsByValue.get( NOT_NULL_DISCRIMINATOR ); + if ( notNullMatch != null ) { + return notNullMatch; + } + + throw new HibernateException( "Cannot interpret discriminator value (" + discriminatorRole + ") : " + relationalValue ); } @Override @@ -126,7 +135,8 @@ public DiscriminatorValueDetails getDetailsForEntityName(String entityName) { } final EntityPersister entityDescriptor = mappingMetamodel.getEntityDescriptor( entityName ); - return register( entityName, entityDescriptor ); + final String implicitName = implicitEntityShortName ? entityDescriptor.getImportedName() : entityName; + return register( implicitName, entityDescriptor ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AnyMappingDomainTypeImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AnyMappingDomainTypeImpl.java index 417236612f30..09e9d8abb4e2 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AnyMappingDomainTypeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AnyMappingDomainTypeImpl.java @@ -49,6 +49,7 @@ public AnyMappingDomainTypeImpl( discriminatorBaseType, bootAnyMapping.getMetaValues(), discriminatorType.getValueStrategy(), + discriminatorType.isImplicitEntityShortName(), mappingMetamodel ) ); diff --git a/hibernate-core/src/main/java/org/hibernate/type/AnyType.java b/hibernate-core/src/main/java/org/hibernate/type/AnyType.java index cee22ced08b9..6ad90c8cb346 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/AnyType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/AnyType.java @@ -71,7 +71,7 @@ private static MetaType wrapDiscriminatorType(Type discriminatorType) { return metaType; } - return new MetaType( discriminatorType, AnyDiscriminatorValueStrategy.AUTO, null ); + return new MetaType( discriminatorType, AnyDiscriminatorValueStrategy.AUTO, false, null ); } public Type getIdentifierType() { diff --git a/hibernate-core/src/main/java/org/hibernate/type/MetaType.java b/hibernate-core/src/main/java/org/hibernate/type/MetaType.java index 45b0095a27a6..2d2c556c7279 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/MetaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/MetaType.java @@ -26,14 +26,17 @@ public class MetaType extends AbstractType { private final Type valueType; private final AnyDiscriminatorValueStrategy valueStrategy; + private final boolean implicitEntityShortName; private final Map discriminatorValuesToEntityNameMap; private final Map entityNameToDiscriminatorValueMap; public MetaType( Type valueType, AnyDiscriminatorValueStrategy valueStrategy, + boolean implicitEntityShortName, Map explicitValueMappings) { this.valueType = valueType; + this.implicitEntityShortName = implicitEntityShortName; if ( explicitValueMappings == null || explicitValueMappings.isEmpty() ) { if ( valueStrategy == AnyDiscriminatorValueStrategy.AUTO ) { @@ -56,10 +59,6 @@ public MetaType( this.valueStrategy = valueStrategy; } - public MetaType(Map discriminatorValuesToEntityNameMap, Type baseType) { - this( baseType, AnyDiscriminatorValueStrategy.AUTO, discriminatorValuesToEntityNameMap ); - } - public Type getBaseType() { return valueType; } @@ -68,6 +67,10 @@ public AnyDiscriminatorValueStrategy getValueStrategy() { return valueStrategy; } + public boolean isImplicitEntityShortName() { + return implicitEntityShortName; + } + public String[] getRegistrationKeys() { return REGISTRATION_KEYS; } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/any/mixed/ImplicitStrategyWithShortNameTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/any/mixed/ImplicitStrategyWithShortNameTest.java new file mode 100644 index 000000000000..9330379026bd --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/any/mixed/ImplicitStrategyWithShortNameTest.java @@ -0,0 +1,104 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.any.mixed; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Table; +import org.hibernate.annotations.Any; +import org.hibernate.annotations.AnyDiscriminator; +import org.hibernate.annotations.AnyKeyJavaClass; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.type.AnyDiscriminatorValueStrategy; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import java.sql.ResultSet; +import java.sql.Statement; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +/** + * @author Steve Ebersole + */ +@SuppressWarnings("JUnitMalformedDeclaration") +public class ImplicitStrategyWithShortNameTest { + @Test + @DomainModel(annotatedClasses = {Payment.class, CashPayment.class, CardPayment.class, CheckPayment.class, Bill.class}) + @SessionFactory + void testIt(SessionFactoryScope sessions) { + sessions.inTransaction( (session) -> { + final Bill bill = new Bill( 1, "Water" ); + session.persist( bill ); + + final CashPayment cashPayment = new CashPayment( 1, 123.45 ); + session.persist( cashPayment ); + + final CardPayment cardPayment = new CardPayment( 1, 987.50, "12345" ); + session.persist( cardPayment ); + + bill.implicitPayment = cashPayment; + bill.mixedPayment = cardPayment; + } ); + + sessions.inTransaction( (session) -> session.doWork( (conn) -> { + final Statement statement = conn.createStatement(); + final ResultSet resultSet = statement.executeQuery( "select implicit_kind, mixed_kind from billz" ); + assertThat( resultSet.next() ).isTrue(); + assertThat( resultSet.getString( 1 ) ).isEqualTo( "CashPayment" ); + assertThat( resultSet.getString( 2 ) ).isEqualTo( "CardPayment" ); + } ) ); + + sessions.inTransaction( (session) -> { + final Bill bill = session.find( Bill.class, 1 ); + assertThat( bill.implicitPayment ).isInstanceOf( CashPayment.class ); + assertThat( bill.mixedPayment ).isInstanceOf( CardPayment.class ); + } ); + } + + @AfterEach + @SessionFactory + void dropTestData(SessionFactoryScope sessions) { + sessions.inTransaction( session -> { + session.createMutationQuery( "delete Bill" ).executeUpdate(); + session.createMutationQuery( "delete CashPayment" ).executeUpdate(); + session.createMutationQuery( "delete CardPayment" ).executeUpdate(); + } ); + } + + @Entity(name="Bill") + @Table(name="billz") + public static class Bill { + @Id + private Integer id; + private String name; + + @Any + @AnyDiscriminator( valueStrategy = AnyDiscriminatorValueStrategy.IMPLICIT, implicitEntityShortName = true ) + @Column(name = "implicit_kind") + @AnyKeyJavaClass( Integer.class ) + @JoinColumn( name = "implicit_fk" ) + private Payment implicitPayment; + + @Any + @AnyDiscriminator( valueStrategy = AnyDiscriminatorValueStrategy.MIXED, implicitEntityShortName = true ) + @Column(name = "mixed_kind") + @AnyKeyJavaClass( Integer.class ) + @JoinColumn( name = "mixed_fk" ) + private Payment mixedPayment; + + public Bill() { + } + + public Bill(Integer id, String name) { + this.id = id; + this.name = name; + } + } +}