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
*/
public interface EmbeddableMappingType extends ManagedMappingType, SelectableMappings {
EmbeddableMappingType createInverseMappingType(
EmbeddedAttributeMapping valueMapping,
TableGroupProducer declaringTableGroupProducer,
SelectableMappings selectableMappings,
MappingModelCreationProcess creationProcess);
EmbeddableValuedModelPart getEmbeddedValueMapping();
EmbeddableRepresentationStrategy getRepresentationStrategy();
@ -36,6 +30,12 @@ public interface EmbeddableMappingType extends ManagedMappingType, SelectableMap
boolean isCreateEmptyCompositesEnabled();
EmbeddableMappingType createInverseMappingType(
EmbeddedAttributeMapping valueMapping,
TableGroupProducer declaringTableGroupProducer,
SelectableMappings selectableMappings,
MappingModelCreationProcess creationProcess);
@Override
default int forEachSelectable(SelectableConsumer 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;
/**
* An embedded (embeddable-valued) model part.
* Describes the mapping of an embeddable (composite).
*
* @see jakarta.persistence.Embedded
* @see jakarta.persistence.EmbeddedId
* @see jakarta.persistence.Embeddable
*
* @author Steve Ebersole
*/
public interface EmbeddableValuedModelPart extends ModelPart, Fetchable, FetchableContainer, TableGroupJoinProducer {
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 final EmbeddableValuedModelPart valueMapping;
private NavigableRole embeddedRole;
private final boolean createEmptyCompositesEnabled;
@ -354,10 +353,10 @@ public class EmbeddableMappingTypeImpl implements EmbeddableMappingType, Selecta
final boolean updateable = bootPropertyDescriptor.isUpdateable();
final boolean includeInOptimisticLocking = bootPropertyDescriptor.isOptimisticLocked();
final CascadeStyle cascadeStyle = compositeType.getCascadeStyle( attributeIndex );
final MutabilityPlan mutabilityPlan;
final MutabilityPlan<?> mutabilityPlan;
if ( updateable ) {
mutabilityPlan = new MutabilityPlan() {
mutabilityPlan = new MutabilityPlan<Object>() {
@Override
public boolean isMutable() {
return true;
@ -394,7 +393,7 @@ public class EmbeddableMappingTypeImpl implements EmbeddableMappingType, Selecta
}
@Override
public MutabilityPlan getMutabilityPlan() {
public MutabilityPlan<?> getMutabilityPlan() {
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
creationProcess.registerInitializationCallback(
"EmbeddableMappingType(" + embeddedRole + ")#initColumnMappings",
"EmbeddableMappingType(" + getEmbeddedValueMapping().getNavigableRole().getFullPath() + ")#initColumnMappings",
this::initColumnMappings
);
return true;
@ -560,7 +559,7 @@ public class EmbeddableMappingTypeImpl implements EmbeddableMappingType, Selecta
}
@Override
public JavaType getMappedJavaTypeDescriptor() {
public JavaType<?> getMappedJavaTypeDescriptor() {
return embeddableJtd;
}
@ -625,10 +624,8 @@ public class EmbeddableMappingTypeImpl implements EmbeddableMappingType, Selecta
}
@Override
public void visitFetchables(
Consumer<Fetchable> fetchableConsumer,
EntityMappingType treatTargetType) {
visitAttributeMappings( attributeMapping -> fetchableConsumer.accept( attributeMapping ) );
public void visitFetchables(Consumer<Fetchable> fetchableConsumer, EntityMappingType treatTargetType) {
visitAttributeMappings( fetchableConsumer );
}
@Override
@ -780,10 +777,8 @@ public class EmbeddableMappingTypeImpl implements EmbeddableMappingType, Selecta
}
@Override
public void visitSubParts(
Consumer<ModelPart> consumer,
EntityMappingType treatTargetType) {
visitAttributeMappings( consumer::accept );
public void visitSubParts(Consumer<ModelPart> consumer, EntityMappingType treatTargetType) {
visitAttributeMappings( consumer );
}
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.Table;
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.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.MappingModelCreationLogger;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.SelectableConsumer;
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.StateArrayContributorMetadata;
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.spi.EmbeddableRepresentationStrategy;
import org.hibernate.persister.entity.EntityPersister;

View File

@ -125,10 +125,6 @@ public class MappingModelCreationHelper {
final PropertyAccess propertyAccess = entityPersister.getRepresentationStrategy()
.resolvePropertyAccess( bootEntityDescriptor.getIdentifierProperty() );
final StateArrayContributorMetadataAccess attributeMetadataAccess = getStateArrayContributorMetadataAccess(
propertyAccess
);
final EmbeddableMappingTypeImpl embeddableMappingType = EmbeddableMappingTypeImpl.from(
(Component) bootProperty.getValue(),
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.JdbcMapping;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping;
import org.hibernate.metamodel.mapping.SelectableMappings;
import org.hibernate.persister.entity.EntityPersister;
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.MappingModelCreationLogger;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping;
import org.hibernate.metamodel.mapping.NonTransientException;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.SelectableConsumer;
@ -67,7 +68,7 @@ import org.hibernate.type.spi.CompositeTypeImplementor;
import org.hibernate.type.spi.TypeConfiguration;
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
@ -104,7 +105,7 @@ public class VirtualIdEmbeddable implements IdentifierValueMapper {
final CompositeType compositeType = (CompositeType) virtualIdSource.getType();
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 );
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