HHH-7841 - Redesign Loader
This commit is contained in:
parent
cbfa233ea1
commit
fafce001e7
|
@ -26,6 +26,7 @@ package org.hibernate.loader.plan.internal;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.loader.plan.spi.EntityReturn;
|
||||
import org.hibernate.loader.plan.spi.LoadPlan;
|
||||
import org.hibernate.loader.plan.spi.Return;
|
||||
|
||||
|
@ -47,6 +48,10 @@ public class LoadPlanImpl implements LoadPlan {
|
|||
this( hasScalars, Collections.singletonList( rootReturn ) );
|
||||
}
|
||||
|
||||
public LoadPlanImpl(EntityReturn entityReturn) {
|
||||
this( false, entityReturn );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAnyScalarReturns() {
|
||||
return hasScalars;
|
||||
|
|
|
@ -36,6 +36,7 @@ import org.jboss.logging.Logger;
|
|||
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.jpa.HibernateEntityManagerFactory;
|
||||
import org.hibernate.jpa.graph.spi.AttributeNodeImplementor;
|
||||
import org.hibernate.jpa.graph.spi.GraphNodeImplementor;
|
||||
|
||||
/**
|
||||
|
@ -49,7 +50,7 @@ public abstract class AbstractGraphNode<T> implements GraphNodeImplementor {
|
|||
private final HibernateEntityManagerFactory entityManagerFactory;
|
||||
private final boolean mutable;
|
||||
|
||||
private Map<String, AttributeNode<?>> attributeNodeMap;
|
||||
private Map<String, AttributeNodeImplementor<?>> attributeNodeMap;
|
||||
|
||||
protected AbstractGraphNode(HibernateEntityManagerFactory entityManagerFactory, boolean mutable) {
|
||||
this.entityManagerFactory = entityManagerFactory;
|
||||
|
@ -62,14 +63,14 @@ public abstract class AbstractGraphNode<T> implements GraphNodeImplementor {
|
|||
this.attributeNodeMap = makeSafeMapCopy( original.attributeNodeMap );
|
||||
}
|
||||
|
||||
private static Map<String, AttributeNode<?>> makeSafeMapCopy(Map<String, AttributeNode<?>> attributeNodeMap) {
|
||||
private static Map<String, AttributeNodeImplementor<?>> makeSafeMapCopy(Map<String, AttributeNodeImplementor<?>> attributeNodeMap) {
|
||||
if ( attributeNodeMap == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final int properSize = CollectionHelper.determineProperSizing( attributeNodeMap );
|
||||
final HashMap<String,AttributeNode<?>> copy = new HashMap<String,AttributeNode<?>>( properSize );
|
||||
for ( Map.Entry<String,AttributeNode<?>> attributeNodeEntry : attributeNodeMap.entrySet() ) {
|
||||
final HashMap<String,AttributeNodeImplementor<?>> copy = new HashMap<String,AttributeNodeImplementor<?>>( properSize );
|
||||
for ( Map.Entry<String,AttributeNodeImplementor<?>> attributeNodeEntry : attributeNodeMap.entrySet() ) {
|
||||
copy.put(
|
||||
attributeNodeEntry.getKey(),
|
||||
( ( AttributeNodeImpl ) attributeNodeEntry.getValue() ).makeImmutableCopy()
|
||||
|
@ -83,6 +84,16 @@ public abstract class AbstractGraphNode<T> implements GraphNodeImplementor {
|
|||
return entityManagerFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AttributeNodeImplementor<?>> attributeImplementorNodes() {
|
||||
if ( attributeNodeMap == null ) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
else {
|
||||
return new ArrayList<AttributeNodeImplementor<?>>( attributeNodeMap.values() );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AttributeNode<?>> attributeNodes() {
|
||||
if ( attributeNodeMap == null ) {
|
||||
|
@ -120,7 +131,7 @@ public abstract class AbstractGraphNode<T> implements GraphNodeImplementor {
|
|||
}
|
||||
|
||||
if ( attributeNodeMap == null ) {
|
||||
attributeNodeMap = new HashMap<String, AttributeNode<?>>();
|
||||
attributeNodeMap = new HashMap<String, AttributeNodeImplementor<?>>();
|
||||
}
|
||||
else {
|
||||
final AttributeNode old = attributeNodeMap.get( attributeNode.getRegistrationName() );
|
||||
|
|
|
@ -0,0 +1,293 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, 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.jpa.graph.internal.advisor;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.jpa.graph.internal.EntityGraphImpl;
|
||||
import org.hibernate.jpa.graph.spi.AttributeNodeImplementor;
|
||||
import org.hibernate.loader.plan.internal.LoadPlanImpl;
|
||||
import org.hibernate.loader.plan.spi.CollectionFetch;
|
||||
import org.hibernate.loader.plan.spi.CompositeFetch;
|
||||
import org.hibernate.loader.plan.spi.CopyContext;
|
||||
import org.hibernate.loader.plan.spi.EntityFetch;
|
||||
import org.hibernate.loader.plan.spi.EntityReturn;
|
||||
import org.hibernate.loader.plan.spi.FetchOwner;
|
||||
import org.hibernate.loader.plan.spi.LoadPlan;
|
||||
import org.hibernate.loader.plan.spi.Return;
|
||||
import org.hibernate.loader.plan.spi.visit.ReturnGraphVisitationStrategy;
|
||||
import org.hibernate.loader.plan.spi.visit.ReturnGraphVisitationStrategyAdapter;
|
||||
import org.hibernate.loader.spi.LoadPlanAdvisor;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class EntityGraphBasedLoadPlanAdvisor implements LoadPlanAdvisor {
|
||||
private static final Logger log = Logger.getLogger( EntityGraphBasedLoadPlanAdvisor.class );
|
||||
|
||||
private final EntityGraphImpl root;
|
||||
private final AdviceStyle adviceStyle;
|
||||
|
||||
public EntityGraphBasedLoadPlanAdvisor(EntityGraphImpl root, AdviceStyle adviceStyle) {
|
||||
if ( root == null ) {
|
||||
throw new IllegalArgumentException( "EntityGraph cannot be null" );
|
||||
}
|
||||
this.root = root;
|
||||
this.adviceStyle = adviceStyle;
|
||||
}
|
||||
|
||||
public LoadPlan advise(LoadPlan loadPlan) {
|
||||
if ( root == null ) {
|
||||
log.debug( "Skipping load plan advising: no entity graph was specified" );
|
||||
}
|
||||
else {
|
||||
// for now, lets assume that the graph and the load-plan returns have to match up
|
||||
EntityReturn entityReturn = findRootEntityReturn( loadPlan );
|
||||
if ( entityReturn == null ) {
|
||||
log.debug( "Skipping load plan advising: not able to find appropriate root entity return in load plan" );
|
||||
}
|
||||
else {
|
||||
final String entityName = entityReturn.getEntityPersister().getEntityName();
|
||||
if ( ! root.appliesTo( entityName ) ) {
|
||||
log.debugf(
|
||||
"Skipping load plan advising: entity types did not match : [%s] and [%s]",
|
||||
root.getEntityType().getName(),
|
||||
entityName
|
||||
);
|
||||
}
|
||||
else {
|
||||
// ok to apply the advice
|
||||
return applyAdvice( entityReturn );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return the original load-plan
|
||||
return loadPlan;
|
||||
}
|
||||
|
||||
private LoadPlan applyAdvice(final EntityReturn entityReturn) {
|
||||
final EntityReturn copy = entityReturn.makeCopy( new CopyContextImpl( entityReturn ) );
|
||||
return new LoadPlanImpl( copy );
|
||||
}
|
||||
|
||||
private EntityReturn findRootEntityReturn(LoadPlan loadPlan) {
|
||||
EntityReturn rootEntityReturn = null;
|
||||
for ( Return rtn : loadPlan.getReturns() ) {
|
||||
if ( ! EntityReturn.class.isInstance( rtn ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( rootEntityReturn != null ) {
|
||||
log.debug( "Multiple EntityReturns were found" );
|
||||
return null;
|
||||
}
|
||||
|
||||
rootEntityReturn = (EntityReturn) rtn;
|
||||
}
|
||||
|
||||
if ( rootEntityReturn == null ) {
|
||||
log.debug( "Unable to find root entity return in load plan" );
|
||||
}
|
||||
|
||||
return rootEntityReturn;
|
||||
}
|
||||
|
||||
public static enum AdviceStyle {
|
||||
FETCH,
|
||||
LOAD
|
||||
}
|
||||
|
||||
public class CopyContextImpl implements CopyContext {
|
||||
private final ReturnGraphVisitationStrategyImpl strategy;
|
||||
|
||||
public CopyContextImpl(EntityReturn entityReturn) {
|
||||
strategy = new ReturnGraphVisitationStrategyImpl( entityReturn );
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnGraphVisitationStrategy getReturnGraphVisitationStrategy() {
|
||||
return strategy;
|
||||
}
|
||||
}
|
||||
|
||||
public class ReturnGraphVisitationStrategyImpl extends ReturnGraphVisitationStrategyAdapter {
|
||||
private ArrayDeque<NodeDescriptor> nodeStack = new ArrayDeque<NodeDescriptor>();
|
||||
|
||||
public ReturnGraphVisitationStrategyImpl(EntityReturn entityReturn) {
|
||||
nodeStack.addFirst( new EntityReferenceDescriptor( entityReturn, new RootEntityGraphNode( root ) ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishingRootReturn(Return rootReturn) {
|
||||
nodeStack.removeFirst();
|
||||
super.finishingRootReturn( rootReturn );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishingFetches(FetchOwner fetchOwner) {
|
||||
nodeStack.peekFirst().applyMissingFetches();
|
||||
super.finishingFetches( fetchOwner );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startingEntityFetch(EntityFetch entityFetch) {
|
||||
super.startingEntityFetch( entityFetch );
|
||||
|
||||
final NodeDescriptor currentNode = nodeStack.peekFirst();
|
||||
final String attributeName = entityFetch.getOwnerPropertyName();
|
||||
final JpaGraphReference fetchedGraphReference = currentNode.attributeProcessed( attributeName );
|
||||
nodeStack.addFirst( new EntityReferenceDescriptor( entityFetch, fetchedGraphReference ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishingEntityFetch(EntityFetch entityFetch) {
|
||||
nodeStack.removeFirst();
|
||||
super.finishingEntityFetch( entityFetch );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startingCollectionFetch(CollectionFetch collectionFetch) {
|
||||
super.startingCollectionFetch( collectionFetch ); //To change body of overridden methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishingCollectionFetch(CollectionFetch collectionFetch) {
|
||||
super.finishingCollectionFetch( collectionFetch ); //To change body of overridden methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startingCompositeFetch(CompositeFetch fetch) {
|
||||
super.startingCompositeFetch( fetch ); //To change body of overridden methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishingCompositeFetch(CompositeFetch fetch) {
|
||||
super.finishingCompositeFetch( fetch ); //To change body of overridden methods use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
private static interface NodeDescriptor {
|
||||
public JpaGraphReference attributeProcessed(String attributeName);
|
||||
|
||||
public void applyMissingFetches();
|
||||
}
|
||||
|
||||
private static abstract class AbstractNodeDescriptor implements NodeDescriptor {
|
||||
private final FetchOwner fetchOwner;
|
||||
private final JpaGraphReference jpaGraphReference;
|
||||
|
||||
protected AbstractNodeDescriptor(FetchOwner fetchOwner, JpaGraphReference jpaGraphReference) {
|
||||
this.fetchOwner = fetchOwner;
|
||||
this.jpaGraphReference = jpaGraphReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JpaGraphReference attributeProcessed(String attributeName) {
|
||||
if ( jpaGraphReference != null ) {
|
||||
return jpaGraphReference.attributeProcessed( attributeName );
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyMissingFetches() {
|
||||
if ( jpaGraphReference != null ) {
|
||||
jpaGraphReference.applyMissingFetches( fetchOwner );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class EntityReferenceDescriptor extends AbstractNodeDescriptor {
|
||||
private EntityReferenceDescriptor(EntityReturn entityReturn, JpaGraphReference correspondingJpaGraphNode) {
|
||||
super( entityReturn, correspondingJpaGraphNode );
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public EntityReferenceDescriptor(EntityFetch entityFetch, JpaGraphReference jpaGraphReference) {
|
||||
super( entityFetch, jpaGraphReference );
|
||||
}
|
||||
}
|
||||
|
||||
private static interface JpaGraphReference {
|
||||
public JpaGraphReference attributeProcessed(String attributeName);
|
||||
public void applyMissingFetches(FetchOwner fetchOwner);
|
||||
}
|
||||
|
||||
private static class RootEntityGraphNode implements JpaGraphReference {
|
||||
private final Map<String,AttributeNodeImplementor> graphAttributeMap;
|
||||
|
||||
private RootEntityGraphNode(EntityGraphImpl entityGraph) {
|
||||
graphAttributeMap = new HashMap<String, AttributeNodeImplementor>();
|
||||
|
||||
final List<AttributeNodeImplementor<?>> explicitAttributeNodes = entityGraph.attributeImplementorNodes();
|
||||
if ( explicitAttributeNodes != null ) {
|
||||
for ( AttributeNodeImplementor node : explicitAttributeNodes ) {
|
||||
graphAttributeMap.put( node.getAttributeName(), node );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JpaGraphReference attributeProcessed(String attributeName) {
|
||||
final AttributeNodeImplementor attributeNode = graphAttributeMap.remove( attributeName );
|
||||
|
||||
if ( attributeNode == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new SubGraphNode( attributeNode );
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void applyMissingFetches(FetchOwner fetchOwner) {
|
||||
for ( AttributeNodeImplementor attributeNode : graphAttributeMap.values() ) {
|
||||
System.out.println( "Found unprocessed attribute node : " + attributeNode.getAttributeName() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class SubGraphNode implements JpaGraphReference {
|
||||
protected SubGraphNode(AttributeNodeImplementor attributeNode) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JpaGraphReference attributeProcessed(String attributeName) {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyMissingFetches(FetchOwner fetchOwner) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
package org.hibernate.jpa.graph.spi;
|
||||
|
||||
import javax.persistence.AttributeNode;
|
||||
import javax.persistence.metamodel.Attribute;
|
||||
|
||||
import org.hibernate.jpa.HibernateEntityManagerFactory;
|
||||
|
@ -30,7 +31,7 @@ import org.hibernate.jpa.HibernateEntityManagerFactory;
|
|||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface AttributeNodeImplementor<T> {
|
||||
public interface AttributeNodeImplementor<T> extends AttributeNode<T> {
|
||||
public HibernateEntityManagerFactory entityManagerFactory();
|
||||
|
||||
public Attribute<?,T> getAttribute();
|
||||
|
|
|
@ -1,107 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, 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.jpa.graph.spi;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.jpa.graph.internal.EntityGraphImpl;
|
||||
import org.hibernate.loader.plan.spi.EntityReturn;
|
||||
import org.hibernate.loader.plan.spi.LoadPlan;
|
||||
import org.hibernate.loader.plan.spi.Return;
|
||||
import org.hibernate.loader.spi.LoadPlanAdvisor;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class EntityGraphBasedLoadPlanAdvisor implements LoadPlanAdvisor {
|
||||
private static final Logger log = Logger.getLogger( EntityGraphBasedLoadPlanAdvisor.class );
|
||||
|
||||
private final EntityGraphImpl root;
|
||||
|
||||
public EntityGraphBasedLoadPlanAdvisor(EntityGraphImpl root) {
|
||||
if ( root == null ) {
|
||||
throw new IllegalArgumentException( "EntityGraph cannot be null" );
|
||||
}
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
public LoadPlan advise(LoadPlan loadPlan) {
|
||||
if ( root == null ) {
|
||||
log.debug( "Skipping load plan advising: no entity graph was specified" );
|
||||
}
|
||||
else {
|
||||
// for now, lets assume that the graph and the load-plan returns have to match up
|
||||
EntityReturn entityReturn = findRootEntityReturn( loadPlan );
|
||||
if ( entityReturn == null ) {
|
||||
log.debug( "Skipping load plan advising: not able to find appropriate root entity return in load plan" );
|
||||
}
|
||||
else {
|
||||
final String entityName = entityReturn.getEntityPersister().getEntityName();
|
||||
if ( ! root.appliesTo( entityName ) ) {
|
||||
log.debugf(
|
||||
"Skipping load plan advising: entity types did not match : [%s] and [%s]",
|
||||
root.getEntityType().getName(),
|
||||
entityName
|
||||
);
|
||||
}
|
||||
else {
|
||||
// ok to apply the advice
|
||||
return applyAdvice( entityReturn );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return the original load-plan
|
||||
return loadPlan;
|
||||
}
|
||||
|
||||
private LoadPlan applyAdvice(final EntityReturn entityReturn) {
|
||||
// final EntityReturn copy = entityReturn.makeCopy( )
|
||||
return null;
|
||||
}
|
||||
|
||||
private EntityReturn findRootEntityReturn(LoadPlan loadPlan) {
|
||||
EntityReturn rootEntityReturn = null;
|
||||
for ( Return rtn : loadPlan.getReturns() ) {
|
||||
if ( ! EntityReturn.class.isInstance( rtn ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( rootEntityReturn != null ) {
|
||||
log.debug( "Multiple EntityReturns were found" );
|
||||
return null;
|
||||
}
|
||||
|
||||
rootEntityReturn = (EntityReturn) rtn;
|
||||
}
|
||||
|
||||
if ( rootEntityReturn == null ) {
|
||||
log.debug( "Unable to find root entity return in load plan" );
|
||||
}
|
||||
|
||||
return rootEntityReturn;
|
||||
}
|
||||
}
|
|
@ -35,5 +35,6 @@ import org.hibernate.jpa.HibernateEntityManagerFactory;
|
|||
*/
|
||||
public interface GraphNodeImplementor {
|
||||
public HibernateEntityManagerFactory entityManagerFactory();
|
||||
public List<AttributeNodeImplementor<?>> attributeImplementorNodes();
|
||||
public List<AttributeNode<?>> attributeNodes();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, 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.jpa.test.graphs;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EntityGraph;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Subgraph;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.jpa.graph.internal.EntityGraphImpl;
|
||||
import org.hibernate.jpa.graph.internal.advisor.EntityGraphBasedLoadPlanAdvisor;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
import org.hibernate.loader.DefaultEntityAliases;
|
||||
import org.hibernate.loader.plan.internal.LoadPlanImpl;
|
||||
import org.hibernate.loader.plan.spi.EntityReturn;
|
||||
import org.hibernate.loader.plan.spi.LoadPlan;
|
||||
import org.hibernate.loader.spi.LoadPlanAdvisor;
|
||||
import org.hibernate.persister.entity.Loadable;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.jpa.graph.internal.advisor.EntityGraphBasedLoadPlanAdvisor.AdviceStyle;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class BasicGraphLoadPlanAdviceTests extends BaseEntityManagerFunctionalTestCase {
|
||||
private static final String ENTIYT_NAME = "org.hibernate.jpa.test.graphs.BasicGraphLoadPlanAdviceTests$Entity1";
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { Entity1.class };
|
||||
}
|
||||
|
||||
public void testNoAdvice() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
}
|
||||
|
||||
private LoadPlan buildBasicLoadPlan() {
|
||||
return new LoadPlanImpl(
|
||||
new EntityReturn(
|
||||
sfi(),
|
||||
"abc",
|
||||
LockMode.NONE,
|
||||
ENTIYT_NAME,
|
||||
"a1",
|
||||
new DefaultEntityAliases( (Loadable) sfi().getEntityPersister( ENTIYT_NAME ), "1" )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private SessionFactoryImplementor sfi() {
|
||||
return entityManagerFactory().unwrap( SessionFactoryImplementor.class );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicGraphBuilding() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
EntityGraph<Entity1> graphRoot = em.createEntityGraph( Entity1.class );
|
||||
assertNull( graphRoot.getName() );
|
||||
assertEquals( 0, graphRoot.getAttributeNodes().size() );
|
||||
|
||||
LoadPlan loadPlan = buildBasicLoadPlan();
|
||||
|
||||
LoadPlan advised = buildAdvisor( graphRoot, AdviceStyle.FETCH ).advise( loadPlan );
|
||||
assertNotSame( advised, loadPlan );
|
||||
}
|
||||
|
||||
private LoadPlanAdvisor buildAdvisor(EntityGraph<Entity1> graphRoot, AdviceStyle adviceStyle) {
|
||||
return new EntityGraphBasedLoadPlanAdvisor( (EntityGraphImpl) graphRoot, adviceStyle );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicSubgraphBuilding() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
EntityGraph<Entity1> graphRoot = em.createEntityGraph( Entity1.class );
|
||||
Subgraph<Entity1> parentGraph = graphRoot.addSubgraph( "parent" );
|
||||
Subgraph<Entity1> childGraph = graphRoot.addSubgraph( "children" );
|
||||
|
||||
assertNull( graphRoot.getName() );
|
||||
assertEquals( 2, graphRoot.getAttributeNodes().size() );
|
||||
assertTrue(
|
||||
graphRoot.getAttributeNodes().get( 0 ).getSubgraphs().containsValue( parentGraph )
|
||||
|| graphRoot.getAttributeNodes().get( 0 ).getSubgraphs().containsValue( childGraph )
|
||||
);
|
||||
assertTrue(
|
||||
graphRoot.getAttributeNodes().get( 1 ).getSubgraphs().containsValue( parentGraph )
|
||||
|| graphRoot.getAttributeNodes().get( 1 ).getSubgraphs().containsValue( childGraph )
|
||||
);
|
||||
|
||||
LoadPlan loadPlan = buildBasicLoadPlan();
|
||||
|
||||
LoadPlan advised = buildAdvisor( graphRoot, AdviceStyle.FETCH ).advise( loadPlan );
|
||||
assertNotSame( advised, loadPlan );
|
||||
}
|
||||
|
||||
@Entity( name = "Entity1" )
|
||||
public static class Entity1 {
|
||||
@Id
|
||||
public Integer id;
|
||||
public String name;
|
||||
@ManyToOne
|
||||
public Entity1 parent;
|
||||
@OneToMany( mappedBy = "parent" )
|
||||
public Set<Entity1> children;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue