diff --git a/hibernate-core/src/main/java/org/hibernate/engine/FetchStrategy.java b/hibernate-core/src/main/java/org/hibernate/engine/FetchStrategy.java
new file mode 100644
index 0000000000..8264eee79a
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/engine/FetchStrategy.java
@@ -0,0 +1,50 @@
+/*
+ * jDocBook, processing of DocBook sources
+ *
+ * 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.engine;
+
+/**
+ * Describes the strategy for fetching an association
+ *
+ * todo not really a fan of the name. not sure of a better one though.
+ * I'd almost rather see this be called the style, but then what to call FetchStyle? HowToFetch?
+ *
+ * @author Steve Ebersole
+ */
+public class FetchStrategy {
+ private final FetchTiming timing;
+ private final FetchStyle style;
+
+ public FetchStrategy(FetchTiming timing, FetchStyle style) {
+ this.timing = timing;
+ this.style = style;
+ }
+
+ public FetchTiming getTiming() {
+ return timing;
+ }
+
+ public FetchStyle getStyle() {
+ return style;
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/internal/CascadeLoadPlanBuilderStrategy.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/internal/CascadeLoadPlanBuilderStrategy.java
new file mode 100644
index 0000000000..ce19b46079
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/internal/CascadeLoadPlanBuilderStrategy.java
@@ -0,0 +1,60 @@
+/*
+ * jDocBook, processing of DocBook sources
+ *
+ * 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.loader.plan.internal;
+
+import org.hibernate.engine.FetchStrategy;
+import org.hibernate.engine.FetchStyle;
+import org.hibernate.engine.FetchTiming;
+import org.hibernate.engine.spi.CascadingAction;
+import org.hibernate.engine.spi.LoadQueryInfluencers;
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
+
+/**
+ * A LoadPlan building strategy for cascade processing; meaning, it builds the LoadPlan for loading related to
+ * cascading a particular action across associations
+ *
+ * @author Steve Ebersole
+ */
+public class CascadeLoadPlanBuilderStrategy extends SingleRootReturnLoadPlanBuilderStrategy {
+ private static final FetchStrategy EAGER = new FetchStrategy( FetchTiming.IMMEDIATE, FetchStyle.JOIN );
+ private static final FetchStrategy DELAYED = new FetchStrategy( FetchTiming.DELAYED, FetchStyle.SELECT );
+
+ private final CascadingAction cascadeActionToMatch;
+
+ public CascadeLoadPlanBuilderStrategy(
+ CascadingAction cascadeActionToMatch,
+ SessionFactoryImplementor sessionFactory,
+ LoadQueryInfluencers loadQueryInfluencers,
+ String rootAlias,
+ int suffixSeed) {
+ super( sessionFactory, loadQueryInfluencers, rootAlias, suffixSeed );
+ this.cascadeActionToMatch = cascadeActionToMatch;
+ }
+
+ @Override
+ protected FetchStrategy determineFetchPlan(AssociationAttributeDefinition attributeDefinition) {
+ return attributeDefinition.determineCascadeStyle().doCascade( cascadeActionToMatch ) ? EAGER : DELAYED;
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/internal/LoadPlanImpl.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/internal/LoadPlanImpl.java
new file mode 100644
index 0000000000..47daeb3c13
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/internal/LoadPlanImpl.java
@@ -0,0 +1,59 @@
+/*
+ * jDocBook, processing of DocBook sources
+ *
+ * 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.loader.plan.internal;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.hibernate.loader.plan.spi.LoadPlan;
+import org.hibernate.loader.plan.spi.Return;
+
+/**
+ * Implementation of LoadPlan.
+ *
+ * @author Steve Ebersole
+ */
+public class LoadPlanImpl implements LoadPlan {
+ private final boolean hasScalars;
+ private final List returns;
+
+ public LoadPlanImpl(boolean hasScalars, List returns) {
+ this.hasScalars = hasScalars;
+ this.returns = returns;
+ }
+
+ public LoadPlanImpl(boolean hasScalars, Return rootReturn) {
+ this( hasScalars, Collections.singletonList( rootReturn ) );
+ }
+
+ @Override
+ public boolean hasAnyScalarReturns() {
+ return hasScalars;
+ }
+
+ @Override
+ public List getReturns() {
+ return returns;
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/internal/SingleRootReturnLoadPlanBuilderStrategy.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/internal/SingleRootReturnLoadPlanBuilderStrategy.java
new file mode 100644
index 0000000000..f329b30e26
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/internal/SingleRootReturnLoadPlanBuilderStrategy.java
@@ -0,0 +1,268 @@
+/*
+ * jDocBook, processing of DocBook sources
+ *
+ * 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.loader.plan.internal;
+
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.engine.FetchStrategy;
+import org.hibernate.engine.FetchStyle;
+import org.hibernate.engine.FetchTiming;
+import org.hibernate.engine.spi.LoadQueryInfluencers;
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.internal.util.StringHelper;
+import org.hibernate.loader.CollectionAliases;
+import org.hibernate.loader.DefaultEntityAliases;
+import org.hibernate.loader.EntityAliases;
+import org.hibernate.loader.GeneratedCollectionAliases;
+import org.hibernate.loader.PropertyPath;
+import org.hibernate.loader.plan.spi.AbstractFetchOwner;
+import org.hibernate.loader.plan.spi.AbstractLoadPlanBuilderStrategy;
+import org.hibernate.loader.plan.spi.CollectionFetch;
+import org.hibernate.loader.plan.spi.CollectionReturn;
+import org.hibernate.loader.plan.spi.CompositeFetch;
+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.LoadPlanBuilderStrategy;
+import org.hibernate.loader.plan.spi.Return;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.entity.Loadable;
+import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
+import org.hibernate.persister.walking.spi.CollectionDefinition;
+import org.hibernate.persister.walking.spi.CompositeDefinition;
+import org.hibernate.persister.walking.spi.EntityDefinition;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+
+/**
+ * LoadPlanBuilderStrategy implementation used for building LoadPlans with a single processing RootEntity LoadPlan building.
+ *
+ * Really this is a single-root LoadPlan building strategy for building LoadPlans for:
+ * - entity load plans
+ * - cascade load plans
+ * - collection initializer plans
+ *
+ *
+ * @author Steve Ebersole
+ */
+public class SingleRootReturnLoadPlanBuilderStrategy
+ extends AbstractLoadPlanBuilderStrategy
+ implements LoadPlanBuilderStrategy {
+
+ private final LoadQueryInfluencers loadQueryInfluencers;
+
+ private final String rootAlias;
+ private int currentSuffixBase;
+
+ private Return rootReturn;
+
+ private PropertyPath propertyPath = new PropertyPath( "" );
+
+ public SingleRootReturnLoadPlanBuilderStrategy(
+ SessionFactoryImplementor sessionFactory,
+ LoadQueryInfluencers loadQueryInfluencers,
+ String rootAlias,
+ int suffixSeed) {
+ super( sessionFactory );
+ this.loadQueryInfluencers = loadQueryInfluencers;
+ this.rootAlias = rootAlias;
+ this.currentSuffixBase = suffixSeed;
+ }
+
+ @Override
+ protected boolean supportsRootEntityReturns() {
+ return true;
+ }
+
+ @Override
+ protected boolean supportsRootCollectionReturns() {
+ return true;
+ }
+
+ @Override
+ protected void addRootReturn(Return rootReturn) {
+ if ( this.rootReturn != null ) {
+ throw new HibernateException( "Root return already identified" );
+ }
+ this.rootReturn = rootReturn;
+ }
+
+ @Override
+ public LoadPlan buildLoadPlan() {
+ return new LoadPlanImpl( false, rootReturn );
+ }
+
+ @Override
+ protected FetchStrategy determineFetchPlan(AssociationAttributeDefinition attributeDefinition) {
+ FetchStrategy fetchStrategy = attributeDefinition.determineFetchPlan( loadQueryInfluencers, propertyPath );
+ if ( fetchStrategy.getTiming() == FetchTiming.IMMEDIATE && fetchStrategy.getStyle() == FetchStyle.JOIN ) {
+ // see if we need to alter the join fetch to another form for any reason
+ fetchStrategy = adjustJoinFetchIfNeeded( attributeDefinition, fetchStrategy );
+ }
+ return fetchStrategy;
+ }
+
+ protected FetchStrategy adjustJoinFetchIfNeeded(
+ AssociationAttributeDefinition attributeDefinition,
+ FetchStrategy fetchStrategy) {
+ if ( currentDepth() > sessionFactory().getSettings().getMaximumFetchDepth() ) {
+ return new FetchStrategy( fetchStrategy.getTiming(), FetchStyle.SELECT );
+ }
+
+ if ( attributeDefinition.getType().isCollectionType() && isTooManyCollections() ) {
+ // todo : have this revert to batch or subselect fetching once "sql gen redesign" is in place
+ return new FetchStrategy( fetchStrategy.getTiming(), FetchStyle.SELECT );
+ }
+
+ return fetchStrategy;
+ }
+
+ @Override
+ protected boolean isTooManyCollections() {
+ return false;
+ }
+
+ @Override
+ protected EntityReturn buildRootEntityReturn(EntityDefinition entityDefinition) {
+ final String entityName = entityDefinition.getEntityPersister().getEntityName();
+ return new EntityReturn(
+ sessionFactory(),
+ rootAlias,
+ LockMode.NONE, // todo : for now
+ entityName,
+ StringHelper.generateAlias( StringHelper.unqualifyEntityName( entityName ), currentDepth() ),
+ new DefaultEntityAliases(
+ (Loadable) entityDefinition.getEntityPersister(),
+ Integer.toString( currentSuffixBase++ ) + '_'
+ )
+ );
+ }
+
+ @Override
+ protected CollectionReturn buildRootCollectionReturn(CollectionDefinition collectionDefinition) {
+ final CollectionPersister persister = collectionDefinition.getCollectionPersister();
+ final String collectionRole = persister.getRole();
+
+ final CollectionAliases collectionAliases = new GeneratedCollectionAliases(
+ collectionDefinition.getCollectionPersister(),
+ Integer.toString( currentSuffixBase++ ) + '_'
+ );
+ final Type elementType = collectionDefinition.getCollectionPersister().getElementType();
+ final EntityAliases elementAliases;
+ if ( elementType.isEntityType() ) {
+ final EntityType entityElementType = (EntityType) elementType;
+ elementAliases = new DefaultEntityAliases(
+ (Loadable) entityElementType.getAssociatedJoinable( sessionFactory() ),
+ Integer.toString( currentSuffixBase++ ) + '_'
+ );
+ }
+ else {
+ elementAliases = null;
+ }
+
+ return new CollectionReturn(
+ sessionFactory(),
+ rootAlias,
+ LockMode.NONE, // todo : for now
+ persister.getOwnerEntityPersister().getEntityName(),
+ StringHelper.unqualify( collectionRole ),
+ collectionAliases,
+ elementAliases
+ );
+ }
+
+ @Override
+ protected CollectionFetch buildCollectionFetch(
+ FetchOwner fetchOwner,
+ AssociationAttributeDefinition attributeDefinition,
+ FetchStrategy fetchStrategy) {
+ final CollectionDefinition collectionDefinition = attributeDefinition.toCollectionDefinition();
+ final CollectionAliases collectionAliases = new GeneratedCollectionAliases(
+ collectionDefinition.getCollectionPersister(),
+ Integer.toString( currentSuffixBase++ ) + '_'
+ );
+ final Type elementType = collectionDefinition.getCollectionPersister().getElementType();
+ final EntityAliases elementAliases;
+ if ( elementType.isEntityType() ) {
+ final EntityType entityElementType = (EntityType) elementType;
+ elementAliases = new DefaultEntityAliases(
+ (Loadable) entityElementType.getAssociatedJoinable( sessionFactory() ),
+ Integer.toString( currentSuffixBase++ ) + '_'
+ );
+ }
+ else {
+ elementAliases = null;
+ }
+
+ return new CollectionFetch(
+ sessionFactory(),
+ createImplicitAlias(),
+ LockMode.NONE, // todo : for now
+ (AbstractFetchOwner) fetchOwner,
+ fetchStrategy,
+ attributeDefinition.getName(),
+ collectionAliases,
+ elementAliases
+ );
+ }
+
+ @Override
+ protected EntityFetch buildEntityFetch(
+ FetchOwner fetchOwner,
+ AssociationAttributeDefinition attributeDefinition,
+ FetchStrategy fetchStrategy) {
+ final EntityDefinition entityDefinition = attributeDefinition.toEntityDefinition();
+
+ return new EntityFetch(
+ sessionFactory(),
+ createImplicitAlias(),
+ LockMode.NONE, // todo : for now
+ (AbstractFetchOwner) fetchOwner,
+ attributeDefinition.getName(),
+ fetchStrategy,
+ StringHelper.generateAlias( entityDefinition.getEntityPersister().getEntityName(), currentDepth() ),
+ new DefaultEntityAliases(
+ (Loadable) entityDefinition.getEntityPersister(),
+ Integer.toString( currentSuffixBase++ ) + '_'
+ )
+ );
+ }
+
+ @Override
+ protected CompositeFetch buildCompositeFetch(FetchOwner fetchOwner, CompositeDefinition attributeDefinition) {
+ return new CompositeFetch(
+ sessionFactory(),
+ createImplicitAlias(),
+ (AbstractFetchOwner) fetchOwner,
+ attributeDefinition.getName()
+ );
+ }
+
+ private int implicitAliasUniqueness = 0;
+
+ private String createImplicitAlias() {
+ return "ia" + implicitAliasUniqueness++;
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/AbstractFetch.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/AbstractFetch.java
new file mode 100644
index 0000000000..e7d2751247
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/AbstractFetch.java
@@ -0,0 +1,88 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2012, 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.loader.plan.spi;
+
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.engine.FetchStrategy;
+import org.hibernate.engine.FetchStyle;
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.loader.PropertyPath;
+
+/**
+ * @author Steve Ebersole
+ */
+public abstract class AbstractFetch extends AbstractFetchOwner implements Fetch {
+ private final FetchOwner owner;
+ private final String ownerProperty;
+ private final FetchStrategy fetchStrategy;
+
+ private final PropertyPath propertyPath;
+
+ public AbstractFetch(
+ SessionFactoryImplementor factory,
+ String alias,
+ LockMode lockMode,
+ AbstractFetchOwner owner,
+ String ownerProperty,
+ FetchStrategy fetchStrategy) {
+ super( factory, alias, lockMode );
+ this.owner = owner;
+ this.ownerProperty = ownerProperty;
+ this.fetchStrategy = fetchStrategy;
+
+ owner.addFetch( this );
+
+ this.propertyPath = owner.getPropertyPath().append( ownerProperty );
+ }
+
+ @Override
+ public FetchOwner getOwner() {
+ return owner;
+ }
+
+ @Override
+ public String getOwnerPropertyName() {
+ return ownerProperty;
+ }
+
+ @Override
+ public FetchStrategy getFetchStrategy() {
+ return fetchStrategy;
+ }
+
+ @Override
+ public void validateFetchPlan(FetchStrategy fetchStrategy) {
+ if ( fetchStrategy.getStyle() == FetchStyle.JOIN ) {
+ if ( this.fetchStrategy.getStyle() != FetchStyle.JOIN ) {
+ throw new HibernateException( "Cannot specify join fetch from owner that is a non-joined fetch" );
+ }
+ }
+ }
+
+ @Override
+ public PropertyPath getPropertyPath() {
+ return propertyPath;
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/AbstractFetchOwner.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/AbstractFetchOwner.java
new file mode 100644
index 0000000000..87063b9278
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/AbstractFetchOwner.java
@@ -0,0 +1,75 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2012, 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.loader.plan.spi;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+
+/**
+ * @author Steve Ebersole
+ */
+public abstract class AbstractFetchOwner extends AbstractPlanNode implements FetchOwner {
+ private final String alias;
+ private final LockMode lockMode;
+
+ private List fetches;
+
+ public AbstractFetchOwner(SessionFactoryImplementor factory, String alias, LockMode lockMode) {
+ super( factory );
+ this.alias = alias;
+ if ( alias == null ) {
+ throw new HibernateException( "alias must be specified" );
+ }
+ this.lockMode = lockMode;
+ }
+
+ public String getAlias() {
+ return alias;
+ }
+
+ public LockMode getLockMode() {
+ return lockMode;
+ }
+
+ void addFetch(Fetch fetch) {
+ if ( fetch.getOwner() != this ) {
+ throw new IllegalArgumentException( "Fetch and owner did not match" );
+ }
+
+ if ( fetches == null ) {
+ fetches = new ArrayList();
+ }
+
+ fetches.add( fetch );
+ }
+
+ @Override
+ public Fetch[] getFetches() {
+ return fetches == null ? NO_FETCHES : fetches.toArray( new Fetch[ fetches.size() ] );
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/AbstractLoadPlanBuilderStrategy.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/AbstractLoadPlanBuilderStrategy.java
new file mode 100644
index 0000000000..f9324daa96
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/AbstractLoadPlanBuilderStrategy.java
@@ -0,0 +1,212 @@
+/*
+ * jDocBook, processing of DocBook sources
+ *
+ * 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.loader.plan.spi;
+
+import java.util.ArrayDeque;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.FetchStrategy;
+import org.hibernate.engine.FetchTiming;
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
+import org.hibernate.persister.walking.spi.AttributeDefinition;
+import org.hibernate.persister.walking.spi.CollectionDefinition;
+import org.hibernate.persister.walking.spi.CompositeDefinition;
+import org.hibernate.persister.walking.spi.EntityDefinition;
+import org.hibernate.type.Type;
+
+/**
+ * @author Steve Ebersole
+ */
+public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilderStrategy {
+ private final SessionFactoryImplementor sessionFactory;
+
+ private ArrayDeque fetchOwnerStack = new ArrayDeque();
+
+ protected AbstractLoadPlanBuilderStrategy(SessionFactoryImplementor sessionFactory) {
+ this.sessionFactory = sessionFactory;
+ }
+
+ public SessionFactoryImplementor sessionFactory() {
+ return sessionFactory;
+ }
+
+ protected FetchOwner currentFetchOwner() {
+ return fetchOwnerStack.peekLast();
+ }
+
+ @Override
+ public void start() {
+ // nothing to do
+ }
+
+ @Override
+ public void finish() {
+ // nothing to do
+ }
+
+ @Override
+ public void startingEntity(EntityDefinition entityDefinition) {
+ if ( fetchOwnerStack.isEmpty() ) {
+ // this is a root...
+ if ( ! supportsRootEntityReturns() ) {
+ throw new HibernateException( "This strategy does not support root entity returns" );
+ }
+ final EntityReturn entityReturn = buildRootEntityReturn( entityDefinition );
+ addRootReturn( entityReturn );
+ fetchOwnerStack.push( entityReturn );
+ }
+ // otherwise this call should represent a fetch which should have been handled in #startingAttribute
+ }
+
+ protected boolean supportsRootEntityReturns() {
+ return false;
+ }
+
+ protected abstract void addRootReturn(Return rootReturn);
+
+ @Override
+ public void finishingEntity(EntityDefinition entityDefinition) {
+ // nothing to do
+ }
+
+ @Override
+ public void startingCollection(CollectionDefinition collectionDefinition) {
+ if ( fetchOwnerStack.isEmpty() ) {
+ // this is a root...
+ if ( ! supportsRootCollectionReturns() ) {
+ throw new HibernateException( "This strategy does not support root collection returns" );
+ }
+ final CollectionReturn collectionReturn = buildRootCollectionReturn( collectionDefinition );
+ addRootReturn( collectionReturn );
+ fetchOwnerStack.push( collectionReturn );
+ }
+ }
+
+ protected boolean supportsRootCollectionReturns() {
+ return false;
+ }
+
+ @Override
+ public void finishingCollection(CollectionDefinition collectionDefinition) {
+ // nothing to do
+ }
+
+ @Override
+ public void startingComposite(CompositeDefinition compositeDefinition) {
+ if ( fetchOwnerStack.isEmpty() ) {
+ throw new HibernateException( "A component cannot be the root of a walk nor a graph" );
+ }
+ }
+
+ @Override
+ public void finishingComposite(CompositeDefinition compositeDefinition) {
+ // nothing to do
+ }
+
+ @Override
+ public boolean startingAttribute(AttributeDefinition attributeDefinition) {
+ final Type attributeType = attributeDefinition.getType();
+
+ final boolean isComponentType = attributeType.isComponentType();
+ final boolean isBasicType = ! ( isComponentType || attributeType.isAssociationType() );
+
+ if ( isBasicType ) {
+ return true;
+ }
+ else if ( isComponentType ) {
+ return handleCompositeAttribute( (CompositeDefinition) attributeDefinition );
+ }
+ else {
+ return handleAssociationAttribute( (AssociationAttributeDefinition) attributeDefinition );
+ }
+ }
+
+
+ @Override
+ public void finishingAttribute(AttributeDefinition attributeDefinition) {
+ final Type attributeType = attributeDefinition.getType();
+
+ final boolean isComponentType = attributeType.isComponentType();
+ final boolean isBasicType = ! ( isComponentType || attributeType.isAssociationType() );
+
+ if ( ! isBasicType ) {
+ fetchOwnerStack.removeLast();
+ }
+ }
+
+ protected boolean handleCompositeAttribute(CompositeDefinition attributeDefinition) {
+ final FetchOwner fetchOwner = fetchOwnerStack.peekLast();
+ final CompositeFetch fetch = buildCompositeFetch( fetchOwner, attributeDefinition );
+ fetchOwnerStack.addLast( fetch );
+ return true;
+ }
+
+ protected boolean handleAssociationAttribute(AssociationAttributeDefinition attributeDefinition) {
+ final FetchStrategy fetchStrategy = determineFetchPlan( attributeDefinition );
+ if ( fetchStrategy.getTiming() != FetchTiming.IMMEDIATE ) {
+ return false;
+ }
+
+ final FetchOwner fetchOwner = fetchOwnerStack.peekLast();
+ fetchOwner.validateFetchPlan( fetchStrategy );
+
+ final Fetch associationFetch;
+ if ( attributeDefinition.isCollection() ) {
+ associationFetch = buildCollectionFetch( fetchOwner, attributeDefinition, fetchStrategy );
+ }
+ else {
+ associationFetch = buildEntityFetch( fetchOwner, attributeDefinition, fetchStrategy );
+ }
+ fetchOwnerStack.addLast( associationFetch );
+
+ return true;
+ }
+
+ protected abstract FetchStrategy determineFetchPlan(AssociationAttributeDefinition attributeDefinition);
+
+ protected int currentDepth() {
+ return fetchOwnerStack.size();
+ }
+
+ protected boolean isTooManyCollections() {
+ return false;
+ }
+
+ protected abstract EntityReturn buildRootEntityReturn(EntityDefinition entityDefinition);
+
+ protected abstract CollectionReturn buildRootCollectionReturn(CollectionDefinition collectionDefinition);
+
+ protected abstract CollectionFetch buildCollectionFetch(
+ FetchOwner fetchOwner,
+ AssociationAttributeDefinition attributeDefinition,
+ FetchStrategy fetchStrategy);
+
+ protected abstract EntityFetch buildEntityFetch(
+ FetchOwner fetchOwner,
+ AssociationAttributeDefinition attributeDefinition,
+ FetchStrategy fetchStrategy);
+
+ protected abstract CompositeFetch buildCompositeFetch(FetchOwner fetchOwner, CompositeDefinition attributeDefinition);
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/AbstractPlanNode.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/AbstractPlanNode.java
new file mode 100644
index 0000000000..eb789612a2
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/AbstractPlanNode.java
@@ -0,0 +1,43 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2012, 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.loader.plan.spi;
+
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+
+/**
+ * Base class for LoadPlan nodes to hold references to the session factory.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class AbstractPlanNode {
+ private final SessionFactoryImplementor sessionFactory;
+
+ public AbstractPlanNode(SessionFactoryImplementor sessionFactory) {
+ this.sessionFactory = sessionFactory;
+ }
+
+ protected SessionFactoryImplementor sessionFactory() {
+ return sessionFactory;
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/CollectionFetch.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/CollectionFetch.java
new file mode 100644
index 0000000000..973d147795
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/CollectionFetch.java
@@ -0,0 +1,80 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2012, 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.loader.plan.spi;
+
+import org.hibernate.LockMode;
+import org.hibernate.engine.FetchStrategy;
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.loader.CollectionAliases;
+import org.hibernate.loader.EntityAliases;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * @author Steve Ebersole
+ */
+public class CollectionFetch extends AbstractFetch implements CollectionReference {
+ private final CollectionAliases collectionAliases;
+ private final EntityAliases elementEntityAliases;
+
+ private final CollectionPersister persister;
+
+ public CollectionFetch(
+ SessionFactoryImplementor sessionFactory,
+ String alias,
+ LockMode lockMode,
+ AbstractFetchOwner owner,
+ FetchStrategy fetchStrategy,
+ String ownerProperty,
+ CollectionAliases collectionAliases,
+ EntityAliases elementEntityAliases) {
+ super( sessionFactory, alias, lockMode, owner, ownerProperty, fetchStrategy );
+ this.collectionAliases = collectionAliases;
+ this.elementEntityAliases = elementEntityAliases;
+
+ final String role = owner.retrieveFetchSourcePersister().getEntityName() + '.' + getOwnerPropertyName();
+ this.persister = sessionFactory.getCollectionPersister( role );
+ }
+
+ @Override
+ public CollectionAliases getCollectionAliases() {
+ return collectionAliases;
+ }
+
+ @Override
+ public EntityAliases getElementEntityAliases() {
+ return elementEntityAliases;
+ }
+
+ @Override
+ public CollectionPersister getCollectionPersister() {
+ return persister;
+ }
+
+ @Override
+ public EntityPersister retrieveFetchSourcePersister() {
+ return ( (QueryableCollection) getCollectionPersister() ).getElementPersister();
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/CollectionReference.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/CollectionReference.java
new file mode 100644
index 0000000000..fa0460e922
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/CollectionReference.java
@@ -0,0 +1,73 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2012, 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.loader.plan.spi;
+
+import org.hibernate.LockMode;
+import org.hibernate.loader.CollectionAliases;
+import org.hibernate.loader.EntityAliases;
+import org.hibernate.persister.collection.CollectionPersister;
+
+/**
+ * Represents a reference to an owned collection either as a return or as a fetch
+ *
+ * @author Steve Ebersole
+ */
+public interface CollectionReference {
+ /**
+ * Retrieve the alias associated with the persister (entity/collection).
+ *
+ * @return The alias
+ */
+ public String getAlias();
+
+ /**
+ * Retrieve the lock mode associated with this return.
+ *
+ * @return The lock mode.
+ */
+ public LockMode getLockMode();
+
+ /**
+ * Retrieves the CollectionPersister describing the collection associated with this Return.
+ *
+ * @return The CollectionPersister.
+ */
+ public CollectionPersister getCollectionPersister();
+
+ /**
+ * Returns the description of the aliases in the JDBC ResultSet that identify values "belonging" to the
+ * this collection.
+ *
+ * @return The ResultSet alias descriptor for the collection
+ */
+ public CollectionAliases getCollectionAliases();
+
+ /**
+ * If the elements of this collection are entities, this methods returns the JDBC ResultSet alias descriptions
+ * for that entity; {@code null} indicates a non-entity collection.
+ *
+ * @return The ResultSet alias descriptor for the collection's entity element, or {@code null}
+ */
+ public EntityAliases getElementEntityAliases();
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/CollectionReturn.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/CollectionReturn.java
new file mode 100644
index 0000000000..0dacc39806
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/CollectionReturn.java
@@ -0,0 +1,113 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2012, 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.loader.plan.spi;
+
+import org.hibernate.LockMode;
+import org.hibernate.engine.FetchStrategy;
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.loader.CollectionAliases;
+import org.hibernate.loader.EntityAliases;
+import org.hibernate.loader.PropertyPath;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * @author Steve Ebersole
+ */
+public class CollectionReturn extends AbstractFetchOwner implements Return, FetchOwner, CollectionReference {
+ private final String ownerEntityName;
+ private final String ownerProperty;
+ private final CollectionAliases collectionAliases;
+ private final EntityAliases elementEntityAliases;
+
+ private final CollectionPersister persister;
+
+ private final PropertyPath propertyPath = new PropertyPath(); // its a root
+
+ public CollectionReturn(
+ SessionFactoryImplementor sessionFactory,
+ String alias,
+ LockMode lockMode,
+ String ownerEntityName,
+ String ownerProperty,
+ CollectionAliases collectionAliases,
+ EntityAliases elementEntityAliases) {
+ super( sessionFactory, alias, lockMode );
+ this.ownerEntityName = ownerEntityName;
+ this.ownerProperty = ownerProperty;
+ this.collectionAliases = collectionAliases;
+ this.elementEntityAliases = elementEntityAliases;
+
+ final String role = ownerEntityName + '.' + ownerProperty;
+ this.persister = sessionFactory.getCollectionPersister( role );
+ }
+
+ /**
+ * Returns the class owning the collection.
+ *
+ * @return The class owning the collection.
+ */
+ public String getOwnerEntityName() {
+ return ownerEntityName;
+ }
+
+ /**
+ * Returns the name of the property representing the collection from the {@link #getOwnerEntityName}.
+ *
+ * @return The name of the property representing the collection on the owner class.
+ */
+ public String getOwnerProperty() {
+ return ownerProperty;
+ }
+
+ @Override
+ public CollectionAliases getCollectionAliases() {
+ return collectionAliases;
+ }
+
+ @Override
+ public EntityAliases getElementEntityAliases() {
+ return elementEntityAliases;
+ }
+
+ @Override
+ public CollectionPersister getCollectionPersister() {
+ return persister;
+ }
+
+ @Override
+ public void validateFetchPlan(FetchStrategy fetchStrategy) {
+ }
+
+ @Override
+ public EntityPersister retrieveFetchSourcePersister() {
+ return ( (QueryableCollection) persister ).getElementPersister();
+ }
+
+ @Override
+ public PropertyPath getPropertyPath() {
+ return propertyPath;
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/CompositeFetch.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/CompositeFetch.java
new file mode 100644
index 0000000000..48d2f4c415
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/CompositeFetch.java
@@ -0,0 +1,51 @@
+/*
+ * jDocBook, processing of DocBook sources
+ *
+ * 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.loader.plan.spi;
+
+import org.hibernate.LockMode;
+import org.hibernate.engine.FetchStrategy;
+import org.hibernate.engine.FetchStyle;
+import org.hibernate.engine.FetchTiming;
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * @author Steve Ebersole
+ */
+public class CompositeFetch extends AbstractFetch implements Fetch {
+ public static final FetchStrategy FETCH_PLAN = new FetchStrategy( FetchTiming.IMMEDIATE, FetchStyle.JOIN );
+
+ public CompositeFetch(
+ SessionFactoryImplementor sessionFactory,
+ String alias,
+ AbstractFetchOwner owner,
+ String ownerProperty) {
+ super( sessionFactory, alias, LockMode.NONE, owner, ownerProperty, FETCH_PLAN );
+ }
+
+ @Override
+ public EntityPersister retrieveFetchSourcePersister() {
+ return getOwner().retrieveFetchSourcePersister();
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/EntityFetch.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/EntityFetch.java
new file mode 100644
index 0000000000..252e3e0288
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/EntityFetch.java
@@ -0,0 +1,78 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2012, 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.loader.plan.spi;
+
+import org.hibernate.LockMode;
+import org.hibernate.engine.FetchStrategy;
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.loader.EntityAliases;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.type.EntityType;
+
+/**
+ * @author Steve Ebersole
+ */
+public class EntityFetch extends AbstractFetch implements EntityReference {
+ private final String sqlTableAlias;
+ private final EntityAliases entityAliases;
+
+ private final EntityPersister persister;
+
+ public EntityFetch(
+ SessionFactoryImplementor sessionFactory,
+ String alias,
+ LockMode lockMode,
+ AbstractFetchOwner owner,
+ String ownerProperty,
+ FetchStrategy fetchStrategy,
+ String sqlTableAlias,
+ EntityAliases entityAliases) {
+ super( sessionFactory, alias, lockMode, owner, ownerProperty, fetchStrategy );
+ this.sqlTableAlias = sqlTableAlias;
+ this.entityAliases = entityAliases;
+
+ final EntityType type = (EntityType) owner.retrieveFetchSourcePersister().getPropertyType( ownerProperty );
+ this.persister = sessionFactory.getEntityPersister( type.getAssociatedEntityName() );
+ }
+
+ @Override
+ public EntityPersister getEntityPersister() {
+ return persister;
+ }
+
+ @Override
+ public EntityAliases getEntityAliases() {
+ return entityAliases;
+ }
+
+ @Override
+ public String getSqlTableAlias() {
+ return sqlTableAlias;
+ }
+
+ @Override
+ public EntityPersister retrieveFetchSourcePersister() {
+ return persister;
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/EntityReference.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/EntityReference.java
new file mode 100644
index 0000000000..d1102acc7b
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/EntityReference.java
@@ -0,0 +1,73 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2012, 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.loader.plan.spi;
+
+import org.hibernate.LockMode;
+import org.hibernate.loader.EntityAliases;
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * Represents a reference to an entity either as a return or as a fetch
+ *
+ * @author Steve Ebersole
+ */
+public interface EntityReference {
+ /**
+ * Retrieve the alias associated with the persister (entity/collection).
+ *
+ * @return The alias
+ */
+ public String getAlias();
+
+ /**
+ * Retrieve the lock mode associated with this return.
+ *
+ * @return The lock mode.
+ */
+ public LockMode getLockMode();
+
+ /**
+ * Retrieves the EntityPersister describing the entity associated with this Return.
+ *
+ * @return The EntityPersister.
+ */
+ public EntityPersister getEntityPersister();
+
+ /**
+ * Returns the description of the aliases in the JDBC ResultSet that identify values "belonging" to the this entity.
+ *
+ * @return The ResultSet alias descriptor.
+ */
+ public EntityAliases getEntityAliases();
+
+ /**
+ * Obtain the SQL table alias associated with this entity.
+ *
+ * TODO : eventually this needs to not be a String, but a representation like I did for the Antlr3 branch
+ * (AliasRoot, I think it was called)
+ *
+ * @return The SQL table alias for this entity
+ */
+ public String getSqlTableAlias();
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/EntityReturn.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/EntityReturn.java
new file mode 100644
index 0000000000..eb14ecf297
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/EntityReturn.java
@@ -0,0 +1,96 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2012, 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.loader.plan.spi;
+
+import org.hibernate.LockMode;
+import org.hibernate.engine.FetchStrategy;
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.loader.EntityAliases;
+import org.hibernate.loader.PropertyPath;
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * @author Steve Ebersole
+ */
+public class EntityReturn extends AbstractFetchOwner implements Return, FetchOwner, EntityReference {
+ private final EntityAliases entityAliases;
+ private final String sqlTableAlias;
+
+ private final EntityPersister persister;
+
+ private final PropertyPath propertyPath = new PropertyPath(); // its a root
+
+ public EntityReturn(
+ SessionFactoryImplementor sessionFactory,
+ String alias,
+ LockMode lockMode,
+ String entityName,
+ String sqlTableAlias,
+ EntityAliases entityAliases) {
+ super( sessionFactory, alias, lockMode );
+ this.entityAliases = entityAliases;
+ this.sqlTableAlias = sqlTableAlias;
+
+ this.persister = sessionFactory.getEntityPersister( entityName );
+ }
+
+ @Override
+ public String getAlias() {
+ return super.getAlias();
+ }
+
+ @Override
+ public LockMode getLockMode() {
+ return super.getLockMode();
+ }
+
+ @Override
+ public EntityPersister getEntityPersister() {
+ return persister;
+ }
+
+ @Override
+ public EntityAliases getEntityAliases() {
+ return entityAliases;
+ }
+
+ @Override
+ public String getSqlTableAlias() {
+ return sqlTableAlias;
+ }
+
+ @Override
+ public void validateFetchPlan(FetchStrategy fetchStrategy) {
+ }
+
+ @Override
+ public EntityPersister retrieveFetchSourcePersister() {
+ return getEntityPersister();
+ }
+
+ @Override
+ public PropertyPath getPropertyPath() {
+ return propertyPath;
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/Fetch.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/Fetch.java
new file mode 100644
index 0000000000..4be5ca8bbc
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/Fetch.java
@@ -0,0 +1,59 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2012, 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.loader.plan.spi;
+
+import org.hibernate.engine.FetchStrategy;
+import org.hibernate.loader.PropertyPath;
+
+/**
+ * Contract for associations that are being fetched.
+ *
+ * NOTE : can represent components/embeddables
+ *
+ * @author Steve Ebersole
+ */
+public interface Fetch extends FetchOwner {
+ /**
+ * Obtain the owner of this fetch.
+ *
+ * @return The fetch owner.
+ */
+ public FetchOwner getOwner();
+
+ /**
+ * Obtain the name of the property, relative to the owner, being fetched.
+ *
+ * @return The fetched property name.
+ */
+ public String getOwnerPropertyName();
+
+ public FetchStrategy getFetchStrategy();
+
+ /**
+ * Get the property path to this fetch
+ *
+ * @return The property path
+ */
+ public PropertyPath getPropertyPath();
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/FetchOwner.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/FetchOwner.java
new file mode 100644
index 0000000000..e28daf1b24
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/FetchOwner.java
@@ -0,0 +1,68 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2012, 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.loader.plan.spi;
+
+import org.hibernate.engine.FetchStrategy;
+import org.hibernate.loader.PropertyPath;
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * Contract for owners of fetches. Any non-scalar return could be a fetch owner.
+ *
+ * @author Steve Ebersole
+ */
+public interface FetchOwner {
+ /**
+ * Convenient constant for returning no fetches from {@link #getFetches()}
+ */
+ public static final Fetch[] NO_FETCHES = new Fetch[0];
+
+ /**
+ * Retrieve the fetches owned by this return.
+ *
+ * @return The owned fetches.
+ */
+ public Fetch[] getFetches();
+
+ /**
+ * Is the asserted plan valid from this owner to a fetch?
+ *
+ * @param fetchStrategy The pla to validate
+ */
+ public void validateFetchPlan(FetchStrategy fetchStrategy);
+
+ /**
+ * Retrieve the EntityPersister that is the base for any property references in the fetches it owns.
+ *
+ * @return The EntityPersister, for property name resolution.
+ */
+ public EntityPersister retrieveFetchSourcePersister();
+
+ /**
+ * Get the property path to this fetch owner
+ *
+ * @return The property path
+ */
+ public PropertyPath getPropertyPath();
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/LoadPlan.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/LoadPlan.java
new file mode 100644
index 0000000000..0173b39714
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/LoadPlan.java
@@ -0,0 +1,61 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2012, 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.loader.plan.spi;
+
+import java.util.List;
+
+/**
+ * Describes a plan for performing a load of results.
+ *
+ * Generally speaking there are 3 forms of load plans:
+ * -
+ * An entity load plan for handling get/load handling. This form will typically have a single
+ * return (of type {@link EntityReturn}) defined by {@link #getReturns()}, possibly defining fetches.
+ *
+ * -
+ * A collection initializer, used to load the contents of a collection. This form will typically have a
+ * single return (of type {@link CollectionReturn} defined by {@link #getReturns()}, possibly defining fetches
+ *
+ * -
+ * A query load plan which can contain multiple returns of mixed type (though implementing {@link Return}).
+ * Again, may possibly define fetches.
+ *
+ *
+ *
+ * @author Steve Ebersole
+ */
+public interface LoadPlan {
+ /**
+ * Convenient form of checking {@link #getReturns()} for scalar root returns.
+ *
+ * @return {@code true} if {@link #getReturns()} contained any scalar returns; {@code false} otherwise.
+ */
+ public boolean hasAnyScalarReturns();
+
+ public List getReturns();
+
+ // todo : would also like to see "call back" style access for handling "subsequent actions" such as:
+ // 1) follow-on locking
+ // 2) join fetch conversions to subselect fetches
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/LoadPlanBuilder.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/LoadPlanBuilder.java
new file mode 100644
index 0000000000..61b7b41ab1
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/LoadPlanBuilder.java
@@ -0,0 +1,64 @@
+/*
+ * jDocBook, processing of DocBook sources
+ *
+ * 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.loader.plan.spi;
+
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.persister.walking.spi.MetadataDrivenModelGraphVisitor;
+
+/**
+ * Coordinates building of a {@link LoadPlan} between the {@link org.hibernate.persister.walking.spi.MetadataDrivenModelGraphVisitor} and
+ * {@link LoadPlanBuilderStrategy}
+ *
+ * @author Steve Ebersole
+ */
+public class LoadPlanBuilder {
+ /**
+ * Coordinates building a LoadPlan that defines just a single root entity return (may have fetches).
+ *
+ * Typically this includes building load plans for entity loading or cascade loading.
+ *
+ * @param strategy The strategy defining the load plan shaping
+ * @param persister The persister for the entity forming the root of the load plan.
+ *
+ * @return The built load plan.
+ */
+ public static LoadPlan buildRootEntityLoadPlan(LoadPlanBuilderStrategy strategy, EntityPersister persister) {
+ MetadataDrivenModelGraphVisitor.visitEntity( strategy, persister );
+ return strategy.buildLoadPlan();
+ }
+
+ /**
+ * Coordinates building a LoadPlan that defines just a single root collection return (may have fetches).
+ *
+ * @param strategy The strategy defining the load plan shaping
+ * @param persister The persister for the collection forming the root of the load plan.
+ *
+ * @return The built load plan.
+ */
+ public static LoadPlan buildRootCollectionLoadPlan(LoadPlanBuilderStrategy strategy, CollectionPersister persister) {
+ MetadataDrivenModelGraphVisitor.visitCollection( strategy, persister );
+ return strategy.buildLoadPlan();
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/LoadPlanBuilderStrategy.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/LoadPlanBuilderStrategy.java
new file mode 100644
index 0000000000..7c40540fbf
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/LoadPlanBuilderStrategy.java
@@ -0,0 +1,40 @@
+/*
+ * jDocBook, processing of DocBook sources
+ *
+ * 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.loader.plan.spi;
+
+import org.hibernate.persister.walking.spi.AssociationVisitationStrategy;
+
+/**
+ * Specialized {@link org.hibernate.persister.walking.spi.AssociationVisitationStrategy} implementation for building {@link LoadPlan} instances.
+ *
+ * @author Steve Ebersole
+ */
+public interface LoadPlanBuilderStrategy extends AssociationVisitationStrategy {
+ /**
+ * After visitation is done, build the load plan.
+ *
+ * @return The load plan
+ */
+ public LoadPlan buildLoadPlan();
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/Return.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/Return.java
new file mode 100644
index 0000000000..b94adfae9d
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/Return.java
@@ -0,0 +1,40 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2012, 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.loader.plan.spi;
+
+/**
+ * Represents a return value in the query results. Not the same as a result (column) in the JDBC ResultSet!
+ *
+ * This is merely a unifying contract; it defines no behavior.
+ *
+ * Return is distinctly different from a {@link Fetch}.
+ *
+ * @see ScalarReturn
+ * @see EntityReturn
+ * @see CollectionReturn
+ *
+ * @author Steve Ebersole
+ */
+public interface Return {
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/ReturnVisitationStrategy.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/ReturnVisitationStrategy.java
new file mode 100644
index 0000000000..4140249b3a
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/ReturnVisitationStrategy.java
@@ -0,0 +1,138 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2012, 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.loader.plan.spi;
+
+/**
+ * @author Steve Ebersole
+ */
+public interface ReturnVisitationStrategy {
+ /**
+ * Notification we are preparing to start visitation.
+ */
+ public void start();
+
+ /**
+ * Notification we are finished visitation.
+ */
+ public void finish();
+
+ /**
+ * Notification that a new root return branch is being started. Will be followed by calls to one of the following
+ * based on the type of return:
+ * - {@link #handleScalarReturn}
+ * - {@link #handleEntityReturn}
+ * - {@link #handleCollectionReturn}
+ *
+ *
+ * @param rootReturn The root return at the root of the branch.
+ */
+ public void startingRootReturn(Return rootReturn);
+
+ /**
+ * Notification that we are finishing up processing a root return branch
+ *
+ * @param rootReturn The RootReturn we are finishing up processing.
+ */
+ public void finishingRootReturn(Return rootReturn);
+
+ /**
+ * Notification that a scalar return is being processed. Will be surrounded by calls to {@link #startingRootReturn}
+ * and {@link #finishingRootReturn}
+ *
+ * @param scalarReturn The scalar return
+ */
+ public void handleScalarReturn(ScalarReturn scalarReturn);
+
+ /**
+ * Notification that a root entity return is being processed. Will be surrounded by calls to
+ * {@link #startingRootReturn} and {@link #finishingRootReturn}
+ *
+ * @param rootEntityReturn The root entity return
+ */
+ public void handleEntityReturn(EntityReturn rootEntityReturn);
+
+ /**
+ * Notification that a root collection return is being processed. Will be surrounded by calls to
+ * {@link #startingRootReturn} and {@link #finishingRootReturn}
+ *
+ * @param rootCollectionReturn The root collection return
+ */
+ public void handleCollectionReturn(CollectionReturn rootCollectionReturn);
+
+ /**
+ * Notification that we are about to start processing the fetches for the given fetch owner.
+ *
+ * @param fetchOwner The fetch owner.
+ */
+ public void startingFetches(FetchOwner fetchOwner);
+
+ /**
+ * Notification that we are finishing up processing the fetches for the given fetch owner.
+ *
+ * @param fetchOwner The fetch owner.
+ */
+ public void finishingFetches(FetchOwner fetchOwner);
+
+ /**
+ * Notification we are starting the processing of an entity fetch
+ *
+ * @param entityFetch The entity fetch
+ */
+ public void startingEntityFetch(EntityFetch entityFetch);
+
+ /**
+ * Notification that we are finishing up the processing of an entity fetch
+ *
+ * @param entityFetch The entity fetch
+ */
+ public void finishingEntityFetch(EntityFetch entityFetch);
+
+ /**
+ * Notification we are starting the processing of a collection fetch
+ *
+ * @param collectionFetch The collection fetch
+ */
+ public void startingCollectionFetch(CollectionFetch collectionFetch);
+
+ /**
+ * Notification that we are finishing up the processing of a collection fetch
+ *
+ * @param collectionFetch The collection fetch
+ */
+ public void finishingCollectionFetch(CollectionFetch collectionFetch);
+
+ /**
+ * Notification we are starting the processing of a component fetch
+ *
+ * @param fetch The composite fetch
+ */
+ public void startingCompositeFetch(CompositeFetch fetch);
+
+ /**
+ * Notification that we are finishing up the processing of a composite fetch
+ *
+ * @param fetch The composite fetch
+ */
+ public void finishingCompositeFetch(CompositeFetch fetch);
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/ReturnVisitor.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/ReturnVisitor.java
new file mode 100644
index 0000000000..cf4aaf6ef9
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/ReturnVisitor.java
@@ -0,0 +1,116 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2012, 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.loader.plan.spi;
+
+/**
+ * Visitor for processing {@link Return} graphs
+ *
+ * @author Steve Ebersole
+ */
+public class ReturnVisitor {
+ public static void visit(Return[] rootReturns, ReturnVisitationStrategy strategy) {
+ new ReturnVisitor( strategy ).visitReturns( rootReturns );
+ }
+
+ private final ReturnVisitationStrategy strategy;
+
+ public ReturnVisitor(ReturnVisitationStrategy strategy) {
+ this.strategy = strategy;
+ }
+
+ private void visitReturns(Return[] rootReturns) {
+ strategy.start();
+
+ for ( Return rootReturn : rootReturns ) {
+ visitRootReturn( rootReturn );
+ }
+
+ strategy.finish();
+ }
+
+ private void visitRootReturn(Return rootReturn) {
+ strategy.startingRootReturn( rootReturn );
+
+ if ( org.hibernate.loader.plan.spi.ScalarReturn.class.isInstance( rootReturn ) ) {
+ strategy.handleScalarReturn( (ScalarReturn) rootReturn );
+ }
+ else {
+ visitNonScalarRootReturn( rootReturn );
+ }
+
+ strategy.finishingRootReturn( rootReturn );
+ }
+
+ private void visitNonScalarRootReturn(Return rootReturn) {
+ if ( EntityReturn.class.isInstance( rootReturn ) ) {
+ strategy.handleEntityReturn( (EntityReturn) rootReturn );
+ visitFetches( (EntityReturn) rootReturn );
+ }
+ else if ( CollectionReturn.class.isInstance( rootReturn ) ) {
+ strategy.handleCollectionReturn( (CollectionReturn) rootReturn );
+ visitFetches( (CollectionReturn) rootReturn );
+ }
+ else {
+ throw new IllegalStateException(
+ "Unexpected return type encountered; expecting a non-scalar root return, but found " +
+ rootReturn.getClass().getName()
+ );
+ }
+ }
+
+ private void visitFetches(FetchOwner fetchOwner) {
+ strategy.startingFetches( fetchOwner );
+
+ for ( Fetch fetch : fetchOwner.getFetches() ) {
+ visitFetch( fetch );
+ }
+
+ strategy.finishingFetches( fetchOwner );
+ }
+
+ private void visitFetch(Fetch fetch) {
+ if ( EntityFetch.class.isInstance( fetch ) ) {
+ strategy.startingEntityFetch( (EntityFetch) fetch );
+ visitFetches( fetch );
+ strategy.finishingEntityFetch( (EntityFetch) fetch );
+ }
+ else if ( CollectionFetch.class.isInstance( fetch ) ) {
+ strategy.startingCollectionFetch( (CollectionFetch) fetch );
+ visitFetches( fetch );
+ strategy.finishingCollectionFetch( (CollectionFetch) fetch );
+ }
+ else if ( CompositeFetch.class.isInstance( fetch ) ) {
+ strategy.startingCompositeFetch( (CompositeFetch) fetch );
+ visitFetches( fetch );
+ strategy.finishingCompositeFetch( (CompositeFetch) fetch );
+ }
+ else {
+ throw new IllegalStateException(
+ "Unexpected return type encountered; expecting a fetch return, but found " +
+ fetch.getClass().getName()
+ );
+ }
+ }
+
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/ScalarReturn.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/ScalarReturn.java
new file mode 100644
index 0000000000..9a3d434bbc
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/spi/ScalarReturn.java
@@ -0,0 +1,52 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2012, 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.loader.plan.spi;
+
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.type.Type;
+
+/**
+ * Represent a simple scalar return within a query result. Generally this would be values of basic (String, Integer,
+ * etc) or composite types.
+ *
+ * @author Steve Ebersole
+ */
+public class ScalarReturn extends AbstractPlanNode implements Return {
+ private final Type type;
+ private final String columnAlias;
+
+ public ScalarReturn(SessionFactoryImplementor factory, Type type, String columnAlias) {
+ super( factory );
+ this.type = type;
+ this.columnAlias = columnAlias;
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ public String getColumnAlias() {
+ return columnAlias;
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java
index 5236a08712..0db82ac72c 100644
--- a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java
+++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java
@@ -79,6 +79,11 @@ import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.entity.PropertyMapping;
import org.hibernate.persister.entity.Queryable;
+import org.hibernate.persister.walking.spi.CollectionDefinition;
+import org.hibernate.persister.walking.spi.CollectionElementDefinition;
+import org.hibernate.persister.walking.spi.CollectionIndexDefinition;
+import org.hibernate.persister.walking.spi.CompositeDefinition;
+import org.hibernate.persister.walking.spi.EntityDefinition;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.sql.Alias;
import org.hibernate.sql.SelectFragment;
@@ -90,6 +95,7 @@ import org.hibernate.sql.ordering.antlr.FormulaReference;
import org.hibernate.sql.ordering.antlr.OrderByAliasResolver;
import org.hibernate.sql.ordering.antlr.OrderByTranslation;
import org.hibernate.sql.ordering.antlr.SqlValueReference;
+import org.hibernate.type.AssociationType;
import org.hibernate.type.CollectionType;
import org.hibernate.type.CompositeType;
import org.hibernate.type.EntityType;
@@ -1934,4 +1940,79 @@ public abstract class AbstractCollectionPersister
public abstract FilterAliasGenerator getFilterAliasGenerator(final String rootAlias);
+
+ // ColectionDefinition impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ @Override
+ public CollectionPersister getCollectionPersister() {
+ return this;
+ }
+
+ @Override
+ public CollectionIndexDefinition getIndexDefinition() {
+ if ( ! hasIndex() ) {
+ return null;
+ }
+
+ return new CollectionIndexDefinition() {
+ @Override
+ public CollectionDefinition getCollectionDefinition() {
+ return AbstractCollectionPersister.this;
+ }
+
+ @Override
+ public Type getType() {
+ return getIndexType();
+ }
+
+ @Override
+ public EntityDefinition toEntityDefinition() {
+ if ( getType().isComponentType() ) {
+ throw new IllegalStateException( "Cannot treat composite collection index type as entity" );
+ }
+ return (EntityPersister) ( (AssociationType) getIndexType() ).getAssociatedJoinable( getFactory() );
+ }
+
+ @Override
+ public CompositeDefinition toCompositeDefinition() {
+ if ( ! getType().isComponentType() ) {
+ throw new IllegalStateException( "Cannot treat entity collection index type as composite" );
+ }
+ // todo : implement
+ throw new NotYetImplementedException();
+ }
+ };
+ }
+
+ @Override
+ public CollectionElementDefinition getElementDefinition() {
+ return new CollectionElementDefinition() {
+ @Override
+ public CollectionDefinition getCollectionDefinition() {
+ return AbstractCollectionPersister.this;
+ }
+
+ @Override
+ public Type getType() {
+ return getElementType();
+ }
+
+ @Override
+ public EntityDefinition toEntityDefinition() {
+ if ( getType().isComponentType() ) {
+ throw new IllegalStateException( "Cannot treat composite collection element type as entity" );
+ }
+ return getElementPersister();
+ }
+
+ @Override
+ public CompositeDefinition toCompositeDefinition() {
+ if ( ! getType().isComponentType() ) {
+ throw new IllegalStateException( "Cannot treat entity collection element type as composite" );
+ }
+ // todo : implement
+ throw new NotYetImplementedException();
+ }
+ };
+ }
}
diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/CollectionPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/CollectionPersister.java
index 3b2e3788dd..ecfe83c7d8 100644
--- a/hibernate-core/src/main/java/org/hibernate/persister/collection/CollectionPersister.java
+++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/CollectionPersister.java
@@ -38,6 +38,7 @@ import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.metadata.CollectionMetadata;
import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.persister.walking.spi.CollectionDefinition;
import org.hibernate.type.CollectionType;
import org.hibernate.type.Type;
@@ -60,7 +61,7 @@ import org.hibernate.type.Type;
* @see org.hibernate.collection.spi.PersistentCollection
* @author Gavin King
*/
-public interface CollectionPersister {
+public interface CollectionPersister extends CollectionDefinition {
/**
* Initialize the given collection with the given key
*/
diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java
index 860f4b74b2..5456404f04 100644
--- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java
+++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java
@@ -59,6 +59,7 @@ import org.hibernate.cache.spi.entry.ReferenceCacheEntryImpl;
import org.hibernate.cache.spi.entry.StandardCacheEntryImpl;
import org.hibernate.cache.spi.entry.StructuredCacheEntry;
import org.hibernate.cache.spi.entry.UnstructuredCacheEntry;
+import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.dialect.lock.LockingStrategy;
import org.hibernate.engine.OptimisticLockStyle;
import org.hibernate.engine.internal.StatefulPersistenceContext;
@@ -91,7 +92,6 @@ import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.jdbc.Expectation;
import org.hibernate.jdbc.Expectations;
import org.hibernate.jdbc.TooManyRowsAffectedException;
-import org.hibernate.loader.entity.BatchingEntityLoader;
import org.hibernate.loader.entity.BatchingEntityLoaderBuilder;
import org.hibernate.loader.entity.CascadeEntityLoader;
import org.hibernate.loader.entity.EntityLoader;
@@ -109,6 +109,7 @@ import org.hibernate.metamodel.binding.SimpleValueBinding;
import org.hibernate.metamodel.binding.SingularAttributeBinding;
import org.hibernate.metamodel.relational.DerivedValue;
import org.hibernate.metamodel.relational.Value;
+import org.hibernate.persister.walking.spi.AttributeDefinition;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.property.BackrefPropertyAccessor;
import org.hibernate.sql.Alias;
@@ -504,7 +505,7 @@ public abstract class AbstractEntityPersister
this.naturalIdRegionAccessStrategy = naturalIdRegionAccessStrategy;
isLazyPropertiesCacheable = persistentClass.isLazyPropertiesCacheable();
- this.entityMetamodel = new EntityMetamodel( persistentClass, factory );
+ this.entityMetamodel = new EntityMetamodel( persistentClass, this, factory );
this.entityTuplizer = this.entityMetamodel.getTuplizer();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -834,7 +835,7 @@ public abstract class AbstractEntityPersister
entityBinding.getHierarchyDetails().getCaching() == null ?
false :
entityBinding.getHierarchyDetails().getCaching().isCacheLazyProperties();
- this.entityMetamodel = new EntityMetamodel( entityBinding, factory );
+ this.entityMetamodel = new EntityMetamodel( entityBinding, this, factory );
this.entityTuplizer = this.entityMetamodel.getTuplizer();
int batch = entityBinding.getBatchSize();
if ( batch == -1 ) {
@@ -3816,10 +3817,11 @@ public abstract class AbstractEntityPersister
}
public void postInstantiate() throws MappingException {
+ generateEntityDefinition();
+
createLoaders();
createUniqueKeyLoaders();
createQueryLoader();
-
}
//needed by subclasses to override the createLoader strategy
@@ -5070,4 +5072,110 @@ public abstract class AbstractEntityPersister
throw new HibernateException( "Illegal attempt to build cache entry for non-cached entity" );
}
}
+
+
+ // EntityDefinition impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ private Iterable embeddedCompositeIdentifierAttributes;
+ private Iterable attributeDefinitions;
+
+ protected void generateEntityDefinition() {
+ collectEmbeddedCompositeIdentifierAttributeDefinitions();
+ collectAttributeDefinitions();
+ }
+
+ @Override
+ public EntityPersister getEntityPersister() {
+ return this;
+ }
+
+ @Override
+ public Iterable getEmbeddedCompositeIdentifierAttributes() {
+ return embeddedCompositeIdentifierAttributes;
+ }
+
+ @Override
+ public Iterable getAttributes() {
+ return attributeDefinitions;
+ }
+
+ private synchronized void collectEmbeddedCompositeIdentifierAttributeDefinitions() {
+ final Type idType = getIdentifierType();
+ if ( !idType.isComponentType() ) {
+ return;
+ }
+
+ final CompositeType cidType = (CompositeType) idType;
+ if ( !cidType.isEmbedded() ) {
+ return;
+ }
+
+ // we have an embedded composite identifier. Most likely we need to process the composite
+ // properties separately, although there is an edge case where the identifier is really
+ // a simple identifier (single value) wrapped in a JPA @IdClass or even in the case of a
+ // a simple identifier (single value) wrapped in a Hibernate composite type.
+ //
+ // We really do not have a built-in method to determine that. However, generally the
+ // persister would report that there is single, physical identifier property which is
+ // explicitly at odds with the notion of "embedded composite". So we use that for now
+ if ( getEntityMetamodel().getIdentifierProperty().isEmbedded() ) {
+ this.embeddedCompositeIdentifierAttributes = new Iterable() {
+ @Override
+ public Iterator iterator() {
+ return new Iterator() {
+ private final int numberOfAttributes = countSubclassProperties();
+ private int currentAttributeNumber = 0;
+
+ @Override
+ public boolean hasNext() {
+ return currentAttributeNumber < numberOfAttributes;
+ }
+
+ @Override
+ public AttributeDefinition next() {
+ // todo : implement
+ throw new NotYetImplementedException();
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException( "Remove operation not supported here" );
+ }
+ };
+ }
+ };
+ }
+ }
+
+ private void collectAttributeDefinitions() {
+ // todo : leverage the attribute definitions housed on EntityMetamodel
+ // for that to work, we'd have to be able to walk our super entity persister(s)
+ attributeDefinitions = new Iterable() {
+ @Override
+ public Iterator iterator() {
+ return new Iterator() {
+// private final int numberOfAttributes = countSubclassProperties();
+ private final int numberOfAttributes = entityMetamodel.getPropertySpan();
+ private int currentAttributeNumber = 0;
+
+ @Override
+ public boolean hasNext() {
+ return currentAttributeNumber < numberOfAttributes;
+ }
+
+ @Override
+ public AttributeDefinition next() {
+ final int attributeNumber = currentAttributeNumber;
+ currentAttributeNumber++;
+ return entityMetamodel.getProperties()[ attributeNumber ];
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException( "Remove operation not supported here" );
+ }
+ };
+ }
+ };
+ }
}
diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java
index f95ea71970..46d3fd8bee 100644
--- a/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java
+++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java
@@ -44,22 +44,25 @@ import org.hibernate.engine.spi.ValueInclusion;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.internal.FilterAliasGenerator;
import org.hibernate.metadata.ClassMetadata;
+import org.hibernate.persister.walking.spi.EntityDefinition;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.tuple.entity.EntityTuplizer;
import org.hibernate.type.Type;
import org.hibernate.type.VersionType;
/**
- * Implementors define mapping and persistence logic for a particular
- * strategy of entity mapping. An instance of entity persisters corresponds
- * to a given mapped entity.
+ * Contract describing mapping information and persistence logic for a particular strategy of entity mapping. A given
+ * persister instance corresponds to a given mapped entity class.
*
- * Implementors must be threadsafe (preferrably immutable) and must provide a constructor
- * matching the signature of: {@link org.hibernate.mapping.PersistentClass}, {@link org.hibernate.engine.spi.SessionFactoryImplementor}
+ * Implementations must be thread-safe (preferably immutable).
*
* @author Gavin King
+ * @author Steve Ebersole
+ *
+ * @see org.hibernate.persister.spi.PersisterFactory
+ * @see org.hibernate.persister.spi.PersisterClassResolver
*/
-public interface EntityPersister extends OptimisticCacheSource {
+public interface EntityPersister extends OptimisticCacheSource, EntityDefinition {
/**
* The property name of the "special" identifier property in HQL
diff --git a/hibernate-core/src/main/java/org/hibernate/persister/walking/internal/Helper.java b/hibernate-core/src/main/java/org/hibernate/persister/walking/internal/Helper.java
new file mode 100644
index 0000000000..29eb9f5dbe
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/persister/walking/internal/Helper.java
@@ -0,0 +1,160 @@
+/*
+ * jDocBook, processing of DocBook sources
+ *
+ * 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.persister.walking.internal;
+
+import java.util.Iterator;
+
+import org.hibernate.FetchMode;
+import org.hibernate.engine.FetchStyle;
+import org.hibernate.engine.FetchTiming;
+import org.hibernate.engine.profile.Fetch;
+import org.hibernate.engine.profile.FetchProfile;
+import org.hibernate.engine.spi.LoadQueryInfluencers;
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.loader.PropertyPath;
+import org.hibernate.persister.collection.AbstractCollectionPersister;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.persister.entity.OuterJoinLoadable;
+import org.hibernate.type.AssociationType;
+
+/**
+ * @author Steve Ebersole
+ */
+public class Helper {
+ /**
+ * Determine the fetch-style (if one) explicitly set for this association via fetch profiles.
+ *
+ * Note that currently fetch profiles only allow specifying join fetching, so this method currently
+ * returns either (a) FetchStyle.JOIN or (b) null
+ *
+ * @param loadQueryInfluencers
+ * @param persister
+ * @param path
+ * @param propertyNumber
+ *
+ * @return
+ */
+ public static FetchStyle determineFetchStyleByProfile(
+ LoadQueryInfluencers loadQueryInfluencers,
+ EntityPersister persister,
+ PropertyPath path,
+ int propertyNumber) {
+ if ( !loadQueryInfluencers.hasEnabledFetchProfiles() ) {
+ // perf optimization
+ return null;
+ }
+
+ // ugh, this stuff has to be made easier...
+ final String fullPath = path.getFullPath();
+ final String rootPropertyName = ( (OuterJoinLoadable) persister ).getSubclassPropertyName( propertyNumber );
+ int pos = fullPath.lastIndexOf( rootPropertyName );
+ final String relativePropertyPath = pos >= 0
+ ? fullPath.substring( pos )
+ : rootPropertyName;
+ final String fetchRole = persister.getEntityName() + "." + relativePropertyPath;
+
+ Iterator profiles = loadQueryInfluencers.getEnabledFetchProfileNames().iterator();
+ while ( profiles.hasNext() ) {
+ final String profileName = ( String ) profiles.next();
+ final FetchProfile profile = loadQueryInfluencers.getSessionFactory().getFetchProfile( profileName );
+ final Fetch fetch = profile.getFetchByRole( fetchRole );
+ if ( fetch != null && Fetch.Style.JOIN == fetch.getStyle() ) {
+ return FetchStyle.JOIN;
+ }
+ }
+ return null;
+ }
+
+ /**
+ *
+ * @param mappingFetchMode The mapping defined fetch mode
+ * @param type The association type
+ * @param sessionFactory The session factory
+ *
+ * @return
+ */
+ public static FetchStyle determineFetchStyleByMetadata(
+ FetchMode mappingFetchMode,
+ AssociationType type,
+ SessionFactoryImplementor sessionFactory) {
+ if ( !type.isEntityType() && !type.isCollectionType() ) {
+ return FetchStyle.SELECT;
+ }
+
+ if ( mappingFetchMode == FetchMode.JOIN ) {
+ return FetchStyle.JOIN;
+ }
+
+ if ( type.isEntityType() ) {
+ EntityPersister persister = (EntityPersister) type.getAssociatedJoinable( sessionFactory );
+ if ( persister.isBatchLoadable() ) {
+ return FetchStyle.BATCH;
+ }
+ }
+ else {
+ CollectionPersister persister = (CollectionPersister) type.getAssociatedJoinable( sessionFactory );
+ if ( persister instanceof AbstractCollectionPersister
+ && ( (AbstractCollectionPersister) persister ).isSubselectLoadable() ) {
+ return FetchStyle.SUBSELECT;
+ }
+ else if ( persister.getBatchSize() > 0 ) {
+ return FetchStyle.BATCH;
+ }
+ }
+
+ return FetchStyle.SELECT;
+ }
+
+ public static FetchTiming determineFetchTiming(
+ FetchStyle style,
+ AssociationType type,
+ SessionFactoryImplementor sessionFactory) {
+ switch ( style ) {
+ case JOIN: {
+ return FetchTiming.IMMEDIATE;
+ }
+ case BATCH:
+ case SUBSELECT: {
+ return FetchTiming.DELAYED;
+ }
+ default: {
+ // SELECT case, can be either
+ return isSubsequentSelectDelayed( type, sessionFactory )
+ ? FetchTiming.DELAYED
+ : FetchTiming.IMMEDIATE;
+ }
+ }
+ }
+
+ private static boolean isSubsequentSelectDelayed(AssociationType type, SessionFactoryImplementor sessionFactory) {
+ if ( type.isEntityType() ) {
+ return ( (EntityPersister) type.getAssociatedJoinable( sessionFactory ) ).hasProxy();
+ }
+ else {
+ final CollectionPersister cp = ( (CollectionPersister) type.getAssociatedJoinable( sessionFactory ) );
+ return cp.isLazy() || cp.isExtraLazy();
+ }
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/AssociationAttributeDefinition.java b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/AssociationAttributeDefinition.java
new file mode 100644
index 0000000000..383b3d4e38
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/AssociationAttributeDefinition.java
@@ -0,0 +1,46 @@
+/*
+ * 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.persister.walking.spi;
+
+import org.hibernate.engine.FetchStrategy;
+import org.hibernate.engine.spi.CascadeStyle;
+import org.hibernate.engine.spi.LoadQueryInfluencers;
+import org.hibernate.loader.PropertyPath;
+
+/**
+ * @author Steve Ebersole
+ */
+public interface AssociationAttributeDefinition extends AttributeDefinition {
+ public AssociationKey getAssociationKey();
+
+ public boolean isCollection();
+
+ public EntityDefinition toEntityDefinition();
+
+ public CollectionDefinition toCollectionDefinition();
+
+ public FetchStrategy determineFetchPlan(LoadQueryInfluencers loadQueryInfluencers, PropertyPath propertyPath);
+
+ public CascadeStyle determineCascadeStyle();
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/AssociationKey.java b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/AssociationKey.java
new file mode 100644
index 0000000000..352c4a548f
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/AssociationKey.java
@@ -0,0 +1,53 @@
+/*
+ * 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.persister.walking.spi;
+
+import java.util.Arrays;
+
+/**
+ * Used to uniquely identify a foreign key, so that we don't join it more than once creating circularities.
+ *
+ * bit of a misnomer to call this an association attribute. But this follows the legacy use of AssociationKey
+ * from old JoinWalkers to denote circular join detection
+ */
+public class AssociationKey {
+ private final String table;
+ private final String[] columns;
+
+ public AssociationKey(String table, String[] columns) {
+ this.table = table;
+ this.columns = columns;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ AssociationKey that = (AssociationKey) other;
+ return that.table.equals(table) && Arrays.equals( columns, that.columns );
+ }
+
+ @Override
+ public int hashCode() {
+ return table.hashCode(); //TODO: inefficient
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/AssociationVisitationStrategy.java b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/AssociationVisitationStrategy.java
new file mode 100644
index 0000000000..1cb649b0d8
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/AssociationVisitationStrategy.java
@@ -0,0 +1,51 @@
+/*
+ * 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.persister.walking.spi;
+
+/**
+ * @author Steve Ebersole
+ */
+public interface AssociationVisitationStrategy {
+ /**
+ * Notification we are preparing to start visitation.
+ */
+ public void start();
+
+ /**
+ * Notification we are finished visitation.
+ */
+ public void finish();
+
+ public void startingEntity(EntityDefinition entityDefinition);
+ public void finishingEntity(EntityDefinition entityDefinition);
+
+ public void startingCollection(CollectionDefinition collectionDefinition);
+ public void finishingCollection(CollectionDefinition collectionDefinition);
+
+ public void startingComposite(CompositeDefinition compositeDefinition);
+ public void finishingComposite(CompositeDefinition compositeDefinition);
+
+ public boolean startingAttribute(AttributeDefinition attributeDefinition);
+ public void finishingAttribute(AttributeDefinition attributeDefinition);
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/AttributeDefinition.java b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/AttributeDefinition.java
new file mode 100644
index 0000000000..ed58612671
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/AttributeDefinition.java
@@ -0,0 +1,35 @@
+/*
+ * 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.persister.walking.spi;
+
+import org.hibernate.type.Type;
+
+/**
+ * @author Steve Ebersole
+ */
+public interface AttributeDefinition {
+ public String getName();
+ public Type getType();
+ public AttributeSource getSource();
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/AttributeSource.java b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/AttributeSource.java
new file mode 100644
index 0000000000..a94dfb1987
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/AttributeSource.java
@@ -0,0 +1,31 @@
+/*
+ * 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.persister.walking.spi;
+
+/**
+* @author Steve Ebersole
+*/
+public interface AttributeSource {
+ public Iterable getAttributes();
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/CollectionDefinition.java b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/CollectionDefinition.java
new file mode 100644
index 0000000000..f7e2fb6ad7
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/CollectionDefinition.java
@@ -0,0 +1,38 @@
+/*
+ * 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.persister.walking.spi;
+
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.type.CollectionType;
+
+/**
+ * @author Steve Ebersole
+ */
+public interface CollectionDefinition {
+ public CollectionPersister getCollectionPersister();
+ public CollectionType getCollectionType();
+
+ public CollectionIndexDefinition getIndexDefinition();
+ public CollectionElementDefinition getElementDefinition();
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/CollectionElementDefinition.java b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/CollectionElementDefinition.java
new file mode 100644
index 0000000000..fd48366c3a
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/CollectionElementDefinition.java
@@ -0,0 +1,39 @@
+/*
+ * jDocBook, processing of DocBook sources
+ *
+ * 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.persister.walking.spi;
+
+import org.hibernate.type.Type;
+
+/**
+ * @author Steve Ebersole
+ */
+public interface CollectionElementDefinition {
+ public CollectionDefinition getCollectionDefinition();
+
+ public Type getType();
+
+ public EntityDefinition toEntityDefinition();
+
+ public CompositeDefinition toCompositeDefinition();
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/CollectionIndexDefinition.java b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/CollectionIndexDefinition.java
new file mode 100644
index 0000000000..700e2b5070
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/CollectionIndexDefinition.java
@@ -0,0 +1,39 @@
+/*
+ * jDocBook, processing of DocBook sources
+ *
+ * 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.persister.walking.spi;
+
+import org.hibernate.type.Type;
+
+/**
+ * @author Steve Ebersole
+ */
+public interface CollectionIndexDefinition {
+ public CollectionDefinition getCollectionDefinition();
+
+ public Type getType();
+
+ public EntityDefinition toEntityDefinition();
+
+ public CompositeDefinition toCompositeDefinition();
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/CompositeDefinition.java b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/CompositeDefinition.java
new file mode 100644
index 0000000000..51c88333f4
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/CompositeDefinition.java
@@ -0,0 +1,30 @@
+/*
+ * 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.persister.walking.spi;
+
+/**
+ * @author Steve Ebersole
+ */
+public interface CompositeDefinition extends AttributeDefinition, AttributeSource {
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/EntityDefinition.java b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/EntityDefinition.java
new file mode 100644
index 0000000000..1e02b42106
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/EntityDefinition.java
@@ -0,0 +1,36 @@
+/*
+ * 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.persister.walking.spi;
+
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * Defines the contract for walking the attributes defined by an entity
+ *
+ * @author Steve Ebersole
+ */
+public interface EntityDefinition extends AttributeSource {
+ public EntityPersister getEntityPersister();
+ public Iterable getEmbeddedCompositeIdentifierAttributes();
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/MetadataDrivenModelGraphVisitor.java b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/MetadataDrivenModelGraphVisitor.java
new file mode 100644
index 0000000000..ccbbceb6bb
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/MetadataDrivenModelGraphVisitor.java
@@ -0,0 +1,208 @@
+/*
+ * 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.persister.walking.spi;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.jboss.logging.Logger;
+
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.loader.PropertyPath;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.type.Type;
+
+/**
+ * Provides model graph visitation based on the defined metadata (as opposed to based on the incoming graph
+ * as we see in cascade processing). In layman terms, we are walking the graph of the users model as defined by
+ * mapped associations.
+ *
+ * Re-implementation of the legacy {@link org.hibernate.loader.JoinWalker} contract to leverage load plans.
+ *
+ * @author Steve Ebersole
+ */
+public class MetadataDrivenModelGraphVisitor {
+ private static final Logger log = Logger.getLogger( MetadataDrivenModelGraphVisitor.class );
+
+ public static void visitEntity(AssociationVisitationStrategy strategy, EntityPersister persister) {
+ strategy.start();
+ try {
+ new MetadataDrivenModelGraphVisitor( strategy, persister.getFactory() )
+ .visitEntityDefinition( persister );
+ }
+ finally {
+ strategy.finish();
+ }
+ }
+
+ public static void visitCollection(AssociationVisitationStrategy strategy, CollectionPersister persister) {
+ strategy.start();
+ try {
+ new MetadataDrivenModelGraphVisitor( strategy, persister.getFactory() )
+ .visitCollectionDefinition( persister );
+ }
+ finally {
+ strategy.finish();
+ }
+ }
+
+ private final AssociationVisitationStrategy strategy;
+ private final SessionFactoryImplementor factory;
+
+ // todo : add a getDepth() method to PropertyPath
+ private PropertyPath currentPropertyPath = new PropertyPath();
+
+ public MetadataDrivenModelGraphVisitor(AssociationVisitationStrategy strategy, SessionFactoryImplementor factory) {
+ this.strategy = strategy;
+ this.factory = factory;
+ }
+
+ private void visitEntityDefinition(EntityDefinition entityDefinition) {
+ strategy.startingEntity( entityDefinition );
+ try {
+ visitAttributes( entityDefinition );
+ optionallyVisitEmbeddedCompositeIdentifier( entityDefinition );
+ }
+ finally {
+ strategy.finishingEntity( entityDefinition );
+ }
+ }
+
+ private void optionallyVisitEmbeddedCompositeIdentifier(EntityDefinition entityDefinition) {
+ // if the entity has a composite identifier, see if we need to handle its sub-properties separately
+ final Iterable embeddedCompositeIdentifierAttributes =
+ entityDefinition.getEmbeddedCompositeIdentifierAttributes();
+ if ( embeddedCompositeIdentifierAttributes == null ) {
+ return;
+ }
+
+ for ( AttributeDefinition attributeDefinition : embeddedCompositeIdentifierAttributes ) {
+ visitAttributeDefinition( attributeDefinition );
+ }
+ }
+
+ private void visitAttributes(AttributeSource attributeSource) {
+ for ( AttributeDefinition attributeDefinition : attributeSource.getAttributes() ) {
+ visitAttributeDefinition( attributeDefinition );
+ }
+ }
+
+ private void visitAttributeDefinition(AttributeDefinition attributeDefinition) {
+ final PropertyPath subPath = currentPropertyPath.append( attributeDefinition.getName() );
+ log.debug( "Visiting attribute path : " + subPath.getFullPath() );
+
+ final boolean continueWalk = strategy.startingAttribute( attributeDefinition );
+ if ( continueWalk ) {
+ final PropertyPath old = currentPropertyPath;
+ currentPropertyPath = subPath;
+ try {
+ if ( attributeDefinition.getType().isAssociationType() ) {
+ visitAssociation( (AssociationAttributeDefinition) attributeDefinition );
+ }
+ else if ( attributeDefinition.getType().isComponentType() ) {
+ visitCompositeDefinition( (CompositeDefinition) attributeDefinition );
+ }
+ }
+ finally {
+ currentPropertyPath = old;
+ }
+ }
+ strategy.finishingAttribute( attributeDefinition );
+ }
+
+ private void visitAssociation(AssociationAttributeDefinition attribute) {
+ // todo : do "too deep" checks; but see note about adding depth to PropertyPath
+
+ if ( isDuplicateAssociation( attribute.getAssociationKey() ) ) {
+ log.debug( "Property path deemed to be circular : " + currentPropertyPath.getFullPath() );
+ return;
+ }
+
+ if ( attribute.isCollection() ) {
+ visitCollectionDefinition( attribute.toCollectionDefinition() );
+ }
+ else {
+ visitEntityDefinition( attribute.toEntityDefinition() );
+ }
+ }
+
+ private void visitCompositeDefinition(CompositeDefinition compositeDefinition) {
+ strategy.startingComposite( compositeDefinition );
+ try {
+ visitAttributes( compositeDefinition );
+ }
+ finally {
+ strategy.finishingComposite( compositeDefinition );
+ }
+ }
+
+ private void visitCollectionDefinition(CollectionDefinition collectionDefinition) {
+ strategy.startingCollection( collectionDefinition );
+
+ try {
+ visitCollectionIndex( collectionDefinition.getIndexDefinition() );
+
+ final CollectionElementDefinition elementDefinition = collectionDefinition.getElementDefinition();
+ if ( elementDefinition.getType().isComponentType() ) {
+ visitCompositeDefinition( elementDefinition.toCompositeDefinition() );
+ }
+ else {
+ visitEntityDefinition( elementDefinition.toEntityDefinition() );
+ }
+ }
+ finally {
+ strategy.finishingCollection( collectionDefinition );
+ }
+ }
+
+ private void visitCollectionIndex(CollectionIndexDefinition collectionIndexDefinition) {
+ if ( collectionIndexDefinition == null ) {
+ return;
+ }
+
+ log.debug( "Visiting collection index : " + currentPropertyPath.getFullPath() );
+ currentPropertyPath = currentPropertyPath.append( "" );
+ try {
+ final Type collectionIndexType = collectionIndexDefinition.getType();
+ if ( collectionIndexType.isComponentType() ) {
+ visitCompositeDefinition( collectionIndexDefinition.toCompositeDefinition() );
+ }
+ else if ( collectionIndexType.isAssociationType() ) {
+ visitEntityDefinition( collectionIndexDefinition.toEntityDefinition() );
+ }
+ }
+ finally {
+ currentPropertyPath = currentPropertyPath.getParent();
+ }
+ }
+
+
+ private final Set visitedAssociationKeys = new HashSet();
+
+ protected boolean isDuplicateAssociation(AssociationKey associationKey) {
+ return !visitedAssociationKeys.add( associationKey );
+ }
+
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/package-info.java b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/package-info.java
new file mode 100644
index 0000000000..90d0cd8faf
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/persister/walking/spi/package-info.java
@@ -0,0 +1,6 @@
+package org.hibernate.persister.walking.spi;
+
+/**
+ * Package for "walking" associations through metadata definition. Ultimately want {@link org.hibernate.persister.walking.spi.AttributeDefinition} and
+ * {@link AttributeSource} etc to become part of the persister model.
+ */
\ No newline at end of file
diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/AbstractAttribute.java b/hibernate-core/src/main/java/org/hibernate/tuple/AbstractAttribute.java
new file mode 100644
index 0000000000..4818c33c22
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tuple/AbstractAttribute.java
@@ -0,0 +1,55 @@
+/*
+ * jDocBook, processing of DocBook sources
+ *
+ * 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.tuple;
+
+import org.hibernate.type.Type;
+
+/**
+ * @author Steve Ebersole
+ */
+public abstract class AbstractAttribute implements Attribute, Property {
+ private final String attributeName;
+ private final Type attributeType;
+
+ protected AbstractAttribute(String attributeName, Type attributeType) {
+ this.attributeName = attributeName;
+ this.attributeType = attributeType;
+ }
+
+ @Override
+ @Deprecated
+ public String getNode() {
+ return null;
+ }
+
+ @Override
+ public String getName() {
+ return attributeName;
+ }
+
+ @Override
+ public Type getType() {
+ return attributeType;
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/AbstractNonIdentifierAttribute.java b/hibernate-core/src/main/java/org/hibernate/tuple/AbstractNonIdentifierAttribute.java
new file mode 100644
index 0000000000..b01458fe64
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tuple/AbstractNonIdentifierAttribute.java
@@ -0,0 +1,133 @@
+/*
+ * 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.tuple;
+
+import org.hibernate.FetchMode;
+import org.hibernate.engine.spi.CascadeStyle;
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.persister.walking.spi.AttributeSource;
+import org.hibernate.type.Type;
+
+/**
+ * @author Steve Ebersole
+ */
+public abstract class AbstractNonIdentifierAttribute extends AbstractAttribute implements NonIdentifierAttribute {
+ private final AttributeSource source;
+ private final SessionFactoryImplementor sessionFactory;
+
+ private final int attributeNumber;
+
+ private final BaselineAttributeInformation attributeInformation;
+
+ protected AbstractNonIdentifierAttribute(
+ AttributeSource source,
+ SessionFactoryImplementor sessionFactory,
+ int attributeNumber,
+ String attributeName,
+ Type attributeType,
+ BaselineAttributeInformation attributeInformation) {
+ super( attributeName, attributeType );
+ this.source = source;
+ this.sessionFactory = sessionFactory;
+ this.attributeNumber = attributeNumber;
+ this.attributeInformation = attributeInformation;
+ }
+
+ @Override
+ public AttributeSource getSource() {
+ return source();
+ }
+
+ protected AttributeSource source() {
+ return source;
+ }
+
+ protected SessionFactoryImplementor sessionFactory() {
+ return sessionFactory;
+ }
+
+ protected int attributeNumber() {
+ return attributeNumber;
+ }
+
+ @Override
+ public boolean isLazy() {
+ return attributeInformation.isLazy();
+ }
+
+ @Override
+ public boolean isInsertable() {
+ return attributeInformation.isInsertable();
+ }
+
+ @Override
+ public boolean isUpdateable() {
+ return attributeInformation.isUpdateable();
+ }
+
+ @Override
+ public boolean isInsertGenerated() {
+ return attributeInformation.isInsertGenerated();
+ }
+
+ @Override
+ public boolean isUpdateGenerated() {
+ return attributeInformation.isUpdateGenerated();
+ }
+
+ @Override
+ public boolean isNullable() {
+ return attributeInformation.isNullable();
+ }
+
+ @Override
+ public boolean isDirtyCheckable() {
+ return attributeInformation.isDirtyCheckable();
+ }
+
+ @Override
+ public boolean isDirtyCheckable(boolean hasUninitializedProperties) {
+ return isDirtyCheckable() && ( !hasUninitializedProperties || !isLazy() );
+ }
+
+ @Override
+ public boolean isVersionable() {
+ return attributeInformation.isVersionable();
+ }
+
+ @Override
+ public CascadeStyle getCascadeStyle() {
+ return attributeInformation.getCascadeStyle();
+ }
+
+ @Override
+ public FetchMode getFetchMode() {
+ return attributeInformation.getFetchMode();
+ }
+
+ @Override
+ public String toString() {
+ return "Attribute[non-identifier]( " + getName() + ")";
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/Attribute.java b/hibernate-core/src/main/java/org/hibernate/tuple/Attribute.java
new file mode 100644
index 0000000000..08e7496204
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tuple/Attribute.java
@@ -0,0 +1,37 @@
+/*
+ * 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.tuple;
+
+import org.hibernate.persister.walking.spi.AttributeDefinition;
+import org.hibernate.type.Type;
+
+/**
+ * Contract for attributes
+ *
+ * @author Steve Ebersole
+ */
+public interface Attribute {
+ public String getName();
+ public Type getType();
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/BaselineAttributeInformation.java b/hibernate-core/src/main/java/org/hibernate/tuple/BaselineAttributeInformation.java
new file mode 100644
index 0000000000..920231b0d9
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tuple/BaselineAttributeInformation.java
@@ -0,0 +1,166 @@
+package org.hibernate.tuple;
+
+import org.hibernate.FetchMode;
+import org.hibernate.engine.spi.CascadeStyle;
+
+/**
+* @author Steve Ebersole
+*/
+public class BaselineAttributeInformation {
+ private final boolean lazy;
+ private final boolean insertable;
+ private final boolean updateable;
+ private final boolean insertGenerated;
+ private final boolean updateGenerated;
+ private final boolean nullable;
+ private final boolean dirtyCheckable;
+ private final boolean versionable;
+ private final CascadeStyle cascadeStyle;
+ private final FetchMode fetchMode;
+ private boolean checkable;
+
+ public BaselineAttributeInformation(
+ boolean lazy,
+ boolean insertable,
+ boolean updateable,
+ boolean insertGenerated,
+ boolean updateGenerated,
+ boolean nullable,
+ boolean dirtyCheckable,
+ boolean versionable,
+ CascadeStyle cascadeStyle,
+ FetchMode fetchMode) {
+ this.lazy = lazy;
+ this.insertable = insertable;
+ this.updateable = updateable;
+ this.insertGenerated = insertGenerated;
+ this.updateGenerated = updateGenerated;
+ this.nullable = nullable;
+ this.dirtyCheckable = dirtyCheckable;
+ this.versionable = versionable;
+ this.cascadeStyle = cascadeStyle;
+ this.fetchMode = fetchMode;
+ }
+
+ public boolean isLazy() {
+ return lazy;
+ }
+
+ public boolean isInsertable() {
+ return insertable;
+ }
+
+ public boolean isUpdateable() {
+ return updateable;
+ }
+
+ public boolean isInsertGenerated() {
+ return insertGenerated;
+ }
+
+ public boolean isUpdateGenerated() {
+ return updateGenerated;
+ }
+
+ public boolean isNullable() {
+ return nullable;
+ }
+
+ public boolean isDirtyCheckable() {
+ return dirtyCheckable;
+ }
+
+ public boolean isVersionable() {
+ return versionable;
+ }
+
+ public CascadeStyle getCascadeStyle() {
+ return cascadeStyle;
+ }
+
+ public FetchMode getFetchMode() {
+ return fetchMode;
+ }
+
+ public boolean isCheckable() {
+ return checkable;
+ }
+
+ public static class Builder {
+ private boolean lazy;
+ private boolean insertable;
+ private boolean updateable;
+ private boolean insertGenerated;
+ private boolean updateGenerated;
+ private boolean nullable;
+ private boolean dirtyCheckable;
+ private boolean versionable;
+ private CascadeStyle cascadeStyle;
+ private FetchMode fetchMode;
+
+ public Builder setLazy(boolean lazy) {
+ this.lazy = lazy;
+ return this;
+ }
+
+ public Builder setInsertable(boolean insertable) {
+ this.insertable = insertable;
+ return this;
+ }
+
+ public Builder setUpdateable(boolean updateable) {
+ this.updateable = updateable;
+ return this;
+ }
+
+ public Builder setInsertGenerated(boolean insertGenerated) {
+ this.insertGenerated = insertGenerated;
+ return this;
+ }
+
+ public Builder setUpdateGenerated(boolean updateGenerated) {
+ this.updateGenerated = updateGenerated;
+ return this;
+ }
+
+ public Builder setNullable(boolean nullable) {
+ this.nullable = nullable;
+ return this;
+ }
+
+ public Builder setDirtyCheckable(boolean dirtyCheckable) {
+ this.dirtyCheckable = dirtyCheckable;
+ return this;
+ }
+
+ public Builder setVersionable(boolean versionable) {
+ this.versionable = versionable;
+ return this;
+ }
+
+ public Builder setCascadeStyle(CascadeStyle cascadeStyle) {
+ this.cascadeStyle = cascadeStyle;
+ return this;
+ }
+
+ public Builder setFetchMode(FetchMode fetchMode) {
+ this.fetchMode = fetchMode;
+ return this;
+ }
+
+ public BaselineAttributeInformation createInformation() {
+ return new BaselineAttributeInformation(
+ lazy,
+ insertable,
+ updateable,
+ insertGenerated,
+ updateGenerated,
+ nullable,
+ dirtyCheckable,
+ versionable,
+ cascadeStyle,
+ fetchMode
+ );
+ }
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/IdentifierAttribute.java b/hibernate-core/src/main/java/org/hibernate/tuple/IdentifierAttribute.java
new file mode 100644
index 0000000000..345ef8f45c
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tuple/IdentifierAttribute.java
@@ -0,0 +1,21 @@
+package org.hibernate.tuple;
+
+import org.hibernate.engine.spi.IdentifierValue;
+import org.hibernate.id.IdentifierGenerator;
+
+/**
+ * @author Steve Ebersole
+ */
+public interface IdentifierAttribute extends Attribute, Property {
+ boolean isVirtual();
+
+ boolean isEmbedded();
+
+ IdentifierValue getUnsavedValue();
+
+ IdentifierGenerator getIdentifierGenerator();
+
+ boolean isIdentifierAssignedByInsert();
+
+ boolean hasIdentifierMapper();
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/IdentifierProperty.java b/hibernate-core/src/main/java/org/hibernate/tuple/IdentifierProperty.java
index ccd05be6ec..54ad0ad32d 100644
--- a/hibernate-core/src/main/java/org/hibernate/tuple/IdentifierProperty.java
+++ b/hibernate-core/src/main/java/org/hibernate/tuple/IdentifierProperty.java
@@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
- * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * Copyright (c) 2008, 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 Middleware LLC.
+ * 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
@@ -20,9 +20,9 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
- *
*/
package org.hibernate.tuple;
+
import org.hibernate.engine.spi.IdentifierValue;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.PostInsertIdentifierGenerator;
@@ -34,7 +34,7 @@ import org.hibernate.type.Type;
*
* @author Steve Ebersole
*/
-public class IdentifierProperty extends Property {
+public class IdentifierProperty extends AbstractAttribute implements IdentifierAttribute {
private boolean virtual;
private boolean embedded;
@@ -63,7 +63,7 @@ public class IdentifierProperty extends Property {
boolean embedded,
IdentifierValue unsavedValue,
IdentifierGenerator identifierGenerator) {
- super(name, node, type);
+ super( name, type );
this.virtual = false;
this.embedded = embedded;
this.hasIdentifierMapper = false;
@@ -87,7 +87,7 @@ public class IdentifierProperty extends Property {
boolean hasIdentifierMapper,
IdentifierValue unsavedValue,
IdentifierGenerator identifierGenerator) {
- super(null, null, type);
+ super( null, type );
this.virtual = true;
this.embedded = embedded;
this.hasIdentifierMapper = hasIdentifierMapper;
@@ -96,27 +96,38 @@ public class IdentifierProperty extends Property {
this.identifierAssignedByInsert = identifierGenerator instanceof PostInsertIdentifierGenerator;
}
+ @Override
public boolean isVirtual() {
return virtual;
}
+ @Override
public boolean isEmbedded() {
return embedded;
}
+ @Override
public IdentifierValue getUnsavedValue() {
return unsavedValue;
}
+ @Override
public IdentifierGenerator getIdentifierGenerator() {
return identifierGenerator;
}
+ @Override
public boolean isIdentifierAssignedByInsert() {
return identifierAssignedByInsert;
}
+ @Override
public boolean hasIdentifierMapper() {
return hasIdentifierMapper;
}
+
+ @Override
+ public String toString() {
+ return "IdentifierAttribute(" + getName() + ")";
+ }
}
diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/NonIdentifierAttribute.java b/hibernate-core/src/main/java/org/hibernate/tuple/NonIdentifierAttribute.java
new file mode 100644
index 0000000000..508572de1d
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tuple/NonIdentifierAttribute.java
@@ -0,0 +1,55 @@
+/*
+ * 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.tuple;
+
+import org.hibernate.FetchMode;
+import org.hibernate.engine.spi.CascadeStyle;
+import org.hibernate.persister.walking.spi.AttributeDefinition;
+
+/**
+ * @author Steve Ebersole
+ */
+public interface NonIdentifierAttribute extends Attribute, AttributeDefinition {
+ public boolean isLazy();
+
+ public boolean isInsertable();
+
+ public boolean isUpdateable();
+
+ public boolean isInsertGenerated();
+
+ public boolean isUpdateGenerated();
+
+ public boolean isNullable();
+
+ public boolean isDirtyCheckable(boolean hasUninitializedProperties);
+
+ public boolean isDirtyCheckable();
+
+ public boolean isVersionable();
+
+ public CascadeStyle getCascadeStyle();
+
+ public FetchMode getFetchMode();
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/Property.java b/hibernate-core/src/main/java/org/hibernate/tuple/Property.java
index b9f04fd924..69ea51cd20 100644
--- a/hibernate-core/src/main/java/org/hibernate/tuple/Property.java
+++ b/hibernate-core/src/main/java/org/hibernate/tuple/Property.java
@@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
- * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * Copyright (c) 2008, 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 Middleware LLC.
+ * 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
@@ -20,52 +20,16 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
- *
*/
package org.hibernate.tuple;
-import java.io.Serializable;
-
-import org.hibernate.type.Type;
/**
* Defines the basic contract of a Property within the runtime metamodel.
*
* @author Steve Ebersole
*/
-public abstract class Property implements Serializable {
- private String name;
- private String node;
- private Type type;
-
- /**
- * Constructor for Property instances.
- *
- * @param name The name by which the property can be referenced within
- * its owner.
- * @param node The node name to use for XML-based representation of this
- * property.
- * @param type The Hibernate Type of this property.
- */
- protected Property(String name, String node, Type type) {
- this.name = name;
- this.node = node;
- this.type = type;
- }
-
- public String getName() {
- return name;
- }
-
- public String getNode() {
- return node;
- }
-
- public Type getType() {
- return type;
- }
-
- public String toString() {
- return "Property(" + name + ':' + type.getName() + ')';
- }
-
+@Deprecated
+public interface Property extends Attribute {
+ @Deprecated
+ public String getNode();
}
diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/PropertyFactory.java b/hibernate-core/src/main/java/org/hibernate/tuple/PropertyFactory.java
index 8c1a51f931..8db4f2048e 100644
--- a/hibernate-core/src/main/java/org/hibernate/tuple/PropertyFactory.java
+++ b/hibernate-core/src/main/java/org/hibernate/tuple/PropertyFactory.java
@@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
- * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * Copyright (c) 2008, 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 Middleware LLC.
+ * 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
@@ -20,17 +20,20 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
- *
*/
package org.hibernate.tuple;
+
import java.lang.reflect.Constructor;
import org.hibernate.EntityMode;
import org.hibernate.FetchMode;
+import org.hibernate.HibernateException;
+import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.engine.internal.UnsavedValueFactory;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.engine.spi.CascadeStyles;
import org.hibernate.engine.spi.IdentifierValue;
+import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.VersionValue;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.internal.util.ReflectHelper;
@@ -45,10 +48,16 @@ import org.hibernate.metamodel.binding.BasicAttributeBinding;
import org.hibernate.metamodel.binding.EntityBinding;
import org.hibernate.metamodel.binding.SimpleValueBinding;
import org.hibernate.metamodel.binding.SingularAttributeBinding;
+import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.property.Getter;
import org.hibernate.property.PropertyAccessor;
import org.hibernate.property.PropertyAccessorFactory;
+import org.hibernate.tuple.entity.EntityBasedAssociationAttribute;
+import org.hibernate.tuple.entity.EntityBasedBasicAttribute;
+import org.hibernate.tuple.entity.EntityBasedCompositeAttribute;
+import org.hibernate.tuple.entity.VersionProperty;
import org.hibernate.type.AssociationType;
+import org.hibernate.type.CompositeType;
import org.hibernate.type.Type;
import org.hibernate.type.VersionType;
@@ -59,16 +68,16 @@ import org.hibernate.type.VersionType;
* @author Steve Ebersole
*/
public class PropertyFactory {
-
/**
- * Generates an IdentifierProperty representation of the for a given entity mapping.
+ * Generates the attribute representation of the identifier for a given entity mapping.
*
* @param mappedEntity The mapping definition of the entity.
* @param generator The identifier value generator to use for this identifier.
* @return The appropriate IdentifierProperty definition.
*/
- public static IdentifierProperty buildIdentifierProperty(PersistentClass mappedEntity, IdentifierGenerator generator) {
-
+ public static IdentifierProperty buildIdentifierAttribute(
+ PersistentClass mappedEntity,
+ IdentifierGenerator generator) {
String mappedUnsavedValue = mappedEntity.getIdentifier().getNullValue();
Type type = mappedEntity.getIdentifier().getType();
Property property = mappedEntity.getIdentifierProperty();
@@ -109,7 +118,9 @@ public class PropertyFactory {
* @param generator The identifier value generator to use for this identifier.
* @return The appropriate IdentifierProperty definition.
*/
- public static IdentifierProperty buildIdentifierProperty(EntityBinding mappedEntity, IdentifierGenerator generator) {
+ public static IdentifierProperty buildIdentifierProperty(
+ EntityBinding mappedEntity,
+ IdentifierGenerator generator) {
final BasicAttributeBinding property = mappedEntity.getHierarchyDetails().getEntityIdentifier().getValueBinding();
@@ -157,7 +168,12 @@ public class PropertyFactory {
* @param lazyAvailable Is property lazy loading currently available.
* @return The appropriate VersionProperty definition.
*/
- public static VersionProperty buildVersionProperty(Property property, boolean lazyAvailable) {
+ public static VersionProperty buildVersionProperty(
+ EntityPersister persister,
+ SessionFactoryImplementor sessionFactory,
+ int attributeNumber,
+ Property property,
+ boolean lazyAvailable) {
String mappedUnsavedValue = ( (KeyValue) property.getValue() ).getNullValue();
VersionValue unsavedValue = UnsavedValueFactory.getUnsavedVersionValue(
@@ -165,23 +181,27 @@ public class PropertyFactory {
getGetter( property ),
(VersionType) property.getType(),
getConstructor( property.getPersistentClass() )
- );
+ );
boolean lazy = lazyAvailable && property.isLazy();
return new VersionProperty(
+ persister,
+ sessionFactory,
+ attributeNumber,
property.getName(),
- property.getNodeName(),
property.getValue().getType(),
- lazy,
- property.isInsertable(),
- property.isUpdateable(),
- property.getGeneration() == PropertyGeneration.INSERT || property.getGeneration() == PropertyGeneration.ALWAYS,
- property.getGeneration() == PropertyGeneration.ALWAYS,
- property.isOptional(),
- property.isUpdateable() && !lazy,
- property.isOptimisticLocked(),
- property.getCascadeStyle(),
+ new BaselineAttributeInformation.Builder()
+ .setLazy( lazy )
+ .setInsertable( property.isInsertable() )
+ .setUpdateable( property.isUpdateable() )
+ .setInsertGenerated( property.getGeneration() == PropertyGeneration.INSERT || property.getGeneration() == PropertyGeneration.ALWAYS )
+ .setUpdateGenerated( property.getGeneration() == PropertyGeneration.ALWAYS )
+ .setNullable( property.isOptional() )
+ .setDirtyCheckable( property.isUpdateable() && !lazy )
+ .setVersionable( property.isOptimisticLocked() )
+ .setCascadeStyle( property.getCascadeStyle() )
+ .createInformation(),
unsavedValue
);
}
@@ -194,52 +214,38 @@ public class PropertyFactory {
* @param lazyAvailable Is property lazy loading currently available.
* @return The appropriate VersionProperty definition.
*/
- public static VersionProperty buildVersionProperty(BasicAttributeBinding property, boolean lazyAvailable) {
- String mappedUnsavedValue = ( (KeyValue) property.getValue() ).getNullValue();
+ public static VersionProperty buildVersionProperty(
+ EntityPersister persister,
+ BasicAttributeBinding property,
+ boolean lazyAvailable) {
+ throw new NotYetImplementedException();
+ }
- VersionValue unsavedValue = UnsavedValueFactory.getUnsavedVersionValue(
- mappedUnsavedValue,
- getGetter( property ),
- (VersionType) property.getHibernateTypeDescriptor().getResolvedTypeMapping(),
- getConstructor( (EntityBinding) property.getContainer() )
- );
-
- boolean lazy = lazyAvailable && property.isLazy();
-
- final CascadeStyle cascadeStyle = property.isAssociation()
- ? ( (AssociationAttributeBinding) property ).getCascadeStyle()
- : CascadeStyles.NONE;
-
- return new VersionProperty(
- property.getAttribute().getName(),
- null,
- property.getHibernateTypeDescriptor().getResolvedTypeMapping(),
- lazy,
- true, // insertable
- true, // updatable
- property.getGeneration() == PropertyGeneration.INSERT
- || property.getGeneration() == PropertyGeneration.ALWAYS,
- property.getGeneration() == PropertyGeneration.ALWAYS,
- property.isNullable(),
- !lazy,
- property.isIncludedInOptimisticLocking(),
- cascadeStyle,
- unsavedValue
- );
+ public static enum NonIdentifierAttributeNature {
+ BASIC,
+ COMPOSITE,
+ ANY,
+ ENTITY,
+ COLLECTION
}
/**
- * Generate a "standard" (i.e., non-identifier and non-version) based on the given
- * mapped property.
+ * Generate a non-identifier (and non-version) attribute based on the given mapped property from the given entity
*
* @param property The mapped property.
* @param lazyAvailable Is property lazy loading currently available.
- * @return The appropriate StandardProperty definition.
+ * @return The appropriate NonIdentifierProperty definition.
*/
- public static StandardProperty buildStandardProperty(Property property, boolean lazyAvailable) {
-
+ public static NonIdentifierAttribute buildEntityBasedAttribute(
+ EntityPersister persister,
+ SessionFactoryImplementor sessionFactory,
+ int attributeNumber,
+ Property property,
+ boolean lazyAvailable) {
final Type type = property.getValue().getType();
-
+
+ final NonIdentifierAttributeNature nature = decode( type );
+
// we need to dirty check collections, since they can cause an owner
// version number increment
@@ -250,30 +256,147 @@ public class PropertyFactory {
boolean alwaysDirtyCheck = type.isAssociationType() &&
( (AssociationType) type ).isAlwaysDirtyChecked();
+ switch ( nature ) {
+ case BASIC: {
+ return new EntityBasedBasicAttribute(
+ persister,
+ sessionFactory,
+ attributeNumber,
+ property.getName(),
+ type,
+ new BaselineAttributeInformation.Builder()
+ .setLazy( lazyAvailable && property.isLazy() )
+ .setInsertable( property.isInsertable() )
+ .setUpdateable( property.isUpdateable() )
+ .setInsertGenerated(
+ property.getGeneration() == PropertyGeneration.INSERT
+ || property.getGeneration() == PropertyGeneration.ALWAYS
+ )
+ .setUpdateGenerated( property.getGeneration() == PropertyGeneration.ALWAYS )
+ .setNullable( property.isOptional() )
+ .setDirtyCheckable( alwaysDirtyCheck || property.isUpdateable() )
+ .setVersionable( property.isOptimisticLocked() )
+ .setCascadeStyle( property.getCascadeStyle() )
+ .setFetchMode( property.getValue().getFetchMode() )
+ .createInformation()
+ );
+ }
+ case COMPOSITE: {
+ return new EntityBasedCompositeAttribute(
+ persister,
+ sessionFactory,
+ attributeNumber,
+ property.getName(),
+ (CompositeType) type,
+ new BaselineAttributeInformation.Builder()
+ .setLazy( lazyAvailable && property.isLazy() )
+ .setInsertable( property.isInsertable() )
+ .setUpdateable( property.isUpdateable() )
+ .setInsertGenerated(
+ property.getGeneration() == PropertyGeneration.INSERT
+ || property.getGeneration() == PropertyGeneration.ALWAYS
+ )
+ .setUpdateGenerated( property.getGeneration() == PropertyGeneration.ALWAYS )
+ .setNullable( property.isOptional() )
+ .setDirtyCheckable( alwaysDirtyCheck || property.isUpdateable() )
+ .setVersionable( property.isOptimisticLocked() )
+ .setCascadeStyle( property.getCascadeStyle() )
+ .setFetchMode( property.getValue().getFetchMode() )
+ .createInformation()
+ );
+ }
+ case ENTITY:
+ case ANY:
+ case COLLECTION: {
+ return new EntityBasedAssociationAttribute(
+ persister,
+ sessionFactory,
+ attributeNumber,
+ property.getName(),
+ (AssociationType) type,
+ new BaselineAttributeInformation.Builder()
+ .setLazy( lazyAvailable && property.isLazy() )
+ .setInsertable( property.isInsertable() )
+ .setUpdateable( property.isUpdateable() )
+ .setInsertGenerated(
+ property.getGeneration() == PropertyGeneration.INSERT
+ || property.getGeneration() == PropertyGeneration.ALWAYS
+ )
+ .setUpdateGenerated( property.getGeneration() == PropertyGeneration.ALWAYS )
+ .setNullable( property.isOptional() )
+ .setDirtyCheckable( alwaysDirtyCheck || property.isUpdateable() )
+ .setVersionable( property.isOptimisticLocked() )
+ .setCascadeStyle( property.getCascadeStyle() )
+ .setFetchMode( property.getValue().getFetchMode() )
+ .createInformation()
+ );
+ }
+ default: {
+ throw new HibernateException( "Internal error" );
+ }
+ }
+ }
+
+ private static NonIdentifierAttributeNature decode(Type type) {
+ if ( type.isAssociationType() ) {
+ AssociationType associationType = (AssociationType) type;
+
+ if ( type.isComponentType() ) {
+ // an any type is both an association and a composite...
+ return NonIdentifierAttributeNature.ANY;
+ }
+
+ return type.isCollectionType()
+ ? NonIdentifierAttributeNature.COLLECTION
+ : NonIdentifierAttributeNature.ENTITY;
+ }
+ else {
+ if ( type.isComponentType() ) {
+ return NonIdentifierAttributeNature.COMPOSITE;
+ }
+
+ return NonIdentifierAttributeNature.BASIC;
+ }
+ }
+
+ @Deprecated
+ public static StandardProperty buildStandardProperty(Property property, boolean lazyAvailable) {
+ final Type type = property.getValue().getType();
+
+ // we need to dirty check collections, since they can cause an owner
+ // version number increment
+
+ // we need to dirty check many-to-ones with not-found="ignore" in order
+ // to update the cache (not the database), since in this case a null
+ // entity reference can lose information
+
+ boolean alwaysDirtyCheck = type.isAssociationType() &&
+ ( (AssociationType) type ).isAlwaysDirtyChecked();
+
return new StandardProperty(
property.getName(),
- property.getNodeName(),
type,
lazyAvailable && property.isLazy(),
property.isInsertable(),
property.isUpdateable(),
- property.getGeneration() == PropertyGeneration.INSERT || property.getGeneration() == PropertyGeneration.ALWAYS,
+ property.getGeneration() == PropertyGeneration.INSERT || property.getGeneration() == PropertyGeneration.ALWAYS,
property.getGeneration() == PropertyGeneration.ALWAYS,
property.isOptional(),
alwaysDirtyCheck || property.isUpdateable(),
property.isOptimisticLocked(),
property.getCascadeStyle(),
- property.getValue().getFetchMode()
- );
+ property.getValue().getFetchMode()
+ );
}
+
/**
* Generate a "standard" (i.e., non-identifier and non-version) based on the given
* mapped property.
*
* @param property The mapped property.
* @param lazyAvailable Is property lazy loading currently available.
- * @return The appropriate StandardProperty definition.
+ * @return The appropriate NonIdentifierProperty definition.
*/
public static StandardProperty buildStandardProperty(AttributeBinding property, boolean lazyAvailable) {
@@ -299,7 +422,6 @@ public class PropertyFactory {
return new StandardProperty(
singularAttributeBinding.getAttribute().getName(),
- null,
type,
lazyAvailable && singularAttributeBinding.isLazy(),
true, // insertable
@@ -325,7 +447,6 @@ public class PropertyFactory {
return new StandardProperty(
pluralAttributeBinding.getAttribute().getName(),
- null,
type,
lazyAvailable && pluralAttributeBinding.isLazy(),
// TODO: fix this when HHH-6356 is fixed; for now assume AbstractPluralAttributeBinding is updatable and insertable
diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/StandardProperty.java b/hibernate-core/src/main/java/org/hibernate/tuple/StandardProperty.java
index 30eb8da053..a4c1adb8c2 100644
--- a/hibernate-core/src/main/java/org/hibernate/tuple/StandardProperty.java
+++ b/hibernate-core/src/main/java/org/hibernate/tuple/StandardProperty.java
@@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
- * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * Copyright (c) 2008, 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 Middleware LLC.
+ * 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
@@ -20,118 +20,69 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
- *
*/
package org.hibernate.tuple;
+
import org.hibernate.FetchMode;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.type.Type;
/**
- * Represents a basic property within the Hibernate runtime-metamodel.
+ * Represents a non-identifier property within the Hibernate runtime-metamodel.
*
* @author Steve Ebersole
*/
-public class StandardProperty extends Property {
+@Deprecated
+public class StandardProperty extends AbstractNonIdentifierAttribute implements NonIdentifierAttribute {
- private final boolean lazy;
- private final boolean insertable;
- private final boolean updateable;
- private final boolean insertGenerated;
- private final boolean updateGenerated;
- private final boolean nullable;
- private final boolean dirtyCheckable;
- private final boolean versionable;
- private final CascadeStyle cascadeStyle;
- private final FetchMode fetchMode;
-
- /**
- * Constructs StandardProperty instances.
- *
- * @param name The name by which the property can be referenced within
- * its owner.
- * @param node The node name to use for XML-based representation of this
- * property.
- * @param type The Hibernate Type of this property.
- * @param lazy Should this property be handled lazily?
- * @param insertable Is this property an insertable value?
- * @param updateable Is this property an updateable value?
- * @param insertGenerated Is this property generated in the database on insert?
- * @param updateGenerated Is this property generated in the database on update?
- * @param nullable Is this property a nullable value?
- * @param checkable Is this property a checkable value?
- * @param versionable Is this property a versionable value?
- * @param cascadeStyle The cascade style for this property's value.
- * @param fetchMode Any fetch mode defined for this property
- */
- public StandardProperty(
- String name,
- String node,
- Type type,
- boolean lazy,
- boolean insertable,
- boolean updateable,
- boolean insertGenerated,
- boolean updateGenerated,
- boolean nullable,
- boolean checkable,
- boolean versionable,
- CascadeStyle cascadeStyle,
- FetchMode fetchMode) {
- super(name, node, type);
- this.lazy = lazy;
- this.insertable = insertable;
- this.updateable = updateable;
- this.insertGenerated = insertGenerated;
- this.updateGenerated = updateGenerated;
- this.nullable = nullable;
- this.dirtyCheckable = checkable;
- this.versionable = versionable;
- this.cascadeStyle = cascadeStyle;
- this.fetchMode = fetchMode;
- }
-
- public boolean isLazy() {
- return lazy;
- }
-
- public boolean isInsertable() {
- return insertable;
- }
-
- public boolean isUpdateable() {
- return updateable;
- }
-
- public boolean isInsertGenerated() {
- return insertGenerated;
- }
-
- public boolean isUpdateGenerated() {
- return updateGenerated;
- }
-
- public boolean isNullable() {
- return nullable;
- }
-
- public boolean isDirtyCheckable(boolean hasUninitializedProperties) {
- return isDirtyCheckable() && ( !hasUninitializedProperties || !isLazy() );
- }
-
- public boolean isDirtyCheckable() {
- return dirtyCheckable;
- }
-
- public boolean isVersionable() {
- return versionable;
- }
-
- public CascadeStyle getCascadeStyle() {
- return cascadeStyle;
- }
-
- public FetchMode getFetchMode() {
- return fetchMode;
+ /**
+ * Constructs NonIdentifierProperty instances.
+ *
+ * @param name The name by which the property can be referenced within
+ * its owner.
+ * @param type The Hibernate Type of this property.
+ * @param lazy Should this property be handled lazily?
+ * @param insertable Is this property an insertable value?
+ * @param updateable Is this property an updateable value?
+ * @param insertGenerated Is this property generated in the database on insert?
+ * @param updateGenerated Is this property generated in the database on update?
+ * @param nullable Is this property a nullable value?
+ * @param checkable Is this property a checkable value?
+ * @param versionable Is this property a versionable value?
+ * @param cascadeStyle The cascade style for this property's value.
+ * @param fetchMode Any fetch mode defined for this property
+ */
+ public StandardProperty(
+ String name,
+ Type type,
+ boolean lazy,
+ boolean insertable,
+ boolean updateable,
+ boolean insertGenerated,
+ boolean updateGenerated,
+ boolean nullable,
+ boolean checkable,
+ boolean versionable,
+ CascadeStyle cascadeStyle,
+ FetchMode fetchMode) {
+ super(
+ null,
+ null,
+ -1,
+ name,
+ type,
+ new BaselineAttributeInformation.Builder()
+ .setLazy( lazy )
+ .setInsertable( insertable )
+ .setUpdateable( updateable )
+ .setInsertGenerated( insertGenerated )
+ .setUpdateGenerated( updateGenerated )
+ .setNullable( nullable )
+ .setDirtyCheckable( checkable )
+ .setVersionable( versionable )
+ .setCascadeStyle( cascadeStyle )
+ .setFetchMode( fetchMode )
+ .createInformation()
+ );
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/VersionProperty.java b/hibernate-core/src/main/java/org/hibernate/tuple/VersionProperty.java
deleted file mode 100644
index 639939eb4c..0000000000
--- a/hibernate-core/src/main/java/org/hibernate/tuple/VersionProperty.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Hibernate, Relational Persistence for Idiomatic Java
- *
- * Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC.
- *
- * 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.tuple;
-import org.hibernate.engine.spi.CascadeStyle;
-import org.hibernate.engine.spi.VersionValue;
-import org.hibernate.type.Type;
-
-/**
- * Represents a version property within the Hibernate runtime-metamodel.
- *
- * @author Steve Ebersole
- */
-public class VersionProperty extends StandardProperty {
-
- private final VersionValue unsavedValue;
-
- /**
- * Constructs VersionProperty instances.
- *
- * @param name The name by which the property can be referenced within
- * its owner.
- * @param node The node name to use for XML-based representation of this
- * property.
- * @param type The Hibernate Type of this property.
- * @param lazy Should this property be handled lazily?
- * @param insertable Is this property an insertable value?
- * @param updateable Is this property an updateable value?
- * @param insertGenerated Is this property generated in the database on insert?
- * @param updateGenerated Is this property generated in the database on update?
- * @param nullable Is this property a nullable value?
- * @param checkable Is this property a checkable value?
- * @param versionable Is this property a versionable value?
- * @param cascadeStyle The cascade style for this property's value.
- * @param unsavedValue The value which, if found as the value of
- * this (i.e., the version) property, represents new (i.e., un-saved)
- * instances of the owning entity.
- */
- public VersionProperty(
- String name,
- String node,
- Type type,
- boolean lazy,
- boolean insertable,
- boolean updateable,
- boolean insertGenerated,
- boolean updateGenerated,
- boolean nullable,
- boolean checkable,
- boolean versionable,
- CascadeStyle cascadeStyle,
- VersionValue unsavedValue) {
- super( name, node, type, lazy, insertable, updateable, insertGenerated, updateGenerated, nullable, checkable, versionable, cascadeStyle, null );
- this.unsavedValue = unsavedValue;
- }
-
- public VersionValue getUnsavedValue() {
- return unsavedValue;
- }
-}
diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/component/AbstractCompositeBasedAttribute.java b/hibernate-core/src/main/java/org/hibernate/tuple/component/AbstractCompositeBasedAttribute.java
new file mode 100644
index 0000000000..9dd83c8885
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tuple/component/AbstractCompositeBasedAttribute.java
@@ -0,0 +1,61 @@
+/*
+ * jDocBook, processing of DocBook sources
+ *
+ * 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.tuple.component;
+
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.tuple.AbstractNonIdentifierAttribute;
+import org.hibernate.tuple.BaselineAttributeInformation;
+import org.hibernate.tuple.NonIdentifierAttribute;
+import org.hibernate.type.Type;
+
+/**
+ * @author Steve Ebersole
+ */
+public abstract class AbstractCompositeBasedAttribute
+ extends AbstractNonIdentifierAttribute
+ implements NonIdentifierAttribute {
+
+ private final int ownerAttributeNumber;
+
+ public AbstractCompositeBasedAttribute(
+ AbstractCompositeDefinition source,
+ SessionFactoryImplementor sessionFactory,
+ int attributeNumber,
+ String attributeName,
+ Type attributeType,
+ BaselineAttributeInformation baselineInfo,
+ int ownerAttributeNumber) {
+ super( source, sessionFactory, attributeNumber, attributeName, attributeType, baselineInfo );
+ this.ownerAttributeNumber = ownerAttributeNumber;
+ }
+
+ protected int ownerAttributeNumber() {
+ return ownerAttributeNumber;
+ }
+
+ @Override
+ public AbstractCompositeDefinition getSource() {
+ return (AbstractCompositeDefinition) super.getSource();
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/component/AbstractCompositeDefinition.java b/hibernate-core/src/main/java/org/hibernate/tuple/component/AbstractCompositeDefinition.java
new file mode 100644
index 0000000000..87ca927f9d
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tuple/component/AbstractCompositeDefinition.java
@@ -0,0 +1,202 @@
+/*
+ * jDocBook, processing of DocBook sources
+ *
+ * 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.tuple.component;
+
+import java.util.Iterator;
+
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.persister.entity.Joinable;
+import org.hibernate.persister.entity.OuterJoinLoadable;
+import org.hibernate.persister.walking.spi.AssociationKey;
+import org.hibernate.persister.walking.spi.AttributeDefinition;
+import org.hibernate.persister.walking.spi.AttributeSource;
+import org.hibernate.persister.walking.spi.CompositeDefinition;
+import org.hibernate.persister.walking.spi.EntityDefinition;
+import org.hibernate.tuple.AbstractNonIdentifierAttribute;
+import org.hibernate.tuple.BaselineAttributeInformation;
+import org.hibernate.type.AssociationType;
+import org.hibernate.type.CompositeType;
+import org.hibernate.type.ForeignKeyDirection;
+import org.hibernate.type.Type;
+
+import static org.hibernate.engine.internal.JoinHelper.getLHSColumnNames;
+import static org.hibernate.engine.internal.JoinHelper.getLHSTableName;
+import static org.hibernate.engine.internal.JoinHelper.getRHSColumnNames;
+
+/**
+ * @author Steve Ebersole
+ */
+public abstract class AbstractCompositeDefinition extends AbstractNonIdentifierAttribute implements CompositeDefinition {
+ protected AbstractCompositeDefinition(
+ AttributeSource source,
+ SessionFactoryImplementor sessionFactory,
+ int attributeNumber,
+ String attributeName,
+ CompositeType attributeType,
+ BaselineAttributeInformation baselineInfo) {
+ super( source, sessionFactory, attributeNumber, attributeName, attributeType, baselineInfo );
+ }
+
+ @Override
+ public CompositeType getType() {
+ return (CompositeType) super.getType();
+ }
+
+ @Override
+ public Iterable getAttributes() {
+ return new Iterable() {
+ @Override
+ public Iterator iterator() {
+ return new Iterator() {
+ private final int numberOfAttributes = getType().getSubtypes().length;
+ private int currentAttributeNumber = 0;
+ private int currentColumnPosition = 0;
+
+ @Override
+ public boolean hasNext() {
+ return currentAttributeNumber < numberOfAttributes;
+ }
+
+ @Override
+ public AttributeDefinition next() {
+ final int attributeNumber = currentAttributeNumber;
+ currentAttributeNumber++;
+
+ final String name = getType().getPropertyNames()[attributeNumber];
+ final Type type = getType().getSubtypes()[attributeNumber];
+
+ int columnPosition = currentColumnPosition;
+ currentColumnPosition += type.getColumnSpan( sessionFactory() );
+
+ if ( type.isAssociationType() ) {
+ // we build the association-key here because of the "goofiness" with 'currentColumnPosition'
+ final AssociationKey associationKey;
+ final AssociationType aType = (AssociationType) type;
+ final Joinable joinable = aType.getAssociatedJoinable( sessionFactory() );
+ if ( aType.getForeignKeyDirection() == ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT ) {
+ associationKey = new AssociationKey(
+ getLHSTableName(
+ aType,
+ attributeNumber(),
+ (OuterJoinLoadable) joinable
+ ),
+ getLHSColumnNames(
+ aType,
+ attributeNumber(),
+ columnPosition,
+ (OuterJoinLoadable) joinable,
+ sessionFactory()
+ )
+ );
+ }
+ else {
+ associationKey = new AssociationKey(
+ joinable.getTableName(),
+ getRHSColumnNames( aType, sessionFactory() )
+ );
+ }
+
+ return new CompositeBasedAssociationAttribute(
+ AbstractCompositeDefinition.this,
+ sessionFactory(),
+ currentAttributeNumber,
+ name,
+ (AssociationType) type,
+ new BaselineAttributeInformation.Builder()
+ .setInsertable( AbstractCompositeDefinition.this.isInsertable() )
+ .setUpdateable( AbstractCompositeDefinition.this.isUpdateable() )
+ .setInsertGenerated( AbstractCompositeDefinition.this.isInsertGenerated() )
+ .setUpdateGenerated( AbstractCompositeDefinition.this.isUpdateGenerated() )
+ .setNullable( getType().getPropertyNullability()[currentAttributeNumber] )
+ .setDirtyCheckable( true )
+ .setVersionable( AbstractCompositeDefinition.this.isVersionable() )
+ .setCascadeStyle( getType().getCascadeStyle( currentAttributeNumber ) )
+ .setFetchMode( getType().getFetchMode( currentAttributeNumber ) )
+ .createInformation(),
+ AbstractCompositeDefinition.this.attributeNumber(),
+ associationKey
+ );
+ }
+ else if ( type.isComponentType() ) {
+ return new CompositeBasedCompositeAttribute(
+ AbstractCompositeDefinition.this,
+ sessionFactory(),
+ currentAttributeNumber,
+ name,
+ (CompositeType) type,
+ new BaselineAttributeInformation.Builder()
+ .setInsertable( AbstractCompositeDefinition.this.isInsertable() )
+ .setUpdateable( AbstractCompositeDefinition.this.isUpdateable() )
+ .setInsertGenerated( AbstractCompositeDefinition.this.isInsertGenerated() )
+ .setUpdateGenerated( AbstractCompositeDefinition.this.isUpdateGenerated() )
+ .setNullable( getType().getPropertyNullability()[currentAttributeNumber] )
+ .setDirtyCheckable( true )
+ .setVersionable( AbstractCompositeDefinition.this.isVersionable() )
+ .setCascadeStyle( getType().getCascadeStyle( currentAttributeNumber ) )
+ .setFetchMode( getType().getFetchMode( currentAttributeNumber ) )
+ .createInformation()
+ );
+ }
+ else {
+ return new CompositeBasedBasicAttribute(
+ AbstractCompositeDefinition.this,
+ sessionFactory(),
+ currentAttributeNumber,
+ name,
+ type,
+ new BaselineAttributeInformation.Builder()
+ .setInsertable( AbstractCompositeDefinition.this.isInsertable() )
+ .setUpdateable( AbstractCompositeDefinition.this.isUpdateable() )
+ .setInsertGenerated( AbstractCompositeDefinition.this.isInsertGenerated() )
+ .setUpdateGenerated( AbstractCompositeDefinition.this.isUpdateGenerated() )
+ .setNullable( getType().getPropertyNullability()[currentAttributeNumber] )
+ .setDirtyCheckable( true )
+ .setVersionable( AbstractCompositeDefinition.this.isVersionable() )
+ .setCascadeStyle( getType().getCascadeStyle( currentAttributeNumber ) )
+ .setFetchMode( getType().getFetchMode( currentAttributeNumber ) )
+ .createInformation()
+ );
+ }
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException( "Remove operation not supported here" );
+ }
+ };
+ }
+ };
+ }
+
+ public EntityPersister locateOwningPersister() {
+ if ( EntityDefinition.class.isInstance( getSource() ) ) {
+ return ( (EntityDefinition) getSource() ).getEntityPersister();
+ }
+ else {
+ return ( (AbstractCompositeDefinition) getSource() ).locateOwningPersister();
+ }
+ }
+}
+
diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/component/ComponentMetamodel.java b/hibernate-core/src/main/java/org/hibernate/tuple/component/ComponentMetamodel.java
index 2de23be05a..2ccd7ffebe 100644
--- a/hibernate-core/src/main/java/org/hibernate/tuple/component/ComponentMetamodel.java
+++ b/hibernate-core/src/main/java/org/hibernate/tuple/component/ComponentMetamodel.java
@@ -32,8 +32,8 @@ import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.Property;
-import org.hibernate.tuple.PropertyFactory;
import org.hibernate.tuple.StandardProperty;
+import org.hibernate.tuple.PropertyFactory;
/**
* Centralizes metamodel information about a component.
diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/component/CompositeBasedAssociationAttribute.java b/hibernate-core/src/main/java/org/hibernate/tuple/component/CompositeBasedAssociationAttribute.java
new file mode 100644
index 0000000000..c064c6e457
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tuple/component/CompositeBasedAssociationAttribute.java
@@ -0,0 +1,157 @@
+/*
+ * jDocBook, processing of DocBook sources
+ *
+ * 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.tuple.component;
+
+import org.hibernate.FetchMode;
+import org.hibernate.engine.FetchStrategy;
+import org.hibernate.engine.FetchStyle;
+import org.hibernate.engine.FetchTiming;
+import org.hibernate.engine.spi.CascadeStyle;
+import org.hibernate.engine.spi.LoadQueryInfluencers;
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.loader.PropertyPath;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.persister.entity.Joinable;
+import org.hibernate.persister.walking.internal.Helper;
+import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
+import org.hibernate.persister.walking.spi.AssociationKey;
+import org.hibernate.persister.walking.spi.CollectionDefinition;
+import org.hibernate.persister.walking.spi.EntityDefinition;
+import org.hibernate.tuple.BaselineAttributeInformation;
+import org.hibernate.type.AssociationType;
+import org.hibernate.type.CompositeType;
+
+/**
+ * @author Steve Ebersole
+ */
+public class CompositeBasedAssociationAttribute
+ extends AbstractCompositeBasedAttribute
+ implements AssociationAttributeDefinition {
+
+ private final AssociationKey associationKey;
+ private Joinable joinable;
+
+ public CompositeBasedAssociationAttribute(
+ AbstractCompositeDefinition source,
+ SessionFactoryImplementor factory,
+ int attributeNumber,
+ String attributeName,
+ AssociationType attributeType,
+ BaselineAttributeInformation baselineInfo,
+ int ownerAttributeNumber,
+ AssociationKey associationKey) {
+ super( source, factory, attributeNumber, attributeName, attributeType, baselineInfo, ownerAttributeNumber );
+ this.associationKey = associationKey;
+ }
+
+ @Override
+ public AssociationType getType() {
+ return (AssociationType) super.getType();
+ }
+
+ protected Joinable getJoinable() {
+ if ( joinable == null ) {
+ joinable = getType().getAssociatedJoinable( sessionFactory() );
+ }
+ return joinable;
+ }
+
+ @Override
+ public AssociationKey getAssociationKey() {
+ return associationKey;
+ }
+
+ @Override
+ public boolean isCollection() {
+ return getJoinable().isCollection();
+ }
+
+ @Override
+ public EntityDefinition toEntityDefinition() {
+ if ( isCollection() ) {
+ throw new IllegalStateException( "Cannot treat collection attribute as entity type" );
+ }
+ return (EntityPersister) getJoinable();
+ }
+
+ @Override
+ public CollectionDefinition toCollectionDefinition() {
+ if ( isCollection() ) {
+ throw new IllegalStateException( "Cannot treat entity attribute as collection type" );
+ }
+ return (CollectionPersister) getJoinable();
+ }
+
+ @Override
+ public FetchStrategy determineFetchPlan(LoadQueryInfluencers loadQueryInfluencers, PropertyPath propertyPath) {
+ final EntityPersister owningPersister = locateOwningPersister();
+
+ FetchStyle style = determineFetchStyleByProfile(
+ loadQueryInfluencers,
+ owningPersister,
+ propertyPath,
+ ownerAttributeNumber()
+ );
+ if ( style == null ) {
+ style = determineFetchStyleByMetadata(
+ getSource().getType().getFetchMode( attributeNumber() ),
+ getType()
+ );
+ }
+
+ return new FetchStrategy( determineFetchTiming( style ), style );
+ }
+
+ protected FetchStyle determineFetchStyleByProfile(
+ LoadQueryInfluencers loadQueryInfluencers,
+ EntityPersister owningPersister,
+ PropertyPath propertyPath,
+ int ownerAttributeNumber) {
+ return Helper.determineFetchStyleByProfile(
+ loadQueryInfluencers,
+ owningPersister,
+ propertyPath,
+ ownerAttributeNumber
+ );
+ }
+
+ protected FetchStyle determineFetchStyleByMetadata(FetchMode fetchMode, AssociationType type) {
+ return Helper.determineFetchStyleByMetadata( fetchMode, type, sessionFactory() );
+ }
+
+ private FetchTiming determineFetchTiming(FetchStyle style) {
+ return Helper.determineFetchTiming( style, getType(), sessionFactory() );
+ }
+
+ private EntityPersister locateOwningPersister() {
+ return getSource().locateOwningPersister();
+ }
+
+ @Override
+ public CascadeStyle determineCascadeStyle() {
+ final CompositeType compositeType = (CompositeType) locateOwningPersister().getPropertyType( getName() );
+ return compositeType.getCascadeStyle( attributeNumber() );
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/component/CompositeBasedBasicAttribute.java b/hibernate-core/src/main/java/org/hibernate/tuple/component/CompositeBasedBasicAttribute.java
new file mode 100644
index 0000000000..a975635599
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tuple/component/CompositeBasedBasicAttribute.java
@@ -0,0 +1,45 @@
+/*
+ * jDocBook, processing of DocBook sources
+ *
+ * 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.tuple.component;
+
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.persister.walking.spi.AttributeSource;
+import org.hibernate.tuple.AbstractNonIdentifierAttribute;
+import org.hibernate.tuple.BaselineAttributeInformation;
+import org.hibernate.type.Type;
+
+/**
+ * @author Steve Ebersole
+ */
+public class CompositeBasedBasicAttribute extends AbstractNonIdentifierAttribute {
+ protected CompositeBasedBasicAttribute(
+ AttributeSource source,
+ SessionFactoryImplementor sessionFactory,
+ int attributeNumber,
+ String attributeName,
+ Type attributeType,
+ BaselineAttributeInformation baselineInfo) {
+ super( source, sessionFactory, attributeNumber, attributeName, attributeType, baselineInfo );
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/component/CompositeBasedCompositeAttribute.java b/hibernate-core/src/main/java/org/hibernate/tuple/component/CompositeBasedCompositeAttribute.java
new file mode 100644
index 0000000000..1cca99c828
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tuple/component/CompositeBasedCompositeAttribute.java
@@ -0,0 +1,46 @@
+/*
+ * jDocBook, processing of DocBook sources
+ *
+ * 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.tuple.component;
+
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.persister.walking.spi.CompositeDefinition;
+import org.hibernate.tuple.BaselineAttributeInformation;
+import org.hibernate.type.CompositeType;
+
+/**
+ * @author Steve Ebersole
+ */
+public class CompositeBasedCompositeAttribute
+ extends AbstractCompositeDefinition
+ implements CompositeDefinition {
+ public CompositeBasedCompositeAttribute(
+ CompositeDefinition source,
+ SessionFactoryImplementor sessionFactory,
+ int attributeNumber,
+ String attributeName,
+ CompositeType attributeType,
+ BaselineAttributeInformation baselineInfo) {
+ super( source, sessionFactory, attributeNumber, attributeName, attributeType, baselineInfo );
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityBasedAttribute.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityBasedAttribute.java
new file mode 100644
index 0000000000..64db5884b3
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityBasedAttribute.java
@@ -0,0 +1,50 @@
+/*
+ * jDocBook, processing of DocBook sources
+ *
+ * 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.tuple.entity;
+
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.tuple.AbstractNonIdentifierAttribute;
+import org.hibernate.tuple.BaselineAttributeInformation;
+import org.hibernate.type.Type;
+
+/**
+ * @author Steve Ebersole
+ */
+public abstract class AbstractEntityBasedAttribute extends AbstractNonIdentifierAttribute {
+ protected AbstractEntityBasedAttribute(
+ EntityPersister source,
+ SessionFactoryImplementor sessionFactory,
+ int attributeNumber,
+ String attributeName,
+ Type attributeType,
+ BaselineAttributeInformation attributeInformation) {
+ super( source, sessionFactory, attributeNumber, attributeName, attributeType, attributeInformation );
+ }
+
+ @Override
+ public EntityPersister getSource() {
+ return (EntityPersister) super.getSource();
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java
index d82567ac21..6c1c08a6f2 100644
--- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java
+++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java
@@ -56,8 +56,9 @@ import org.hibernate.property.Setter;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.ProxyFactory;
import org.hibernate.tuple.Instantiator;
+import org.hibernate.tuple.NonIdentifierAttribute;
import org.hibernate.tuple.StandardProperty;
-import org.hibernate.tuple.VersionProperty;
+import org.hibernate.tuple.entity.VersionProperty;
import org.hibernate.type.ComponentType;
import org.hibernate.type.CompositeType;
import org.hibernate.type.EntityType;
@@ -604,7 +605,7 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer {
final Object[] result = new Object[span];
for ( int j = 0; j < span; j++ ) {
- StandardProperty property = entityMetamodel.getProperties()[j];
+ NonIdentifierAttribute property = entityMetamodel.getProperties()[j];
if ( getAll || !property.isLazy() ) {
result[j] = getters[j].get( entity );
}
diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityBasedAssociationAttribute.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityBasedAssociationAttribute.java
new file mode 100644
index 0000000000..f19f1d8439
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityBasedAssociationAttribute.java
@@ -0,0 +1,132 @@
+package org.hibernate.tuple.entity;
+
+import org.hibernate.engine.FetchStrategy;
+import org.hibernate.engine.FetchStyle;
+import org.hibernate.engine.spi.CascadeStyle;
+import org.hibernate.engine.spi.LoadQueryInfluencers;
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.loader.PropertyPath;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.persister.entity.Joinable;
+import org.hibernate.persister.entity.OuterJoinLoadable;
+import org.hibernate.persister.walking.internal.Helper;
+import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
+import org.hibernate.persister.walking.spi.AssociationKey;
+import org.hibernate.persister.walking.spi.CollectionDefinition;
+import org.hibernate.persister.walking.spi.EntityDefinition;
+import org.hibernate.tuple.BaselineAttributeInformation;
+import org.hibernate.type.AssociationType;
+import org.hibernate.type.ForeignKeyDirection;
+
+import static org.hibernate.engine.internal.JoinHelper.getLHSColumnNames;
+import static org.hibernate.engine.internal.JoinHelper.getLHSTableName;
+import static org.hibernate.engine.internal.JoinHelper.getRHSColumnNames;
+
+/**
+* @author Steve Ebersole
+*/
+public class EntityBasedAssociationAttribute
+ extends AbstractEntityBasedAttribute
+ implements AssociationAttributeDefinition {
+
+ private Joinable joinable;
+
+ public EntityBasedAssociationAttribute(
+ EntityPersister source,
+ SessionFactoryImplementor sessionFactory,
+ int attributeNumber,
+ String attributeName,
+ AssociationType attributeType,
+ BaselineAttributeInformation baselineInfo) {
+ super( source, sessionFactory, attributeNumber, attributeName, attributeType, baselineInfo );
+ }
+
+ @Override
+ public AssociationType getType() {
+ return (AssociationType) super.getType();
+ }
+
+ protected Joinable getJoinable() {
+ if ( joinable == null ) {
+ joinable = getType().getAssociatedJoinable( sessionFactory() );
+ }
+ return joinable;
+ }
+
+ @Override
+ public AssociationKey getAssociationKey() {
+ final AssociationType type = getType();
+ final Joinable joinable = type.getAssociatedJoinable( sessionFactory() );
+
+ if ( type.getForeignKeyDirection() == ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT ) {
+ final String lhsTableName;
+ final String[] lhsColumnNames;
+
+ if ( joinable.isCollection() ) {
+ final QueryableCollection collectionPersister = (QueryableCollection) joinable;
+ lhsTableName = collectionPersister.getTableName();
+ lhsColumnNames = collectionPersister.getElementColumnNames();
+ }
+ else {
+ final OuterJoinLoadable entityPersister = (OuterJoinLoadable) joinable;
+ lhsTableName = getLHSTableName( type, attributeNumber(), entityPersister );
+ lhsColumnNames = getLHSColumnNames( type, attributeNumber(), entityPersister, sessionFactory() );
+ }
+ return new AssociationKey( lhsTableName, lhsColumnNames );
+ }
+ else {
+ return new AssociationKey( joinable.getTableName(), getRHSColumnNames( type, sessionFactory() ) );
+ }
+ }
+
+ @Override
+ public boolean isCollection() {
+ return getJoinable().isCollection();
+ }
+
+ @Override
+ public EntityDefinition toEntityDefinition() {
+ if ( isCollection() ) {
+ throw new IllegalStateException( "Cannot treat collection-valued attribute as entity type" );
+ }
+ return (EntityPersister) getJoinable();
+ }
+
+ @Override
+ public CollectionDefinition toCollectionDefinition() {
+ if ( ! isCollection() ) {
+ throw new IllegalStateException( "Cannot treat entity-valued attribute as collection type" );
+ }
+ return (QueryableCollection) getJoinable();
+ }
+
+ @Override
+ public FetchStrategy determineFetchPlan(LoadQueryInfluencers loadQueryInfluencers, PropertyPath propertyPath) {
+ final EntityPersister owningPersister = getSource().getEntityPersister();
+
+ FetchStyle style = Helper.determineFetchStyleByProfile(
+ loadQueryInfluencers,
+ owningPersister,
+ propertyPath,
+ attributeNumber()
+ );
+ if ( style == null ) {
+ style = Helper.determineFetchStyleByMetadata(
+ ((OuterJoinLoadable) getSource().getEntityPersister()).getFetchMode( attributeNumber() ),
+ getType(),
+ sessionFactory()
+ );
+ }
+
+ return new FetchStrategy(
+ Helper.determineFetchTiming( style, getType(), sessionFactory() ),
+ style
+ );
+ }
+
+ @Override
+ public CascadeStyle determineCascadeStyle() {
+ return getSource().getEntityPersister().getPropertyCascadeStyles()[attributeNumber()];
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityBasedBasicAttribute.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityBasedBasicAttribute.java
new file mode 100644
index 0000000000..ed08bfca29
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityBasedBasicAttribute.java
@@ -0,0 +1,44 @@
+/*
+ * jDocBook, processing of DocBook sources
+ *
+ * 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.tuple.entity;
+
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.tuple.BaselineAttributeInformation;
+import org.hibernate.type.Type;
+
+/**
+ * @author Steve Ebersole
+ */
+public class EntityBasedBasicAttribute extends AbstractEntityBasedAttribute {
+ public EntityBasedBasicAttribute(
+ EntityPersister source,
+ SessionFactoryImplementor factory,
+ int attributeNumber,
+ String attributeName,
+ Type attributeType,
+ BaselineAttributeInformation baselineInfo) {
+ super( source, factory, attributeNumber, attributeName, attributeType, baselineInfo );
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityBasedCompositeAttribute.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityBasedCompositeAttribute.java
new file mode 100644
index 0000000000..514bdd5dd5
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityBasedCompositeAttribute.java
@@ -0,0 +1,49 @@
+/*
+ * jDocBook, processing of DocBook sources
+ *
+ * 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.tuple.entity;
+
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.tuple.component.AbstractCompositeDefinition;
+import org.hibernate.persister.walking.spi.CompositeDefinition;
+import org.hibernate.tuple.BaselineAttributeInformation;
+import org.hibernate.type.CompositeType;
+
+/**
+ * @author Steve Ebersole
+ */
+public class EntityBasedCompositeAttribute
+ extends AbstractCompositeDefinition
+ implements CompositeDefinition {
+
+ public EntityBasedCompositeAttribute(
+ EntityPersister source,
+ SessionFactoryImplementor factory,
+ int attributeNumber,
+ String attributeName,
+ CompositeType attributeType,
+ BaselineAttributeInformation baselineInfo) {
+ super( source, factory, attributeNumber, attributeName, attributeType, baselineInfo );
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java
index ac2d02a4d0..7d0b2717fe 100644
--- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java
+++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java
@@ -57,10 +57,12 @@ import org.hibernate.metamodel.binding.BasicAttributeBinding;
import org.hibernate.metamodel.binding.EntityBinding;
import org.hibernate.metamodel.domain.Attribute;
import org.hibernate.metamodel.domain.SingularAttribute;
+import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.tuple.IdentifierProperty;
+import org.hibernate.tuple.NonIdentifierAttribute;
import org.hibernate.tuple.PropertyFactory;
import org.hibernate.tuple.StandardProperty;
-import org.hibernate.tuple.VersionProperty;
+import org.hibernate.tuple.entity.VersionProperty;
import org.hibernate.type.AssociationType;
import org.hibernate.type.CompositeType;
import org.hibernate.type.EntityType;
@@ -78,17 +80,18 @@ public class EntityMetamodel implements Serializable {
private static final int NO_VERSION_INDX = -66;
private final SessionFactoryImplementor sessionFactory;
+ private final AbstractEntityPersister persister;
private final String name;
private final String rootName;
private final EntityType entityType;
- private final IdentifierProperty identifierProperty;
+ private final IdentifierProperty identifierAttribute;
private final boolean versioned;
private final int propertySpan;
private final int versionPropertyIndex;
- private final StandardProperty[] properties;
+ private final NonIdentifierAttribute[] properties;
// temporary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private final String[] propertyNames;
private final Type[] propertyTypes;
@@ -136,17 +139,21 @@ public class EntityMetamodel implements Serializable {
private final EntityTuplizer entityTuplizer;
private final EntityInstrumentationMetadata instrumentationMetadata;
- public EntityMetamodel(PersistentClass persistentClass, SessionFactoryImplementor sessionFactory) {
+ public EntityMetamodel(
+ PersistentClass persistentClass,
+ AbstractEntityPersister persister,
+ SessionFactoryImplementor sessionFactory) {
this.sessionFactory = sessionFactory;
+ this.persister = persister;
name = persistentClass.getEntityName();
rootName = persistentClass.getRootClass().getEntityName();
entityType = sessionFactory.getTypeResolver().getTypeFactory().manyToOne( name );
- identifierProperty = PropertyFactory.buildIdentifierProperty(
- persistentClass,
- sessionFactory.getIdentifierGenerator( rootName )
- );
+ identifierAttribute = PropertyFactory.buildIdentifierAttribute(
+ persistentClass,
+ sessionFactory.getIdentifierGenerator( rootName )
+ );
versioned = persistentClass.isVersioned();
@@ -157,7 +164,7 @@ public class EntityMetamodel implements Serializable {
boolean hasLazy = false;
propertySpan = persistentClass.getPropertyClosureSpan();
- properties = new StandardProperty[propertySpan];
+ properties = new NonIdentifierAttribute[propertySpan];
List naturalIdNumbers = new ArrayList();
// temporary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
propertyNames = new String[propertySpan];
@@ -191,10 +198,22 @@ public class EntityMetamodel implements Serializable {
if ( prop == persistentClass.getVersion() ) {
tempVersionProperty = i;
- properties[i] = PropertyFactory.buildVersionProperty( prop, instrumentationMetadata.isInstrumented() );
+ properties[i] = PropertyFactory.buildVersionProperty(
+ persister,
+ sessionFactory,
+ i,
+ prop,
+ instrumentationMetadata.isInstrumented()
+ );
}
else {
- properties[i] = PropertyFactory.buildStandardProperty( prop, instrumentationMetadata.isInstrumented() );
+ properties[i] = PropertyFactory.buildEntityBasedAttribute(
+ persister,
+ sessionFactory,
+ i,
+ prop,
+ instrumentationMetadata.isInstrumented()
+ );
}
if ( prop.isNaturalIdentifier() ) {
@@ -363,15 +382,19 @@ public class EntityMetamodel implements Serializable {
}
}
- public EntityMetamodel(EntityBinding entityBinding, SessionFactoryImplementor sessionFactory) {
+ public EntityMetamodel(
+ EntityBinding entityBinding,
+ AbstractEntityPersister persister,
+ SessionFactoryImplementor sessionFactory) {
this.sessionFactory = sessionFactory;
+ this.persister = persister;
name = entityBinding.getEntity().getName();
rootName = entityBinding.getHierarchyDetails().getRootEntityBinding().getEntity().getName();
entityType = sessionFactory.getTypeResolver().getTypeFactory().manyToOne( name );
- identifierProperty = PropertyFactory.buildIdentifierProperty(
+ identifierAttribute = PropertyFactory.buildIdentifierProperty(
entityBinding,
sessionFactory.getIdentifierGenerator( rootName )
);
@@ -398,7 +421,7 @@ public class EntityMetamodel implements Serializable {
entityBinding.getAttributeBindingClosureSpan() :
entityBinding.getAttributeBindingClosureSpan() - 1;
- properties = new StandardProperty[propertySpan];
+ properties = new NonIdentifierAttribute[propertySpan];
List naturalIdNumbers = new ArrayList();
// temporary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
propertyNames = new String[propertySpan];
@@ -435,6 +458,7 @@ public class EntityMetamodel implements Serializable {
if ( attributeBinding == entityBinding.getHierarchyDetails().getVersioningAttributeBinding() ) {
tempVersionProperty = i;
properties[i] = PropertyFactory.buildVersionProperty(
+ persister,
entityBinding.getHierarchyDetails().getVersioningAttributeBinding(),
instrumentationMetadata.isInstrumented()
);
@@ -595,7 +619,7 @@ public class EntityMetamodel implements Serializable {
}
}
- private ValueInclusion determineInsertValueGenerationType(Property mappingProperty, StandardProperty runtimeProperty) {
+ private ValueInclusion determineInsertValueGenerationType(Property mappingProperty, NonIdentifierAttribute runtimeProperty) {
if ( runtimeProperty.isInsertGenerated() ) {
return ValueInclusion.FULL;
}
@@ -607,7 +631,7 @@ public class EntityMetamodel implements Serializable {
return ValueInclusion.NONE;
}
- private ValueInclusion determineInsertValueGenerationType(AttributeBinding mappingProperty, StandardProperty runtimeProperty) {
+ private ValueInclusion determineInsertValueGenerationType(AttributeBinding mappingProperty, NonIdentifierAttribute runtimeProperty) {
if ( runtimeProperty.isInsertGenerated() ) {
return ValueInclusion.FULL;
}
@@ -636,7 +660,7 @@ public class EntityMetamodel implements Serializable {
return false;
}
- private ValueInclusion determineUpdateValueGenerationType(Property mappingProperty, StandardProperty runtimeProperty) {
+ private ValueInclusion determineUpdateValueGenerationType(Property mappingProperty, NonIdentifierAttribute runtimeProperty) {
if ( runtimeProperty.isUpdateGenerated() ) {
return ValueInclusion.FULL;
}
@@ -648,7 +672,7 @@ public class EntityMetamodel implements Serializable {
return ValueInclusion.NONE;
}
- private ValueInclusion determineUpdateValueGenerationType(AttributeBinding mappingProperty, StandardProperty runtimeProperty) {
+ private ValueInclusion determineUpdateValueGenerationType(AttributeBinding mappingProperty, NonIdentifierAttribute runtimeProperty) {
if ( runtimeProperty.isUpdateGenerated() ) {
return ValueInclusion.FULL;
}
@@ -762,7 +786,7 @@ public class EntityMetamodel implements Serializable {
}
public IdentifierProperty getIdentifierProperty() {
- return identifierProperty;
+ return identifierAttribute;
}
public int getPropertySpan() {
@@ -782,7 +806,7 @@ public class EntityMetamodel implements Serializable {
}
}
- public StandardProperty[] getProperties() {
+ public NonIdentifierAttribute[] getProperties() {
return properties;
}
diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/VersionProperty.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/VersionProperty.java
new file mode 100644
index 0000000000..51a8e67d4e
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/VersionProperty.java
@@ -0,0 +1,70 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, 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.tuple.entity;
+
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.engine.spi.VersionValue;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.tuple.AbstractNonIdentifierAttribute;
+import org.hibernate.tuple.BaselineAttributeInformation;
+import org.hibernate.type.Type;
+
+/**
+ * Represents a version property within the Hibernate runtime-metamodel.
+ *
+ * @author Steve Ebersole
+ */
+public class VersionProperty extends AbstractNonIdentifierAttribute {
+
+ private final VersionValue unsavedValue;
+
+ /**
+ * Constructs VersionProperty instances.
+ *
+ * @param source Reference back to the source of this attribute (the persister)
+ * @param sessionFactory The session factory this is part of.
+ * @param attributeNumber The attribute number within thje
+ * @param attributeName The name by which the property can be referenced within
+ * its owner.
+ * @param attributeType The Hibernate Type of this property.
+ * @param attributeInformation The basic attribute information.
+ * @param unsavedValue The value which, if found as the value of
+ * this (i.e., the version) property, represents new (i.e., un-saved)
+ * instances of the owning entity.
+ */
+ public VersionProperty(
+ EntityPersister source,
+ SessionFactoryImplementor sessionFactory,
+ int attributeNumber,
+ String attributeName,
+ Type attributeType,
+ BaselineAttributeInformation attributeInformation, VersionValue unsavedValue) {
+ super( source, sessionFactory, attributeNumber, attributeName, attributeType, attributeInformation );
+ this.unsavedValue = unsavedValue;
+ }
+
+ public VersionValue getUnsavedValue() {
+ return unsavedValue;
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/type/TypeHelper.java b/hibernate-core/src/main/java/org/hibernate/type/TypeHelper.java
index df23ae8603..126e792d2a 100644
--- a/hibernate-core/src/main/java/org/hibernate/type/TypeHelper.java
+++ b/hibernate-core/src/main/java/org/hibernate/type/TypeHelper.java
@@ -28,7 +28,7 @@ import java.util.Map;
import org.hibernate.bytecode.instrumentation.spi.LazyPropertyInitializer;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.property.BackrefPropertyAccessor;
-import org.hibernate.tuple.StandardProperty;
+import org.hibernate.tuple.NonIdentifierAttribute;
/**
* Collection of convenience methods relating to operations across arrays of types...
@@ -280,7 +280,7 @@ public class TypeHelper {
* @return Array containing indices of the dirty properties, or null if no properties considered dirty.
*/
public static int[] findDirty(
- final StandardProperty[] properties,
+ final NonIdentifierAttribute[] properties,
final Object[] currentState,
final Object[] previousState,
final boolean[][] includeColumns,
@@ -328,7 +328,7 @@ public class TypeHelper {
* @return Array containing indices of the modified properties, or null if no properties considered modified.
*/
public static int[] findModified(
- final StandardProperty[] properties,
+ final NonIdentifierAttribute[] properties,
final Object[] currentState,
final Object[] previousState,
final boolean[][] includeColumns,
diff --git a/hibernate-core/src/test/java/org/hibernate/loader/plan/spi/LoadPlanBuilderTest.java b/hibernate-core/src/test/java/org/hibernate/loader/plan/spi/LoadPlanBuilderTest.java
new file mode 100644
index 0000000000..597b900344
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/loader/plan/spi/LoadPlanBuilderTest.java
@@ -0,0 +1,149 @@
+/*
+ * jDocBook, processing of DocBook sources
+ *
+ * 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.loader.plan.spi;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import java.util.List;
+
+import org.hibernate.engine.spi.CascadingActions;
+import org.hibernate.engine.spi.LoadQueryInfluencers;
+import org.hibernate.loader.plan.internal.CascadeLoadPlanBuilderStrategy;
+import org.hibernate.loader.plan.internal.SingleRootReturnLoadPlanBuilderStrategy;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.entity.EntityPersister;
+
+import org.junit.Test;
+
+import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
+import org.hibernate.testing.junit4.ExtraAssertions;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * @author Steve Ebersole
+ */
+public class LoadPlanBuilderTest extends BaseCoreFunctionalTestCase {
+ @Override
+ protected Class>[] getAnnotatedClasses() {
+ return new Class[] { Message.class, Poster.class };
+ }
+
+ @Test
+ public void testSimpleBuild() {
+ EntityPersister ep = (EntityPersister) sessionFactory().getClassMetadata(Message.class);
+ SingleRootReturnLoadPlanBuilderStrategy strategy = new SingleRootReturnLoadPlanBuilderStrategy(
+ sessionFactory(),
+ LoadQueryInfluencers.NONE,
+ "abc",
+ 0
+ );
+ LoadPlan plan = LoadPlanBuilder.buildRootEntityLoadPlan( strategy, ep );
+ assertFalse( plan.hasAnyScalarReturns() );
+ assertEquals( 1, plan.getReturns().size() );
+ Return rtn = plan.getReturns().get( 0 );
+ EntityReturn entityReturn = ExtraAssertions.assertTyping( EntityReturn.class, rtn );
+ assertEquals( "abc", entityReturn.getAlias() );
+ assertNotNull( entityReturn.getFetches() );
+ assertEquals( 1, entityReturn.getFetches().length );
+ Fetch fetch = entityReturn.getFetches()[0];
+ EntityFetch entityFetch = ExtraAssertions.assertTyping( EntityFetch.class, fetch );
+ assertNotNull( entityFetch.getFetches() );
+ assertEquals( 0, entityFetch.getFetches().length );
+ }
+
+ @Test
+ public void testCascadeBasedBuild() {
+ EntityPersister ep = (EntityPersister) sessionFactory().getClassMetadata(Message.class);
+ CascadeLoadPlanBuilderStrategy strategy = new CascadeLoadPlanBuilderStrategy(
+ CascadingActions.MERGE,
+ sessionFactory(),
+ LoadQueryInfluencers.NONE,
+ "abc",
+ 0
+ );
+ LoadPlan plan = LoadPlanBuilder.buildRootEntityLoadPlan( strategy, ep );
+ assertFalse( plan.hasAnyScalarReturns() );
+ assertEquals( 1, plan.getReturns().size() );
+ Return rtn = plan.getReturns().get( 0 );
+ EntityReturn entityReturn = ExtraAssertions.assertTyping( EntityReturn.class, rtn );
+ assertEquals( "abc", entityReturn.getAlias() );
+ assertNotNull( entityReturn.getFetches() );
+ assertEquals( 1, entityReturn.getFetches().length );
+ Fetch fetch = entityReturn.getFetches()[0];
+ EntityFetch entityFetch = ExtraAssertions.assertTyping( EntityFetch.class, fetch );
+ assertNotNull( entityFetch.getFetches() );
+ assertEquals( 0, entityFetch.getFetches().length );
+ }
+
+ @Test
+ public void testCollectionInitializerCase() {
+ CollectionPersister cp = sessionFactory().getCollectionPersister( Poster.class.getName() + ".messages" );
+ SingleRootReturnLoadPlanBuilderStrategy strategy = new SingleRootReturnLoadPlanBuilderStrategy(
+ sessionFactory(),
+ LoadQueryInfluencers.NONE,
+ "abc",
+ 0
+ );
+ LoadPlan plan = LoadPlanBuilder.buildRootCollectionLoadPlan( strategy, cp );
+ assertFalse( plan.hasAnyScalarReturns() );
+ assertEquals( 1, plan.getReturns().size() );
+ Return rtn = plan.getReturns().get( 0 );
+ CollectionReturn collectionReturn = ExtraAssertions.assertTyping( CollectionReturn.class, rtn );
+ assertEquals( "abc", collectionReturn.getAlias() );
+
+ assertNotNull( collectionReturn.getFetches() );
+ assertEquals( 1, collectionReturn.getFetches().length ); // the collection elements are fetched
+ Fetch fetch = collectionReturn.getFetches()[0];
+ EntityFetch entityFetch = ExtraAssertions.assertTyping( EntityFetch.class, fetch );
+ assertNotNull( entityFetch.getFetches() );
+ assertEquals( 0, entityFetch.getFetches().length );
+ }
+
+ @Entity( name = "Message" )
+ public static class Message {
+ @Id
+ private Integer id;
+ private String name;
+ @ManyToOne( cascade = CascadeType.MERGE )
+ @JoinColumn
+ private Poster poster;
+ }
+
+ @Entity( name = "Poster" )
+ public static class Poster {
+ @Id
+ private Integer id;
+ private String name;
+ @OneToMany(mappedBy = "poster")
+ private List messages;
+ }
+
+}
\ No newline at end of file
diff --git a/hibernate-core/src/test/java/org/hibernate/persister/walking/BasicWalkingTest.java b/hibernate-core/src/test/java/org/hibernate/persister/walking/BasicWalkingTest.java
new file mode 100644
index 0000000000..07c193bb13
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/persister/walking/BasicWalkingTest.java
@@ -0,0 +1,177 @@
+/*
+ * jDocBook, processing of DocBook sources
+ *
+ * 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.persister.walking;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import java.util.List;
+
+import org.hibernate.annotations.common.util.StringHelper;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.persister.walking.spi.AssociationVisitationStrategy;
+import org.hibernate.persister.walking.spi.AttributeDefinition;
+import org.hibernate.persister.walking.spi.CollectionDefinition;
+import org.hibernate.persister.walking.spi.CompositeDefinition;
+import org.hibernate.persister.walking.spi.EntityDefinition;
+import org.hibernate.persister.walking.spi.MetadataDrivenModelGraphVisitor;
+
+import org.junit.Test;
+
+import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
+
+/**
+ * @author Steve Ebersole
+ */
+public class BasicWalkingTest extends BaseCoreFunctionalTestCase {
+ @Override
+ protected Class>[] getAnnotatedClasses() {
+ return new Class[] { Message.class, Poster.class };
+ }
+
+ @Test
+ public void testIt() {
+ EntityPersister ep = (EntityPersister) sessionFactory().getClassMetadata(Message.class);
+ MetadataDrivenModelGraphVisitor.visitEntity(
+ new AssociationVisitationStrategy() {
+ private int depth = 0;
+
+ @Override
+ public void start() {
+ System.out.println( ">> Start" );
+ }
+
+ @Override
+ public void finish() {
+ System.out.println( "<< Finish" );
+ }
+
+ @Override
+ public void startingEntity(EntityDefinition entityDefinition) {
+ System.out.println(
+ String.format(
+ "%s Starting entity (%s)",
+ StringHelper.repeat( ">>", ++depth ),
+ entityDefinition.toString()
+ )
+ );
+ }
+
+ @Override
+ public void finishingEntity(EntityDefinition entityDefinition) {
+ System.out.println(
+ String.format(
+ "%s Finishing entity (%s)",
+ StringHelper.repeat( "<<", depth-- ),
+ entityDefinition.toString()
+ )
+ );
+ }
+
+ @Override
+ public void startingCollection(CollectionDefinition collectionDefinition) {
+ System.out.println(
+ String.format(
+ "%s Starting collection (%s)",
+ StringHelper.repeat( ">>", ++depth ),
+ collectionDefinition.toString()
+ )
+ );
+ }
+
+ @Override
+ public void finishingCollection(CollectionDefinition collectionDefinition) {
+ System.out.println(
+ String.format(
+ "%s Finishing collection (%s)",
+ StringHelper.repeat( ">>", depth-- ),
+ collectionDefinition.toString()
+ )
+ );
+ }
+
+ @Override
+ public void startingComposite(CompositeDefinition compositeDefinition) {
+ System.out.println(
+ String.format(
+ "%s Starting composite (%s)",
+ StringHelper.repeat( ">>", ++depth ),
+ compositeDefinition.toString()
+ )
+ );
+ }
+
+ @Override
+ public void finishingComposite(CompositeDefinition compositeDefinition) {
+ System.out.println(
+ String.format(
+ "%s Finishing composite (%s)",
+ StringHelper.repeat( ">>", depth-- ),
+ compositeDefinition.toString()
+ )
+ );
+ }
+
+ @Override
+ public boolean startingAttribute(AttributeDefinition attributeDefinition) {
+ System.out.println(
+ String.format(
+ "%s Handling attribute (%s)",
+ StringHelper.repeat( ">>", depth + 1 ),
+ attributeDefinition.toString()
+ )
+ );
+ return true;
+ }
+
+ @Override
+ public void finishingAttribute(AttributeDefinition attributeDefinition) {
+ // nothing to do
+ }
+ },
+ ep
+ );
+ }
+
+ @Entity( name = "Message" )
+ public static class Message {
+ @Id
+ private Integer id;
+ private String name;
+ @ManyToOne
+ @JoinColumn
+ private Poster poster;
+ }
+
+ @Entity( name = "Poster" )
+ public static class Poster {
+ @Id
+ private Integer id;
+ private String name;
+ @OneToMany(mappedBy = "poster")
+ private List messages;
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/cfg/persister/GoofyPersisterClassProvider.java b/hibernate-core/src/test/java/org/hibernate/test/cfg/persister/GoofyPersisterClassProvider.java
index 3e32129981..6af678c8a5 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/cfg/persister/GoofyPersisterClassProvider.java
+++ b/hibernate-core/src/test/java/org/hibernate/test/cfg/persister/GoofyPersisterClassProvider.java
@@ -37,6 +37,7 @@ import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
import org.hibernate.cache.spi.entry.CacheEntry;
import org.hibernate.cache.spi.entry.CacheEntryStructure;
+import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.engine.spi.Mapping;
@@ -54,6 +55,9 @@ import org.hibernate.metamodel.binding.PluralAttributeBinding;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.spi.PersisterClassResolver;
+import org.hibernate.persister.walking.spi.AttributeDefinition;
+import org.hibernate.persister.walking.spi.CollectionElementDefinition;
+import org.hibernate.persister.walking.spi.CollectionIndexDefinition;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.tuple.entity.EntityTuplizer;
import org.hibernate.tuple.entity.NonPojoInstrumentationMetadata;
@@ -579,6 +583,21 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver {
// TODO Auto-generated method stub
return null;
}
+
+ @Override
+ public EntityPersister getEntityPersister() {
+ return this;
+ }
+
+ @Override
+ public Iterable getEmbeddedCompositeIdentifierAttributes() {
+ throw new NotYetImplementedException();
+ }
+
+ @Override
+ public Iterable getAttributes() {
+ throw new NotYetImplementedException();
+ }
}
public static class NoopCollectionPersister implements CollectionPersister {
@@ -606,8 +625,23 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
+ @Override
+ public CollectionPersister getCollectionPersister() {
+ return this;
+ }
+
public CollectionType getCollectionType() {
- return null; //To change body of implemented methods use File | Settings | File Templates.
+ throw new NotYetImplementedException();
+ }
+
+ @Override
+ public CollectionIndexDefinition getIndexDefinition() {
+ throw new NotYetImplementedException();
+ }
+
+ @Override
+ public CollectionElementDefinition getElementDefinition() {
+ throw new NotYetImplementedException();
}
public Type getKeyType() {
diff --git a/hibernate-core/src/test/java/org/hibernate/test/legacy/CustomPersister.java b/hibernate-core/src/test/java/org/hibernate/test/legacy/CustomPersister.java
index 62258c377b..55b96323ab 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/legacy/CustomPersister.java
+++ b/hibernate-core/src/test/java/org/hibernate/test/legacy/CustomPersister.java
@@ -17,6 +17,7 @@ import org.hibernate.cache.spi.entry.CacheEntry;
import org.hibernate.cache.spi.entry.CacheEntryStructure;
import org.hibernate.cache.spi.entry.StandardCacheEntryImpl;
import org.hibernate.cache.spi.entry.UnstructuredCacheEntry;
+import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.engine.internal.TwoPhaseLoad;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.engine.spi.Mapping;
@@ -34,6 +35,7 @@ import org.hibernate.internal.util.compare.EqualsHelper;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.persister.walking.spi.AttributeDefinition;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.tuple.entity.EntityTuplizer;
import org.hibernate.tuple.entity.NonPojoInstrumentationMetadata;
@@ -671,4 +673,19 @@ public class CustomPersister implements EntityPersister {
public FilterAliasGenerator getFilterAliasGenerator(String rootAlias) {
return new StaticFilterAliasGenerator(rootAlias);
}
+
+ @Override
+ public EntityPersister getEntityPersister() {
+ return this;
+ }
+
+ @Override
+ public Iterable getEmbeddedCompositeIdentifierAttributes() {
+ throw new NotYetImplementedException();
+ }
+
+ @Override
+ public Iterable getAttributes() {
+ throw new NotYetImplementedException();
+ }
}