HHH-8722 HHH-8723 : Reorg AbstractLoadPlanBuildingAssociationVisitationStrategy and add Any support

This commit is contained in:
Gail Badner 2013-11-18 21:44:06 -08:00
parent 4e6f3a9753
commit de7cddc879
5 changed files with 121 additions and 32 deletions

View File

@ -390,6 +390,7 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
final Type attributeType = attributeDefinition.getType(); final Type attributeType = attributeDefinition.getType();
final boolean isAnyType = attributeType.isAnyType();
final boolean isComponentType = attributeType.isComponentType(); final boolean isComponentType = attributeType.isComponentType();
final boolean isAssociationType = attributeType.isAssociationType(); final boolean isAssociationType = attributeType.isAssociationType();
final boolean isBasicType = ! ( isComponentType || isAssociationType ); final boolean isBasicType = ! ( isComponentType || isAssociationType );
@ -397,6 +398,11 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
if ( isBasicType ) { if ( isBasicType ) {
return true; return true;
} }
else if ( isAnyType ) {
// If isAnyType is true, then isComponentType and isAssociationType will also be true
// so need to check isAnyType first so that it is handled properly.
return handleAnyAttribute( (AssociationAttributeDefinition) attributeDefinition );
}
else if ( isAssociationType ) { else if ( isAssociationType ) {
return handleAssociationAttribute( (AssociationAttributeDefinition) attributeDefinition ); return handleAssociationAttribute( (AssociationAttributeDefinition) attributeDefinition );
} }
@ -553,7 +559,11 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
} }
@Override @Override
public void foundAny(AssociationAttributeDefinition attributeDefinition, AnyMappingDefinition anyDefinition) { public void foundAny(AnyMappingDefinition anyDefinition) {
// do nothing.
}
protected boolean handleAnyAttribute(AssociationAttributeDefinition attributeDefinition) {
// for ANY mappings we need to build a Fetch: // for ANY mappings we need to build a Fetch:
// 1) fetch type is SELECT, timing might be IMMEDIATE or DELAYED depending on whether it was defined as lazy // 1) fetch type is SELECT, timing might be IMMEDIATE or DELAYED depending on whether it was defined as lazy
// 2) (because the fetch cannot be a JOIN...) do not push it to the stack // 2) (because the fetch cannot be a JOIN...) do not push it to the stack
@ -564,10 +574,12 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
fetchOwner.buildAnyFetch( fetchOwner.buildAnyFetch(
attributeDefinition, attributeDefinition,
anyDefinition, attributeDefinition.toAnyDefinition(),
fetchStrategy, fetchStrategy,
this this
); );
return false;
} }
protected boolean handleCompositeAttribute(CompositionDefinition attributeDefinition) { protected boolean handleCompositeAttribute(CompositionDefinition attributeDefinition) {

View File

@ -25,7 +25,9 @@ package org.hibernate.loader.plan2.build.spi;
import java.util.ArrayDeque; import java.util.ArrayDeque;
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.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.jboss.logging.MDC; import org.jboss.logging.MDC;
@ -91,6 +93,8 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
private final ArrayDeque<ExpandingFetchSource> fetchSourceStack = new ArrayDeque<ExpandingFetchSource>(); private final ArrayDeque<ExpandingFetchSource> fetchSourceStack = new ArrayDeque<ExpandingFetchSource>();
private final Set<AttributeDefinition> pushedAttributes = new HashSet<AttributeDefinition>( );
protected AbstractLoadPlanBuildingAssociationVisitationStrategy(SessionFactoryImplementor sessionFactory) { protected AbstractLoadPlanBuildingAssociationVisitationStrategy(SessionFactoryImplementor sessionFactory) {
this.sessionFactory = sessionFactory; this.sessionFactory = sessionFactory;
this.querySpaces = new QuerySpacesImpl( sessionFactory ); this.querySpaces = new QuerySpacesImpl( sessionFactory );
@ -151,6 +155,7 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
propertyPathStack.pop(); propertyPathStack.pop();
MDC.remove( MDC_KEY ); MDC.remove( MDC_KEY );
fetchSourceStack.clear(); fetchSourceStack.clear();
pushedAttributes.clear();
} }
@ -198,6 +203,15 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
@Override @Override
public void finishingEntity(EntityDefinition entityDefinition) { public void finishingEntity(EntityDefinition entityDefinition) {
final boolean isRoot = fetchSourceStack.size() == 1 && collectionReferenceStack.isEmpty();
if ( !isRoot ) {
return;
}
popEntityFromStack( entityDefinition );
}
private void popEntityFromStack(EntityDefinition entityDefinition) {
// pop the current fetch owner, and make sure what we just popped represents this entity // pop the current fetch owner, and make sure what we just popped represents this entity
final ExpandingFetchSource fetchSource = popFromStack(); final ExpandingFetchSource fetchSource = popFromStack();
@ -370,10 +384,19 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
@Override @Override
public void finishingCollection(CollectionDefinition collectionDefinition) { public void finishingCollection(CollectionDefinition collectionDefinition) {
final boolean isRoot = fetchSourceStack.isEmpty() && collectionReferenceStack.size() == 1;
if ( !isRoot ) {
return;
}
popFromCollectionStack( collectionDefinition );
}
private void popFromCollectionStack(CollectionDefinition collectionDefinition) {
// pop the current fetch owner, and make sure what we just popped represents this collection // pop the current fetch owner, and make sure what we just popped represents this collection
final CollectionReference collectionReference = popFromCollectionStack(); final CollectionReference collectionReference = popFromCollectionStack();
if ( ! collectionReference.getCollectionPersister().equals( collectionDefinition.getCollectionPersister() ) ) { if ( ! collectionReference.getCollectionPersister().equals( collectionDefinition.getCollectionPersister() ) ) {
throw new WalkingException( "Mismatched FetchSource from stack on pop" ); throw new WalkingException( "Mismatched CollectionReference from stack on pop" );
} }
log.tracef( log.tracef(
@ -426,14 +449,17 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
return; return;
} }
if ( indexType.isComponentType() ) { if ( indexType.isEntityType() || indexType.isComponentType() ) {
// todo : validate the stack? // todo : validate the stack?
popFromStack(); final ExpandingFetchSource fetchSource = popFromStack();
if ( !CollectionFetchableIndex.class.isInstance( fetchSource ) ) {
throw new WalkingException(
"CollectionReference did not return an expected index graph : " +
indexDefinition.getCollectionDefinition().getCollectionPersister().getRole()
);
}
} }
// entity indexes would be popped during finishingEntity processing
log.tracef( log.tracef(
"%s Finished collection index graph : %s", "%s Finished collection index graph : %s",
StringHelper.repeat( "<<", fetchSourceStack.size() ), StringHelper.repeat( "<<", fetchSourceStack.size() ),
@ -484,19 +510,16 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
return; return;
} }
if ( elementType.isComponentType() ) { if ( elementType.isComponentType() || elementType.isAssociationType()) {
// pop it from the stack // pop it from the stack
final ExpandingFetchSource popped = popFromStack(); final ExpandingFetchSource popped = popFromStack();
// validation // validation
if ( ! CollectionFetchableElement.class.isInstance( popped ) ) { if ( ! CollectionFetchableElement.class.isInstance( popped ) ) {
throw new WalkingException( "Mismatched FetchSource from stack on pop" ); throw new WalkingException( "Mismatched FetchSource from stack on pop" );
} }
} }
// entity indexes would be popped during finishingEntity processing
log.tracef( log.tracef(
"%s Finished collection element graph : %s", "%s Finished collection element graph : %s",
StringHelper.repeat( "<<", fetchSourceStack.size() ), StringHelper.repeat( "<<", fetchSourceStack.size() ),
@ -512,22 +535,22 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
compositionDefinition.getName() compositionDefinition.getName()
); );
if ( fetchSourceStack.isEmpty() ) { if ( fetchSourceStack.isEmpty() && collectionReferenceStack.isEmpty() ) {
throw new HibernateException( "A component cannot be the root of a walk nor a graph" ); throw new HibernateException( "A component cannot be the root of a walk nor a graph" );
} }
final CompositeFetch compositeFetch = currentSource().buildCompositeFetch( compositionDefinition ); //final CompositeFetch compositeFetch = currentSource().buildCompositeFetch( compositionDefinition );
pushToStack( (ExpandingFetchSource) compositeFetch ); //pushToStack( (ExpandingFetchSource) compositeFetch );
} }
@Override @Override
public void finishingComposite(CompositionDefinition compositionDefinition) { public void finishingComposite(CompositionDefinition compositionDefinition) {
// pop the current fetch owner, and make sure what we just popped represents this composition // pop the current fetch owner, and make sure what we just popped represents this composition
final ExpandingFetchSource popped = popFromStack(); //final ExpandingFetchSource popped = popFromStack();
if ( ! CompositeFetch.class.isInstance( popped ) ) { //if ( ! CompositeFetch.class.isInstance( popped ) ) {
throw new WalkingException( "Mismatched FetchSource from stack on pop" ); // throw new WalkingException( "Mismatched FetchSource from stack on pop" );
} //}
log.tracef( log.tracef(
"%s Finishing composite : %s", "%s Finishing composite : %s",
@ -546,6 +569,7 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
final Type attributeType = attributeDefinition.getType(); final Type attributeType = attributeDefinition.getType();
final boolean isAnyType = attributeType.isAnyType();
final boolean isComponentType = attributeType.isComponentType(); final boolean isComponentType = attributeType.isComponentType();
final boolean isAssociationType = attributeType.isAssociationType(); final boolean isAssociationType = attributeType.isAssociationType();
final boolean isBasicType = ! ( isComponentType || isAssociationType ); final boolean isBasicType = ! ( isComponentType || isAssociationType );
@ -553,6 +577,11 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
if ( isBasicType ) { if ( isBasicType ) {
return true; return true;
} }
else if ( isAnyType ) {
// If isAnyType is true, then isComponentType and isAssociationType will also be true
// so need to check isAnyType first so that it is handled properly.
return handleAnyAttribute( (AssociationAttributeDefinition) attributeDefinition );
}
else if ( isAssociationType ) { else if ( isAssociationType ) {
return handleAssociationAttribute( (AssociationAttributeDefinition) attributeDefinition ); return handleAssociationAttribute( (AssociationAttributeDefinition) attributeDefinition );
} }
@ -563,6 +592,46 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
@Override @Override
public void finishingAttribute(AttributeDefinition attributeDefinition) { public void finishingAttribute(AttributeDefinition attributeDefinition) {
if ( pushedAttributes.contains( attributeDefinition ) ) {
final Type attributeType = attributeDefinition.getType();
if ( attributeType.isComponentType() ) {
// pop the current fetch owner, and make sure what we just popped represents this composition
final ExpandingFetchSource popped = popFromStack();
if ( ! CompositeFetch.class.isInstance( popped ) ) {
throw new WalkingException( "Mismatched FetchSource from stack on pop" );
}
}
else if ( attributeType.isAssociationType() ) {
final AssociationAttributeDefinition associationAttributeDefinition =
(AssociationAttributeDefinition) attributeDefinition;
if ( attributeType.isCollectionType() ) {
popFromCollectionStack( associationAttributeDefinition.toCollectionDefinition() );
}
else if ( attributeType.isEntityType() ) {
popEntityFromStack( associationAttributeDefinition.toEntityDefinition() );
}
else {
throw new WalkingException(
String.format(
"Unexpected attribute of type [%s] was pushed: %s",
associationAttributeDefinition.getType(),
associationAttributeDefinition
)
);
}
}
else {
throw new WalkingException(
String.format(
"Unexpected attribute of type [%s] was pushed: %s",
attributeDefinition.getType(),
attributeDefinition
)
);
}
pushedAttributes.remove( attributeDefinition );
}
log.tracef( log.tracef(
"%s Finishing up attribute : %s", "%s Finishing up attribute : %s",
StringHelper.repeat( "<<", fetchSourceStack.size() ), StringHelper.repeat( "<<", fetchSourceStack.size() ),
@ -759,7 +828,11 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
// } // }
@Override @Override
public void foundAny(AssociationAttributeDefinition attributeDefinition, AnyMappingDefinition anyDefinition) { public void foundAny(AnyMappingDefinition anyDefinition) {
// do nothing.
}
protected boolean handleAnyAttribute(AssociationAttributeDefinition attributeDefinition) {
// for ANY mappings we need to build a Fetch: // for ANY mappings we need to build a Fetch:
// 1) fetch type is SELECT, timing might be IMMEDIATE or DELAYED depending on whether it was defined as lazy // 1) fetch type is SELECT, timing might be IMMEDIATE or DELAYED depending on whether it was defined as lazy
// 2) (because the fetch cannot be a JOIN...) do not push it to the stack // 2) (because the fetch cannot be a JOIN...) do not push it to the stack
@ -774,12 +847,13 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
// fetchStrategy, // fetchStrategy,
// this // this
// ); // );
return false;
} }
protected boolean handleCompositeAttribute(CompositionDefinition attributeDefinition) { protected boolean handleCompositeAttribute(CompositionDefinition attributeDefinition) {
// final ExpandingFetchSource currentSource = currentSource(); final CompositeFetch compositeFetch = currentSource().buildCompositeFetch( attributeDefinition );
// final CompositeFetch fetch = currentSource.buildCompositeFetch( attributeDefinition, this ); pushToStack( (ExpandingFetchSource) compositeFetch );
// pushToStack( (ExpandingFetchSource) fetch ); pushedAttributes.add( attributeDefinition );
return true; return true;
} }
@ -814,6 +888,9 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
pushToCollectionStack( fetch ); pushToCollectionStack( fetch );
} }
} }
if ( fetchStrategy.getStyle() == FetchStyle.JOIN ) {
pushedAttributes.add( attributeDefinition );
}
return fetchStrategy.getStyle() == FetchStyle.JOIN; return fetchStrategy.getStyle() == FetchStyle.JOIN;
} }

View File

@ -165,7 +165,7 @@ public interface AssociationVisitationStrategy {
*/ */
public void finishingAttribute(AttributeDefinition attributeDefinition); public void finishingAttribute(AttributeDefinition attributeDefinition);
public void foundAny(AssociationAttributeDefinition attributeDefinition, AnyMappingDefinition anyDefinition); public void foundAny(AnyMappingDefinition anyDefinition);
public void associationKeyRegistered(AssociationKey associationKey); public void associationKeyRegistered(AssociationKey associationKey);
public FetchSource registeredFetchSource(AssociationKey associationKey); public FetchSource registeredFetchSource(AssociationKey associationKey);

View File

@ -128,12 +128,12 @@ public class MetamodelGraphWalker {
final EncapsulatedEntityIdentifierDefinition idAsEncapsulated = (EncapsulatedEntityIdentifierDefinition) identifierDefinition; final EncapsulatedEntityIdentifierDefinition idAsEncapsulated = (EncapsulatedEntityIdentifierDefinition) identifierDefinition;
final AttributeDefinition idAttr = idAsEncapsulated.getAttributeDefinition(); final AttributeDefinition idAttr = idAsEncapsulated.getAttributeDefinition();
if ( CompositionDefinition.class.isInstance( idAttr ) ) { if ( CompositionDefinition.class.isInstance( idAttr ) ) {
visitAttributes( (CompositionDefinition) idAttr ); visitCompositeDefinition( (CompositionDefinition) idAttr );
} }
} }
else { else {
// NonEncapsulatedEntityIdentifierDefinition itself is defined as a CompositionDefinition // NonEncapsulatedEntityIdentifierDefinition itself is defined as a CompositionDefinition
visitAttributes( (NonEncapsulatedEntityIdentifierDefinition) identifierDefinition ); visitCompositeDefinition( (NonEncapsulatedEntityIdentifierDefinition) identifierDefinition );
} }
strategy.finishingEntityIdentifier( identifierDefinition ); strategy.finishingEntityIdentifier( identifierDefinition );
@ -196,7 +196,7 @@ public class MetamodelGraphWalker {
final AssociationAttributeDefinition.AssociationNature nature = attribute.getAssociationNature(); final AssociationAttributeDefinition.AssociationNature nature = attribute.getAssociationNature();
if ( nature == AssociationAttributeDefinition.AssociationNature.ANY ) { if ( nature == AssociationAttributeDefinition.AssociationNature.ANY ) {
visitAnyDefinition( attribute, attribute.toAnyDefinition() ); visitAnyDefinition( attribute.toAnyDefinition() );
} }
else if ( nature == AssociationAttributeDefinition.AssociationNature.COLLECTION ) { else if ( nature == AssociationAttributeDefinition.AssociationNature.COLLECTION ) {
visitCollectionDefinition( attribute.toCollectionDefinition() ); visitCollectionDefinition( attribute.toCollectionDefinition() );
@ -206,8 +206,8 @@ public class MetamodelGraphWalker {
} }
} }
private void visitAnyDefinition(AssociationAttributeDefinition attributeDefinition, AnyMappingDefinition anyDefinition) { private void visitAnyDefinition(AnyMappingDefinition anyDefinition) {
strategy.foundAny( attributeDefinition, anyDefinition ); strategy.foundAny( anyDefinition );
} }
private void visitCompositeDefinition(CompositionDefinition compositionDefinition) { private void visitCompositeDefinition(CompositionDefinition compositionDefinition) {
@ -241,7 +241,7 @@ public class MetamodelGraphWalker {
try { try {
final Type collectionIndexType = collectionIndexDefinition.getType(); final Type collectionIndexType = collectionIndexDefinition.getType();
if ( collectionIndexType.isComponentType() ) { if ( collectionIndexType.isComponentType() ) {
visitAttributes( collectionIndexDefinition.toCompositeDefinition() ); visitCompositeDefinition( collectionIndexDefinition.toCompositeDefinition() );
} }
else if ( collectionIndexType.isAssociationType() ) { else if ( collectionIndexType.isAssociationType() ) {
visitEntityDefinition( collectionIndexDefinition.toEntityDefinition() ); visitEntityDefinition( collectionIndexDefinition.toEntityDefinition() );
@ -259,7 +259,7 @@ public class MetamodelGraphWalker {
strategy.startingCollectionElements( elementDefinition ); strategy.startingCollectionElements( elementDefinition );
if ( elementDefinition.getType().isComponentType() ) { if ( elementDefinition.getType().isComponentType() ) {
visitAttributes( elementDefinition.toCompositeElementDefinition() ); visitCompositeDefinition( elementDefinition.toCompositeElementDefinition() );
} }
else if ( elementDefinition.getType().isEntityType() ) { else if ( elementDefinition.getType().isEntityType() ) {
if ( ! collectionDefinition.getCollectionPersister().isOneToMany() ) { if ( ! collectionDefinition.getCollectionPersister().isOneToMany() ) {

View File

@ -230,7 +230,7 @@ public class LoggingAssociationVisitationStrategy implements AssociationVisitati
// } // }
@Override @Override
public void foundAny(AssociationAttributeDefinition attributeDefinition, AnyMappingDefinition anyDefinition) { public void foundAny(AnyMappingDefinition anyDefinition) {
// nothing to do // nothing to do
} }