HHH-12375 Fix for eager loading same named properties with conflicting types
This commit is contained in:
parent
f030e7f39f
commit
7dd640a65e
|
@ -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!
|
||||||
|
|
|
@ -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 );
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue