Introduce `VirtualIdEmbeddable` and `IdClassEmbeddable`

This 3rd commit cleans up some code

Still need to
  - integrate EmbeddableInstantiator work
  - integrate embedded forms.  `VirtualIdEmbeddable` does not really need it as it can use the id-mapping itself as the embedded form.  But `IdClassEmbedded` should really be integrated
  - integrate `VirtualKeyEmbeddable` and `VirtualKeyEmbedded` for use as inverse composite fks
  - share `#finishInit` handling for `EmbeddableMappingType`, `VirtualIdEmbeddable` and `IdClassEmbeddable`
This commit is contained in:
Steve Ebersole 2021-11-21 08:08:34 -06:00
parent dd4f380ea9
commit 86e8b2751c
9 changed files with 95 additions and 123 deletions

View File

@ -20,12 +20,6 @@ import org.hibernate.sql.ast.tree.from.TableGroupProducer;
* @see EmbeddableValuedModelPart * @see EmbeddableValuedModelPart
*/ */
public interface EmbeddableMappingType extends ManagedMappingType, SelectableMappings { public interface EmbeddableMappingType extends ManagedMappingType, SelectableMappings {
EmbeddableMappingType createInverseMappingType(
EmbeddedAttributeMapping valueMapping,
TableGroupProducer declaringTableGroupProducer,
SelectableMappings selectableMappings,
MappingModelCreationProcess creationProcess);
EmbeddableValuedModelPart getEmbeddedValueMapping(); EmbeddableValuedModelPart getEmbeddedValueMapping();
EmbeddableRepresentationStrategy getRepresentationStrategy(); EmbeddableRepresentationStrategy getRepresentationStrategy();
@ -36,6 +30,12 @@ public interface EmbeddableMappingType extends ManagedMappingType, SelectableMap
boolean isCreateEmptyCompositesEnabled(); boolean isCreateEmptyCompositesEnabled();
EmbeddableMappingType createInverseMappingType(
EmbeddedAttributeMapping valueMapping,
TableGroupProducer declaringTableGroupProducer,
SelectableMappings selectableMappings,
MappingModelCreationProcess creationProcess);
@Override @Override
default int forEachSelectable(SelectableConsumer consumer) { default int forEachSelectable(SelectableConsumer consumer) {
return ManagedMappingType.super.forEachSelectable( consumer ); return ManagedMappingType.super.forEachSelectable( consumer );

View File

@ -21,13 +21,11 @@ import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.FetchableContainer; import org.hibernate.sql.results.graph.FetchableContainer;
/** /**
* An embedded (embeddable-valued) model part. * Describes the mapping of an embeddable (composite).
* *
* @see jakarta.persistence.Embedded * @see jakarta.persistence.Embedded
* @see jakarta.persistence.EmbeddedId * @see jakarta.persistence.EmbeddedId
* @see jakarta.persistence.Embeddable * @see jakarta.persistence.Embeddable
*
* @author Steve Ebersole
*/ */
public interface EmbeddableValuedModelPart extends ModelPart, Fetchable, FetchableContainer, TableGroupJoinProducer { public interface EmbeddableValuedModelPart extends ModelPart, Fetchable, FetchableContainer, TableGroupJoinProducer {
EmbeddableMappingType getEmbeddableTypeDescriptor(); EmbeddableMappingType getEmbeddableTypeDescriptor();

View File

@ -0,0 +1,72 @@
/*
* 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.engine.spi.SharedSessionContractImplementor;
import org.hibernate.mapping.IndexedConsumer;
import org.hibernate.metamodel.mapping.internal.IdClassEmbeddable;
import org.hibernate.metamodel.mapping.internal.VirtualIdEmbeddable;
import org.hibernate.sql.results.graph.FetchOptions;
import org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable;
/**
* A "non-aggregated" composite identifier, which means that the entity itself
* does not define a singular representation of its identifier like an
* {@link jakarta.persistence.EmbeddedId} does.
*
* An IdClass can be used to provide a simple, singular representation of the
* identifier for easier reference in API calls. JPA requires using an IdClass
* when mapping such identifiers. Hibernate supports mapping such identifiers
* with or without the IdClass; without, the entity itself is used as the
* identifier.
*
* @see jakarta.persistence.IdClass
* @see jakarta.persistence.MapsId
*/
public interface NonAggregatedIdentifierMapping extends CompositeIdentifierMapping, EmbeddableValuedFetchable, FetchOptions {
/**
* The virtual-id representation of this id mapping
*/
VirtualIdEmbeddable getVirtualIdEmbeddable();
/**
* The id-class representation of this id mapping
*/
IdClassEmbeddable getIdClassEmbeddable();
/**
* The id-class, if there is one, otherwise the virtual-id.
*/
IdentifierValueMapper getIdentifierValueMapper();
/**
* Think of an AttributeConverter for id values to account for representation
* difference between virtual and id-class mappings
*/
interface IdentifierValueMapper extends EmbeddableMappingType {
EmbeddableValuedModelPart getEmbeddedPart();
/**
* Extract the identifier out of the given entity, returning the mapper's
* representation
*/
Object getIdentifier(Object entity, SharedSessionContractImplementor session);
/**
* Extract the identifier out of the given entity, returning the mapper's
* representation
*/
void setIdentifier(Object entity, Object id, SharedSessionContractImplementor session);
/**
* Convenience method to iterate the attributes for this mapper's representation
*/
default void forEachAttribute(IndexedConsumer<SingularAttributeMapping> consumer) {
getEmbeddedPart().getEmbeddableTypeDescriptor().forEachAttributeMapping( (IndexedConsumer) consumer );
}
}
}

View File

@ -155,7 +155,6 @@ public class EmbeddableMappingTypeImpl implements EmbeddableMappingType, Selecta
private SelectableMappings selectableMappings; private SelectableMappings selectableMappings;
private final EmbeddableValuedModelPart valueMapping; private final EmbeddableValuedModelPart valueMapping;
private NavigableRole embeddedRole;
private final boolean createEmptyCompositesEnabled; private final boolean createEmptyCompositesEnabled;
@ -354,10 +353,10 @@ public class EmbeddableMappingTypeImpl implements EmbeddableMappingType, Selecta
final boolean updateable = bootPropertyDescriptor.isUpdateable(); final boolean updateable = bootPropertyDescriptor.isUpdateable();
final boolean includeInOptimisticLocking = bootPropertyDescriptor.isOptimisticLocked(); final boolean includeInOptimisticLocking = bootPropertyDescriptor.isOptimisticLocked();
final CascadeStyle cascadeStyle = compositeType.getCascadeStyle( attributeIndex ); final CascadeStyle cascadeStyle = compositeType.getCascadeStyle( attributeIndex );
final MutabilityPlan mutabilityPlan; final MutabilityPlan<?> mutabilityPlan;
if ( updateable ) { if ( updateable ) {
mutabilityPlan = new MutabilityPlan() { mutabilityPlan = new MutabilityPlan<Object>() {
@Override @Override
public boolean isMutable() { public boolean isMutable() {
return true; return true;
@ -394,7 +393,7 @@ public class EmbeddableMappingTypeImpl implements EmbeddableMappingType, Selecta
} }
@Override @Override
public MutabilityPlan getMutabilityPlan() { public MutabilityPlan<?> getMutabilityPlan() {
return mutabilityPlan; return mutabilityPlan;
} }
@ -523,7 +522,7 @@ public class EmbeddableMappingTypeImpl implements EmbeddableMappingType, Selecta
// We need the attribute mapping types to finish initialization first before we can build the column mappings // We need the attribute mapping types to finish initialization first before we can build the column mappings
creationProcess.registerInitializationCallback( creationProcess.registerInitializationCallback(
"EmbeddableMappingType(" + embeddedRole + ")#initColumnMappings", "EmbeddableMappingType(" + getEmbeddedValueMapping().getNavigableRole().getFullPath() + ")#initColumnMappings",
this::initColumnMappings this::initColumnMappings
); );
return true; return true;
@ -560,7 +559,7 @@ public class EmbeddableMappingTypeImpl implements EmbeddableMappingType, Selecta
} }
@Override @Override
public JavaType getMappedJavaTypeDescriptor() { public JavaType<?> getMappedJavaTypeDescriptor() {
return embeddableJtd; return embeddableJtd;
} }
@ -625,10 +624,8 @@ public class EmbeddableMappingTypeImpl implements EmbeddableMappingType, Selecta
} }
@Override @Override
public void visitFetchables( public void visitFetchables(Consumer<Fetchable> fetchableConsumer, EntityMappingType treatTargetType) {
Consumer<Fetchable> fetchableConsumer, visitAttributeMappings( fetchableConsumer );
EntityMappingType treatTargetType) {
visitAttributeMappings( attributeMapping -> fetchableConsumer.accept( attributeMapping ) );
} }
@Override @Override
@ -780,10 +777,8 @@ public class EmbeddableMappingTypeImpl implements EmbeddableMappingType, Selecta
} }
@Override @Override
public void visitSubParts( public void visitSubParts(Consumer<ModelPart> consumer, EntityMappingType treatTargetType) {
Consumer<ModelPart> consumer, visitAttributeMappings( consumer );
EntityMappingType treatTargetType) {
visitAttributeMappings( consumer::accept );
} }
public Object[] getPropertyValues(Object compositeInstance) { public Object[] getPropertyValues(Object compositeInstance) {

View File

@ -35,14 +35,14 @@ import org.hibernate.mapping.RootClass;
import org.hibernate.mapping.Selectable; import org.hibernate.mapping.Selectable;
import org.hibernate.mapping.Table; import org.hibernate.mapping.Table;
import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.internal.EmbeddableMappingTypeImpl; import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart; import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping; import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.MappingModelCreationLogger; import org.hibernate.metamodel.mapping.MappingModelCreationLogger;
import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping;
import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.SelectableConsumer; import org.hibernate.metamodel.mapping.SelectableConsumer;
import org.hibernate.metamodel.mapping.SelectableMapping; import org.hibernate.metamodel.mapping.SelectableMapping;
@ -50,7 +50,7 @@ import org.hibernate.metamodel.mapping.SelectableMappings;
import org.hibernate.metamodel.mapping.SingularAttributeMapping; import org.hibernate.metamodel.mapping.SingularAttributeMapping;
import org.hibernate.metamodel.mapping.StateArrayContributorMetadata; import org.hibernate.metamodel.mapping.StateArrayContributorMetadata;
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess; import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
import org.hibernate.metamodel.mapping.internal.NonAggregatedIdentifierMapping.IdentifierValueMapper; import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping.IdentifierValueMapper;
import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy; import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;

View File

@ -125,10 +125,6 @@ public class MappingModelCreationHelper {
final PropertyAccess propertyAccess = entityPersister.getRepresentationStrategy() final PropertyAccess propertyAccess = entityPersister.getRepresentationStrategy()
.resolvePropertyAccess( bootEntityDescriptor.getIdentifierProperty() ); .resolvePropertyAccess( bootEntityDescriptor.getIdentifierProperty() );
final StateArrayContributorMetadataAccess attributeMetadataAccess = getStateArrayContributorMetadataAccess(
propertyAccess
);
final EmbeddableMappingTypeImpl embeddableMappingType = EmbeddableMappingTypeImpl.from( final EmbeddableMappingTypeImpl embeddableMappingType = EmbeddableMappingTypeImpl.from(
(Component) bootProperty.getValue(), (Component) bootProperty.getValue(),
cidType, cidType,

View File

@ -1,41 +0,0 @@
/*
* 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.internal;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.mapping.IndexedConsumer;
import org.hibernate.metamodel.mapping.CompositeIdentifierMapping;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
import org.hibernate.sql.results.graph.FetchOptions;
import org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable;
/**
* @author Steve Ebersole
*/
public interface NonAggregatedIdentifierMapping extends CompositeIdentifierMapping, EmbeddableValuedFetchable, FetchOptions {
IdClassEmbeddable getIdClassEmbeddable();
VirtualIdEmbeddable getVirtualIdEmbeddable();
IdentifierValueMapper getIdentifierValueMapper();
/**
* Think of an AttributeConverter for id values. Handles representation
* difference between virtual and id-class mappings
*/
interface IdentifierValueMapper extends EmbeddableMappingType {
EmbeddableValuedModelPart getEmbeddedPart();
Object getIdentifier(Object entity, SharedSessionContractImplementor session);
void setIdentifier(Object entity, Object id, SharedSessionContractImplementor session);
default void forEachAttribute(IndexedConsumer<SingularAttributeMapping> consumer) {
getEmbeddedPart().getEmbeddableTypeDescriptor().forEachAttributeMapping( (IndexedConsumer) consumer );
}
}
}

View File

@ -23,6 +23,7 @@ import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.EmbeddableMappingType; import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping;
import org.hibernate.metamodel.mapping.SelectableMappings; import org.hibernate.metamodel.mapping.SelectableMappings;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.query.NavigablePath; import org.hibernate.query.NavigablePath;

View File

@ -37,6 +37,7 @@ import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.MappingModelCreationLogger; import org.hibernate.metamodel.mapping.MappingModelCreationLogger;
import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping;
import org.hibernate.metamodel.mapping.NonTransientException; import org.hibernate.metamodel.mapping.NonTransientException;
import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.SelectableConsumer; import org.hibernate.metamodel.mapping.SelectableConsumer;
@ -67,7 +68,7 @@ import org.hibernate.type.spi.CompositeTypeImplementor;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
import static org.hibernate.internal.util.collections.CollectionHelper.arrayList; import static org.hibernate.internal.util.collections.CollectionHelper.arrayList;
import static org.hibernate.metamodel.mapping.internal.NonAggregatedIdentifierMapping.IdentifierValueMapper; import static org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping.IdentifierValueMapper;
/** /**
* Embeddable describing the virtual-id aspect of a non-aggregated composite id * Embeddable describing the virtual-id aspect of a non-aggregated composite id
@ -104,7 +105,7 @@ public class VirtualIdEmbeddable implements IdentifierValueMapper {
final CompositeType compositeType = (CompositeType) virtualIdSource.getType(); final CompositeType compositeType = (CompositeType) virtualIdSource.getType();
this.attributeMappings = arrayList( (compositeType).getPropertyNames().length ); this.attributeMappings = arrayList( (compositeType).getPropertyNames().length );
// todo (6.0) : can this be a separate VirtualIdEmbedded? // todo (6.0) : can/should this be a separate VirtualIdEmbedded?
( (CompositeTypeImplementor) compositeType ).injectMappingModelPart( idMapping, creationProcess ); ( (CompositeTypeImplementor) compositeType ).injectMappingModelPart( idMapping, creationProcess );
creationProcess.registerInitializationCallback( creationProcess.registerInitializationCallback(
@ -146,56 +147,6 @@ public class VirtualIdEmbeddable implements IdentifierValueMapper {
); );
} }
public VirtualIdEmbeddable(
NonAggregatedIdentifierMapping idMapping,
EntityMappingType identifiedEntityMapping,
Component bootDescriptor,
CompositeType compositeType,
String rootTableExpression,
String[] rootTableKeyColumnNames,
MappingModelCreationProcess creationProcess) {
this.sessionFactory = creationProcess.getCreationContext().getSessionFactory();
this.navigableRole = idMapping.getNavigableRole();
this.idMapping = idMapping;
this.javaType = identifiedEntityMapping.getJavaTypeDescriptor();
this.attributeMappings = arrayList( compositeType.getPropertyNames().length );
this.representationStrategy = new VirtualIdRepresentationStrategy( identifiedEntityMapping );
( (CompositeTypeImplementor) compositeType ).injectMappingModelPart( getEmbeddedValueMapping(), creationProcess );
creationProcess.registerInitializationCallback(
"EmbeddableMappingType(" + navigableRole.getFullPath() + ")#finishInitialization",
() -> {
try {
final boolean finished = finishInitialization(
bootDescriptor,
compositeType,
rootTableExpression,
rootTableKeyColumnNames,
creationProcess
);
if ( finished ) {
return finished;
}
}
catch (Exception e) {
if ( e instanceof NonTransientException ) {
throw e;
}
}
MappingModelCreationLogger.LOGGER.debugf(
"EmbeddableMappingType(%s) finalization was not able to complete successfully",
navigableRole
);
return false;
}
);
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// IdentifierValueMapper // IdentifierValueMapper