HHH-13446 - Validate mapped-by values got from annotations in bytecode enhancers

This commit is contained in:
barreiro 2019-08-25 03:29:15 +01:00 committed by Sanne Grinovero
parent b4a8052a15
commit 1dd787eaa1
4 changed files with 45 additions and 10 deletions

View File

@ -58,9 +58,10 @@ final class BiDirectionalAssociationHandler implements Implementation {
String mappedBy = getMappedBy( persistentField, targetEntity, enhancementContext ); String mappedBy = getMappedBy( persistentField, targetEntity, enhancementContext );
if ( mappedBy == null || mappedBy.isEmpty() ) { if ( mappedBy == null || mappedBy.isEmpty() ) {
log.infof( log.infof(
"Could not find bi-directional association for field [%s#%s]", "Bi-directional association not managed for field [%s#%s]: Could not find target field in [%s]",
managedCtClass.getName(), managedCtClass.getName(),
persistentField.getName() persistentField.getName(),
targetEntity.getCanonicalName()
); );
return implementation; return implementation;
} }
@ -101,7 +102,7 @@ final class BiDirectionalAssociationHandler implements Implementation {
if ( persistentField.getType().asErasure().isAssignableTo( Map.class ) || targetType.isAssignableTo( Map.class ) ) { if ( persistentField.getType().asErasure().isAssignableTo( Map.class ) || targetType.isAssignableTo( Map.class ) ) {
log.infof( log.infof(
"Bi-directional association for field [%s#%s] not managed: @ManyToMany in java.util.Map attribute not supported ", "Bi-directional association not managed for field [%s#%s]: @ManyToMany in java.util.Map attribute not supported ",
managedCtClass.getName(), managedCtClass.getName(),
persistentField.getName() persistentField.getName()
); );
@ -145,7 +146,7 @@ final class BiDirectionalAssociationHandler implements Implementation {
if ( targetClass == null ) { if ( targetClass == null ) {
log.infof( log.infof(
"Could not find type of bi-directional association for field [%s#%s]", "Bi-directional association not managed for field [%s#%s]: Could not find target type",
managedCtClass.getName(), managedCtClass.getName(),
persistentField.getName() persistentField.getName()
); );
@ -183,7 +184,20 @@ final class BiDirectionalAssociationHandler implements Implementation {
return getMappedByManyToMany( target, targetEntity, context ); return getMappedByManyToMany( target, targetEntity, context );
} }
else { else {
return mappedBy; // HHH-13446 - mappedBy from annotation may not be a valid bi-directional association, verify by calling isValidMappedBy()
return isValidMappedBy( target, targetEntity, mappedBy, context ) ? mappedBy : "";
}
}
private static boolean isValidMappedBy(AnnotatedFieldDescription persistentField, TypeDescription targetEntity, String mappedBy, ByteBuddyEnhancementContext context) {
try {
FieldDescription f = FieldLocator.ForClassHierarchy.Factory.INSTANCE.make( targetEntity ).locate( mappedBy ).getField();
AnnotatedFieldDescription annotatedF = new AnnotatedFieldDescription( context, f );
return context.isPersistentField( annotatedF ) && persistentField.getDeclaringType().asErasure().isAssignableTo( entityType( f.getType() ) );
}
catch ( IllegalStateException e ) {
return false;
} }
} }

View File

@ -325,7 +325,7 @@ public class PersistentAttributesEnhancer extends EnhancerImpl {
final CtClass targetEntity = PersistentAttributesHelper.getTargetEntityClass( managedCtClass, persistentField ); final CtClass targetEntity = PersistentAttributesHelper.getTargetEntityClass( managedCtClass, persistentField );
if ( targetEntity == null ) { if ( targetEntity == null ) {
log.infof( log.infof(
"Could not find type of bi-directional association for field [%s#%s]", "Bi-directional association not managed for field [%s#%s]: Could not find target type",
managedCtClass.getName(), managedCtClass.getName(),
persistentField.getName() persistentField.getName()
); );
@ -334,9 +334,10 @@ public class PersistentAttributesEnhancer extends EnhancerImpl {
final String mappedBy = PersistentAttributesHelper.getMappedBy( persistentField, targetEntity, enhancementContext ); final String mappedBy = PersistentAttributesHelper.getMappedBy( persistentField, targetEntity, enhancementContext );
if ( mappedBy == null || mappedBy.isEmpty() ) { if ( mappedBy == null || mappedBy.isEmpty() ) {
log.infof( log.infof(
"Could not find bi-directional association for field [%s#%s]", "Bi-directional association not managed for field [%s#%s]: Could not find target field in [%s]",
managedCtClass.getName(), managedCtClass.getName(),
persistentField.getName() persistentField.getName(),
targetEntity.getName()
); );
return; return;
} }
@ -459,7 +460,7 @@ public class PersistentAttributesEnhancer extends EnhancerImpl {
if ( PersistentAttributesHelper.isAssignable( persistentField.getType(), Map.class.getName() ) || if ( PersistentAttributesHelper.isAssignable( persistentField.getType(), Map.class.getName() ) ||
PersistentAttributesHelper.isAssignable( targetEntity.getField( mappedBy ).getType(), Map.class.getName() ) ) { PersistentAttributesHelper.isAssignable( targetEntity.getField( mappedBy ).getType(), Map.class.getName() ) ) {
log.infof( log.infof(
"Bi-directional association for field [%s#%s] not managed: @ManyToMany in java.util.Map attribute not supported ", "Bi-directional association not managed for field [%s#%s]: @ManyToMany in java.util.Map attribute not supported ",
managedCtClass.getName(), managedCtClass.getName(),
persistentField.getName() persistentField.getName()
); );

View File

@ -209,7 +209,23 @@ public class PersistentAttributesHelper {
public static String getMappedBy(CtField persistentField, CtClass targetEntity, JavassistEnhancementContext context) throws NotFoundException { public static String getMappedBy(CtField persistentField, CtClass targetEntity, JavassistEnhancementContext context) throws NotFoundException {
final String local = getMappedByFromAnnotation( persistentField ); final String local = getMappedByFromAnnotation( persistentField );
return local.isEmpty() ? getMappedByFromTargetEntity( persistentField, targetEntity, context ) : local; if ( local == null || local.isEmpty() ) {
return getMappedByFromTargetEntity( persistentField, targetEntity, context );
}
else {
// HHH-13446 - mappedBy from annotation may not be a valid bi-directional association, verify by calling isValidMappedBy()
return isValidMappedBy( persistentField, targetEntity, local, context ) ? local : "";
}
}
private static boolean isValidMappedBy(CtField persistentField, CtClass targetEntity, String mappedBy, JavassistEnhancementContext context) {
try {
CtField f = targetEntity.getField( mappedBy );
return context.isPersistentField( f ) && isAssignable( persistentField.getDeclaringClass(), inferFieldTypeName( f ) );
}
catch ( NotFoundException e ) {
return false;
}
} }
private static String getMappedByFromAnnotation(CtField persistentField) { private static String getMappedByFromAnnotation(CtField persistentField) {

View File

@ -73,6 +73,10 @@ public class OneToManyAssociationTest {
String name; String name;
// HHH-13446 - Type not validated in bi-directional association mapping
@OneToMany(cascade = CascadeType.ALL, mappedBy = "custId", fetch = FetchType.EAGER)
List<CustomerInventory> inventoryIdList = new ArrayList<>();
@OneToMany( mappedBy = "customer", cascade = CascadeType.ALL, fetch = FetchType.EAGER ) @OneToMany( mappedBy = "customer", cascade = CascadeType.ALL, fetch = FetchType.EAGER )
List<CustomerInventory> customerInventories = new ArrayList<>(); List<CustomerInventory> customerInventories = new ArrayList<>();