HHH-16166 Change subtype property access and deprecate unused method in PersistentClass

This commit is contained in:
Marco Belladelli 2023-02-22 14:59:27 +01:00 committed by Christian Beikov
parent 06490876d6
commit d6b5357c7b
3 changed files with 185 additions and 64 deletions

View File

@ -10,6 +10,7 @@ import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.function.BiConsumer;
import java.util.function.Function; import java.util.function.Function;
import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.naming.Identifier;
@ -18,6 +19,7 @@ import org.hibernate.boot.model.relational.QualifiedNameParser;
import org.hibernate.boot.model.relational.QualifiedTableName; import org.hibernate.boot.model.relational.QualifiedTableName;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.Size; import org.hibernate.engine.jdbc.Size;
import org.hibernate.generator.Generator;
import org.hibernate.id.OptimizableGenerator; import org.hibernate.id.OptimizableGenerator;
import org.hibernate.id.enhanced.Optimizer; import org.hibernate.id.enhanced.Optimizer;
import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreLogging;
@ -27,23 +29,25 @@ import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Column; import org.hibernate.mapping.Column;
import org.hibernate.mapping.Contributable; import org.hibernate.mapping.Contributable;
import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Selectable; import org.hibernate.mapping.Selectable;
import org.hibernate.mapping.SimpleValue; import org.hibernate.mapping.SimpleValue;
import org.hibernate.mapping.Value;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor; import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
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.PluralAttributeMapping; import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext; import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.SingleTableEntityPersister; import org.hibernate.persister.entity.SingleTableEntityPersister;
import org.hibernate.generator.Generator;
import org.hibernate.type.BasicType; import org.hibernate.type.BasicType;
import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
import static org.hibernate.boot.model.internal.BinderHelper.findPropertyByName;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
* @author Christian Beikov * @author Christian Beikov
@ -198,61 +202,98 @@ public class TemporaryTable implements Exportable, Contributable {
); );
} }
entityDescriptor.visitSubTypeAttributeMappings( visitPluralAttributes( entityDescriptor, (pluralAttribute, attributeName) -> {
attribute -> { if ( pluralAttribute.getSeparateCollectionTable() != null ) {
if ( attribute instanceof PluralAttributeMapping ) { // Ensure that the FK target columns are available
final PluralAttributeMapping pluralAttribute = (PluralAttributeMapping) attribute; final ForeignKeyDescriptor keyDescriptor = pluralAttribute.getKeyDescriptor();
if ( keyDescriptor == null ) {
if ( pluralAttribute.getSeparateCollectionTable() != null ) { // This is expected to happen when processing a
// Ensure that the FK target columns are available // PostInitCallbackEntry because the callbacks
ForeignKeyDescriptor keyDescriptor = pluralAttribute.getKeyDescriptor(); // are not ordered. The exception is caught in
if ( keyDescriptor == null ) { // MappingModelCreationProcess.executePostInitCallbacks()
// This is expected to happen when processing a // and the callback is re-queued.
// PostInitCallbackEntry because the callbacks throw new IllegalStateException( "Not yet ready: " + pluralAttribute );
// are not ordered. The exception is caught in
// MappingModelCreationProcess.executePostInitCallbacks()
// and the callback is re-queued.
throw new IllegalStateException( "Not yet ready: " + pluralAttribute );
}
final ModelPart fkTarget = keyDescriptor.getTargetPart();
if ( !fkTarget.isEntityIdentifierMapping() ) {
final Value value = entityBinding.getSubclassProperty( pluralAttribute.getAttributeName() )
.getValue();
final Iterator<Selectable> columnIterator =
( (Collection) value ).getKey().getColumnIterator();
fkTarget.forEachSelectable(
(columnIndex, selection) -> {
final Selectable selectable = columnIterator.next();
if ( selectable instanceof Column ) {
final Column column = (Column) selectable;
columns.add(
new TemporaryTableColumn(
temporaryTable,
column.getText( dialect ),
selection.getJdbcMapping(),
column.getSqlType(
runtimeModelCreationContext.getMetadata()
),
column.getColumnSize(
dialect,
runtimeModelCreationContext.getMetadata()
),
column.isNullable()
)
);
}
}
);
}
}
}
} }
); final ModelPart fkTarget = keyDescriptor.getTargetPart();
if ( !fkTarget.isEntityIdentifierMapping() ) {
final PersistentClass declaringClass = runtimeModelCreationContext.getBootModel()
.getEntityBinding( pluralAttribute.findContainingEntityMapping().getEntityName() );
final Property property = findPropertyByName( declaringClass, attributeName );
assert property != null;
final Iterator<Selectable> columnIterator = ( (Collection) property.getValue() ).getKey().getColumnIterator();
fkTarget.forEachSelectable(
(columnIndex, selection) -> {
final Selectable selectable = columnIterator.next();
if ( selectable instanceof Column ) {
final Column column = (Column) selectable;
columns.add(
new TemporaryTableColumn(
temporaryTable,
column.getText( dialect ),
selection.getJdbcMapping(),
column.getSqlType(
runtimeModelCreationContext.getMetadata()
),
column.getColumnSize(
dialect,
runtimeModelCreationContext.getMetadata()
),
column.isNullable()
)
);
}
}
);
}
}
} );
return columns; return columns;
} }
); );
} }
private static void visitPluralAttributes(
EntityMappingType entityDescriptor,
BiConsumer<PluralAttributeMapping, String> consumer) {
entityDescriptor.visitSubTypeAttributeMappings(
attribute -> {
if ( attribute instanceof PluralAttributeMapping ) {
consumer.accept( (PluralAttributeMapping) attribute, attribute.getAttributeName() );
}
else if ( attribute instanceof EmbeddedAttributeMapping ) {
visitPluralAttributes(
(EmbeddedAttributeMapping) attribute,
attribute.getAttributeName(),
consumer
);
}
}
);
}
private static void visitPluralAttributes(
EmbeddedAttributeMapping attributeMapping,
String attributeName,
BiConsumer<PluralAttributeMapping, String> consumer) {
attributeMapping.visitSubParts(
modelPart -> {
if ( modelPart instanceof PluralAttributeMapping ) {
final PluralAttributeMapping pluralAttribute = (PluralAttributeMapping) modelPart;
consumer.accept( pluralAttribute, attributeName + "." + pluralAttribute.getAttributeName() );
}
else if ( modelPart instanceof EmbeddedAttributeMapping ) {
final EmbeddedAttributeMapping embeddedAttribute = (EmbeddedAttributeMapping) modelPart;
visitPluralAttributes(
embeddedAttribute,
attributeName + "." + embeddedAttribute.getAttributeName(),
consumer
);
}
},
null
);
}
public static TemporaryTable createEntityTable( public static TemporaryTable createEntityTable(
EntityMappingType entityDescriptor, EntityMappingType entityDescriptor,
Function<String, String> temporaryTableNameAdjuster, Function<String, String> temporaryTableNameAdjuster,
@ -356,8 +397,9 @@ public class TemporaryTable implements Exportable, Contributable {
entityDescriptor.visitSubTypeAttributeMappings( entityDescriptor.visitSubTypeAttributeMappings(
attribute -> { attribute -> {
if ( !( attribute instanceof PluralAttributeMapping ) ) { if ( !( attribute instanceof PluralAttributeMapping ) ) {
final SimpleValue value = (SimpleValue) entityBinding.getSubclassProperty( attribute.getAttributeName() ) final PersistentClass declaringClass = runtimeModelCreationContext.getBootModel()
.getValue(); .getEntityBinding( attribute.findContainingEntityMapping().getEntityName() );
final SimpleValue value = (SimpleValue) declaringClass.getProperty( attribute.getAttributeName() ).getValue();
final Iterator<Selectable> columnIterator = value.getConstraintColumnIterator(); final Iterator<Selectable> columnIterator = value.getConstraintColumnIterator();
attribute.forEachSelectable( attribute.forEachSelectable(
(columnIndex, selection) -> { (columnIndex, selection) -> {

View File

@ -644,6 +644,7 @@ public abstract class PersistentClass implements IdentifiableTypeClass, Attribut
} }
} }
@Deprecated(since = "6.2")
public Property getSubclassProperty(String propertyName) throws MappingException { public Property getSubclassProperty(String propertyName) throws MappingException {
final Property identifierProperty = getIdentifierProperty(); final Property identifierProperty = getIdentifierProperty();
if ( identifierProperty != null if ( identifierProperty != null

View File

@ -17,11 +17,15 @@ import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import jakarta.persistence.CollectionTable;
import jakarta.persistence.ElementCollection;
import jakarta.persistence.Embeddable;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue; import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.Inheritance; import jakarta.persistence.Inheritance;
import jakarta.persistence.InheritanceType; import jakarta.persistence.InheritanceType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany; import jakarta.persistence.OneToMany;
import jakarta.persistence.Table; import jakarta.persistence.Table;
@ -31,14 +35,15 @@ import static org.assertj.core.api.Assertions.assertThat;
/** /**
* @author Marco Belladelli * @author Marco Belladelli
*/ */
@DomainModel(annotatedClasses = { @DomainModel( annotatedClasses = {
JoinedInheritanceSameAttributeNameTest.BaseObj.class, JoinedInheritanceSameAttributeNameTest.BaseObj.class,
JoinedInheritanceSameAttributeNameTest.Comment.class, JoinedInheritanceSameAttributeNameTest.Comment.class,
JoinedInheritanceSameAttributeNameTest.Author.class,
JoinedInheritanceSameAttributeNameTest.Post.class, JoinedInheritanceSameAttributeNameTest.Post.class,
JoinedInheritanceSameAttributeNameTest.Author.class JoinedInheritanceSameAttributeNameTest.AuthorEmbedded.class,
}) } )
@SessionFactory @SessionFactory
@JiraKey("HHH-16166") @JiraKey( "HHH-16166" )
public class JoinedInheritanceSameAttributeNameTest { public class JoinedInheritanceSameAttributeNameTest {
@BeforeAll @BeforeAll
public void setUp(SessionFactoryScope scope) { public void setUp(SessionFactoryScope scope) {
@ -51,6 +56,8 @@ public class JoinedInheritanceSameAttributeNameTest {
session.persist( post ); session.persist( post );
session.persist( comment ); session.persist( comment );
session.persist( author ); session.persist( author );
final AuthorEmbedded authorEmbedded = new AuthorEmbedded( "Andrea", "comments" );
session.persist( authorEmbedded );
} ); } );
} }
@ -76,8 +83,8 @@ public class JoinedInheritanceSameAttributeNameTest {
} ); } );
} }
@Entity(name = "BaseObj") @Entity( name = "BaseObj" )
@Inheritance(strategy = InheritanceType.JOINED) @Inheritance( strategy = InheritanceType.JOINED )
public static class BaseObj { public static class BaseObj {
@Id @Id
@GeneratedValue @GeneratedValue
@ -94,8 +101,8 @@ public class JoinedInheritanceSameAttributeNameTest {
} }
} }
@Entity(name = "Comment") @Entity( name = "Comment" )
@Table(name = "Comments") @Table( name = "Comments" )
public static class Comment extends BaseObj { public static class Comment extends BaseObj {
@ManyToOne @ManyToOne
private Post post; private Post post;
@ -124,9 +131,9 @@ public class JoinedInheritanceSameAttributeNameTest {
* This sub-entity has the same attribute name * This sub-entity has the same attribute name
* as {@link Author} but with a different (Collection) type * as {@link Author} but with a different (Collection) type
*/ */
@Entity(name = "Post") @Entity( name = "Post" )
public static class Post extends BaseObj { public static class Post extends BaseObj {
@OneToMany(mappedBy = "post") @OneToMany( mappedBy = "post" )
private Set<Comment> comments; private Set<Comment> comments;
public Post() { public Post() {
@ -142,7 +149,7 @@ public class JoinedInheritanceSameAttributeNameTest {
* This sub-entity has the same attribute name * This sub-entity has the same attribute name
* as {@link Post} but with a different (SimpleValue) type * as {@link Post} but with a different (SimpleValue) type
*/ */
@Entity(name = "Author") @Entity( name = "Author" )
public static class Author extends BaseObj { public static class Author extends BaseObj {
private String comments; private String comments;
@ -161,4 +168,75 @@ public class JoinedInheritanceSameAttributeNameTest {
this.comments = comments; this.comments = comments;
} }
} }
@Embeddable
public static class NestedEmbeddable {
@ElementCollection
@CollectionTable(
name = "author_comments",
joinColumns = @JoinColumn( name = "name", referencedColumnName = "name" )
)
private Set<String> comments;
private Integer testProperty;
public NestedEmbeddable() {
comments = new HashSet<>();
}
public Set<String> getComments() {
return comments;
}
public void setComments(Set<String> comments) {
this.comments = comments;
}
public Integer getTestProperty() {
return testProperty;
}
public void setTestProperty(Integer testProperty) {
this.testProperty = testProperty;
}
}
@Embeddable
public static class AuthorEmbeddable {
private NestedEmbeddable nestedEmbeddable;
public AuthorEmbeddable() {
this.nestedEmbeddable = new NestedEmbeddable();
}
public NestedEmbeddable getNestedEmbeddable() {
return nestedEmbeddable;
}
public void setNestedEmbeddable(NestedEmbeddable nestedEmbeddable) {
this.nestedEmbeddable = nestedEmbeddable;
}
}
@Entity( name = "AuthorEmbedded" )
public static class AuthorEmbedded extends BaseObj {
private AuthorEmbeddable authorEmbeddable;
public AuthorEmbedded() {
}
public AuthorEmbedded(String name, String comment) {
setName( name );
this.authorEmbeddable = new AuthorEmbeddable();
this.authorEmbeddable.getNestedEmbeddable().getComments().add( comment );
}
public AuthorEmbeddable getAuthorEmbeddable() {
return authorEmbeddable;
}
public void setAuthorEmbeddable(AuthorEmbeddable authorEmbeddable) {
this.authorEmbeddable = authorEmbeddable;
}
}
} }