HHH-16313 HHH-16313 Check mappedBy type when binding entity associations

This commit is contained in:
Marco Belladelli 2023-03-15 11:40:51 +01:00 committed by Christian Beikov
parent 83894d39ab
commit cdada7a916
4 changed files with 46 additions and 9 deletions

View File

@ -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() + "'"
);
}
}

View File

@ -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;

View File

@ -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(

View File

@ -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;
}
}