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

This commit is contained in:
Gail Badner 2013-11-19 23:09:14 -08:00
parent eeb5a3f2c2
commit b42b759a0d
1 changed files with 88 additions and 71 deletions

View File

@ -169,12 +169,6 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
@Override
public void startingEntity(EntityDefinition entityDefinition) {
log.tracef(
"%s Starting entity : %s",
StringHelper.repeat( ">>", fetchSourceStack.size() ),
entityDefinition.getEntityPersister().getEntityName()
);
// see if the EntityDefinition is a root...
final boolean isRoot = fetchSourceStack.isEmpty();
if ( ! isRoot ) {
@ -183,6 +177,13 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
}
// if we get here, it is a root
log.tracef(
"%s Starting root entity : %s",
StringHelper.repeat( ">>", fetchSourceStack.size() ),
entityDefinition.getEntityPersister().getEntityName()
);
if ( !supportsRootEntityReturns() ) {
throw new HibernateException( "This strategy does not support root entity returns" );
}
@ -210,13 +211,18 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
}
// if we get here, it is a root
popEntityFromStack( entityDefinition );
final ExpandingFetchSource popped = popFromStack();
checkPoppedEntity( popped, entityDefinition );
log.tracef(
"%s Finished root entity : %s",
StringHelper.repeat( "<<", fetchSourceStack.size() ),
entityDefinition.getEntityPersister().getEntityName()
);
}
private void popEntityFromStack(EntityDefinition entityDefinition) {
// pop the current fetch owner, and make sure what we just popped represents this entity
final ExpandingFetchSource fetchSource = popFromStack();
private void checkPoppedEntity(ExpandingFetchSource fetchSource, EntityDefinition entityDefinition) {
// make sure what we just fetchSource represents entityDefinition
if ( ! EntityReference.class.isInstance( fetchSource ) ) {
throw new WalkingException(
String.format(
@ -232,12 +238,6 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
if ( ! entityReference.getEntityPersister().equals( entityDefinition.getEntityPersister() ) ) {
throw new WalkingException( "Mismatched FetchSource from stack on pop" );
}
log.tracef(
"%s Finished entity : %s",
StringHelper.repeat( "<<", fetchSourceStack.size() ),
entityDefinition.getEntityPersister().getEntityName()
);
}
@ -337,14 +337,12 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
return last;
}
private CollectionReference currentCollection() {
return collectionReferenceStack.peekFirst();
}
@Override
public void startingCollection(CollectionDefinition collectionDefinition) {
log.tracef(
"%s Starting collection : %s",
StringHelper.repeat( ">>", fetchSourceStack.size() ),
collectionDefinition.getCollectionPersister().getRole()
);
// see if the EntityDefinition is a root...
final boolean isRoot = fetchSourceStack.isEmpty();
if ( ! isRoot ) {
@ -352,6 +350,12 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
return;
}
log.tracef(
"%s Starting root collection : %s",
StringHelper.repeat( ">>", fetchSourceStack.size() ),
collectionDefinition.getCollectionPersister().getRole()
);
// if we get here, it is a root
if ( ! supportsRootCollectionReturns() ) {
throw new HibernateException( "This strategy does not support root collection returns" );
@ -377,40 +381,37 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
public void finishingCollection(CollectionDefinition collectionDefinition) {
final boolean isRoot = fetchSourceStack.isEmpty() && collectionReferenceStack.size() == 1;
if ( !isRoot ) {
// if not, this call should represent a fetch which will be handled in #finishingAttribute
return;
}
popFromCollectionStack( collectionDefinition );
}
private void popFromCollectionStack(CollectionDefinition collectionDefinition) {
// pop the current fetch owner, and make sure what we just popped represents this collection
final CollectionReference collectionReference = popFromCollectionStack();
if ( ! collectionReference.getCollectionPersister().equals( collectionDefinition.getCollectionPersister() ) ) {
throw new WalkingException( "Mismatched CollectionReference from stack on pop" );
}
final CollectionReference popped = popFromCollectionStack();
checkedPoppedCollection( popped, collectionDefinition );
log.tracef(
"%s Finished collection : %s",
"%s Finished root collection : %s",
StringHelper.repeat( "<<", fetchSourceStack.size() ),
collectionDefinition.getCollectionPersister().getRole()
);
}
private void checkedPoppedCollection(CollectionReference poppedCollectionReference, CollectionDefinition collectionDefinition) {
// make sure what we just poppedCollectionReference represents collectionDefinition.
if ( ! poppedCollectionReference.getCollectionPersister().equals( collectionDefinition.getCollectionPersister() ) ) {
throw new WalkingException( "Mismatched CollectionReference from stack on pop" );
}
}
@Override
public void startingCollectionIndex(CollectionIndexDefinition indexDefinition) {
final Type indexType = indexDefinition.getType();
if ( indexType.isAnyType() ) {
return;
}
log.tracef(
"%s Starting collection index graph : %s",
StringHelper.repeat( ">>", fetchSourceStack.size() ),
indexDefinition.getCollectionDefinition().getCollectionPersister().getRole()
);
final CollectionReference collectionReference = collectionReferenceStack.peekFirst();
final CollectionReference collectionReference = currentCollection();
final CollectionFetchableIndex indexGraph = collectionReference.getIndexGraph();
if ( indexType.isEntityType() || indexType.isComponentType() ) {
@ -420,7 +421,9 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
indexDefinition.getCollectionDefinition().getCollectionPersister().getRole()
);
}
pushToStack( (ExpandingFetchSource) indexGraph );
if ( !indexType.isAnyType() ) {
pushToStack( (ExpandingFetchSource) indexGraph );
}
}
else {
if ( indexGraph != null ) {
@ -437,10 +440,9 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
final Type indexType = indexDefinition.getType();
if ( indexType.isAnyType() ) {
return;
// nothing to do because the index graph was not pushed in #startingCollectionIndex.
}
if ( indexType.isEntityType() || indexType.isComponentType() ) {
else if ( indexType.isEntityType() || indexType.isComponentType() ) {
// todo : validate the stack?
final ExpandingFetchSource fetchSource = popFromStack();
if ( !CollectionFetchableIndex.class.isInstance( fetchSource ) ) {
@ -467,7 +469,7 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
elementDefinition.getCollectionDefinition().getCollectionPersister().getRole()
);
final CollectionReference collectionReference = collectionReferenceStack.peekFirst();
final CollectionReference collectionReference = currentCollection();
final CollectionFetchableElement elementGraph = collectionReference.getElementGraph();
if ( elementType.isAssociationType() || elementType.isComponentType() ) {
@ -496,7 +498,7 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
final Type elementType = elementDefinition.getType();
if ( elementType.isAnyType() ) {
// nothing to do because the element graph was not pushed
// nothing to do because the element graph was not pushed in #startingCollectionElement..
}
else if ( elementType.isComponentType() || elementType.isAssociationType()) {
// pop it from the stack
@ -526,16 +528,22 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
if ( fetchSourceStack.isEmpty() && collectionReferenceStack.isEmpty() ) {
throw new HibernateException( "A component cannot be the root of a walk nor a graph" );
}
// No need to push anything here; it should have been pushed by
// #startingAttribute, #startingCollectionElements, #startingCollectionIndex, or #startingEntityIdentifier
final FetchSource currentSource = currentSource();
if ( !CompositeFetch.class.isInstance( currentSource ) &&
!CollectionFetchableElement.class.isInstance( currentSource ) &&
!CollectionFetchableIndex.class.isInstance( currentSource ) &&
!ExpandingEntityIdentifierDescription.class.isInstance( currentSource ) ) {
throw new WalkingException( "Mismatched FetchSource from stack on pop" );
}
}
@Override
public void finishingComposite(CompositionDefinition compositionDefinition) {
// 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" );
//}
// No need to pop anything here; it will be popped by
// #finishingAttribute, #finishingCollectionElements, #finishingCollectionIndex, or #finishingEntityIdentifier
log.tracef(
"%s Finishing composite : %s",
@ -543,7 +551,9 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
compositionDefinition.getName()
);
}
protected PropertyPath currentPropertyPath = new PropertyPath( "" );
@Override
public boolean startingAttribute(AttributeDefinition attributeDefinition) {
log.tracef(
@ -574,12 +584,34 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
public void finishingAttribute(AttributeDefinition attributeDefinition) {
final Type attributeType = attributeDefinition.getType();
if ( attributeType.isAnyType() ) {
// If attributeType.isAnyType() is true, then attributeType.isComponentType() and
// attributeType.isAssociationType() will also be true, so need to
// check attributeType.isAnyType() first.
// Nothing to do because AnyFetch does not implement ExpandingFetchSource (i.e., it cannot be pushed/popped).
if ( attributeType.isAssociationType() ) {
final AssociationAttributeDefinition associationAttributeDefinition =
(AssociationAttributeDefinition) attributeDefinition;
if ( attributeType.isAnyType() ) {
// Nothing to do because AnyFetch does not implement ExpandingFetchSource (i.e., it cannot be pushed/popped).
}
else if ( attributeType.isEntityType() ) {
final ExpandingFetchSource source = currentSource();
// One way to find out if the fetch was pushed is to check the fetch strategy; rather than recomputing
// the fetch strategy, simply check if current source's fetched attribute definition matches
// associationAttributeDefinition.
if ( AttributeFetch.class.isInstance( source ) &&
associationAttributeDefinition.equals( AttributeFetch.class.cast( source ).getFetchedAttributeDefinition() ) ) {
final ExpandingFetchSource popped = popFromStack();
checkPoppedEntity( popped, associationAttributeDefinition.toEntityDefinition() );
}
}
else if ( attributeType.isCollectionType() ) {
final CollectionReference currentCollection = currentCollection();
// One way to find out if the fetch was pushed is to check the fetch strategy; rather than recomputing
// the fetch strategy, simply check if current collection's fetched attribute definition matches
// associationAttributeDefinition.
if ( AttributeFetch.class.isInstance( currentCollection ) &&
associationAttributeDefinition.equals( AttributeFetch.class.cast( currentCollection ).getFetchedAttributeDefinition() ) ) {
final CollectionReference popped = popFromCollectionStack();
checkedPoppedCollection( popped, associationAttributeDefinition.toCollectionDefinition() );
}
}
}
else if ( attributeType.isComponentType() ) {
// CompositeFetch is always pushed, during #startingAttribute(),
@ -604,21 +636,6 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
);
}
}
else if ( attributeType.isEntityType() ) {
final ExpandingFetchSource source = currentSource();
if ( AttributeFetch.class.isInstance( source ) &&
attributeDefinition.equals( AttributeFetch.class.cast( source ).getFetchedAttributeDefinition() ) ) {
popEntityFromStack( ( (AssociationAttributeDefinition) attributeDefinition ).toEntityDefinition() );
}
}
else if ( attributeType.isCollectionType() ) {
final CollectionReference currentCollection = collectionReferenceStack.peekFirst();
if ( currentCollection != null &&
AttributeFetch.class.isInstance( currentCollection ) &&
attributeDefinition.equals( AttributeFetch.class.cast( currentCollection ).getFetchedAttributeDefinition() ) ) {
popFromCollectionStack( ( (AssociationAttributeDefinition) attributeDefinition ).toCollectionDefinition() );
}
}
log.tracef(
"%s Finishing up attribute : %s",