HHH-12375 Fix for eager loading same named properties with conflicting types

This commit is contained in:
Christian Beikov 2018-03-09 21:18:50 +01:00 committed by Andrea Boriero
parent c56b6d7dc7
commit c8217d9f09
3 changed files with 126 additions and 14 deletions

View File

@ -152,9 +152,9 @@ 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 ) { if ( existingType != null || typesByPropertyPath.containsKey( 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 || !( type instanceof AssociationType ) ) { if ( type == existingType || existingType == null || !( type instanceof AssociationType ) ) {
logDuplicateRegistration( logDuplicateRegistration(
path, path,
existingType, existingType,
@ -173,12 +173,12 @@ public abstract class AbstractPropertyMapping implements PropertyMapping {
return; return;
} }
Type newType; Type newType = null;
MetadataImplementor metadata = (MetadataImplementor) factory; MetadataImplementor metadata = (MetadataImplementor) factory;
if ( type instanceof AnyType ) { if ( type instanceof AnyType ) {
// TODO: not sure how to handle any types // TODO: not sure how to handle any types. For now we just return and let the first type dictate what type the property has...
throw new UnsupportedOperationException( "Not yet implemented!" ); return;
} }
else if ( type instanceof CollectionType ) { else if ( type instanceof CollectionType ) {
Collection thisCollection = metadata.getCollectionBinding( ( (CollectionType) existingType ).getRole() ); Collection thisCollection = metadata.getCollectionBinding( ( (CollectionType) existingType ).getRole() );
@ -193,7 +193,7 @@ public abstract class AbstractPropertyMapping implements PropertyMapping {
return; return;
} }
// When we discover incompatible types, we register "null" as property type to signal that the property is not resolvable on the parent type // When we discover incompatible types, we use "null" as property type to signal that the property is not resolvable on the parent type
newType = null; newType = null;
if ( LOG.isTraceEnabled() ) { if ( LOG.isTraceEnabled() ) {
LOG.tracev( LOG.tracev(
@ -220,9 +220,6 @@ public abstract class AbstractPropertyMapping implements PropertyMapping {
newType = getCommonType( metadata, entityType1, entityType2 ); newType = getCommonType( metadata, entityType1, entityType2 );
} }
else {
throw new IllegalStateException( "Unexpected association type: " + type );
}
typesByPropertyPath.put( path, newType ); typesByPropertyPath.put( path, newType );
// Set everything to empty to signal action has to be taken! // Set everything to empty to signal action has to be taken!

View File

@ -13,6 +13,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.PropertyPath; import org.hibernate.loader.PropertyPath;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.collection.QueryableCollection; import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.Type; import org.hibernate.type.Type;
@ -90,8 +91,9 @@ public class MetamodelGraphWalker {
private void visitEntityDefinition(EntityDefinition entityDefinition) { private void visitEntityDefinition(EntityDefinition entityDefinition) {
strategy.startingEntity( entityDefinition ); strategy.startingEntity( entityDefinition );
AbstractEntityPersister persister = (AbstractEntityPersister) entityDefinition.getEntityPersister();
visitIdentifierDefinition( entityDefinition.getEntityKeyDefinition() ); visitIdentifierDefinition( entityDefinition.getEntityKeyDefinition() );
visitAttributes( entityDefinition ); visitAttributes( entityDefinition, persister);
strategy.finishingEntity( entityDefinition ); strategy.finishingEntity( entityDefinition );
} }
@ -122,17 +124,17 @@ public class MetamodelGraphWalker {
strategy.finishingEntityIdentifier( identifierDefinition ); strategy.finishingEntityIdentifier( identifierDefinition );
} }
private void visitAttributes(AttributeSource attributeSource) { private void visitAttributes(AttributeSource attributeSource, AbstractEntityPersister sourcePersister) {
final Iterable<AttributeDefinition> attributeDefinitions = attributeSource.getAttributes(); final Iterable<AttributeDefinition> attributeDefinitions = attributeSource.getAttributes();
if ( attributeDefinitions == null ) { if ( attributeDefinitions == null ) {
return; return;
} }
for ( AttributeDefinition attributeDefinition : attributeDefinitions ) { for ( AttributeDefinition attributeDefinition : attributeDefinitions ) {
visitAttributeDefinition( attributeDefinition ); visitAttributeDefinition( attributeDefinition, sourcePersister);
} }
} }
private void visitAttributeDefinition(AttributeDefinition attributeDefinition) { private void visitAttributeDefinition(AttributeDefinition attributeDefinition, AbstractEntityPersister sourcePersister) {
final PropertyPath subPath = currentPropertyPath.append( attributeDefinition.getName() ); final PropertyPath subPath = currentPropertyPath.append( attributeDefinition.getName() );
log.debug( "Visiting attribute path : " + subPath.getFullPath() ); log.debug( "Visiting attribute path : " + subPath.getFullPath() );
@ -147,6 +149,14 @@ public class MetamodelGraphWalker {
// EARLY EXIT!!! // EARLY EXIT!!!
return; return;
} }
if ( sourcePersister != null ) {
String[] columns = sourcePersister.toColumns(attributeDefinition.getName());
// Empty columns means that the attribute is not resolvable on this persister
if ( columns.length == 0 ) {
return;
}
}
} }
@ -196,7 +206,7 @@ public class MetamodelGraphWalker {
private void visitCompositeDefinition(CompositionDefinition compositionDefinition) { private void visitCompositeDefinition(CompositionDefinition compositionDefinition) {
strategy.startingComposite( compositionDefinition ); strategy.startingComposite( compositionDefinition );
visitAttributes( compositionDefinition ); visitAttributes( compositionDefinition, null );
strategy.finishingComposite( compositionDefinition ); strategy.finishingComposite( compositionDefinition );
} }

View File

@ -0,0 +1,105 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2014, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.inheritance.discriminator;
import org.hibernate.Session;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Assert;
import org.junit.Test;
import javax.persistence.*;
import java.util.Set;
/**
* Test cases for joined inheritance with eager fetching.
*
* @author Christian Beikov
*/
public class JoinedInheritanceEagerTest extends BaseCoreFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] {
BaseEntity.class,
EntityA.class,
EntityB.class,
EntityC.class,
EntityD.class
};
}
@Test
@TestForIssue( jiraKey = "HHH-12375" )
public void joinUnrelatedCollectionOnBaseType() {
final Session s = openSession();
s.getTransaction().begin();
try {
s.createQuery("from BaseEntity b join b.attributes").list();
Assert.fail("Expected a resolution exception for property 'attributes'!");
} catch (IllegalArgumentException ex) {
Assert.assertTrue(ex.getMessage().contains("could not resolve property: attributes "));
} finally {
s.getTransaction().commit();
s.close();
}
}
@Entity(name = "BaseEntity")
@Inheritance(strategy = InheritanceType.JOINED)
public static class BaseEntity {
@Id
private long id;
}
@Entity(name = "EntityA")
public static class EntityA extends BaseEntity {
@OneToMany(fetch = FetchType.LAZY)
private Set<EntityC> attributes;
@ManyToOne(fetch = FetchType.EAGER)
private EntityC relation;
}
@Entity(name = "EntityB")
public static class EntityB extends BaseEntity {
@OneToMany(fetch = FetchType.LAZY)
private Set<EntityD> attributes;
@ManyToOne(fetch = FetchType.EAGER)
private EntityD relation;
}
@Entity(name = "EntityC")
public static class EntityC {
@Id
private long id;
}
@Entity(name = "EntityD")
public static class EntityD {
@Id
private long id;
}
}