Implemented @Parent

This commit is contained in:
Andrea Boriero 2020-07-24 15:37:42 +01:00
parent d3978a0871
commit b26b397d59
6 changed files with 93 additions and 37 deletions

View File

@ -8,6 +8,7 @@ package org.hibernate.metamodel.mapping;
import java.util.List; import java.util.List;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter; import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.sql.ast.Clause; import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.spi.SqlAstCreationState; import org.hibernate.sql.ast.spi.SqlAstCreationState;
@ -46,7 +47,9 @@ public interface EmbeddableValuedModelPart extends ModelPart, Fetchable, Fetchab
/** /**
* @see org.hibernate.annotations.Parent * @see org.hibernate.annotations.Parent
*/ */
SingularAttributeMapping getParentInjectionAttributeMapping(); default PropertyAccess getParentInjectionAttributePropertyAccess() {
return null;
}
Expression toSqlExpression( Expression toSqlExpression(
TableGroup tableGroup, TableGroup tableGroup,

View File

@ -22,9 +22,9 @@ import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.ManagedMappingType; import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess; import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.property.access.internal.PropertyAccessStrategyBasicImpl;
import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.query.NavigablePath; import org.hibernate.query.NavigablePath;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter; import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
@ -62,6 +62,7 @@ public class EmbeddedAttributeMapping
private final String tableExpression; private final String tableExpression;
private final String[] attrColumnNames; private final String[] attrColumnNames;
private final EmbeddableMappingType embeddableMappingType; private final EmbeddableMappingType embeddableMappingType;
private final PropertyAccess parentInjectionAttributeProperyAccess;
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public EmbeddedAttributeMapping( public EmbeddedAttributeMapping(
@ -71,6 +72,7 @@ public class EmbeddedAttributeMapping
String tableExpression, String tableExpression,
String[] attrColumnNames, String[] attrColumnNames,
StateArrayContributorMetadataAccess attributeMetadataAccess, StateArrayContributorMetadataAccess attributeMetadataAccess,
String parentInjectionAttributeName,
FetchStrategy mappedFetchStrategy, FetchStrategy mappedFetchStrategy,
EmbeddableMappingType embeddableMappingType, EmbeddableMappingType embeddableMappingType,
ManagedMappingType declaringType, ManagedMappingType declaringType,
@ -83,6 +85,15 @@ public class EmbeddedAttributeMapping
declaringType, declaringType,
propertyAccess propertyAccess
); );
if ( parentInjectionAttributeName != null ) {
parentInjectionAttributeProperyAccess = PropertyAccessStrategyBasicImpl.INSTANCE.buildPropertyAccess(
embeddableMappingType.getMappedJavaTypeDescriptor().getJavaType(),
parentInjectionAttributeName
);
}
else {
parentInjectionAttributeProperyAccess = null;
}
this.navigableRole = navigableRole; this.navigableRole = navigableRole;
this.tableExpression = tableExpression; this.tableExpression = tableExpression;
this.attrColumnNames = attrColumnNames; this.attrColumnNames = attrColumnNames;
@ -99,12 +110,6 @@ public class EmbeddedAttributeMapping
return embeddableMappingType; return embeddableMappingType;
} }
@Override
public SingularAttributeMapping getParentInjectionAttributeMapping() {
// todo (6.0) : implement
return null;
}
@Override @Override
public String getContainingTableExpression() { public String getContainingTableExpression() {
return tableExpression; return tableExpression;
@ -115,6 +120,11 @@ public class EmbeddedAttributeMapping
return Arrays.asList( attrColumnNames ); return Arrays.asList( attrColumnNames );
} }
@Override
public PropertyAccess getParentInjectionAttributePropertyAccess() {
return parentInjectionAttributeProperyAccess;
}
@Override @Override
public void visitJdbcTypes( public void visitJdbcTypes(
Consumer<JdbcMapping> action, Consumer<JdbcMapping> action,

View File

@ -22,9 +22,10 @@ import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.MappingType; import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.property.access.internal.PropertyAccessStrategyBasicImpl;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.query.NavigablePath; import org.hibernate.query.NavigablePath;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter; import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.sql.ast.Clause; import org.hibernate.sql.ast.Clause;
@ -59,7 +60,7 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF
private final String containingTableExpression; private final String containingTableExpression;
private final SingularAttributeMapping parentInjectionAttribute; private final PropertyAccess parentInjectionAttributeProperyAccess;
private final List<String> columnExpressions; private final List<String> columnExpressions;
private final String sqlAliasStem; private final String sqlAliasStem;
@ -68,15 +69,24 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF
CollectionPersister collectionDescriptor, CollectionPersister collectionDescriptor,
Nature nature, Nature nature,
EmbeddableMappingType embeddableMappingType, EmbeddableMappingType embeddableMappingType,
SingularAttributeMapping parentInjectionAttribute, String parentInjectionAttributeName,
String containingTableExpression, String containingTableExpression,
List<String> columnExpressions, List<String> columnExpressions,
String sqlAliasStem) { String sqlAliasStem) {
this.navigableRole = collectionDescriptor.getNavigableRole().appendContainer( nature.getName() ); this.navigableRole = collectionDescriptor.getNavigableRole().appendContainer( nature.getName() );
this.collectionDescriptor = collectionDescriptor; this.collectionDescriptor = collectionDescriptor;
this.nature = nature; this.nature = nature;
if ( parentInjectionAttributeName != null ) {
parentInjectionAttributeProperyAccess = PropertyAccessStrategyBasicImpl.INSTANCE.buildPropertyAccess(
embeddableMappingType.getMappedJavaTypeDescriptor().getJavaType(),
parentInjectionAttributeName
);
}
else {
parentInjectionAttributeProperyAccess = null;
}
this.embeddableMappingType = embeddableMappingType; this.embeddableMappingType = embeddableMappingType;
this.parentInjectionAttribute = parentInjectionAttribute;
this.containingTableExpression = containingTableExpression; this.containingTableExpression = containingTableExpression;
this.columnExpressions = columnExpressions; this.columnExpressions = columnExpressions;
this.sqlAliasStem = sqlAliasStem; this.sqlAliasStem = sqlAliasStem;
@ -108,8 +118,8 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF
} }
@Override @Override
public SingularAttributeMapping getParentInjectionAttributeMapping() { public PropertyAccess getParentInjectionAttributePropertyAccess() {
return parentInjectionAttribute; return parentInjectionAttributeProperyAccess;
} }
@Override @Override

View File

@ -413,8 +413,9 @@ public class MappingModelCreationHelper {
creationProcess creationProcess
); );
final Component component = (Component) bootProperty.getValue();
final EmbeddableMappingType embeddableMappingType = EmbeddableMappingType.from( final EmbeddableMappingType embeddableMappingType = EmbeddableMappingType.from(
(Component) bootProperty.getValue(), component,
attrType, attrType,
attributeMappingType -> new EmbeddedAttributeMapping( attributeMappingType -> new EmbeddedAttributeMapping(
attrName, attrName,
@ -423,6 +424,7 @@ public class MappingModelCreationHelper {
tableExpression, tableExpression,
attrColumnNames, attrColumnNames,
attributeMetadataAccess, attributeMetadataAccess,
component.getParentProperty(),
FetchStrategy.IMMEDIATE_JOIN, FetchStrategy.IMMEDIATE_JOIN,
attributeMappingType, attributeMappingType,
declaringType, declaringType,
@ -1115,7 +1117,7 @@ public class MappingModelCreationHelper {
CollectionPart.Nature.INDEX, CollectionPart.Nature.INDEX,
inflightDescriptor, inflightDescriptor,
// parent-injection // parent-injection
null, component.getParentProperty(),
tableExpression, tableExpression,
columnExpressions, columnExpressions,
sqlAliasStem sqlAliasStem
@ -1206,7 +1208,7 @@ public class MappingModelCreationHelper {
CollectionPart.Nature.ELEMENT, CollectionPart.Nature.ELEMENT,
embeddableMappingType, embeddableMappingType,
// parent-injection // parent-injection
null, component.getParentProperty(),
tableExpression, tableExpression,
columnExpressions, columnExpressions,
sqlAliasStem sqlAliasStem

View File

@ -9,16 +9,20 @@ package org.hibernate.sql.results.graph.embeddable;
import java.util.IdentityHashMap; import java.util.IdentityHashMap;
import java.util.Map; import java.util.Map;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.metamodel.mapping.EmbeddableMappingType; import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart; import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
import org.hibernate.metamodel.mapping.StateArrayContributorMapping; import org.hibernate.metamodel.mapping.StateArrayContributorMapping;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.query.NavigablePath; import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.graph.AbstractFetchParentAccess; import org.hibernate.sql.results.graph.AbstractFetchParentAccess;
import org.hibernate.sql.results.graph.AssemblerCreationState; import org.hibernate.sql.results.graph.AssemblerCreationState;
import org.hibernate.sql.results.graph.DomainResultAssembler; import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParentAccess; import org.hibernate.sql.results.graph.FetchParentAccess;
import org.hibernate.sql.results.graph.Initializer;
import org.hibernate.sql.results.graph.collection.CollectionInitializer;
import org.hibernate.sql.results.graph.entity.EntityInitializer;
import org.hibernate.sql.results.internal.NullValueAssembler; import org.hibernate.sql.results.internal.NullValueAssembler;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState; import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
@ -28,7 +32,7 @@ import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentAccess implements EmbeddableInitializer { public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentAccess implements EmbeddableInitializer {
private final NavigablePath navigablePath; private final NavigablePath navigablePath;
private final EmbeddableValuedModelPart embeddedModelPartDescriptor; private final EmbeddableValuedModelPart embeddedModelPartDescriptor;
private final FetchParentAccess fetchParentAccess; private FetchParentAccess fetchParentAccess;
private final Map<StateArrayContributorMapping, DomainResultAssembler> assemblerMap; private final Map<StateArrayContributorMapping, DomainResultAssembler> assemblerMap;
@ -92,26 +96,27 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
// todo (6.0) : register "parent resolution listener" if the composite is defined for `@Parent` // todo (6.0) : register "parent resolution listener" if the composite is defined for `@Parent`
// something like: // something like:
final SingularAttributeMapping parentInjectionTarget = embeddedModelPartDescriptor.getParentInjectionAttributeMapping(); final PropertyAccess parentInjectionPropertyAccess = embeddedModelPartDescriptor.getParentInjectionAttributePropertyAccess();
if ( parentInjectionTarget != null ) { if ( parentInjectionPropertyAccess != null ) {
getFetchParentAccess().findFirstEntityDescriptorAccess().registerResolutionListener( if ( getFetchParentAccess() != null ) {
// todo (6.0) : this is the legacy behavior getFetchParentAccess().findFirstEntityDescriptorAccess().registerResolutionListener(
// - the first entity is injected as the parent, even if the composite // todo (6.0) : this is the legacy behavior
// is defined on another composite // - the first entity is injected as the parent, even if the composite
owner -> { // is defined on another composite
if ( compositeInstance == null ) { owner -> {
return; if ( compositeInstance == null ) {
return;
}
parentInjectionPropertyAccess.getSetter().set(
compositeInstance,
owner,
rowProcessingState.getSession().getFactory()
);
} }
parentInjectionTarget.getPropertyAccess().getSetter().set( );
compositeInstance, }
owner,
rowProcessingState.getSession().getFactory()
);
}
);
} }
} }
@Override @Override
@ -130,6 +135,33 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
@Override @Override
public void initializeInstance(RowProcessingState rowProcessingState) { public void initializeInstance(RowProcessingState rowProcessingState) {
final PropertyAccess parentInjectionPropertyAccess = embeddedModelPartDescriptor.getParentInjectionAttributePropertyAccess();
if ( parentInjectionPropertyAccess != null && getFetchParentAccess() == null ) {
Initializer initializer = rowProcessingState.resolveInitializer( navigablePath.getParent() );
final Object owner;
if ( initializer instanceof CollectionInitializer ) {
owner = ( (CollectionInitializer) initializer ).getCollectionInstance().getOwner();
}
else if ( initializer instanceof EntityInitializer ) {
owner = ( (EntityInitializer) initializer ).getEntityInstance();
parentInjectionPropertyAccess.getSetter().set(
compositeInstance,
owner,
rowProcessingState.getSession().getFactory()
);
}
else {
throw new NotYetImplementedFor6Exception( getClass() );
}
parentInjectionPropertyAccess.getSetter().set(
compositeInstance,
owner,
rowProcessingState.getSession().getFactory()
);
}
EmbeddableLoadingLogger.INSTANCE.debugf( EmbeddableLoadingLogger.INSTANCE.debugf(
"Initializing composite instance [%s] : %s", "Initializing composite instance [%s] : %s",
navigablePath, navigablePath,

View File

@ -484,7 +484,6 @@ public class EmbeddedTest {
} }
@Test @Test
@FailureExpected(reason = "@Parent annotation mapping has not yet been implemented")
public void testParent(SessionFactoryScope scope) { public void testParent(SessionFactoryScope scope) {
Book book = new Book(); Book book = new Book();
scope.inTransaction( scope.inTransaction(