Fix ToOneAttributeMapping bidirectionalAttributeName value determination

This commit is contained in:
Andrea Boriero 2021-12-06 14:18:42 +01:00 committed by Andrea Boriero
parent 71204a9e97
commit 7dc70e9350
4 changed files with 65 additions and 34 deletions

View File

@ -31,6 +31,7 @@ import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property; import org.hibernate.mapping.Property;
import org.hibernate.mapping.Selectable; import org.hibernate.mapping.Selectable;
import org.hibernate.mapping.ToOne; import org.hibernate.mapping.ToOne;
import org.hibernate.mapping.Value;
import org.hibernate.metamodel.mapping.AssociationKey; import org.hibernate.metamodel.mapping.AssociationKey;
import org.hibernate.metamodel.mapping.CollectionPart; import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart; import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
@ -236,7 +237,10 @@ public class ToOneAttributeMapping
final Iterator<Property> propertyClosureIterator = entityBinding.getPropertyClosureIterator(); final Iterator<Property> propertyClosureIterator = entityBinding.getPropertyClosureIterator();
while ( propertyClosureIterator.hasNext() ) { while ( propertyClosureIterator.hasNext() ) {
final Property property = propertyClosureIterator.next(); final Property property = propertyClosureIterator.next();
if ( property.getValue() instanceof OneToOne && name.equals( ( (OneToOne) property.getValue() ).getMappedByProperty() ) ) { if ( property.getValue() instanceof OneToOne
&& name.equals( ( (OneToOne) property.getValue() ).getMappedByProperty() )
&& ( (OneToOne) property.getValue() ).getReferencedEntityName().equals(
declaringType.getJavaTypeDescriptor().getJavaType().getTypeName() ) ) {
bidirectionalAttributeName = property.getName(); bidirectionalAttributeName = property.getName();
break; break;
} }
@ -247,7 +251,11 @@ public class ToOneAttributeMapping
final Iterator<Property> propertyClosureIterator = entityBinding.getPropertyClosureIterator(); final Iterator<Property> propertyClosureIterator = entityBinding.getPropertyClosureIterator();
while ( propertyClosureIterator.hasNext() ) { while ( propertyClosureIterator.hasNext() ) {
final Property property = propertyClosureIterator.next(); final Property property = propertyClosureIterator.next();
if ( property.getValue() instanceof Collection && name.equals( ( (Collection) property.getValue() ).getMappedByProperty() ) ) { final Value value = property.getValue();
if ( value instanceof Collection
&& name.equals( ( (Collection) value ).getMappedByProperty() )
&& ( (Collection) value ).getElement().getType().getName()
.equals( declaringType.getJavaTypeDescriptor().getJavaType().getTypeName() ) ) {
bidirectionalAttributeName = property.getName(); bidirectionalAttributeName = property.getName();
break; break;
} }
@ -1046,6 +1054,7 @@ public class ToOneAttributeMapping
final ModelPart bidirectionalModelPart = entityMappingType.findSubPart( bidirectionalAttributeName ); final ModelPart bidirectionalModelPart = entityMappingType.findSubPart( bidirectionalAttributeName );
// Add the inverse association key side as well to be able to resolve to a CircularFetch // Add the inverse association key side as well to be able to resolve to a CircularFetch
if ( bidirectionalModelPart instanceof ToOneAttributeMapping ) { if ( bidirectionalModelPart instanceof ToOneAttributeMapping ) {
assert bidirectionalModelPart.getPartMappingType() == declaringTableGroupProducer;
final ToOneAttributeMapping bidirectionalAttribute = (ToOneAttributeMapping) bidirectionalModelPart; final ToOneAttributeMapping bidirectionalAttribute = (ToOneAttributeMapping) bidirectionalModelPart;
final AssociationKey secondKey = bidirectionalAttribute.getForeignKeyDescriptor().getAssociationKey(); final AssociationKey secondKey = bidirectionalAttribute.getForeignKeyDescriptor().getAssociationKey();
if ( creationState.registerVisitedAssociationKey( secondKey ) ) { if ( creationState.registerVisitedAssociationKey( secondKey ) ) {

View File

@ -15,6 +15,7 @@ import org.hibernate.PropertyAccessException;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.ReflectHelper; import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.property.access.internal.AbstractFieldSerialForm; import org.hibernate.property.access.internal.AbstractFieldSerialForm;
import org.hibernate.proxy.HibernateProxy;
/** /**
* Field-based implementation of Setter * Field-based implementation of Setter
@ -67,15 +68,19 @@ public class SetterFieldImpl implements Setter {
); );
} }
else { else {
final String valueType;
if ( value instanceof HibernateProxy ) {
valueType = ( (HibernateProxy) value ).getHibernateLazyInitializer().getEntityName();
}
else {
valueType = value.getClass().getTypeName();
}
throw new PropertyAccessException( throw new PropertyAccessException(
e, e,
String.format( String.format(
Locale.ROOT, Locale.ROOT,
"Could not set value [%s (`%s`)] by reflection", "Could not set value of type [%s]",
value, valueType
value == null ? "<null>" : value.getClass().getTypeName(),
containerClass == null ? "<dynamic>" : containerClass.getTypeName(),
propertyName
), ),
true, true,
containerClass, containerClass,

View File

@ -8,7 +8,6 @@ package org.hibernate.sql.results.graph;
import java.util.List; import java.util.List;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.metamodel.mapping.AssociationKey; import org.hibernate.metamodel.mapping.AssociationKey;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor; import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.ModelPart;
@ -50,9 +49,7 @@ public interface DomainResultCreationState {
* Resolve the ModelPart associated with a given NavigablePath. More specific ModelParts should be preferred - e.g. * Resolve the ModelPart associated with a given NavigablePath. More specific ModelParts should be preferred - e.g.
* the SingularAssociationAttributeMapping rather than just the EntityTypeMapping for the associated type * the SingularAssociationAttributeMapping rather than just the EntityTypeMapping for the associated type
*/ */
default ModelPart resolveModelPart(NavigablePath navigablePath) { ModelPart resolveModelPart(NavigablePath navigablePath);
throw new NotYetImplementedFor6Exception( getClass() );
}
/** /**
* Visit fetches for the given parent. * Visit fetches for the given parent.

View File

@ -6,8 +6,11 @@
*/ */
package org.hibernate.orm.test.loading; package org.hibernate.orm.test.loading;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.hibernate.testing.orm.junit.DomainModel;
import org.junit.Test; import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.Id; import jakarta.persistence.Id;
@ -15,16 +18,19 @@ import jakarta.persistence.OneToOne;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
public class LoadContainedInDoubleContainingTest extends BaseCoreFunctionalTestCase { @DomainModel(
annotatedClasses = {
@Override LoadContainedInDoubleContainingTest.Containing.class,
protected Class<?>[] getAnnotatedClasses() { LoadContainedInDoubleContainingTest.OtherContained.class,
return new Class[] { Containing.class, OtherContained.class, Contained.class }; LoadContainedInDoubleContainingTest.Contained.class
} }
)
@SessionFactory
public class LoadContainedInDoubleContainingTest {
@Test @BeforeEach
public void test() { public void setUp(SessionFactoryScope scope) {
inTransaction( session -> { scope.inTransaction( session -> {
Containing containing = new Containing( 1, "initial" ); Containing containing = new Containing( 1, "initial" );
OtherContained otherContained = new OtherContained( 2, "initial" ); OtherContained otherContained = new OtherContained( 2, "initial" );
containing.setOtherContained( otherContained ); containing.setOtherContained( otherContained );
@ -32,19 +38,20 @@ public class LoadContainedInDoubleContainingTest extends BaseCoreFunctionalTestC
session.persist( containing ); session.persist( containing );
session.persist( otherContained ); session.persist( otherContained );
} ); } );
}
inTransaction( session -> { @Test
OtherContained entity = session.load( OtherContained.class, 2 ); public void test(SessionFactoryScope scope) {
String text = entity.getText(); scope.inTransaction( session -> {
OtherContained otherContained = session.load( OtherContained.class, 2 );
String text = otherContained.getText();
assertThat( text ).isEqualTo( "initial" ); assertThat( text ).isEqualTo( "initial" );
} ); } );
} }
@Entity(name = Containing.NAME) @Entity(name = "Containing")
public static class Containing { public static class Containing {
static final String NAME = "Containing";
@Id @Id
private Integer id; private Integer id;
private String text; private String text;
@ -69,34 +76,39 @@ public class LoadContainedInDoubleContainingTest extends BaseCoreFunctionalTestC
public Integer getId() { public Integer getId() {
return id; return id;
} }
public void setId(Integer id) { public void setId(Integer id) {
this.id = id; this.id = id;
} }
public String getText() { public String getText() {
return text; return text;
} }
public void setText(String text) { public void setText(String text) {
this.text = text; this.text = text;
} }
public Contained getContained() { public Contained getContained() {
return contained; return contained;
} }
public void setContained(Contained contained) { public void setContained(Contained contained) {
this.contained = contained; this.contained = contained;
} }
public OtherContained getOtherContained() { public OtherContained getOtherContained() {
return otherContained; return otherContained;
} }
public void setOtherContained(OtherContained otherContained) { public void setOtherContained(OtherContained otherContained) {
this.otherContained = otherContained; this.otherContained = otherContained;
} }
} }
@Entity(name = Contained.NAME) @Entity(name = "Contained")
public static class Contained { public static class Contained {
static final String NAME = "Contained";
@Id @Id
private Integer id; private Integer id;
private String text; private String text;
@ -115,28 +127,31 @@ public class LoadContainedInDoubleContainingTest extends BaseCoreFunctionalTestC
public Integer getId() { public Integer getId() {
return id; return id;
} }
public void setId(Integer id) { public void setId(Integer id) {
this.id = id; this.id = id;
} }
public String getText() { public String getText() {
return text; return text;
} }
public void setText(String text) { public void setText(String text) {
this.text = text; this.text = text;
} }
public Containing getContaining() { public Containing getContaining() {
return containing; return containing;
} }
public void setContaining(Containing containing) { public void setContaining(Containing containing) {
this.containing = containing; this.containing = containing;
} }
} }
@Entity(name = OtherContained.NAME) @Entity(name = "OtherContained")
public static class OtherContained { public static class OtherContained {
static final String NAME = "OtherContained";
@Id @Id
private Integer id; private Integer id;
private String text; private String text;
@ -155,18 +170,23 @@ public class LoadContainedInDoubleContainingTest extends BaseCoreFunctionalTestC
public Integer getId() { public Integer getId() {
return id; return id;
} }
public void setId(Integer id) { public void setId(Integer id) {
this.id = id; this.id = id;
} }
public String getText() { public String getText() {
return text; return text;
} }
public void setText(String text) { public void setText(String text) {
this.text = text; this.text = text;
} }
public Containing getContaining() { public Containing getContaining() {
return containing; return containing;
} }
public void setContaining(Containing containing) { public void setContaining(Containing containing) {
this.containing = containing; this.containing = containing;
} }