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
  • Loading branch information
sebersole committed Oct 22, 2024
1 parent f82c581 commit b1135b5
Show file tree
Hide file tree
Showing 17 changed files with 664 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
import java.lang.annotation.Target;

import jakarta.persistence.DiscriminatorType;
import org.hibernate.type.AnyDiscriminatorValueStrategy;

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 @@ -44,4 +46,12 @@
* or {@link JdbcTypeCode}.
*/
DiscriminatorType value() default DiscriminatorType.STRING;

/**
* How the discriminator value should be handled in regard to explicit
* {@linkplain AnyDiscriminatorValue} mappings, if any.
*
* @since 7.0
*/
AnyDiscriminatorValueStrategy valueStrategy() default AUTO;
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
import org.hibernate.annotations.AnyDiscriminator;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.Columns;
import org.hibernate.annotations.Formula;
Expand Down Expand Up @@ -107,6 +108,11 @@ private static void bindAny(
context
);

final AnyDiscriminator anyDiscriminator = property.getDirectAnnotationUsage( AnyDiscriminator.class );
if ( anyDiscriminator != null ) {
value.setDiscriminatorValueStrategy( anyDiscriminator.valueStrategy() );
}

final PropertyBinder binder = new PropertyBinder();
binder.setName( inferredData.getPropertyName() );
binder.setValue( value );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,28 @@

import org.hibernate.annotations.AnyDiscriminator;
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;

/**
* Used in creating dynamic annotation instances (e.g. from XML)
*/
public AnyDiscriminatorAnnotation(SourceModelBuildingContext modelContext) {
this.value = jakarta.persistence.DiscriminatorType.STRING;
this.valueStrategy = AnyDiscriminatorValueStrategy.AUTO;
}

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

/**
Expand All @@ -50,5 +54,14 @@ public void value(jakarta.persistence.DiscriminatorType value) {
this.value = value;
}

@Override
public AnyDiscriminatorValueStrategy valueStrategy() {
return valueStrategy;
}

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


}
26 changes: 26 additions & 0 deletions hibernate-core/src/main/java/org/hibernate/mapping/Any.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
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;
Expand All @@ -34,6 +35,7 @@ public class Any extends SimpleValue {

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

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

Expand Down Expand Up @@ -128,6 +131,28 @@ public void setIdentifierType(String identifierType) {
this.keyMapping.setTypeName( identifierType );
}

/**
* Current strategy for interpreting {@linkplain org.hibernate.annotations.AnyDiscriminatorValue} definitions,
* especially in terms of implicit, explicit and potentially missing values.
*
* @since 7.0
*/
@Incubating
public AnyDiscriminatorValueStrategy getDiscriminatorValueStrategy() {
return discriminatorValueStrategy;
}

/**
* Set the strategy
*
* @see #getDiscriminatorValueStrategy
* @since 7.0
*/
@Incubating
public void setDiscriminatorValueStrategy(AnyDiscriminatorValueStrategy discriminatorValueStrategy) {
this.discriminatorValueStrategy = discriminatorValueStrategy;
}

@Override
public AnyType getType() throws MappingException {
if ( resolvedType == null ) {
Expand All @@ -150,6 +175,7 @@ public AnyType getType() throws MappingException {
resolvedType = MappingHelper.anyMapping(
discriminatorType,
identifierType,
discriminatorValueStrategy,
metaValueToEntityNameMap,
isLazy(),
getBuildingContext()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
*/
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 @@ -16,7 +18,6 @@
* @author Gavin King
*/
public abstract class DiscriminatorConverter<O,R> implements BasicValueConverter<O,R> {

private final String discriminatorName;
private final JavaType<O> domainJavaType;
private final JavaType<R> relationalJavaType;
Expand All @@ -30,6 +31,9 @@ public DiscriminatorConverter(
this.relationalJavaType = relationalJavaType;
}

@Incubating
public abstract AnyDiscriminatorValueStrategy getValueStrategy();

public String getDiscriminatorName() {
return discriminatorName;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,22 @@
*/
package org.hibernate.metamodel.mapping;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;

import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.metamodel.mapping.internal.EmbeddableDiscriminatorValueDetailsImpl;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.AnyDiscriminatorValueStrategy;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.java.JavaType;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;

/**
* Handles conversion of discriminator values for embeddable subtype classes
* to their domain typed form.
Expand Down Expand Up @@ -65,6 +66,12 @@ public EmbeddableDiscriminatorConverter(
} );
}

@Override
public AnyDiscriminatorValueStrategy getValueStrategy() {
// discriminators for embeddables are always explicit
return AnyDiscriminatorValueStrategy.EXPLICIT;
}

@Override
public O toDomainValue(R relationalForm) {
assert relationalForm == null || getRelationalJavaType().isInstance( relationalForm );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.AnyDiscriminatorValueStrategy;
import org.hibernate.type.descriptor.java.CharacterJavaType;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.java.StringJavaType;
Expand Down Expand Up @@ -60,6 +61,19 @@ public ExplicitDiscriminatorConverter(
} );
}

@Override
public AnyDiscriminatorValueStrategy getValueStrategy() {
return AnyDiscriminatorValueStrategy.EXPLICIT;
}

public Map<Object, DiscriminatorValueDetails> getDetailsByValue() {
return detailsByValue;
}

public Map<String, DiscriminatorValueDetails> getDetailsByEntityName() {
return detailsByEntityName;
}

@Override
public DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object relationalForm) {
if ( relationalForm == null ) {
Expand All @@ -80,13 +94,13 @@ public DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object relation
if ( relationalForm.getClass().isEnum() ) {
final Object enumValue;
if ( getRelationalJavaType() instanceof StringJavaType ) {
enumValue = ( (Enum) relationalForm ).name();
enumValue = ( (Enum<?>) relationalForm ).name();
}
else if ( getRelationalJavaType() instanceof CharacterJavaType ) {
enumValue = ( (Enum) relationalForm ).name().charAt( 0 );
enumValue = ( (Enum<?>) relationalForm ).name().charAt( 0 );
}
else {
enumValue = ( (Enum) relationalForm ).ordinal();
enumValue = ( (Enum<?>) relationalForm ).ordinal();
}
final DiscriminatorValueDetails enumMatch = detailsByValue.get( enumValue );
if ( enumMatch != null ) {
Expand All @@ -108,7 +122,7 @@ public DiscriminatorValueDetails getDetailsForEntityName(String entityName) {
if ( valueDetails != null) {
return valueDetails;
}
throw new HibernateException( "Unknown entity name (" + discriminatorRole + ") : " + entityName );
throw new HibernateException( "Entity not explicitly mapped for ANY discriminator (" + discriminatorRole + ") : " + entityName );
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.AnyDiscriminatorValueStrategy;
import org.hibernate.type.descriptor.java.JavaType;

import java.util.Map;
Expand Down Expand Up @@ -51,17 +52,28 @@ public ImplicitDiscriminatorConverter(
this.detailsByEntityName = CollectionHelper.concurrentMap( 8 );
}

@Override
public AnyDiscriminatorValueStrategy getValueStrategy() {
return AnyDiscriminatorValueStrategy.IMPLICIT;
}

public Map<Object, DiscriminatorValueDetails> getDetailsByValue() {
return detailsByValue;
}

public Map<String, DiscriminatorValueDetails> getDetailsByEntityName() {
return detailsByEntityName;
}

@Override
public DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object value) {
if ( value instanceof String incoming ) {
final DiscriminatorValueDetails existingDetails = detailsByValue.get( incoming );
if ( existingDetails != null ) {
return existingDetails;
}
final String entityName = mappingMetamodel.getImportedName( incoming );
final EntityPersister persister = mappingMetamodel.findEntityDescriptor( entityName );
final EntityPersister persister = mappingMetamodel.findEntityDescriptor( incoming );
if ( persister != null ) {
assert persister.getImportedName().equals( incoming );
return register( incoming, persister );
}
}
Expand All @@ -76,7 +88,7 @@ public DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object value) {
private DiscriminatorValueDetails register(Object value, EntityPersister entityDescriptor) {
final DiscriminatorValueDetails details = new DiscriminatorValueDetailsImpl( value, entityDescriptor );
detailsByValue.put( value, details );
detailsByEntityName.put( entityDescriptor.getImportedName(), details );
detailsByEntityName.put( entityDescriptor.getEntityName(), details );
return details;
}

Expand All @@ -88,7 +100,7 @@ public DiscriminatorValueDetails getDetailsForEntityName(String entityName) {
}
final EntityPersister persister = mappingMetamodel.findEntityDescriptor( entityName );
if ( persister!= null ) {
return register( persister.getImportedName(), persister );
return register( persister.getEntityName(), persister );
}
throw new HibernateException( String.format(
ROOT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.AnyDiscriminatorValueStrategy;
import org.hibernate.type.descriptor.java.CharacterJavaType;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.java.StringJavaType;
Expand Down Expand Up @@ -59,6 +60,19 @@ private DiscriminatorValueDetails register(Object value, EntityPersister entityD
return details;
}

@Override
public AnyDiscriminatorValueStrategy getValueStrategy() {
return AnyDiscriminatorValueStrategy.MIXED;
}

public Map<Object, DiscriminatorValueDetails> getDetailsByValue() {
return detailsByValue;
}

public Map<String, DiscriminatorValueDetails> getDetailsByEntityName() {
return detailsByEntityName;
}

@Override
public DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object relationalForm) {
if ( relationalForm == null ) {
Expand All @@ -79,13 +93,13 @@ public DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object relation
if ( relationalForm.getClass().isEnum() ) {
final Object enumValue;
if ( getRelationalJavaType() instanceof StringJavaType ) {
enumValue = ( (Enum) relationalForm ).name();
enumValue = ( (Enum<?>) relationalForm ).name();
}
else if ( getRelationalJavaType() instanceof CharacterJavaType ) {
enumValue = ( (Enum) relationalForm ).name().charAt( 0 );
enumValue = ( (Enum<?>) relationalForm ).name().charAt( 0 );
}
else {
enumValue = ( (Enum) relationalForm ).ordinal();
enumValue = ( (Enum<?>) relationalForm ).ordinal();
}
final DiscriminatorValueDetails enumMatch = detailsByValue.get( enumValue );
if ( enumMatch != null ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/
package org.hibernate.type;

import org.hibernate.Incubating;
import org.hibernate.annotations.AnyDiscriminatorValue;

/**
Expand All @@ -12,8 +13,10 @@
*
* @see AnyDiscriminatorValue
*
* @since 7.0
* @author Steve Ebersole
*/
@Incubating
public enum AnyDiscriminatorValueStrategy {
/**
* Pick between {@link #IMPLICIT} and {@link #EXPLICIT} based on
Expand Down
Loading

0 comments on commit b1135b5

Please sign in to comment.