HHH-12375 - HHH-12383 - Remove path from AbstractPropertyMapping#typesByPropertyPath for imcompatible type properties

This commit is contained in:
Andrea Boriero 2018-03-16 19:40:20 +00:00
parent 47d3c13aa6
commit dcc188efc5
1 changed files with 73 additions and 81 deletions

View File

@ -7,7 +7,9 @@
package org.hibernate.persister.entity; package org.hibernate.persister.entity;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.QueryException; import org.hibernate.QueryException;
@ -17,7 +19,8 @@ import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.ArrayHelper; import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.mapping.*; import org.hibernate.mapping.Collection;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.sql.Template; import org.hibernate.sql.Template;
import org.hibernate.type.AnyType; import org.hibernate.type.AnyType;
import org.hibernate.type.AssociationType; import org.hibernate.type.AssociationType;
@ -37,11 +40,12 @@ import org.hibernate.type.Type;
public abstract class AbstractPropertyMapping implements PropertyMapping { public abstract class AbstractPropertyMapping implements PropertyMapping {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( AbstractPropertyMapping.class ); private static final CoreMessageLogger LOG = CoreLogging.messageLogger( AbstractPropertyMapping.class );
private final Map<String, Type> typesByPropertyPath = new HashMap<String, Type>(); private final Map<String, Type> typesByPropertyPath = new HashMap<>();
private final Map<String, String[]> columnsByPropertyPath = new HashMap<String, String[]>(); private final Set<String> duplicateIncompatiblePaths = new HashSet<>();
private final Map<String, String[]> columnReadersByPropertyPath = new HashMap<String, String[]>(); private final Map<String, String[]> columnsByPropertyPath = new HashMap<>();
private final Map<String, String[]> columnReaderTemplatesByPropertyPath = new HashMap<String, String[]>(); private final Map<String, String[]> columnReadersByPropertyPath = new HashMap<>();
private final Map<String, String[]> formulaTemplatesByPropertyPath = new HashMap<String, String[]>(); private final Map<String, String[]> columnReaderTemplatesByPropertyPath = new HashMap<>();
private final Map<String, String[]> formulaTemplatesByPropertyPath = new HashMap<>();
public String[] getIdentifierColumnNames() { public String[] getIdentifierColumnNames() {
throw new UnsupportedOperationException( "one-to-one is not supported here" ); throw new UnsupportedOperationException( "one-to-one is not supported here" );
@ -130,7 +134,7 @@ public abstract class AbstractPropertyMapping implements PropertyMapping {
private void logIncompatibleRegistration(String path, Type existingType, Type type) { private void logIncompatibleRegistration(String path, Type existingType, Type type) {
if ( LOG.isTraceEnabled() ) { if ( LOG.isTraceEnabled() ) {
LOG.tracev( LOG.tracev(
"Skipped adding same named type incompatible property to base type [{0}] for property [{1}], existing type = [{2}], incoming type = [{3}]", "Skipped adding attribute [{1}] to base-type [{0}] as more than one sub-type defined the attribute using incompatible types (strictly speaking the attributes are not inherited); existing type = [{2}], incoming type = [{3}]",
getEntityName(), getEntityName(),
path, path,
existingType, existingType,
@ -164,71 +168,52 @@ public abstract class AbstractPropertyMapping implements PropertyMapping {
String[] formulaTemplates, String[] formulaTemplates,
Mapping factory) { Mapping factory) {
Type existingType = typesByPropertyPath.get( path ); Type existingType = typesByPropertyPath.get( path );
if ( existingType != null || typesByPropertyPath.containsKey( path ) ) { if ( existingType != null || duplicateIncompatiblePaths.contains( path ) ) {
// If types match or the new type is not an association type, there is nothing for us to do // If types match or the new type is not an association type, there is nothing for us to do
if ( type == existingType || existingType == null || !( type instanceof AssociationType ) ) { if ( type == existingType || existingType == null || !( type instanceof AssociationType ) ) {
logDuplicateRegistration( logDuplicateRegistration( path, existingType, type );
path,
existingType,
type
);
return;
} }
else if ( !( existingType instanceof AssociationType ) ) {
// Workaround for org.hibernate.cfg.annotations.PropertyBinder.bind() adding a component for *ToOne ids // Workaround for org.hibernate.cfg.annotations.PropertyBinder.bind() adding a component for *ToOne ids
if ( !( existingType instanceof AssociationType ) ) { logDuplicateRegistration( path, existingType, type );
logDuplicateRegistration(
path,
existingType,
type
);
return;
} }
else {
Type newType = null;
MetadataImplementor metadata = (MetadataImplementor) factory;
if ( type instanceof AnyType && existingType instanceof AnyType ) { if ( type instanceof AnyType && existingType instanceof AnyType ) {
// TODO: not sure how to handle any types. For now we just return and let the first type dictate what type the property has... // TODO: not sure how to handle any types. For now we just return and let the first type dictate what type the property has...
return;
} }
else if ( type instanceof CollectionType && existingType instanceof CollectionType ) { else {
Type commonType = null;
MetadataImplementor metadata = (MetadataImplementor) factory;
if ( type instanceof CollectionType && existingType instanceof CollectionType ) {
Collection thisCollection = metadata.getCollectionBinding( ( (CollectionType) existingType ).getRole() ); Collection thisCollection = metadata.getCollectionBinding( ( (CollectionType) existingType ).getRole() );
Collection otherCollection = metadata.getCollectionBinding( ( (CollectionType) type ).getRole() ); Collection otherCollection = metadata.getCollectionBinding( ( (CollectionType) type ).getRole() );
if ( thisCollection.isSame( otherCollection ) ) { if ( thisCollection.isSame( otherCollection ) ) {
logDuplicateRegistration( logDuplicateRegistration( path, existingType, type );
path,
existingType,
type
);
return; return;
} }
else {
// When we discover incompatible types, we use "null" as property type to signal that the property is not resolvable on the parent type logIncompatibleRegistration( path, existingType, type );
newType = null; }
logIncompatibleRegistration(path, existingType, type);
} }
else if ( type instanceof EntityType && existingType instanceof EntityType ) { else if ( type instanceof EntityType && existingType instanceof EntityType ) {
EntityType entityType1 = (EntityType) existingType; EntityType entityType1 = (EntityType) existingType;
EntityType entityType2 = (EntityType) type; EntityType entityType2 = (EntityType) type;
if ( entityType1.getAssociatedEntityName().equals( entityType2.getAssociatedEntityName() ) ) { if ( entityType1.getAssociatedEntityName().equals( entityType2.getAssociatedEntityName() ) ) {
logDuplicateRegistration( logDuplicateRegistration( path, existingType, type );
path,
existingType,
type
);
return; return;
} }
else {
newType = getCommonType( metadata, entityType1, entityType2 ); commonType = getCommonType( metadata, entityType1, entityType2 );
}
} }
else { else {
logIncompatibleRegistration(path, existingType, type); logIncompatibleRegistration( path, existingType, type );
} }
if ( commonType == null ) {
typesByPropertyPath.put( path, newType ); duplicateIncompatiblePaths.add( path );
typesByPropertyPath.remove( path );
// Set everything to empty to signal action has to be taken! // Set everything to empty to signal action has to be taken!
// org.hibernate.hql.internal.ast.tree.DotNode.dereferenceEntityJoin() is reacting to this // org.hibernate.hql.internal.ast.tree.DotNode.dereferenceEntityJoin() is reacting to this
String[] empty = new String[0]; String[] empty = new String[0];
@ -238,8 +223,14 @@ public abstract class AbstractPropertyMapping implements PropertyMapping {
if ( formulaTemplates != null ) { if ( formulaTemplates != null ) {
formulaTemplatesByPropertyPath.put( path, empty ); formulaTemplatesByPropertyPath.put( path, empty );
} }
return;
} }
else {
typesByPropertyPath.put( path, commonType );
}
}
}
}
else {
typesByPropertyPath.put( path, type ); typesByPropertyPath.put( path, type );
columnsByPropertyPath.put( path, columns ); columnsByPropertyPath.put( path, columns );
columnReadersByPropertyPath.put( path, columnReaders ); columnReadersByPropertyPath.put( path, columnReaders );
@ -248,6 +239,7 @@ public abstract class AbstractPropertyMapping implements PropertyMapping {
formulaTemplatesByPropertyPath.put( path, formulaTemplates ); formulaTemplatesByPropertyPath.put( path, formulaTemplates );
} }
} }
}
private Type getCommonType(MetadataImplementor metadata, EntityType entityType1, EntityType entityType2) { private Type getCommonType(MetadataImplementor metadata, EntityType entityType1, EntityType entityType2) {
PersistentClass thisClass = metadata.getEntityBinding( entityType1.getAssociatedEntityName() ); PersistentClass thisClass = metadata.getEntityBinding( entityType1.getAssociatedEntityName() );