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.List;
import java.util.UUID;
import java.util.function.BiConsumer;
import java.util.function.Function;
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.dialect.Dialect;
import org.hibernate.engine.jdbc.Size;
import org.hibernate.generator.Generator;
import org.hibernate.id.OptimizableGenerator;
import org.hibernate.id.enhanced.Optimizer;
import org.hibernate.internal.CoreLogging;
@ -27,23 +29,25 @@ import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Contributable;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Selectable;
import org.hibernate.mapping.SimpleValue;
import org.hibernate.mapping.Value;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.SingleTableEntityPersister;
import org.hibernate.generator.Generator;
import org.hibernate.type.BasicType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.spi.TypeConfiguration;
import static org.hibernate.boot.model.internal.BinderHelper.findPropertyByName;
/**
* @author Steve Ebersole
* @author Christian Beikov
@ -198,61 +202,98 @@ public class TemporaryTable implements Exportable, Contributable {
);
}
entityDescriptor.visitSubTypeAttributeMappings(
attribute -> {
if ( attribute instanceof PluralAttributeMapping ) {
final PluralAttributeMapping pluralAttribute = (PluralAttributeMapping) attribute;
if ( pluralAttribute.getSeparateCollectionTable() != null ) {
// Ensure that the FK target columns are available
ForeignKeyDescriptor keyDescriptor = pluralAttribute.getKeyDescriptor();
if ( keyDescriptor == null ) {
// This is expected to happen when processing a
// PostInitCallbackEntry because the callbacks
// 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()
)
);
}
}
);
}
}
}
visitPluralAttributes( entityDescriptor, (pluralAttribute, attributeName) -> {
if ( pluralAttribute.getSeparateCollectionTable() != null ) {
// Ensure that the FK target columns are available
final ForeignKeyDescriptor keyDescriptor = pluralAttribute.getKeyDescriptor();
if ( keyDescriptor == null ) {
// This is expected to happen when processing a
// PostInitCallbackEntry because the callbacks
// 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 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;
}
);
}
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(
EntityMappingType entityDescriptor,
Function<String, String> temporaryTableNameAdjuster,
@ -356,8 +397,9 @@ public class TemporaryTable implements Exportable, Contributable {
entityDescriptor.visitSubTypeAttributeMappings(
attribute -> {
if ( !( attribute instanceof PluralAttributeMapping ) ) {
final SimpleValue value = (SimpleValue) entityBinding.getSubclassProperty( attribute.getAttributeName() )
.getValue();
final PersistentClass declaringClass = runtimeModelCreationContext.getBootModel()
.getEntityBinding( attribute.findContainingEntityMapping().getEntityName() );
final SimpleValue value = (SimpleValue) declaringClass.getProperty( attribute.getAttributeName() ).getValue();
final Iterator<Selectable> columnIterator = value.getConstraintColumnIterator();
attribute.forEachSelectable(
(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 {
final Property identifierProperty = getIdentifierProperty();
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.Test;
import jakarta.persistence.CollectionTable;
import jakarta.persistence.ElementCollection;
import jakarta.persistence.Embeddable;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Inheritance;
import jakarta.persistence.InheritanceType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
@ -31,14 +35,15 @@ import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Marco Belladelli
*/
@DomainModel(annotatedClasses = {
@DomainModel( annotatedClasses = {
JoinedInheritanceSameAttributeNameTest.BaseObj.class,
JoinedInheritanceSameAttributeNameTest.Comment.class,
JoinedInheritanceSameAttributeNameTest.Author.class,
JoinedInheritanceSameAttributeNameTest.Post.class,
JoinedInheritanceSameAttributeNameTest.Author.class
})
JoinedInheritanceSameAttributeNameTest.AuthorEmbedded.class,
} )
@SessionFactory
@JiraKey("HHH-16166")
@JiraKey( "HHH-16166" )
public class JoinedInheritanceSameAttributeNameTest {
@BeforeAll
public void setUp(SessionFactoryScope scope) {
@ -51,6 +56,8 @@ public class JoinedInheritanceSameAttributeNameTest {
session.persist( post );
session.persist( comment );
session.persist( author );
final AuthorEmbedded authorEmbedded = new AuthorEmbedded( "Andrea", "comments" );
session.persist( authorEmbedded );
} );
}
@ -76,8 +83,8 @@ public class JoinedInheritanceSameAttributeNameTest {
} );
}
@Entity(name = "BaseObj")
@Inheritance(strategy = InheritanceType.JOINED)
@Entity( name = "BaseObj" )
@Inheritance( strategy = InheritanceType.JOINED )
public static class BaseObj {
@Id
@GeneratedValue
@ -94,8 +101,8 @@ public class JoinedInheritanceSameAttributeNameTest {
}
}
@Entity(name = "Comment")
@Table(name = "Comments")
@Entity( name = "Comment" )
@Table( name = "Comments" )
public static class Comment extends BaseObj {
@ManyToOne
private Post post;
@ -124,9 +131,9 @@ public class JoinedInheritanceSameAttributeNameTest {
* This sub-entity has the same attribute name
* as {@link Author} but with a different (Collection) type
*/
@Entity(name = "Post")
@Entity( name = "Post" )
public static class Post extends BaseObj {
@OneToMany(mappedBy = "post")
@OneToMany( mappedBy = "post" )
private Set<Comment> comments;
public Post() {
@ -142,7 +149,7 @@ public class JoinedInheritanceSameAttributeNameTest {
* This sub-entity has the same attribute name
* as {@link Post} but with a different (SimpleValue) type
*/
@Entity(name = "Author")
@Entity( name = "Author" )
public static class Author extends BaseObj {
private String comments;
@ -161,4 +168,75 @@ public class JoinedInheritanceSameAttributeNameTest {
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;
}
}
}