Skip to content

Commit

Permalink
HHH-18729 - Allow custom strategy for implicit discriminator-value de…
Browse files Browse the repository at this point in the history
…termination for ANY

- allow opting into use of short-name
- potentially look at allowing an "implicit value mapper" later
  • Loading branch information
sebersole committed Oct 24, 2024
1 parent 1fa10e3 commit a9f058f
Show file tree
Hide file tree
Showing 16 changed files with 249 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
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)
*/
public AnyDiscriminatorAnnotation(SourceModelBuildingContext modelContext) {
this.value = jakarta.persistence.DiscriminatorType.STRING;
this.valueStrategy = AnyDiscriminatorValueStrategy.AUTO;
this.implicitEntityShortName = false;
}

/**
Expand All @@ -31,13 +33,16 @@ public AnyDiscriminatorAnnotation(SourceModelBuildingContext modelContext) {
public AnyDiscriminatorAnnotation(AnyDiscriminator annotation, SourceModelBuildingContext modelContext) {
this.value = annotation.value();
this.valueStrategy = annotation.valueStrategy();
this.implicitEntityShortName = annotation.implicitEntityShortName();
}

/**
* Used in creating annotation instances from Jandex variant
*/
public AnyDiscriminatorAnnotation(Map<String, Object> attributeValues, SourceModelBuildingContext modelContext) {
this.value = (jakarta.persistence.DiscriminatorType) attributeValues.get( "value" );
this.valueStrategy = (AnyDiscriminatorValueStrategy) attributeValues.get( "valueStrategy" );
this.implicitEntityShortName = (boolean) attributeValues.get( "implicitEntityShortName" );
}

@Override
Expand All @@ -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;
}
}
29 changes: 15 additions & 14 deletions hibernate-core/src/main/java/org/hibernate/mapping/Any.java
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand All @@ -36,6 +36,7 @@ public class Any extends SimpleValue {
// common
private Map<Object,String> metaValueToEntityNameMap;
private AnyDiscriminatorValueStrategy discriminatorValueStrategy = AnyDiscriminatorValueStrategy.AUTO;
private boolean implicitEntityShortName = false;
private boolean lazy = true;

private AnyType resolvedType;
Expand Down Expand Up @@ -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
Expand All @@ -176,6 +176,7 @@ public AnyType getType() throws MappingException {
discriminatorType,
identifierType,
discriminatorValueStrategy,
implicitEntityShortName,
metaValueToEntityNameMap,
isLazy(),
getBuildingContext()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,17 +129,26 @@ public static AnyType anyMapping(
Map<Object, String> 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<Object, String> 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 );
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ public AnyDiscriminatorPart(
BasicType<?> underlyingJdbcMapping,
Map<Object,String> valueToEntityNameMap,
AnyDiscriminatorValueStrategy valueStrategy,
boolean implicitEntityShortName,
MappingMetamodelImplementor mappingMetamodel) {
this.navigableRole = partRole;
this.declaringType = declaringType;
Expand All @@ -106,6 +107,7 @@ public AnyDiscriminatorPart(
underlyingJdbcMapping,
valueToEntityNameMap,
valueStrategy,
implicitEntityShortName,
mappingMetamodel
);
}
Expand All @@ -115,6 +117,7 @@ public AnyDiscriminatorPart(
BasicType<?> underlyingJdbcMapping,
Map<Object, String> valueToEntityNameMap,
AnyDiscriminatorValueStrategy valueStrategy,
boolean implicitEntityShortName,
MappingMetamodelImplementor mappingMetamodel) {
if ( valueStrategy == AnyDiscriminatorValueStrategy.AUTO ) {
if ( valueToEntityNameMap == null || valueToEntityNameMap.isEmpty() ) {
Expand All @@ -132,6 +135,7 @@ public AnyDiscriminatorPart(
ClassJavaType.INSTANCE,
underlyingJdbcMapping.getJavaTypeDescriptor(),
valueToEntityNameMap,
implicitEntityShortName,
mappingMetamodel
);
case EXPLICIT -> new ExplicitDiscriminatorConverter<>(
Expand All @@ -146,6 +150,7 @@ public AnyDiscriminatorPart(
ClassJavaType.INSTANCE,
underlyingJdbcMapping.getJavaTypeDescriptor(),
valueToEntityNameMap,
implicitEntityShortName,
mappingMetamodel
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ public static DiscriminatedAssociationMapping from(
(BasicType<?>) metaType.getBaseType(),
metaType.getDiscriminatorValuesToEntityNameMap(),
metaType.getValueStrategy(),
metaType.isImplicitEntityShortName(),
creationProcess.getCreationContext().getSessionFactory().getMappingMetamodel()
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand All @@ -75,12 +76,12 @@ public Map<String, DiscriminatorValueDetails> 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;
Expand All @@ -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 ) {
Expand All @@ -112,7 +113,7 @@ else if ( getRelationalJavaType() instanceof CharacterJavaType ) {
ROOT,
"Unknown discriminator value (%s) : %s",
discriminatorRole,
relationalForm
relationalValue
) );
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
*/
public class ImplicitDiscriminatorConverter<O,R> extends DiscriminatorConverter<O,R> {
private final NavigableRole discriminatorRole;
private final boolean implicitEntityShortName;
private final MappingMetamodelImplementor mappingMetamodel;
private final Map<Object, DiscriminatorValueDetails> detailsByValue;
private final Map<String,DiscriminatorValueDetails> detailsByEntityName;
Expand All @@ -35,9 +36,11 @@ public ImplicitDiscriminatorConverter(
JavaType<O> domainJavaType,
JavaType<R> relationalJavaType,
Map<Object,String> explicitValueMappings,
boolean implicitEntityShortName,
MappingMetamodelImplementor mappingMetamodel) {
super( discriminatorRole.getFullPath(), domainJavaType, relationalJavaType );
this.discriminatorRole = discriminatorRole;
this.implicitEntityShortName = implicitEntityShortName;
this.mappingMetamodel = mappingMetamodel;

if ( CollectionHelper.isNotEmpty( explicitValueMappings ) ) {
Expand Down Expand Up @@ -66,22 +69,47 @@ public Map<String, DiscriminatorValueDetails> 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
) );
}

Expand All @@ -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",
Expand Down
Loading

0 comments on commit a9f058f

Please sign in to comment.