From 7f2a3917f458c2e3393c674327808f48b98a87bf Mon Sep 17 00:00:00 2001 From: Marco Belladelli Date: Wed, 15 Mar 2023 11:40:51 +0100 Subject: [PATCH] HHH-16313 HHH-16313 Check mappedBy type when binding entity associations --- .../boot/model/internal/BinderHelper.java | 30 +++++++++++++++++++ .../boot/model/internal/CollectionBinder.java | 17 +++++++---- .../model/internal/OneToOneSecondPass.java | 2 ++ .../PolymorphicAssociationTest2.java | 6 ++-- 4 files changed, 46 insertions(+), 9 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BinderHelper.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BinderHelper.java index 6564f902bf..805a543516 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BinderHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BinderHelper.java @@ -1071,4 +1071,34 @@ public class BinderHelper { public static boolean isDefault(XClass clazz, MetadataBuildingContext context) { return context.getBootstrapContext().getReflectionManager().equals( clazz, void.class ); } + + public static void checkMappedByType( + String mappedBy, + Value targetValue, + String propertyName, + PropertyHolder propertyHolder) { + final ToOne toOne; + if ( targetValue instanceof Collection ) { + toOne = (ToOne) ( (Collection) targetValue ).getElement(); + } + else { + toOne = (ToOne) targetValue; + } + final String referencedEntityName = toOne.getReferencedEntityName(); + PersistentClass referencedClass = propertyHolder.getPersistentClass(); + while ( referencedClass != null ) { + if ( referencedClass.getEntityName().equals( referencedEntityName ) ) { + return; + } + else { + referencedClass = referencedClass.getSuperclass(); + } + } + throw new AnnotationException( + "Association '" + qualify( propertyHolder.getPath(), propertyName ) + + "' is 'mappedBy' a property named '" + mappedBy + + "' which references the wrong entity type '" + referencedEntityName + + "', expected '" + propertyHolder.getEntityName() + "'" + ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java index 3c1ae67e35..fbdefe4722 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java @@ -153,6 +153,7 @@ import static org.hibernate.boot.model.internal.AnnotatedColumn.buildFormulaFrom import static org.hibernate.boot.model.internal.AnnotatedJoinColumns.buildJoinColumnsWithDefaultColumnSuffix; import static org.hibernate.boot.model.internal.AnnotatedJoinColumns.buildJoinTableJoinColumns; import static org.hibernate.boot.model.internal.BinderHelper.buildAnyValue; +import static org.hibernate.boot.model.internal.BinderHelper.checkMappedByType; import static org.hibernate.boot.model.internal.BinderHelper.createSyntheticPropertyReference; import static org.hibernate.boot.model.internal.BinderHelper.getCascadeStrategy; import static org.hibernate.boot.model.internal.BinderHelper.getFetchMode; @@ -171,7 +172,6 @@ import static org.hibernate.internal.util.StringHelper.isEmpty; import static org.hibernate.internal.util.StringHelper.isNotEmpty; import static org.hibernate.internal.util.StringHelper.nullIfEmpty; import static org.hibernate.internal.util.StringHelper.qualify; -import static org.hibernate.internal.util.config.ConfigurationHelper.getBoolean; /** * Base class for stateful binders responsible for producing mapping model objects of type {@link Collection}. @@ -1554,15 +1554,20 @@ public abstract class CollectionBinder { } private boolean isReversePropertyInJoin(XClass elementType, PersistentClass persistentClass) { - if ( persistentClass != null && isUnownedCollection()) { + if ( persistentClass != null && isUnownedCollection() ) { + final Property mappedByProperty; try { - return persistentClass.getJoinNumber( persistentClass.getRecursiveProperty( mappedBy ) ) != 0; + mappedByProperty = persistentClass.getRecursiveProperty( mappedBy ); } catch (MappingException e) { - throw new AnnotationException( "Collection '" + safeCollectionRole() - + "' is 'mappedBy' a property named '" + mappedBy - + "' which does not exist in the target entity '" + elementType.getName() + "'" ); + throw new AnnotationException( + "Collection '" + safeCollectionRole() + + "' is 'mappedBy' a property named '" + mappedBy + + "' which does not exist in the target entity '" + elementType.getName() + "'" + ); } + checkMappedByType( mappedBy, mappedByProperty.getValue(), propertyName, propertyHolder ); + return persistentClass.getJoinNumber( mappedByProperty ) != 0; } else { return false; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/OneToOneSecondPass.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/OneToOneSecondPass.java index 232ec5ec97..9061b5227e 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/OneToOneSecondPass.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/OneToOneSecondPass.java @@ -32,6 +32,7 @@ import org.hibernate.type.ForeignKeyDirection; import jakarta.persistence.ForeignKey; +import static org.hibernate.boot.model.internal.BinderHelper.checkMappedByType; import static org.hibernate.boot.model.internal.BinderHelper.findPropertyByName; import static org.hibernate.boot.model.internal.BinderHelper.getPath; import static org.hibernate.boot.model.internal.ToOneBinder.bindForeignKeyNameAndDefinition; @@ -152,6 +153,7 @@ public class OneToOneSecondPass implements SecondPass { + "' of the target entity type '" + oneToOne.getReferencedEntityName() + "' which is not a '@OneToOne' or '@ManyToOne' association" ); } + checkMappedByType( mappedBy, targetProperty.getValue(), oneToOne.getPropertyName(), propertyHolder ); } private void bindTargetManyToOne( diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/polymorphic/PolymorphicAssociationTest2.java b/hibernate-core/src/test/java/org/hibernate/orm/test/polymorphic/PolymorphicAssociationTest2.java index 00b6923c1f..db535cede3 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/polymorphic/PolymorphicAssociationTest2.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/polymorphic/PolymorphicAssociationTest2.java @@ -152,7 +152,7 @@ public class PolymorphicAssociationTest2 { private String name; @OneToOne(fetch = FetchType.LAZY) - private DerivedLevel2 level2Parent; + private Level2 level2Parent; public Integer getId() { return id; @@ -170,11 +170,11 @@ public class PolymorphicAssociationTest2 { this.name = name; } - public DerivedLevel2 getLevel2Parent() { + public Level2 getLevel2Parent() { return level2Parent; } - public void setLevel2Parent(DerivedLevel2 level2Parent) { + public void setLevel2Parent(Level2 level2Parent) { this.level2Parent = level2Parent; } }