-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
HHH-16339 - Unify entity and any discriminator handling
- Loading branch information
Showing
39 changed files
with
844 additions
and
557 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
183 changes: 183 additions & 0 deletions
183
hibernate-core/src/main/java/org/hibernate/metamodel/mapping/DiscriminatorConverter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
/* | ||
* 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 java.util.List; | ||
import java.util.Map; | ||
import java.util.function.Consumer; | ||
import java.util.function.Function; | ||
|
||
import org.hibernate.engine.spi.SessionFactoryImplementor; | ||
import org.hibernate.internal.util.collections.CollectionHelper; | ||
import org.hibernate.metamodel.RepresentationMode; | ||
import org.hibernate.metamodel.mapping.internal.DiscriminatorValueDetailsImpl; | ||
import org.hibernate.metamodel.model.domain.NavigableRole; | ||
import org.hibernate.metamodel.spi.MappingMetamodelImplementor; | ||
import org.hibernate.type.BasicType; | ||
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter; | ||
import org.hibernate.type.descriptor.java.JavaType; | ||
|
||
import static org.hibernate.persister.entity.DiscriminatorHelper.NOT_NULL_DISCRIMINATOR; | ||
import static org.hibernate.persister.entity.DiscriminatorHelper.NULL_DISCRIMINATOR; | ||
|
||
/** | ||
* Conversion of discriminator values between the entity name/Class domain form and | ||
* its generally CHARACTER or INTEGER based relational form | ||
* | ||
* @param <O> The domain type - either <ul> | ||
* <li> | ||
* the {@linkplain EntityMappingType#getMappedJavaType() entity Class} for unnamed entities | ||
* </li> | ||
* <li> | ||
* the {@linkplain EntityMappingType#getEntityName() entity name} for named entities | ||
* </li> | ||
* </ul> | ||
* @param <R> The Java type of the relational form of the discriminator | ||
* | ||
* @author Steve Ebersole | ||
*/ | ||
public class DiscriminatorConverter<O,R> implements BasicValueConverter<O,R> { | ||
public static <O,R> DiscriminatorConverter<O,R> fromValueMappings( | ||
NavigableRole role, | ||
JavaType<O> domainJavaType, | ||
BasicType<R> underlyingJdbcMapping, | ||
Map<Object,String> valueMappings, | ||
SessionFactoryImplementor sessionFactory) { | ||
final MappingMetamodelImplementor mappingMetamodel = sessionFactory.getMappingMetamodel(); | ||
final List<DiscriminatorValueDetails> valueDetailsList = CollectionHelper.arrayList( valueMappings.size() ); | ||
valueMappings.forEach( (value, entityName) -> { | ||
final DiscriminatorValueDetails valueDetails = new DiscriminatorValueDetailsImpl( | ||
value, | ||
mappingMetamodel.getEntityDescriptor( entityName ) | ||
); | ||
valueDetailsList.add( valueDetails ); | ||
} ); | ||
|
||
return new DiscriminatorConverter<>( | ||
role, | ||
domainJavaType, | ||
underlyingJdbcMapping.getJavaTypeDescriptor(), | ||
valueDetailsList | ||
); | ||
} | ||
|
||
private final NavigableRole discriminatorRole; | ||
private final JavaType<O> domainJavaType; | ||
private final JavaType<R> relationalJavaType; | ||
|
||
private final Map<Object, DiscriminatorValueDetails> discriminatorValueToEntityNameMap; | ||
private final Map<String,DiscriminatorValueDetails> entityNameToDiscriminatorValueMap; | ||
|
||
public DiscriminatorConverter( | ||
NavigableRole discriminatorRole, | ||
JavaType<O> domainJavaType, | ||
JavaType<R> relationalJavaType, | ||
List<DiscriminatorValueDetails> valueMappings) { | ||
this.discriminatorRole = discriminatorRole; | ||
this.domainJavaType = domainJavaType; | ||
this.relationalJavaType = relationalJavaType; | ||
|
||
this.discriminatorValueToEntityNameMap = CollectionHelper.concurrentMap( valueMappings.size() ); | ||
this.entityNameToDiscriminatorValueMap = CollectionHelper.concurrentMap( valueMappings.size() ); | ||
valueMappings.forEach( (valueDetails) -> { | ||
discriminatorValueToEntityNameMap.put( valueDetails.getValue(), valueDetails ); | ||
entityNameToDiscriminatorValueMap.put( valueDetails.getIndicatedEntityName(), valueDetails ); | ||
} ); | ||
} | ||
|
||
public NavigableRole getNavigableRole() { | ||
return discriminatorRole; | ||
} | ||
|
||
@Override | ||
public JavaType<O> getDomainJavaType() { | ||
return domainJavaType; | ||
} | ||
|
||
@Override | ||
public JavaType<R> getRelationalJavaType() { | ||
return relationalJavaType; | ||
} | ||
|
||
public DiscriminatorValueDetails getDetailsForRelationalForm(R relationalForm) { | ||
return getDetailsForDiscriminatorValue( relationalForm ); | ||
} | ||
|
||
@Override | ||
public O toDomainValue(R relationalForm) { | ||
assert relationalForm == null || relationalJavaType.isInstance( relationalForm ); | ||
|
||
final DiscriminatorValueDetails matchingValueDetails = getDetailsForRelationalForm( relationalForm ); | ||
if ( matchingValueDetails == null ) { | ||
throw new IllegalStateException( "Could not resolve discriminator value" ); | ||
} | ||
|
||
final EntityMappingType indicatedEntity = matchingValueDetails.getIndicatedEntity(); | ||
//noinspection unchecked | ||
return indicatedEntity.getRepresentationStrategy().getMode() == RepresentationMode.POJO | ||
&& indicatedEntity.getEntityName().equals( indicatedEntity.getJavaType().getJavaTypeClass().getName() ) | ||
? (O) indicatedEntity.getJavaType().getJavaTypeClass() | ||
: (O) indicatedEntity.getEntityName(); | ||
} | ||
|
||
public DiscriminatorValueDetails getDetailsForEntityName(String entityName) { | ||
return entityNameToDiscriminatorValueMap.get( entityName ); | ||
} | ||
|
||
public DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object value) { | ||
if ( value == null ) { | ||
return discriminatorValueToEntityNameMap.get( NULL_DISCRIMINATOR ); | ||
} | ||
|
||
final DiscriminatorValueDetails valueMatch = discriminatorValueToEntityNameMap.get( value ); | ||
if ( valueMatch != null ) { | ||
return valueMatch; | ||
} | ||
|
||
return discriminatorValueToEntityNameMap.get( NOT_NULL_DISCRIMINATOR ); | ||
} | ||
|
||
@Override | ||
public R toRelationalValue(O domainForm) { | ||
assert domainForm == null || domainForm instanceof String || domainForm instanceof Class; | ||
|
||
if ( domainForm == null ) { | ||
return null; | ||
} | ||
|
||
final String entityName; | ||
if ( domainForm instanceof Class ) { | ||
entityName = ( (Class<?>) domainForm ).getName(); | ||
} | ||
else { | ||
entityName = (String) domainForm; | ||
} | ||
|
||
final DiscriminatorValueDetails discriminatorValueDetails = getDetailsForEntityName( entityName ); | ||
//noinspection unchecked | ||
return (R) discriminatorValueDetails.getValue(); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "DiscriminatorConverter(" + discriminatorRole.getFullPath() + ")"; | ||
} | ||
|
||
public void forEachValueDetail(Consumer<DiscriminatorValueDetails> consumer) { | ||
discriminatorValueToEntityNameMap.forEach( (value, detail) -> consumer.accept( detail ) ); | ||
} | ||
|
||
public <X> X fromValueDetails(Function<DiscriminatorValueDetails,X> handler) { | ||
for ( DiscriminatorValueDetails detail : discriminatorValueToEntityNameMap.values() ) { | ||
final X result = handler.apply( detail ); | ||
if ( result != null ) { | ||
return result; | ||
} | ||
} | ||
return null; | ||
} | ||
} |
62 changes: 62 additions & 0 deletions
62
hibernate-core/src/main/java/org/hibernate/metamodel/mapping/DiscriminatorMapping.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/* | ||
* 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.spi.NavigablePath; | ||
import org.hibernate.sql.ast.spi.SqlAstCreationState; | ||
import org.hibernate.sql.ast.tree.expression.Expression; | ||
import org.hibernate.sql.ast.tree.from.TableGroup; | ||
import org.hibernate.sql.results.graph.Fetchable; | ||
import org.hibernate.type.descriptor.java.JavaType; | ||
|
||
/** | ||
* Mapping of a discriminator, for either {@linkplain EntityMappingType#getDiscriminatorMapping() entity} or | ||
* {@linkplain DiscriminatedAssociationModelPart#getDiscriminatorMapping() association} (ANY) discrimination. | ||
* <p/> | ||
* Represents a composition of <ul> | ||
* <li>a {@linkplain #getValueConverter() converter} between the domain and relational form</li> | ||
* <li>a {@linkplain #getUnderlyingJdbcMapping JDBC mapping} to read and write the relational values</li> | ||
* </ul> | ||
* | ||
* @author Steve Ebersole | ||
*/ | ||
public interface DiscriminatorMapping extends VirtualModelPart, BasicValuedModelPart, Fetchable { | ||
/** | ||
* Information about the value mappings | ||
*/ | ||
DiscriminatorConverter<?,?> getValueConverter(); | ||
|
||
JdbcMapping getUnderlyingJdbcMapping(); | ||
|
||
/** | ||
* The domain Java form, which is either {@code JavaType<Class>} (entity class) | ||
* or {@code JavaType<String>} (entity name). | ||
*/ | ||
default JavaType<?> getDomainJavaType() { | ||
return getValueConverter().getDomainJavaType(); | ||
} | ||
|
||
/** | ||
* The relational Java form. This will typically be some form of integer | ||
* or character value. | ||
*/ | ||
default JavaType<?> getRelationalJavaType() { | ||
return getValueConverter().getRelationalJavaType(); | ||
} | ||
|
||
/** | ||
* Create the appropriate SQL expression for this discriminator | ||
* | ||
* @param jdbcMappingToUse The JDBC mapping to use. This allows opting between | ||
* the "domain result type" (aka Class) and the "underlying type" (Integer, String, etc) | ||
*/ | ||
Expression resolveSqlExpression( | ||
NavigablePath navigablePath, | ||
JdbcMapping jdbcMappingToUse, | ||
TableGroup tableGroup, | ||
SqlAstCreationState creationState); | ||
} |
33 changes: 33 additions & 0 deletions
33
hibernate-core/src/main/java/org/hibernate/metamodel/mapping/DiscriminatorType.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
/* | ||
* 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.model.domain.BasicDomainType; | ||
import org.hibernate.type.BasicType; | ||
import org.hibernate.type.ConvertedBasicType; | ||
import org.hibernate.type.descriptor.java.JavaType; | ||
|
||
/** | ||
* Union of {@link ConvertedBasicType} and {@link BasicDomainType} capabilities. | ||
* | ||
* @implNote We need the {@link BasicDomainType} aspect for handling in SQM trees. | ||
* | ||
* @param <O> The Java type of the domain form of the discriminator. | ||
* | ||
* @author Steve Ebersole | ||
*/ | ||
public interface DiscriminatorType<O> extends ConvertedBasicType<O>, BasicDomainType<O> { | ||
@Override | ||
DiscriminatorConverter<O, ?> getValueConverter(); | ||
|
||
BasicType<?> getUnderlyingJdbcMapping(); | ||
|
||
@Override | ||
default JavaType<O> getJavaTypeDescriptor() { | ||
return ConvertedBasicType.super.getJavaTypeDescriptor(); | ||
} | ||
} |
37 changes: 37 additions & 0 deletions
37
hibernate-core/src/main/java/org/hibernate/metamodel/mapping/DiscriminatorValueDetails.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/* | ||
* 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; | ||
|
||
/** | ||
* Details for a particular discriminator value. | ||
* | ||
* @apiNote For {@linkplain jakarta.persistence.InheritanceType#JOINED joined} and | ||
* {@linkplain jakarta.persistence.InheritanceType#TABLE_PER_CLASS union} inheritance, | ||
* the discriminator also effectively indicates a specific table. That table can be | ||
* found via {@linkplain EntityMappingType#getMappedTableDetails()} for the | ||
* {@linkplain #getIndicatedEntity() indicated entity} | ||
* | ||
* @see jakarta.persistence.DiscriminatorValue | ||
*/ | ||
public interface DiscriminatorValueDetails { | ||
/** | ||
* The discriminator value | ||
*/ | ||
Object getValue(); | ||
|
||
/** | ||
* The name of the concrete entity-type mapped to this {@linkplain #getValue() discriminator value} | ||
*/ | ||
default String getIndicatedEntityName() { | ||
return getIndicatedEntity().getEntityName(); | ||
} | ||
|
||
/** | ||
* Form of {@link #getIndicatedEntityName()} returning the matched {@link EntityMappingType} | ||
*/ | ||
EntityMappingType getIndicatedEntity(); | ||
} |
Oops, something went wrong.