Skip to content

Commit

Permalink
HHH-18728 - Allow mixed discriminator-value mappings for ANY
Browse files Browse the repository at this point in the history
HHH-18729 - Allow custom strategy for implicit discriminator-value determination for ANY
  • Loading branch information
sebersole committed Oct 25, 2024
1 parent 24a1b2c commit 9397b1e
Show file tree
Hide file tree
Showing 25 changed files with 273 additions and 613 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,12 @@
import java.lang.annotation.Target;

import jakarta.persistence.DiscriminatorType;
import org.hibernate.type.AnyDiscriminatorValueStrategy;
import org.hibernate.metamodel.spi.ImplicitDiscriminatorStrategy;

import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static org.hibernate.type.AnyDiscriminatorValueStrategy.AUTO;

/**
* A simplified way to specify the type of the discriminator in an {@link Any}
Expand Down Expand Up @@ -48,16 +47,8 @@
DiscriminatorType value() default DiscriminatorType.STRING;

/**
* How the discriminator value should be handled in regard to explicit
* {@linkplain AnyDiscriminatorValue} mappings, if any.
*
* @since 7.0
* Determines how to handle mappings which are not explicitly defined by
* any associated {@linkplain AnyDiscriminatorValue} annotations
*/
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;
Class<? extends ImplicitDiscriminatorStrategy> implicitValueStrategy() default ImplicitDiscriminatorStrategy.class;
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
import org.hibernate.mapping.Any;
import org.hibernate.mapping.Join;
import org.hibernate.mapping.Property;
import org.hibernate.metamodel.internal.FullNameImplicitDiscriminatorStrategy;
import org.hibernate.metamodel.internal.ShortNameImplicitDiscriminatorStrategy;
import org.hibernate.metamodel.spi.ImplicitDiscriminatorStrategy;
import org.hibernate.models.spi.MemberDetails;

import jakarta.persistence.Column;
Expand Down Expand Up @@ -110,8 +113,7 @@ private static void bindAny(

final AnyDiscriminator anyDiscriminator = property.getDirectAnnotationUsage( AnyDiscriminator.class );
if ( anyDiscriminator != null ) {
value.setDiscriminatorValueStrategy( anyDiscriminator.valueStrategy() );
value.setImplicitEntityShortName( anyDiscriminator.implicitEntityShortName() );
value.setImplicitDiscriminatorValueStrategy( resolveImplicitDiscriminatorStrategy( anyDiscriminator, context ) );
}

final PropertyBinder binder = new PropertyBinder();
Expand All @@ -135,4 +137,23 @@ private static void bindAny(
propertyHolder.addProperty( prop, inferredData.getAttributeMember(), columns, inferredData.getDeclaringClass() );
binder.callAttributeBindersInSecondPass( prop );
}

private static ImplicitDiscriminatorStrategy resolveImplicitDiscriminatorStrategy(
AnyDiscriminator anyDiscriminator,
MetadataBuildingContext context) {
final Class<? extends ImplicitDiscriminatorStrategy> implicitValueStrategy = anyDiscriminator.implicitValueStrategy();
if ( ImplicitDiscriminatorStrategy.class.equals( implicitValueStrategy ) ) {
return null;
}

if ( FullNameImplicitDiscriminatorStrategy.class.equals( implicitValueStrategy ) ) {
return FullNameImplicitDiscriminatorStrategy.FULL_NAME_STRATEGY;
}

if ( ShortNameImplicitDiscriminatorStrategy.class.equals( implicitValueStrategy ) ) {
return ShortNameImplicitDiscriminatorStrategy.SHORT_NAME_STRATEGY;
}

return context.getBootstrapContext().getCustomTypeProducer().produceBeanInstance( implicitValueStrategy );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,38 @@
import java.util.Map;

import org.hibernate.annotations.AnyDiscriminator;
import org.hibernate.metamodel.spi.ImplicitDiscriminatorStrategy;
import org.hibernate.models.spi.SourceModelBuildingContext;
import org.hibernate.type.AnyDiscriminatorValueStrategy;

@SuppressWarnings({ "ClassExplicitlyAnnotation", "unused" })
@jakarta.annotation.Generated("org.hibernate.orm.build.annotations.ClassGeneratorProcessor")
public class AnyDiscriminatorAnnotation implements AnyDiscriminator {
private jakarta.persistence.DiscriminatorType value;
private AnyDiscriminatorValueStrategy valueStrategy;
private boolean implicitEntityShortName;
private Class<? extends ImplicitDiscriminatorStrategy> implicitValueStrategy;

/**
* 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;
this.implicitValueStrategy = ImplicitDiscriminatorStrategy.class;
}

/**
* Used in creating annotation instances from JDK variant
*/
public AnyDiscriminatorAnnotation(AnyDiscriminator annotation, SourceModelBuildingContext modelContext) {
this.value = annotation.value();
this.valueStrategy = annotation.valueStrategy();
this.implicitEntityShortName = annotation.implicitEntityShortName();
this.implicitValueStrategy = annotation.implicitValueStrategy();
}

/**
* 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" );
//noinspection unchecked
this.implicitValueStrategy = (Class<? extends ImplicitDiscriminatorStrategy>) attributeValues.get( "implicitValueStrategy" );
}

@Override
Expand All @@ -60,20 +57,11 @@ public void value(jakarta.persistence.DiscriminatorType value) {
}

@Override
public AnyDiscriminatorValueStrategy valueStrategy() {
return valueStrategy;
public Class<? extends ImplicitDiscriminatorStrategy> implicitValueStrategy() {
return implicitValueStrategy;
}

public void valueStrategy(AnyDiscriminatorValueStrategy valueStrategy) {
this.valueStrategy = valueStrategy;
}

@Override
public boolean implicitEntityShortName() {
return implicitEntityShortName;
}

public void implicitEntityShortName(boolean implicitEntityShortName) {
this.implicitEntityShortName = implicitEntityShortName;
public void implicitValueStrategy(Class<? extends ImplicitDiscriminatorStrategy> implicitValueStrategy) {
this.implicitValueStrategy = implicitValueStrategy;
}
}
33 changes: 9 additions & 24 deletions hibernate-core/src/main/java/org/hibernate/mapping/Any.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
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.metamodel.spi.ImplicitDiscriminatorStrategy;
import org.hibernate.type.AnyType;
import org.hibernate.type.MappingContext;
import org.hibernate.type.Type;
Expand All @@ -35,8 +35,7 @@ public class Any extends SimpleValue {

// common
private Map<Object,String> metaValueToEntityNameMap;
private AnyDiscriminatorValueStrategy discriminatorValueStrategy = AnyDiscriminatorValueStrategy.AUTO;
private boolean implicitEntityShortName = false;
private ImplicitDiscriminatorStrategy implicitValueStrategy;
private boolean lazy = true;

private AnyType resolvedType;
Expand Down Expand Up @@ -76,7 +75,7 @@ public Any(Any original) {
this.metaValueToEntityNameMap = original.metaValueToEntityNameMap == null
? null
: new HashMap<>(original.metaValueToEntityNameMap);
this.discriminatorValueStrategy = original.discriminatorValueStrategy;
this.implicitValueStrategy = original.implicitValueStrategy;
this.lazy = original.lazy;
}

Expand Down Expand Up @@ -133,24 +132,16 @@ public void setIdentifierType(String identifierType) {
}

/**
* Set the strategy for interpreting {@linkplain org.hibernate.annotations.AnyDiscriminatorValue}
* definitions in terms of implicit, explicit and potentially missing values.
* Set the strategy for dealing with discriminator mappings which are not explicitly defined by
* {@linkplain org.hibernate.annotations.AnyDiscriminatorValue}.
*
* @since 7.0
*/
@Incubating
public void setDiscriminatorValueStrategy(AnyDiscriminatorValueStrategy discriminatorValueStrategy) {
this.discriminatorValueStrategy = discriminatorValueStrategy;
}

/**
* Set whether to use the entity's short-name for implicit discriminator value mappings
* @apiNote {@code null} indicates to not allow implicit mappings.
*
* @since 7.0
*/
@Incubating
public void setImplicitEntityShortName(boolean implicitEntityShortName) {
this.implicitEntityShortName = implicitEntityShortName;
public void setImplicitDiscriminatorValueStrategy(ImplicitDiscriminatorStrategy implicitValueStrategy) {
this.implicitValueStrategy = implicitValueStrategy;
}

@Override
Expand All @@ -175,9 +166,8 @@ public AnyType getType() throws MappingException {
resolvedType = MappingHelper.anyMapping(
discriminatorType,
identifierType,
discriminatorValueStrategy,
implicitEntityShortName,
metaValueToEntityNameMap,
implicitValueStrategy,
isLazy(),
getBuildingContext()
);
Expand Down Expand Up @@ -335,7 +325,6 @@ public void setKey(BasicValue keyDescriptor) {
public static class MetaValue extends SimpleValue {
private String typeName;
private String columnName;
private AnyDiscriminatorValueStrategy valueStrategy;

private final Consumer<Selectable> selectableConsumer;

Expand Down Expand Up @@ -428,10 +417,6 @@ public boolean isValid(MappingContext mappingContext) {
return columnName != null
&& getType().getColumnSpan( mappingContext ) == 1;
}

public AnyDiscriminatorValueStrategy getValueStrategy() {
return valueStrategy;
}
}

public static class KeyValue extends SimpleValue {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.spi.ImplicitDiscriminatorStrategy;
import org.hibernate.resource.beans.internal.FallbackBeanInstanceProducer;
import org.hibernate.resource.beans.spi.ManagedBean;
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
import org.hibernate.resource.beans.spi.ProvidedInstanceManagedBeanImpl;
import org.hibernate.type.AnyDiscriminatorValueStrategy;
import org.hibernate.type.AnyType;
import org.hibernate.type.CollectionType;
import org.hibernate.type.CustomCollectionType;
Expand Down Expand Up @@ -132,9 +132,8 @@ public static AnyType anyMapping(
return anyMapping(
discriminatorType,
identifierType,
AnyDiscriminatorValueStrategy.AUTO,
false,
explicitValeMappings,
null,
lazy,
buildingContext
);
Expand All @@ -143,12 +142,11 @@ public static AnyType anyMapping(
public static AnyType anyMapping(
Type discriminatorType,
Type identifierType,
AnyDiscriminatorValueStrategy discriminatorValueStrategy,
boolean implicitEntityShortName,
Map<Object, String> explicitValeMappings,
ImplicitDiscriminatorStrategy implicitValueStrategy,
boolean lazy,
MetadataBuildingContext buildingContext) {
final MetaType metaType = new MetaType( discriminatorType, discriminatorValueStrategy, implicitEntityShortName, explicitValeMappings );
final MetaType metaType = new MetaType( discriminatorType, implicitValueStrategy, explicitValeMappings );
return new AnyType( buildingContext.getBootstrapContext().getTypeConfiguration(), metaType, identifierType, lazy );
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* SPDX-License-Identifier: LGPL-2.1-or-later
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.metamodel.internal;

import org.hibernate.HibernateException;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.metamodel.spi.ImplicitDiscriminatorStrategy;
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
import org.hibernate.persister.entity.EntityPersister;

/**
* @author Steve Ebersole
*/
public class FullNameImplicitDiscriminatorStrategy implements ImplicitDiscriminatorStrategy {
public static final FullNameImplicitDiscriminatorStrategy FULL_NAME_STRATEGY = new FullNameImplicitDiscriminatorStrategy();

@Override
public Object toDiscriminatorValue(EntityMappingType entityMapping, NavigableRole discriminatorRole, MappingMetamodelImplementor mappingModel) {
return entityMapping.getEntityName();
}

@Override
public EntityMappingType toEntityMapping(Object discriminatorValue, NavigableRole discriminatorRole, MappingMetamodelImplementor mappingModel) {
if ( discriminatorValue instanceof String assumedEntityName ) {
final EntityPersister persister = mappingModel.findEntityDescriptor( assumedEntityName );

if ( persister != null ) {
return persister;
}
}

throw new HibernateException( "Cannot interpret discriminator value (" + discriminatorRole + ") : " + discriminatorValue );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* SPDX-License-Identifier: LGPL-2.1-or-later
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.metamodel.internal;

import org.hibernate.HibernateException;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.metamodel.spi.ImplicitDiscriminatorStrategy;
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;

/**
* @author Steve Ebersole
*/
public class ShortNameImplicitDiscriminatorStrategy implements ImplicitDiscriminatorStrategy {
public static final ShortNameImplicitDiscriminatorStrategy SHORT_NAME_STRATEGY = new ShortNameImplicitDiscriminatorStrategy();

@Override
public Object toDiscriminatorValue(EntityMappingType entityMapping, NavigableRole discriminatorRole, MappingMetamodelImplementor mappingModel) {
return entityMapping.getImportedName();
}

@Override
public EntityMappingType toEntityMapping(Object discriminatorValue, NavigableRole discriminatorRole, MappingMetamodelImplementor mappingModel) {
if ( discriminatorValue instanceof String assumedEntityName ) {
final String importedName = mappingModel.getImportedName( assumedEntityName );
final EntityMappingType entityMapping = mappingModel.findEntityDescriptor( importedName );
if ( entityMapping != null ) {
return entityMapping;
}
}

throw new HibernateException( "Cannot interpret discriminator value (" + discriminatorRole + ") : " + discriminatorValue );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
*/
package org.hibernate.metamodel.mapping;

import org.hibernate.Incubating;
import org.hibernate.metamodel.RepresentationMode;
import org.hibernate.type.AnyDiscriminatorValueStrategy;
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
import org.hibernate.type.descriptor.java.JavaType;

Expand All @@ -31,9 +29,6 @@ public DiscriminatorConverter(
this.relationalJavaType = relationalJavaType;
}

@Incubating
public abstract AnyDiscriminatorValueStrategy getValueStrategy();

public String getDiscriminatorName() {
return discriminatorName;
}
Expand Down Expand Up @@ -101,5 +96,8 @@ public String toString() {

public abstract void forEachValueDetail(Consumer<DiscriminatorValueDetails> consumer);

/**
* Find and return the first DiscriminatorValueDetails which matches the given {@code handler}
*/
public abstract <X> X fromValueDetails(Function<DiscriminatorValueDetails,X> handler);
}
Loading

0 comments on commit 9397b1e

Please sign in to comment.