HHH-9485 - Duplicate Property with AccessType.PROPERTY and MappedSuperclass

This commit is contained in:
Steve Ebersole 2016-02-22 16:35:32 -06:00
parent 8d2de0beaa
commit a5cbe326d6
5 changed files with 156 additions and 6 deletions

View File

@ -1497,8 +1497,17 @@ public final class AnnotationBinder {
private static int addProperty(
PropertyContainer propertyContainer,
XProperty property,
List<PropertyData> annElts,
List<PropertyData> inFlightPropertyDataList,
MetadataBuildingContext context) {
// see if inFlightPropertyDataList already contains a PropertyData for this name,
// and if so, skip it..
for ( PropertyData propertyData : inFlightPropertyDataList ) {
if ( propertyData.getPropertyName().equals( property.getName() ) ) {
// EARLY EXIT!!!
return 0;
}
}
final XClass declaringClass = propertyContainer.getDeclaringClass();
final XClass entity = propertyContainer.getEntityAtStake();
int idPropertyCounter = 0;
@ -1515,7 +1524,7 @@ public final class AnnotationBinder {
*/
final XAnnotatedElement element = propertyAnnotatedElement.getProperty();
if ( element.isAnnotationPresent( Id.class ) || element.isAnnotationPresent( EmbeddedId.class ) ) {
annElts.add( 0, propertyAnnotatedElement );
inFlightPropertyDataList.add( 0, propertyAnnotatedElement );
/**
* The property must be put in hibernate.properties as it's a system wide property. Fixable?
* TODO support true/false/default on the property instead of present / not present
@ -1573,7 +1582,7 @@ public final class AnnotationBinder {
idPropertyCounter++;
}
else {
annElts.add( propertyAnnotatedElement );
inFlightPropertyDataList.add( propertyAnnotatedElement );
}
if ( element.isAnnotationPresent( MapsId.class ) ) {
context.getMetadataCollector().addPropertyAnnotatedWithMapsId( entity, propertyAnnotatedElement );
@ -1597,6 +1606,16 @@ public final class AnnotationBinder {
boolean inSecondPass,
MetadataBuildingContext context,
Map<XClass, InheritanceState> inheritanceStatePerClass) throws MappingException {
if ( entityBinder.isPropertyDefinedInSuperHierarchy( inferredData.getPropertyName() ) ) {
LOG.debugf(
"Skipping attribute [%s : %s] as it was already processed as part of super hierarchy",
inferredData.getClassOrElementName(),
inferredData.getPropertyName()
);
return;
}
/**
* inSecondPass can only be used to apply right away the second pass of a composite-element
* Because it's a value type, there is no bidirectional association, hence second pass

View File

@ -80,7 +80,9 @@ import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.mapping.DependantValue;
import org.hibernate.mapping.Join;
import org.hibernate.mapping.MappedSuperclass;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.RootClass;
import org.hibernate.mapping.SimpleValue;
import org.hibernate.mapping.SingleTableSubclass;
@ -159,6 +161,24 @@ public class EntityBinder {
bindHibernateAnnotation( hibAnn );
}
/**
* For the most part, this is a simple delegation to {@link PersistentClass#isPropertyDefinedInHierarchy},
* after verifying that PersistentClass is indeed set here.
*
* @param name The name of the property to check
*
* @return {@code true} if a property by that given name does already exist in the super hierarchy.
*/
@SuppressWarnings("SimplifiableIfStatement")
public boolean isPropertyDefinedInSuperHierarchy(String name) {
// Yes, yes... persistentClass can be null because EntityBinder can be used
// to bind components as well, of course...
if ( persistentClass == null ) {
return false;
}
return persistentClass.isPropertyDefinedInSuperHierarchy( name );
}
@SuppressWarnings("SimplifiableConditionalExpression")
private void bindHibernateAnnotation(org.hibernate.annotations.Entity hibAnn) {

View File

@ -163,4 +163,51 @@ public class MappedSuperclass {
public void setDeclaredIdentifierMapper(Component identifierMapper) {
this.identifierMapper = identifierMapper;
}
/**
* Check to see if this MappedSuperclass defines a property with the given name.
*
* @param name The property name to check
*
* @return {@code true} if a property with that name exists; {@code false} if not
*/
@SuppressWarnings("WeakerAccess")
public boolean hasProperty(String name) {
final Iterator itr = getDeclaredPropertyIterator();
while ( itr.hasNext() ) {
final Property property = (Property) itr.next();
if ( property.getName().equals( name ) ) {
return true;
}
}
return false;
}
/**
* Check to see if a property with the given name exists in this MappedSuperclass
* or in any of its super hierarchy.
*
* @param name The property name to check
*
* @return {@code true} if a property with that name exists; {@code false} if not
*/
@SuppressWarnings({"WeakerAccess", "RedundantIfStatement"})
public boolean isPropertyDefinedInHierarchy(String name) {
if ( hasProperty( name ) ) {
return true;
}
if ( getSuperMappedSuperclass() != null
&& getSuperMappedSuperclass().isPropertyDefinedInHierarchy( name ) ) {
return true;
}
if ( getSuperPersistentClass() != null
&& getSuperPersistentClass().isPropertyDefinedInHierarchy( name ) ) {
return true;
}
return false;
}
}

View File

@ -22,7 +22,6 @@ import org.hibernate.engine.OptimisticLockStyle;
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.internal.FilterConfiguration;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.EmptyIterator;
import org.hibernate.internal.util.collections.JoinedIterator;
@ -498,6 +497,73 @@ public abstract class PersistentClass implements AttributeContainer, Serializabl
}
}
/**
* Check to see if this PersistentClass defines a property with the given name.
*
* @param name The property name to check
*
* @return {@code true} if a property with that name exists; {@code false} if not
*/
@SuppressWarnings("WeakerAccess")
public boolean hasProperty(String name) {
final Property identifierProperty = getIdentifierProperty();
if ( identifierProperty != null && identifierProperty.getName().equals( name ) ) {
return true;
}
final Iterator itr = getPropertyClosureIterator();
while ( itr.hasNext() ) {
final Property property = (Property) itr.next();
if ( property.getName().equals( name ) ) {
return true;
}
}
return false;
}
/**
* Check to see if a property with the given name exists in the super hierarchy
* of this PersistentClass. Does not check this PersistentClass, just up the
* hierarchy
*
* @param name The property name to check
*
* @return {@code true} if a property with that name exists; {@code false} if not
*/
public boolean isPropertyDefinedInSuperHierarchy(String name) {
return getSuperclass() != null && getSuperclass().isPropertyDefinedInHierarchy( name );
}
/**
* Check to see if a property with the given name exists in this PersistentClass
* or in any of its super hierarchy. Unlike {@link #isPropertyDefinedInSuperHierarchy},
* this method does check this PersistentClass
*
* @param name The property name to check
*
* @return {@code true} if a property with that name exists; {@code false} if not
*/
@SuppressWarnings({"WeakerAccess", "RedundantIfStatement"})
public boolean isPropertyDefinedInHierarchy(String name) {
if ( hasProperty( name ) ) {
return true;
}
if ( getSuperMappedSuperclass() != null
&& getSuperMappedSuperclass().isPropertyDefinedInHierarchy( name ) ) {
return true;
}
if ( getSuperclass() != null
&& getSuperclass().isPropertyDefinedInHierarchy( name ) ) {
return true;
}
return false;
}
/**
* @deprecated prefer {@link #getOptimisticLockStyle}
*/

View File

@ -43,7 +43,6 @@ public class InheritedAttributeOverridingTest extends BaseUnitTestCase {
@Test
@TestForIssue( jiraKey = "HHH-9485" )
@FailureExpected( jiraKey = "HHH-9485" )
public void testInheritedAttributeOverridingMappedsuperclass() {
Metadata metadata = new MetadataSources( standardServiceRegistry )
.addAnnotatedClass( A.class )
@ -55,7 +54,6 @@ public class InheritedAttributeOverridingTest extends BaseUnitTestCase {
@Test
@TestForIssue( jiraKey = "HHH-9485" )
@FailureExpected( jiraKey = "HHH-9485" )
public void testInheritedAttributeOverridingEntity() {
Metadata metadata = new MetadataSources( standardServiceRegistry )
.addAnnotatedClass( C.class )