HHH-7841 - Redesign Loader

This commit is contained in:
Steve Ebersole 2013-03-11 15:55:53 -05:00
parent c75dafbedd
commit 3d332371bd
76 changed files with 3729 additions and 431 deletions

View File

@ -0,0 +1,43 @@
/*
* 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;
/**
* Marks a group of exceptions that generally indicate an internal Hibernate error or bug.
*
* @author Steve Ebersole
*/
public abstract class HibernateError extends HibernateException {
public HibernateError(String message) {
super( message );
}
public HibernateError(Throwable root) {
super( root );
}
public HibernateError(String message, Throwable root) {
super( message, root );
}
}

View File

@ -63,6 +63,7 @@ import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.BasicLoader;
import org.hibernate.loader.spi.AfterLoadAction;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.Loadable;

View File

@ -79,6 +79,7 @@ import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.FetchingScrollableResultsImpl;
import org.hibernate.internal.ScrollableResultsImpl;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.loader.spi.AfterLoadAction;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Loadable;
@ -245,10 +246,6 @@ public abstract class Loader {
: sql;
}
protected static interface AfterLoadAction {
public void afterLoad(SessionImplementor session, Object entity, Loadable persister);
}
protected boolean shouldUseFollowOnLocking(
QueryParameters parameters,
Dialect dialect,
@ -509,7 +506,7 @@ public abstract class Loader {
}
// We call getKeyFromResultSet() here so that we can know the
// key value upon which to doAfterTransactionCompletion the breaking logic. However,
// key value upon which to perform the breaking logic. However,
// it is also then called from getRowFromResultSet() which is certainly
// not the most efficient. But the call here is needed, and there
// currently is no other way without refactoring of the doQuery()/getRowFromResultSet()
@ -527,7 +524,7 @@ public abstract class Loader {
catch ( SQLException sqle ) {
throw factory.getSQLExceptionHelper().convert(
sqle,
"could not doAfterTransactionCompletion sequential read of results (forward)",
"could not perform sequential read of results (forward)",
getSQLString()
);
}

View File

@ -43,6 +43,7 @@ import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.JoinWalker;
import org.hibernate.loader.Loader;
import org.hibernate.loader.spi.AfterLoadAction;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.type.Type;

View File

@ -45,6 +45,7 @@ import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.internal.CriteriaImpl;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.OuterJoinLoader;
import org.hibernate.loader.spi.AfterLoadAction;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.entity.Lockable;
import org.hibernate.persister.entity.OuterJoinLoadable;

View File

@ -27,7 +27,6 @@ import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@ -41,10 +40,7 @@ import org.hibernate.QueryException;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.LimitHelper;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.hql.internal.HolderInstantiator;
@ -53,10 +49,10 @@ import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.loader.EntityAliases;
import org.hibernate.loader.Loader;
import org.hibernate.loader.spi.AfterLoadAction;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.entity.Lockable;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.type.CollectionType;

View File

@ -43,6 +43,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.spi.AfterLoadAction;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.pretty.MessageHelper;

View File

@ -52,6 +52,7 @@ import org.hibernate.hql.internal.ast.tree.SelectClause;
import org.hibernate.internal.IteratorImpl;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.BasicLoader;
import org.hibernate.loader.spi.AfterLoadAction;
import org.hibernate.param.ParameterSpecification;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.collection.QueryableCollection;

View File

@ -0,0 +1,58 @@
/*
* 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.loader.internal;
import java.sql.ResultSet;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.loader.spi.OnDemandResultSetProcessor;
/**
* @author Steve Ebersole
*/
public class OnDemandResultSetProcessorImpl implements OnDemandResultSetProcessor {
@Override
public Object extractSingleRow(
ResultSet resultSet,
SessionImplementor session,
QueryParameters queryParameters) {
return null;
}
@Override
public Object extractSequentialRowsForward(
ResultSet resultSet, SessionImplementor session, QueryParameters queryParameters) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public Object extractSequentialRowsReverse(
ResultSet resultSet,
SessionImplementor session,
QueryParameters queryParameters,
boolean isLogicallyAfterLast) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
}

View File

@ -0,0 +1,557 @@
/*
* 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.loader.internal;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jboss.logging.Logger;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.StaleObjectStateException;
import org.hibernate.WrongClassException;
import org.hibernate.engine.internal.TwoPhaseLoad;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.EntityUniqueKey;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SubselectFetch;
import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.PostLoadEvent;
import org.hibernate.event.spi.PreLoadEvent;
import org.hibernate.loader.EntityAliases;
import org.hibernate.loader.plan.spi.CollectionFetch;
import org.hibernate.loader.plan.spi.CollectionReturn;
import org.hibernate.loader.plan.spi.EntityReference;
import org.hibernate.loader.plan.spi.LoadPlan;
import org.hibernate.loader.plan.spi.LoadPlanVisitationStrategyAdapter;
import org.hibernate.loader.plan.spi.LoadPlanVisitor;
import org.hibernate.loader.spi.AfterLoadAction;
import org.hibernate.loader.spi.NamedParameterContext;
import org.hibernate.loader.spi.ResultSetProcessingContext;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.entity.UniqueKeyLoadable;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;
import org.hibernate.type.VersionType;
/**
* @author Steve Ebersole
*/
public class ResultSetProcessingContextImpl implements ResultSetProcessingContext {
private static final Logger LOG = Logger.getLogger( ResultSetProcessingContextImpl.class );
private final ResultSet resultSet;
private final SessionImplementor session;
private final LoadPlan loadPlan;
private final boolean readOnly;
private final QueryParameters queryParameters;
private final NamedParameterContext namedParameterContext;
private final boolean hadSubselectFetches;
private final EntityKey dictatedRootEntityKey;
private List<HydratedEntityRegistration> currentRowHydratedEntityRegistrationList;
private Map<EntityPersister,Set<EntityKey>> subselectLoadableEntityKeyMap;
private List<HydratedEntityRegistration> hydratedEntityRegistrationList;
public ResultSetProcessingContextImpl(
ResultSet resultSet,
SessionImplementor session,
LoadPlan loadPlan,
boolean readOnly,
boolean useOptionalEntityKey,
QueryParameters queryParameters,
NamedParameterContext namedParameterContext,
boolean hadSubselectFetches) {
this.resultSet = resultSet;
this.session = session;
this.loadPlan = loadPlan;
this.readOnly = readOnly;
this.queryParameters = queryParameters;
this.namedParameterContext = namedParameterContext;
this.hadSubselectFetches = hadSubselectFetches;
if ( useOptionalEntityKey ) {
this.dictatedRootEntityKey = ResultSetProcessorHelper.getOptionalObjectKey( queryParameters, session );
if ( this.dictatedRootEntityKey == null ) {
throw new HibernateException( "Unable to resolve optional entity-key" );
}
}
else {
this.dictatedRootEntityKey = null;
}
}
@Override
public SessionImplementor getSession() {
return session;
}
@Override
public QueryParameters getQueryParameters() {
return queryParameters;
}
@Override
public EntityKey getDictatedRootEntityKey() {
return dictatedRootEntityKey;
}
private Map<EntityReference,IdentifierResolutionContext> identifierResolutionContextMap;
@Override
public IdentifierResolutionContext getIdentifierResolutionContext(final EntityReference entityReference) {
if ( identifierResolutionContextMap == null ) {
identifierResolutionContextMap = new HashMap<EntityReference, IdentifierResolutionContext>();
}
IdentifierResolutionContext context = identifierResolutionContextMap.get( entityReference );
if ( context == null ) {
context = new IdentifierResolutionContext() {
private Serializable hydratedForm;
private EntityKey entityKey;
@Override
public EntityReference getEntityReference() {
return entityReference;
}
@Override
public void registerHydratedForm(Serializable hydratedForm) {
if ( this.hydratedForm != null ) {
// this could be bad...
}
this.hydratedForm = hydratedForm;
}
@Override
public Serializable getHydratedForm() {
return hydratedForm;
}
@Override
public void registerEntityKey(EntityKey entityKey) {
if ( this.entityKey != null ) {
// again, could be trouble...
}
this.entityKey = entityKey;
}
@Override
public EntityKey getEntityKey() {
return entityKey;
}
};
identifierResolutionContextMap.put( entityReference, context );
}
return context;
}
@Override
public void checkVersion(
ResultSet resultSet,
EntityPersister persister,
EntityAliases entityAliases,
EntityKey entityKey,
Object entityInstance) throws SQLException {
final Object version = session.getPersistenceContext().getEntry( entityInstance ).getVersion();
if ( version != null ) {
//null version means the object is in the process of being loaded somewhere else in the ResultSet
VersionType versionType = persister.getVersionType();
Object currentVersion = versionType.nullSafeGet(
resultSet,
entityAliases.getSuffixedVersionAliases(),
session,
null
);
if ( !versionType.isEqual(version, currentVersion) ) {
if ( session.getFactory().getStatistics().isStatisticsEnabled() ) {
session.getFactory().getStatisticsImplementor()
.optimisticFailure( persister.getEntityName() );
}
throw new StaleObjectStateException( persister.getEntityName(), entityKey.getIdentifier() );
}
}
}
@Override
public String getConcreteEntityTypeName(
final ResultSet rs,
final EntityPersister persister,
final EntityAliases entityAliases,
final EntityKey entityKey) throws SQLException {
final Loadable loadable = (Loadable) persister;
if ( ! loadable.hasSubclasses() ) {
return persister.getEntityName();
}
final Object discriminatorValue = loadable.getDiscriminatorType().nullSafeGet(
rs,
entityAliases.getSuffixedDiscriminatorAlias(),
session,
null
);
final String result = loadable.getSubclassForDiscriminatorValue( discriminatorValue );
if ( result == null ) {
// whoops! we got an instance of another class hierarchy branch
throw new WrongClassException(
"Discriminator: " + discriminatorValue,
entityKey.getIdentifier(),
persister.getEntityName()
);
}
return result;
}
@Override
public void loadFromResultSet(
ResultSet resultSet,
Object entityInstance,
String concreteEntityTypeName,
EntityKey entityKey,
EntityAliases entityAliases,
LockMode acquiredLockMode,
EntityPersister rootPersister,
boolean eagerFetch,
EntityType associationType) throws SQLException {
final Serializable id = entityKey.getIdentifier();
// Get the persister for the _subclass_
final Loadable persister = (Loadable) getSession().getFactory().getEntityPersister( concreteEntityTypeName );
if ( LOG.isTraceEnabled() ) {
LOG.tracev(
"Initializing object from ResultSet: {0}",
MessageHelper.infoString(
persister,
id,
getSession().getFactory()
)
);
}
// add temp entry so that the next step is circular-reference
// safe - only needed because some types don't take proper
// advantage of two-phase-load (esp. components)
TwoPhaseLoad.addUninitializedEntity(
entityKey,
entityInstance,
persister,
acquiredLockMode,
!eagerFetch,
session
);
// This is not very nice (and quite slow):
final String[][] cols = persister == rootPersister ?
entityAliases.getSuffixedPropertyAliases() :
entityAliases.getSuffixedPropertyAliases(persister);
final Object[] values = persister.hydrate(
resultSet,
id,
entityInstance,
(Loadable) rootPersister,
cols,
eagerFetch,
session
);
final Object rowId = persister.hasRowId() ? resultSet.getObject( entityAliases.getRowIdAlias() ) : null;
if ( associationType != null ) {
String ukName = associationType.getRHSUniqueKeyPropertyName();
if ( ukName != null ) {
final int index = ( (UniqueKeyLoadable) persister ).getPropertyIndex( ukName );
final Type type = persister.getPropertyTypes()[index];
// polymorphism not really handled completely correctly,
// perhaps...well, actually its ok, assuming that the
// entity name used in the lookup is the same as the
// the one used here, which it will be
EntityUniqueKey euk = new EntityUniqueKey(
rootPersister.getEntityName(), //polymorphism comment above
ukName,
type.semiResolve( values[index], session, entityInstance ),
type,
persister.getEntityMode(),
session.getFactory()
);
session.getPersistenceContext().addEntity( euk, entityInstance );
}
}
TwoPhaseLoad.postHydrate(
persister,
id,
values,
rowId,
entityInstance,
acquiredLockMode,
!eagerFetch,
session
);
}
@Override
public void registerHydratedEntity(EntityPersister persister, EntityKey entityKey, Object entityInstance) {
if ( currentRowHydratedEntityRegistrationList == null ) {
currentRowHydratedEntityRegistrationList = new ArrayList<HydratedEntityRegistration>();
}
currentRowHydratedEntityRegistrationList.add( new HydratedEntityRegistration( persister, entityKey, entityInstance ) );
}
/**
* Package-protected
*/
void finishUpRow() {
if ( currentRowHydratedEntityRegistrationList == null ) {
return;
}
// managing the running list of registrations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( hydratedEntityRegistrationList == null ) {
hydratedEntityRegistrationList = new ArrayList<HydratedEntityRegistration>();
}
hydratedEntityRegistrationList.addAll( currentRowHydratedEntityRegistrationList );
// managing the map forms needed for subselect fetch generation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( ! hadSubselectFetches ) {
return;
}
if ( subselectLoadableEntityKeyMap == null ) {
subselectLoadableEntityKeyMap = new HashMap<EntityPersister, Set<EntityKey>>();
}
for ( HydratedEntityRegistration registration : currentRowHydratedEntityRegistrationList ) {
Set<EntityKey> entityKeys = subselectLoadableEntityKeyMap.get( registration.persister );
if ( entityKeys == null ) {
entityKeys = new HashSet<EntityKey>();
subselectLoadableEntityKeyMap.put( registration.persister, entityKeys );
}
entityKeys.add( registration.key );
}
// release the currentRowHydratedEntityRegistrationList entries
currentRowHydratedEntityRegistrationList.clear();
}
/**
* Package-protected
*
* @param afterLoadActionList List of after-load actions to perform
*/
void finishUp(List<AfterLoadAction> afterLoadActionList) {
initializeEntitiesAndCollections( afterLoadActionList );
createSubselects();
if ( hydratedEntityRegistrationList != null ) {
hydratedEntityRegistrationList.clear();
hydratedEntityRegistrationList = null;
}
if ( subselectLoadableEntityKeyMap != null ) {
subselectLoadableEntityKeyMap.clear();
subselectLoadableEntityKeyMap = null;
}
}
private void initializeEntitiesAndCollections(List<AfterLoadAction> afterLoadActionList) {
// for arrays, we should end the collection load before resolving the entities, since the
// actual array instances are not instantiated during loading
finishLoadingArrays();
// IMPORTANT: reuse the same event instances for performance!
final PreLoadEvent preLoadEvent;
final PostLoadEvent postLoadEvent;
if ( session.isEventSource() ) {
preLoadEvent = new PreLoadEvent( (EventSource) session );
postLoadEvent = new PostLoadEvent( (EventSource) session );
}
else {
preLoadEvent = null;
postLoadEvent = null;
}
// now finish loading the entities (2-phase load)
performTwoPhaseLoad( preLoadEvent, postLoadEvent );
// now we can finalize loading collections
finishLoadingCollections();
// finally, perform post-load operations
postLoad( postLoadEvent, afterLoadActionList );
}
private void finishLoadingArrays() {
LoadPlanVisitor.visit(
loadPlan,
new LoadPlanVisitationStrategyAdapter() {
@Override
public void handleCollectionReturn(CollectionReturn rootCollectionReturn) {
endLoadingArray( rootCollectionReturn.getCollectionPersister() );
}
@Override
public void startingCollectionFetch(CollectionFetch collectionFetch) {
endLoadingArray( collectionFetch.getCollectionPersister() );
}
private void endLoadingArray(CollectionPersister persister) {
if ( persister.isArray() ) {
session.getPersistenceContext()
.getLoadContexts()
.getCollectionLoadContext( resultSet )
.endLoadingCollections( persister );
}
}
}
);
}
private void performTwoPhaseLoad(PreLoadEvent preLoadEvent, PostLoadEvent postLoadEvent) {
final int numberOfHydratedObjects = hydratedEntityRegistrationList == null
? 0
: hydratedEntityRegistrationList.size();
LOG.tracev( "Total objects hydrated: {0}", numberOfHydratedObjects );
if ( hydratedEntityRegistrationList == null ) {
return;
}
for ( HydratedEntityRegistration registration : hydratedEntityRegistrationList ) {
TwoPhaseLoad.initializeEntity( registration.instance, readOnly, session, preLoadEvent, postLoadEvent );
}
}
private void finishLoadingCollections() {
LoadPlanVisitor.visit(
loadPlan,
new LoadPlanVisitationStrategyAdapter() {
@Override
public void handleCollectionReturn(CollectionReturn rootCollectionReturn) {
endLoadingArray( rootCollectionReturn.getCollectionPersister() );
}
@Override
public void startingCollectionFetch(CollectionFetch collectionFetch) {
endLoadingArray( collectionFetch.getCollectionPersister() );
}
private void endLoadingArray(CollectionPersister persister) {
if ( ! persister.isArray() ) {
session.getPersistenceContext()
.getLoadContexts()
.getCollectionLoadContext( resultSet )
.endLoadingCollections( persister );
}
}
}
);
}
private void postLoad(PostLoadEvent postLoadEvent, List<AfterLoadAction> afterLoadActionList) {
// Until this entire method is refactored w/ polymorphism, postLoad was
// split off from initializeEntity. It *must* occur after
// endCollectionLoad to ensure the collection is in the
// persistence context.
if ( hydratedEntityRegistrationList == null ) {
return;
}
for ( HydratedEntityRegistration registration : hydratedEntityRegistrationList ) {
TwoPhaseLoad.postLoad( registration.instance, session, postLoadEvent );
if ( afterLoadActionList != null ) {
for ( AfterLoadAction afterLoadAction : afterLoadActionList ) {
afterLoadAction.afterLoad( session, registration.instance, (Loadable) registration.persister );
}
}
}
}
private void createSubselects() {
if ( subselectLoadableEntityKeyMap.size() <= 1 ) {
// if we only returned one entity, query by key is more efficient; so do nothing here
return;
}
final Map<String, int[]> namedParameterLocMap =
ResultSetProcessorHelper.buildNamedParameterLocMap( queryParameters, namedParameterContext );
for ( Map.Entry<EntityPersister, Set<EntityKey>> entry : subselectLoadableEntityKeyMap.entrySet() ) {
if ( ! entry.getKey().hasSubselectLoadableCollections() ) {
continue;
}
SubselectFetch subselectFetch = new SubselectFetch(
//getSQLString(),
null, // aliases[i],
(Loadable) entry.getKey(),
queryParameters,
entry.getValue(),
namedParameterLocMap
);
for ( EntityKey key : entry.getValue() ) {
session.getPersistenceContext().getBatchFetchQueue().addSubselect( key, subselectFetch );
}
}
}
private static class HydratedEntityRegistration {
private final EntityPersister persister;
private final EntityKey key;
private final Object instance;
private HydratedEntityRegistration(EntityPersister persister, EntityKey key, Object instance) {
this.persister = persister;
this.key = key;
this.instance = instance;
}
}
}

View File

@ -0,0 +1,77 @@
/*
* 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.loader.internal;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.loader.EntityAliases;
import org.hibernate.loader.plan.spi.EntityReference;
import org.hibernate.loader.plan.spi.Fetch;
import org.hibernate.loader.spi.NamedParameterContext;
import org.hibernate.loader.spi.ResultSetProcessingContext;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.CompositeType;
import org.hibernate.type.Type;
/**
* @author Steve Ebersole
*/
public class ResultSetProcessorHelper {
public static EntityKey getOptionalObjectKey(QueryParameters queryParameters, SessionImplementor session) {
final Object optionalObject = queryParameters.getOptionalObject();
final Serializable optionalId = queryParameters.getOptionalId();
final String optionalEntityName = queryParameters.getOptionalEntityName();
if ( optionalObject != null && optionalEntityName != null ) {
return session.generateEntityKey( optionalId, session.getEntityPersister( optionalEntityName, optionalObject ) );
}
else {
return null;
}
}
public static Map<String, int[]> buildNamedParameterLocMap(
QueryParameters queryParameters,
NamedParameterContext namedParameterContext) {
if ( queryParameters.getNamedParameters() == null || queryParameters.getNamedParameters().isEmpty() ) {
return null;
}
final Map<String, int[]> namedParameterLocMap = new HashMap<String, int[]>();
for ( String name : queryParameters.getNamedParameters().keySet() ) {
namedParameterLocMap.put(
name,
namedParameterContext.getNamedParameterLocations( name )
);
}
return namedParameterLocMap;
}
}

View File

@ -0,0 +1,207 @@
/*
* 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.loader.internal;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.jboss.logging.Logger;
import org.hibernate.dialect.pagination.LimitHelper;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.loader.plan.spi.CollectionFetch;
import org.hibernate.loader.plan.spi.CollectionReturn;
import org.hibernate.loader.plan.spi.EntityFetch;
import org.hibernate.loader.plan.spi.LoadPlan;
import org.hibernate.loader.plan.spi.LoadPlanVisitationStrategyAdapter;
import org.hibernate.loader.plan.spi.LoadPlanVisitor;
import org.hibernate.loader.plan.spi.Return;
import org.hibernate.loader.spi.AfterLoadAction;
import org.hibernate.loader.spi.NamedParameterContext;
import org.hibernate.loader.spi.OnDemandResultSetProcessor;
import org.hibernate.loader.spi.ResultSetProcessor;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.transform.ResultTransformer;
/**
* @author Steve Ebersole
*/
public class ResultSetProcessorImpl implements ResultSetProcessor {
private static final Logger LOG = Logger.getLogger( ResultSetProcessorImpl.class );
private final LoadPlan loadPlan;
private final boolean hadSubselectFetches;
public ResultSetProcessorImpl(LoadPlan loadPlan) {
this.loadPlan = loadPlan;
LocalVisitationStrategy strategy = new LocalVisitationStrategy();
LoadPlanVisitor.visit( loadPlan, strategy );
this.hadSubselectFetches = strategy.hadSubselectFetches;
}
@Override
public OnDemandResultSetProcessor toOnDemandForm() {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public List extractResults(
ResultSet resultSet,
final SessionImplementor session,
QueryParameters queryParameters,
NamedParameterContext namedParameterContext,
boolean returnProxies,
boolean readOnly,
ResultTransformer forcedResultTransformer,
List<AfterLoadAction> afterLoadActionList) throws SQLException {
handlePotentiallyEmptyCollectionRootReturns( queryParameters.getCollectionKeys(), resultSet, session );
final int maxRows;
final RowSelection selection = queryParameters.getRowSelection();
if ( LimitHelper.hasMaxRows( selection ) ) {
maxRows = selection.getMaxRows();
LOG.tracef( "Limiting ResultSet processing to just %s rows", maxRows );
}
else {
maxRows = Integer.MAX_VALUE;
}
final ResultSetProcessingContextImpl context = new ResultSetProcessingContextImpl(
resultSet,
session,
loadPlan,
readOnly,
true, // use optional entity key? for now, always say yes
queryParameters,
namedParameterContext,
hadSubselectFetches
);
final List loadResults = new ArrayList();
final int rootReturnCount = loadPlan.getReturns().size();
LOG.trace( "Processing result set" );
int count;
for ( count = 0; count < maxRows && resultSet.next(); count++ ) {
LOG.debugf( "Starting ResultSet row #%s", count );
Object logicalRow;
if ( rootReturnCount == 1 ) {
loadPlan.getReturns().get( 0 ).hydrate( resultSet, context );
loadPlan.getReturns().get( 0 ).resolve( resultSet, context );
logicalRow = loadPlan.getReturns().get( 0 ).read( resultSet, context );
}
else {
for ( Return rootReturn : loadPlan.getReturns() ) {
rootReturn.hydrate( resultSet, context );
}
for ( Return rootReturn : loadPlan.getReturns() ) {
rootReturn.resolve( resultSet, context );
}
logicalRow = new Object[ rootReturnCount ];
int pos = 0;
for ( Return rootReturn : loadPlan.getReturns() ) {
( (Object[]) logicalRow )[pos] = rootReturn.read( resultSet, context );
pos++;
}
}
// todo : apply transformers here?
loadResults.add( logicalRow );
context.finishUpRow();
}
LOG.tracev( "Done processing result set ({0} rows)", count );
context.finishUp( afterLoadActionList );
session.getPersistenceContext().initializeNonLazyCollections();
return loadResults;
}
private void handlePotentiallyEmptyCollectionRootReturns(
Serializable[] collectionKeys,
ResultSet resultSet,
SessionImplementor session) {
if ( collectionKeys == null ) {
// this is not a collection initializer (and empty collections will be detected by looking for
// the owner's identifier in the result set)
return;
}
// this is a collection initializer, so we must create a collection
// for each of the passed-in keys, to account for the possibility
// that the collection is empty and has no rows in the result set
//
// todo : move this inside CollectionReturn ?
CollectionPersister persister = ( (CollectionReturn) loadPlan.getReturns().get( 0 ) ).getCollectionPersister();
for ( Serializable key : collectionKeys ) {
if ( LOG.isDebugEnabled() ) {
LOG.debugf(
"Preparing collection intializer : %s",
MessageHelper.collectionInfoString( persister, key, session.getFactory() )
);
session.getPersistenceContext()
.getLoadContexts()
.getCollectionLoadContext( resultSet )
.getLoadingCollection( persister, key );
}
}
}
private class LocalVisitationStrategy extends LoadPlanVisitationStrategyAdapter {
private boolean hadSubselectFetches = false;
@Override
public void startingEntityFetch(EntityFetch entityFetch) {
// only collections are currently supported for subselect fetching.
// hadSubselectFetches = hadSubselectFetches
// | entityFetch.getFetchStrategy().getStyle() == FetchStyle.SUBSELECT;
}
@Override
public void startingCollectionFetch(CollectionFetch collectionFetch) {
hadSubselectFetches = hadSubselectFetches
| collectionFetch.getFetchStrategy().getStyle() == FetchStyle.SUBSELECT;
}
}
}

View File

@ -0,0 +1,92 @@
/*
* 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.loader.plan.internal;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.loader.EntityAliases;
import org.hibernate.loader.plan.spi.AbstractFetchOwner;
import org.hibernate.loader.plan.spi.CollectionFetch;
import org.hibernate.loader.plan.spi.CompositeFetch;
import org.hibernate.loader.plan.spi.EntityFetch;
import org.hibernate.loader.plan.spi.FetchOwner;
import org.hibernate.loader.plan.spi.LoadPlanBuildingContext;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
/**
* @author Steve Ebersole
*/
public class LoadPlanBuildingHelper {
public static CollectionFetch buildStandardCollectionFetch(
FetchOwner fetchOwner,
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
final CollectionAliases collectionAliases = loadPlanBuildingContext.resolveCollectionColumnAliases( attributeDefinition );
final EntityAliases elementEntityAliases = loadPlanBuildingContext.resolveEntityColumnAliases( attributeDefinition );
return new CollectionFetch(
loadPlanBuildingContext.getSessionFactory(),
loadPlanBuildingContext.resolveFetchSourceAlias( attributeDefinition ),
LockMode.NONE, // todo : for now
fetchOwner,
fetchStrategy,
attributeDefinition.getName(),
collectionAliases,
elementEntityAliases
);
}
public static EntityFetch buildStandardEntityFetch(
FetchOwner fetchOwner,
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
return new EntityFetch(
loadPlanBuildingContext.getSessionFactory(),
loadPlanBuildingContext.resolveFetchSourceAlias( attributeDefinition ),
LockMode.NONE, // todo : for now
fetchOwner,
attributeDefinition.getName(),
fetchStrategy,
null, // sql table alias
loadPlanBuildingContext.resolveEntityColumnAliases( attributeDefinition )
);
}
public static CompositeFetch buildStandardCompositeFetch(
FetchOwner fetchOwner,
CompositionDefinition attributeDefinition,
LoadPlanBuildingContext loadPlanBuildingContext) {
return new CompositeFetch(
loadPlanBuildingContext.getSessionFactory(),
loadPlanBuildingContext.resolveFetchSourceAlias( attributeDefinition ),
(AbstractFetchOwner) fetchOwner,
attributeDefinition.getName()
);
}
}

View File

@ -32,26 +32,18 @@ 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.entity.EntityPersister;
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;
@ -74,7 +66,6 @@ public class SingleRootReturnLoadPlanBuilderStrategy
private final LoadQueryInfluencers loadQueryInfluencers;
private final String rootAlias;
private int currentSuffixBase;
private Return rootReturn;
@ -85,10 +76,9 @@ public class SingleRootReturnLoadPlanBuilderStrategy
LoadQueryInfluencers loadQueryInfluencers,
String rootAlias,
int suffixSeed) {
super( sessionFactory );
super( sessionFactory, suffixSeed );
this.loadQueryInfluencers = loadQueryInfluencers;
this.rootAlias = rootAlias;
this.currentSuffixBase = suffixSeed;
}
@Override
@ -153,10 +143,7 @@ public class SingleRootReturnLoadPlanBuilderStrategy
LockMode.NONE, // todo : for now
entityName,
StringHelper.generateAlias( StringHelper.unqualifyEntityName( entityName ), currentDepth() ),
new DefaultEntityAliases(
(Loadable) entityDefinition.getEntityPersister(),
Integer.toString( currentSuffixBase++ ) + '_'
)
generateEntityColumnAliases( entityDefinition.getEntityPersister() )
);
}
@ -165,17 +152,16 @@ public class SingleRootReturnLoadPlanBuilderStrategy
final CollectionPersister persister = collectionDefinition.getCollectionPersister();
final String collectionRole = persister.getRole();
final CollectionAliases collectionAliases = new GeneratedCollectionAliases(
collectionDefinition.getCollectionPersister(),
Integer.toString( currentSuffixBase++ ) + '_'
final CollectionAliases collectionAliases = generateCollectionColumnAliases(
collectionDefinition.getCollectionPersister()
);
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++ ) + '_'
elementAliases = generateEntityColumnAliases(
(EntityPersister) entityElementType.getAssociatedJoinable( sessionFactory() )
);
}
else {
@ -193,76 +179,16 @@ public class SingleRootReturnLoadPlanBuilderStrategy
);
}
@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
);
// LoadPlanBuildingContext impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public String resolveRootSourceAlias(EntityDefinition definition) {
return rootAlias;
}
@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++;
public String resolveRootSourceAlias(CollectionDefinition definition) {
return rootAlias;
}
}

View File

@ -0,0 +1,143 @@
/*
* 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.loader.plan.spi;
import org.hibernate.LockMode;
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.type.Type;
/**
* @author Steve Ebersole
*/
public abstract class AbstractCollectionReference extends AbstractPlanNode implements CollectionReference {
private final String alias;
private final LockMode lockMode;
private final CollectionPersister collectionPersister;
private final PropertyPath propertyPath;
private final CollectionAliases collectionAliases;
private final EntityAliases elementEntityAliases;
private final FetchOwner indexGraph;
private final FetchOwner elementGraph;
protected AbstractCollectionReference(
SessionFactoryImplementor sessionFactory,
String alias,
LockMode lockMode,
CollectionPersister collectionPersister,
PropertyPath propertyPath,
CollectionAliases collectionAliases,
EntityAliases elementEntityAliases) {
super( sessionFactory );
this.alias = alias;
this.lockMode = lockMode;
this.collectionPersister = collectionPersister;
this.propertyPath = propertyPath;
this.collectionAliases = collectionAliases;
this.elementEntityAliases = elementEntityAliases;
this.indexGraph = buildIndexGraph( getCollectionPersister() );
this.elementGraph = buildElementGraph( getCollectionPersister() );
}
private FetchOwner buildIndexGraph(CollectionPersister persister) {
if ( persister.hasIndex() ) {
final Type type = persister.getIndexType();
if ( type.isAssociationType() ) {
if ( type.isEntityType() ) {
return new EntityIndexGraph( sessionFactory(), this, propertyPath() );
}
}
else if ( type.isComponentType() ) {
return new CompositeIndexGraph( sessionFactory(), this, propertyPath() );
}
}
return null;
}
private FetchOwner buildElementGraph(CollectionPersister persister) {
final Type type = persister.getElementType();
if ( type.isAssociationType() ) {
if ( type.isEntityType() ) {
return new EntityElementGraph( sessionFactory(), this, propertyPath() );
}
}
else if ( type.isComponentType() ) {
return new CompositeElementGraph( sessionFactory(), this, propertyPath() );
}
return null;
}
public PropertyPath propertyPath() {
return propertyPath;
}
@Override
public String getAlias() {
return alias;
}
@Override
public LockMode getLockMode() {
return lockMode;
}
@Override
public CollectionAliases getCollectionAliases() {
return collectionAliases;
}
@Override
public EntityAliases getElementEntityAliases() {
return elementEntityAliases;
}
@Override
public CollectionPersister getCollectionPersister() {
return collectionPersister;
}
@Override
public FetchOwner getIndexGraph() {
return indexGraph;
}
@Override
public FetchOwner getElementGraph() {
return elementGraph;
}
@Override
public boolean hasEntityElements() {
return getCollectionPersister().isOneToMany() || getCollectionPersister().isManyToMany();
}
}

View File

@ -44,7 +44,7 @@ public abstract class AbstractFetch extends AbstractFetchOwner implements Fetch
SessionFactoryImplementor factory,
String alias,
LockMode lockMode,
AbstractFetchOwner owner,
FetchOwner owner,
String ownerProperty,
FetchStrategy fetchStrategy) {
super( factory, alias, lockMode );
@ -85,4 +85,9 @@ public abstract class AbstractFetch extends AbstractFetchOwner implements Fetch
public PropertyPath getPropertyPath() {
return propertyPath;
}
@Override
public String toString() {
return "Fetch(" + propertyPath.getFullPath() + ")";
}
}

View File

@ -56,7 +56,8 @@ public abstract class AbstractFetchOwner extends AbstractPlanNode implements Fet
return lockMode;
}
void addFetch(Fetch fetch) {
@Override
public void addFetch(Fetch fetch) {
if ( fetch.getOwner() != this ) {
throw new IllegalArgumentException( "Fetch and owner did not match" );
}

View File

@ -23,29 +23,62 @@
*/
package org.hibernate.loader.plan.spi;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jboss.logging.Logger;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.EntityKey;
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.internal.LoadPlanBuildingHelper;
import org.hibernate.loader.spi.ResultSetProcessingContext;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.spi.HydratedCompoundValueHandler;
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.CollectionElementDefinition;
import org.hibernate.persister.walking.spi.CollectionIndexDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.persister.walking.spi.EntityDefinition;
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
import org.hibernate.persister.walking.spi.WalkingException;
import org.hibernate.type.Type;
import static org.hibernate.loader.spi.ResultSetProcessingContext.IdentifierResolutionContext;
/**
* @author Steve Ebersole
*/
public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilderStrategy {
public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilderStrategy, LoadPlanBuildingContext {
private static final Logger log = Logger.getLogger( AbstractLoadPlanBuilderStrategy.class );
private final SessionFactoryImplementor sessionFactory;
private ArrayDeque<FetchOwner> fetchOwnerStack = new ArrayDeque<FetchOwner>();
private ArrayDeque<CollectionReference> collectionReferenceStack = new ArrayDeque<CollectionReference>();
protected AbstractLoadPlanBuilderStrategy(SessionFactoryImplementor sessionFactory) {
protected AbstractLoadPlanBuilderStrategy(SessionFactoryImplementor sessionFactory, int suffixSeed) {
this.sessionFactory = sessionFactory;
this.currentSuffixBase = suffixSeed;
}
public SessionFactoryImplementor sessionFactory() {
@ -53,21 +86,39 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
}
protected FetchOwner currentFetchOwner() {
return fetchOwnerStack.peekLast();
return fetchOwnerStack.peekFirst();
}
@Override
public void start() {
// nothing to do
if ( ! fetchOwnerStack.isEmpty() ) {
throw new WalkingException(
"Fetch owner stack was not empty on start; " +
"be sure to not use LoadPlanBuilderStrategy instances concurrently"
);
}
if ( ! collectionReferenceStack.isEmpty() ) {
throw new WalkingException(
"Collection reference stack was not empty on start; " +
"be sure to not use LoadPlanBuilderStrategy instances concurrently"
);
}
}
@Override
public void finish() {
// nothing to do
fetchOwnerStack.clear();
collectionReferenceStack.clear();
}
@Override
public void startingEntity(EntityDefinition entityDefinition) {
log.tracef(
"%s Starting entity : %s",
StringHelper.repeat( ">>", fetchOwnerStack.size() ),
entityDefinition.getEntityPersister().getEntityName()
);
if ( fetchOwnerStack.isEmpty() ) {
// this is a root...
if ( ! supportsRootEntityReturns() ) {
@ -75,7 +126,7 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
}
final EntityReturn entityReturn = buildRootEntityReturn( entityDefinition );
addRootReturn( entityReturn );
fetchOwnerStack.push( entityReturn );
pushToStack( entityReturn );
}
// otherwise this call should represent a fetch which should have been handled in #startingAttribute
}
@ -88,11 +139,112 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
@Override
public void finishingEntity(EntityDefinition entityDefinition) {
// nothing to do
// pop the current fetch owner, and make sure what we just popped represents this entity
final FetchOwner poppedFetchOwner = popFromStack();
if ( ! EntityReference.class.isInstance( poppedFetchOwner ) ) {
throw new WalkingException( "Mismatched FetchOwner from stack on pop" );
}
final EntityReference entityReference = (EntityReference) poppedFetchOwner;
// NOTE : this is not the most exhaustive of checks because of hierarchical associations (employee/manager)
if ( ! entityReference.getEntityPersister().equals( entityDefinition.getEntityPersister() ) ) {
throw new WalkingException( "Mismatched FetchOwner from stack on pop" );
}
log.tracef(
"%s Finished entity : %s",
StringHelper.repeat( "<<", fetchOwnerStack.size() ),
entityDefinition.getEntityPersister().getEntityName()
);
}
@Override
public void startingEntityIdentifier(EntityIdentifierDefinition entityIdentifierDefinition) {
log.tracef(
"%s Starting entity identifier : %s",
StringHelper.repeat( ">>", fetchOwnerStack.size() ),
entityIdentifierDefinition.getEntityDefinition().getEntityPersister().getEntityName()
);
final EntityReference entityReference = (EntityReference) currentFetchOwner();
// perform some stack validation
if ( ! entityReference.getEntityPersister().equals( entityIdentifierDefinition.getEntityDefinition().getEntityPersister() ) ) {
throw new WalkingException(
String.format(
"Encountered unexpected fetch owner [%s] in stack while processing entity identifier for [%s]",
entityReference.getEntityPersister().getEntityName(),
entityIdentifierDefinition.getEntityDefinition().getEntityPersister().getEntityName()
)
);
}
final FetchOwner identifierAttributeCollector;
if ( entityIdentifierDefinition.isEncapsulated() ) {
identifierAttributeCollector = new EncapsulatedIdentifierAttributeCollector( entityReference );
}
else {
identifierAttributeCollector = new NonEncapsulatedIdentifierAttributeCollector( entityReference );
}
pushToStack( identifierAttributeCollector );
}
@Override
public void finishingEntityIdentifier(EntityIdentifierDefinition entityIdentifierDefinition) {
// perform some stack validation on exit, first on the current stack element we want to pop
{
final FetchOwner poppedFetchOwner = popFromStack();
if ( ! AbstractIdentifierAttributeCollector.class.isInstance( poppedFetchOwner ) ) {
throw new WalkingException( "Unexpected state in FetchOwner stack" );
}
final EntityReference entityReference = (EntityReference) poppedFetchOwner;
if ( ! entityReference.getEntityPersister().equals( entityIdentifierDefinition.getEntityDefinition().getEntityPersister() ) ) {
throw new WalkingException(
String.format(
"Encountered unexpected fetch owner [%s] in stack while processing entity identifier for [%s]",
entityReference.getEntityPersister().getEntityName(),
entityIdentifierDefinition.getEntityDefinition().getEntityPersister().getEntityName()
)
);
}
}
// and then on the element before it
{
final FetchOwner currentFetchOwner = currentFetchOwner();
if ( ! EntityReference.class.isInstance( currentFetchOwner ) ) {
throw new WalkingException( "Unexpected state in FetchOwner stack" );
}
final EntityReference entityReference = (EntityReference) currentFetchOwner;
if ( ! entityReference.getEntityPersister().equals( entityIdentifierDefinition.getEntityDefinition().getEntityPersister() ) ) {
throw new WalkingException(
String.format(
"Encountered unexpected fetch owner [%s] in stack while processing entity identifier for [%s]",
entityReference.getEntityPersister().getEntityName(),
entityIdentifierDefinition.getEntityDefinition().getEntityPersister().getEntityName()
)
);
}
}
log.tracef(
"%s Finished entity identifier : %s",
StringHelper.repeat( "<<", fetchOwnerStack.size() ),
entityIdentifierDefinition.getEntityDefinition().getEntityPersister().getEntityName()
);
}
@Override
public void startingCollection(CollectionDefinition collectionDefinition) {
log.tracef(
"%s Starting collection : %s",
StringHelper.repeat( ">>", fetchOwnerStack.size() ),
collectionDefinition.getCollectionPersister().getRole()
);
if ( fetchOwnerStack.isEmpty() ) {
// this is a root...
if ( ! supportsRootCollectionReturns() ) {
@ -100,7 +252,7 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
}
final CollectionReturn collectionReturn = buildRootCollectionReturn( collectionDefinition );
addRootReturn( collectionReturn );
fetchOwnerStack.push( collectionReturn );
pushToCollectionStack( collectionReturn );
}
}
@ -109,24 +261,96 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
}
@Override
public void finishingCollection(CollectionDefinition collectionDefinition) {
// nothing to do
public void startingCollectionIndex(CollectionIndexDefinition collectionIndexDefinition) {
final Type indexType = collectionIndexDefinition.getType();
if ( indexType.isAssociationType() || indexType.isComponentType() ) {
final CollectionReference collectionReference = collectionReferenceStack.peekFirst();
final FetchOwner indexGraph = collectionReference.getIndexGraph();
if ( indexGraph == null ) {
throw new WalkingException( "Collection reference did not return index handler" );
}
pushToStack( indexGraph );
}
}
@Override
public void startingComposite(CompositeDefinition compositeDefinition) {
public void finishingCollectionIndex(CollectionIndexDefinition collectionIndexDefinition) {
// nothing to do here
// - the element graph pushed while starting would be popped in finishing/Entity/finishingComposite
}
@Override
public void startingCollectionElements(CollectionElementDefinition elementDefinition) {
if ( elementDefinition.getType().isAssociationType() || elementDefinition.getType().isComponentType() ) {
final CollectionReference collectionReference = collectionReferenceStack.peekFirst();
final FetchOwner elementGraph = collectionReference.getElementGraph();
if ( elementGraph == null ) {
throw new WalkingException( "Collection reference did not return element handler" );
}
pushToStack( elementGraph );
}
}
@Override
public void finishingCollectionElements(CollectionElementDefinition elementDefinition) {
// nothing to do here
// - the element graph pushed while starting would be popped in finishing/Entity/finishingComposite
}
@Override
public void finishingCollection(CollectionDefinition collectionDefinition) {
// pop the current fetch owner, and make sure what we just popped represents this collection
final CollectionReference collectionReference = popFromCollectionStack();
if ( ! collectionReference.getCollectionPersister().equals( collectionDefinition.getCollectionPersister() ) ) {
throw new WalkingException( "Mismatched FetchOwner from stack on pop" );
}
log.tracef(
"%s Finished collection : %s",
StringHelper.repeat( "<<", fetchOwnerStack.size() ),
collectionDefinition.getCollectionPersister().getRole()
);
}
@Override
public void startingComposite(CompositionDefinition compositionDefinition) {
log.tracef(
"%s Starting composition : %s",
StringHelper.repeat( ">>", fetchOwnerStack.size() ),
compositionDefinition.getName()
);
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
public void finishingComposite(CompositionDefinition compositionDefinition) {
// pop the current fetch owner, and make sure what we just popped represents this composition
final FetchOwner poppedFetchOwner = popFromStack();
if ( ! CompositeFetch.class.isInstance( poppedFetchOwner ) ) {
throw new WalkingException( "Mismatched FetchOwner from stack on pop" );
}
// NOTE : not much else we can really check here atm since on the walking spi side we do not have path
log.tracef(
"%s Finished composition : %s",
StringHelper.repeat( "<<", fetchOwnerStack.size() ),
compositionDefinition.getName()
);
}
@Override
public boolean startingAttribute(AttributeDefinition attributeDefinition) {
log.tracef(
"%s Starting attribute %s",
StringHelper.repeat( ">>", fetchOwnerStack.size() ),
attributeDefinition
);
final Type attributeType = attributeDefinition.getType();
final boolean isComponentType = attributeType.isComponentType();
@ -136,30 +360,26 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
return true;
}
else if ( isComponentType ) {
return handleCompositeAttribute( (CompositeDefinition) attributeDefinition );
return handleCompositeAttribute( (CompositionDefinition) 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();
}
log.tracef(
"%s Finishing up attribute : %s",
StringHelper.repeat( "<<", fetchOwnerStack.size() ),
attributeDefinition
);
}
protected boolean handleCompositeAttribute(CompositeDefinition attributeDefinition) {
final FetchOwner fetchOwner = fetchOwnerStack.peekLast();
final CompositeFetch fetch = buildCompositeFetch( fetchOwner, attributeDefinition );
fetchOwnerStack.addLast( fetch );
protected boolean handleCompositeAttribute(CompositionDefinition attributeDefinition) {
final FetchOwner fetchOwner = currentFetchOwner();
final CompositeFetch fetch = fetchOwner.buildCompositeFetch( attributeDefinition, this );
pushToStack( fetch );
return true;
}
@ -169,17 +389,20 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
return false;
}
final FetchOwner fetchOwner = fetchOwnerStack.peekLast();
final FetchOwner fetchOwner = currentFetchOwner();
fetchOwner.validateFetchPlan( fetchStrategy );
final Fetch associationFetch;
if ( attributeDefinition.isCollection() ) {
associationFetch = buildCollectionFetch( fetchOwner, attributeDefinition, fetchStrategy );
associationFetch = fetchOwner.buildCollectionFetch( attributeDefinition, fetchStrategy, this );
}
else {
associationFetch = buildEntityFetch( fetchOwner, attributeDefinition, fetchStrategy );
associationFetch = fetchOwner.buildEntityFetch( attributeDefinition, fetchStrategy, this );
}
if ( FetchOwner.class.isInstance( associationFetch ) ) {
pushToStack( (FetchOwner) associationFetch );
}
fetchOwnerStack.addLast( associationFetch );
return true;
}
@ -194,19 +417,309 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
return false;
}
private void pushToStack(FetchOwner fetchOwner) {
log.trace( "Pushing fetch owner to stack : " + fetchOwner );
fetchOwnerStack.addFirst( fetchOwner );
}
private FetchOwner popFromStack() {
final FetchOwner last = fetchOwnerStack.removeFirst();
log.trace( "Popped fetch owner from stack : " + last );
if ( FetchStackAware.class.isInstance( last ) ) {
( (FetchStackAware) last ).poppedFromStack();
}
return last;
}
private void pushToCollectionStack(CollectionReference collectionReference) {
log.trace( "Pushing collection reference to stack : " + collectionReference );
collectionReferenceStack.addFirst( collectionReference );
}
private CollectionReference popFromCollectionStack() {
final CollectionReference last = collectionReferenceStack.removeFirst();
log.trace( "Popped collection reference from stack : " + last );
if ( FetchStackAware.class.isInstance( last ) ) {
( (FetchStackAware) last ).poppedFromStack();
}
return last;
}
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);
// LoadPlanBuildingContext impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private int currentSuffixBase;
private int implicitAliasUniqueness = 0;
private String createImplicitAlias() {
return "ia" + implicitAliasUniqueness++;
}
@Override
public SessionFactoryImplementor getSessionFactory() {
return sessionFactory();
}
@Override
public EntityAliases resolveEntityColumnAliases(AssociationAttributeDefinition attributeDefinition) {
return generateEntityColumnAliases( attributeDefinition.toEntityDefinition().getEntityPersister() );
}
protected EntityAliases generateEntityColumnAliases(EntityPersister persister) {
return new DefaultEntityAliases( (Loadable) persister, Integer.toString( currentSuffixBase++ ) + '_' );
}
@Override
public CollectionAliases resolveCollectionColumnAliases(AssociationAttributeDefinition attributeDefinition) {
return generateCollectionColumnAliases( attributeDefinition.toCollectionDefinition().getCollectionPersister() );
}
protected CollectionAliases generateCollectionColumnAliases(CollectionPersister persister) {
return new GeneratedCollectionAliases( persister, Integer.toString( currentSuffixBase++ ) + '_' );
}
@Override
public String resolveRootSourceAlias(EntityDefinition definition) {
return createImplicitAlias();
}
@Override
public String resolveRootSourceAlias(CollectionDefinition definition) {
return createImplicitAlias();
}
@Override
public String resolveFetchSourceAlias(AssociationAttributeDefinition attributeDefinition) {
return createImplicitAlias();
}
@Override
public String resolveFetchSourceAlias(CompositionDefinition compositionDefinition) {
return createImplicitAlias();
}
public static interface FetchStackAware {
public void poppedFromStack();
}
protected static abstract class AbstractIdentifierAttributeCollector
implements FetchOwner, EntityReference, FetchStackAware {
protected final EntityReference entityReference;
private final PropertyPath propertyPath;
protected final List<EntityFetch> identifierFetches = new ArrayList<EntityFetch>();
protected final Map<EntityFetch,HydratedCompoundValueHandler> fetchToHydratedStateExtractorMap
= new HashMap<EntityFetch, HydratedCompoundValueHandler>();
public AbstractIdentifierAttributeCollector(EntityReference entityReference) {
this.entityReference = entityReference;
this.propertyPath = ( (FetchOwner) entityReference ).getPropertyPath().append( "<id>" );
}
@Override
public String getAlias() {
return entityReference.getAlias();
}
@Override
public LockMode getLockMode() {
return entityReference.getLockMode();
}
@Override
public EntityPersister getEntityPersister() {
return entityReference.getEntityPersister();
}
@Override
public IdentifierDescription getIdentifierDescription() {
return entityReference.getIdentifierDescription();
}
@Override
public CollectionFetch buildCollectionFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
throw new WalkingException( "Entity identifier cannot contain persistent collections" );
}
@Override
public EntityFetch buildEntityFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
// we have a key-many-to-one
//
// IMPL NOTE: we pass ourselves as the FetchOwner which will route the fetch back throw our #addFetch
// impl. We collect them there and later build the IdentifierDescription
final EntityFetch fetch = LoadPlanBuildingHelper.buildStandardEntityFetch(
this,
attributeDefinition,
fetchStrategy,
loadPlanBuildingContext
);
fetchToHydratedStateExtractorMap.put( fetch, attributeDefinition.getHydratedCompoundValueExtractor() );
return fetch;
}
@Override
public CompositeFetch buildCompositeFetch(
CompositionDefinition attributeDefinition, LoadPlanBuildingContext loadPlanBuildingContext) {
// nested composition. Unusual, but not disallowed.
//
// IMPL NOTE: we pass ourselves as the FetchOwner which will route the fetch back throw our #addFetch
// impl. We collect them there and later build the IdentifierDescription
return LoadPlanBuildingHelper.buildStandardCompositeFetch(
this,
attributeDefinition,
loadPlanBuildingContext
);
}
@Override
public void poppedFromStack() {
final IdentifierDescription identifierDescription = buildIdentifierDescription();
entityReference.injectIdentifierDescription( identifierDescription );
}
protected abstract IdentifierDescription buildIdentifierDescription();
@Override
public void addFetch(Fetch fetch) {
identifierFetches.add( (EntityFetch) fetch );
}
@Override
public Fetch[] getFetches() {
return ( (FetchOwner) entityReference ).getFetches();
}
@Override
public void validateFetchPlan(FetchStrategy fetchStrategy) {
( (FetchOwner) entityReference ).validateFetchPlan( fetchStrategy );
}
@Override
public EntityPersister retrieveFetchSourcePersister() {
return ( (FetchOwner) entityReference ).retrieveFetchSourcePersister();
}
@Override
public PropertyPath getPropertyPath() {
return propertyPath;
}
@Override
public void injectIdentifierDescription(IdentifierDescription identifierDescription) {
throw new WalkingException(
"IdentifierDescription collector should not get injected with IdentifierDescription"
);
}
}
protected static class EncapsulatedIdentifierAttributeCollector extends AbstractIdentifierAttributeCollector {
public EncapsulatedIdentifierAttributeCollector(EntityReference entityReference) {
super( entityReference );
}
@Override
protected IdentifierDescription buildIdentifierDescription() {
return new IdentifierDescriptionImpl(
entityReference,
identifierFetches.toArray( new EntityFetch[ identifierFetches.size() ] ),
null
);
}
}
protected static class NonEncapsulatedIdentifierAttributeCollector extends AbstractIdentifierAttributeCollector {
public NonEncapsulatedIdentifierAttributeCollector(EntityReference entityReference) {
super( entityReference );
}
@Override
protected IdentifierDescription buildIdentifierDescription() {
return new IdentifierDescriptionImpl(
entityReference,
identifierFetches.toArray( new EntityFetch[ identifierFetches.size() ] ),
fetchToHydratedStateExtractorMap
);
}
}
private static class IdentifierDescriptionImpl implements IdentifierDescription {
private final EntityReference entityReference;
private final EntityFetch[] identifierFetches;
private final Map<EntityFetch,HydratedCompoundValueHandler> fetchToHydratedStateExtractorMap;
private IdentifierDescriptionImpl(
EntityReference entityReference, EntityFetch[] identifierFetches,
Map<EntityFetch, HydratedCompoundValueHandler> fetchToHydratedStateExtractorMap) {
this.entityReference = entityReference;
this.identifierFetches = identifierFetches;
this.fetchToHydratedStateExtractorMap = fetchToHydratedStateExtractorMap;
}
@Override
public Fetch[] getFetches() {
return identifierFetches;
}
@Override
public void hydrate(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
final IdentifierResolutionContext ownerIdentifierResolutionContext =
context.getIdentifierResolutionContext( entityReference );
final Serializable ownerIdentifierHydratedState = ownerIdentifierResolutionContext.getHydratedForm();
for ( EntityFetch fetch : identifierFetches ) {
final IdentifierResolutionContext identifierResolutionContext =
context.getIdentifierResolutionContext( fetch );
// if the identifier was already hydrated, nothing to do
if ( identifierResolutionContext.getHydratedForm() != null ) {
continue;
}
// try to extract the sub-hydrated value from the owners tuple array
if ( fetchToHydratedStateExtractorMap != null && ownerIdentifierHydratedState != null ) {
Serializable extracted = (Serializable) fetchToHydratedStateExtractorMap.get( fetch )
.extract( ownerIdentifierHydratedState );
identifierResolutionContext.registerHydratedForm( extracted );
continue;
}
// if we can't, then read from result set
fetch.hydrate( resultSet, context );
}
}
@Override
public EntityKey resolve(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
for ( EntityFetch fetch : identifierFetches ) {
final IdentifierResolutionContext identifierResolutionContext =
context.getIdentifierResolutionContext( fetch );
if ( identifierResolutionContext.getEntityKey() != null ) {
continue;
}
EntityKey fetchKey = fetch.resolveInIdentifier( resultSet, context );
identifierResolutionContext.registerEntityKey( fetchKey );
}
final IdentifierResolutionContext ownerIdentifierResolutionContext =
context.getIdentifierResolutionContext( entityReference );
Serializable hydratedState = ownerIdentifierResolutionContext.getHydratedForm();
Serializable resolvedId = (Serializable) entityReference.getEntityPersister()
.getIdentifierType()
.resolve( hydratedState, context.getSession(), null );
return context.getSession().generateEntityKey( resolvedId, entityReference.getEntityPersister() );
}
}
}

View File

@ -23,58 +23,75 @@
*/
package org.hibernate.loader.plan.spi;
import java.sql.ResultSet;
import java.sql.SQLException;
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;
import org.hibernate.loader.PropertyPath;
import org.hibernate.loader.spi.ResultSetProcessingContext;
/**
* @author Steve Ebersole
*/
public class CollectionFetch extends AbstractFetch implements CollectionReference {
private final CollectionAliases collectionAliases;
private final EntityAliases elementEntityAliases;
private final CollectionPersister persister;
public class CollectionFetch extends AbstractCollectionReference implements CollectionReference, Fetch {
private final FetchOwner fetchOwner;
private final FetchStrategy fetchStrategy;
public CollectionFetch(
SessionFactoryImplementor sessionFactory,
String alias,
LockMode lockMode,
AbstractFetchOwner owner,
FetchOwner fetchOwner,
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 );
super(
sessionFactory,
alias,
lockMode,
sessionFactory.getCollectionPersister(
fetchOwner.retrieveFetchSourcePersister().getEntityName() + '.' + ownerProperty
),
fetchOwner.getPropertyPath().append( ownerProperty ),
collectionAliases,
elementEntityAliases
);
this.fetchOwner = fetchOwner;
this.fetchStrategy = fetchStrategy;
}
@Override
public CollectionAliases getCollectionAliases() {
return collectionAliases;
public FetchOwner getOwner() {
return fetchOwner;
}
@Override
public EntityAliases getElementEntityAliases() {
return elementEntityAliases;
public String getOwnerPropertyName() {
return getPropertyPath().getProperty();
}
@Override
public CollectionPersister getCollectionPersister() {
return persister;
public FetchStrategy getFetchStrategy() {
return fetchStrategy;
}
@Override
public EntityPersister retrieveFetchSourcePersister() {
return ( (QueryableCollection) getCollectionPersister() ).getElementPersister();
public PropertyPath getPropertyPath() {
return propertyPath();
}
@Override
public void hydrate(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public Object resolve(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
}

View File

@ -55,6 +55,12 @@ public interface CollectionReference {
*/
public CollectionPersister getCollectionPersister();
public FetchOwner getIndexGraph();
public FetchOwner getElementGraph();
public boolean hasEntityElements();
/**
* Returns the description of the aliases in the JDBC ResultSet that identify values "belonging" to the
* this collection.

View File

@ -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.loader.plan.spi;
/**
* @author Steve Ebersole
*/
public interface CollectionReferenceImplementor {
}

View File

@ -23,28 +23,22 @@
*/
package org.hibernate.loader.plan.spi;
import java.sql.ResultSet;
import java.sql.SQLException;
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;
import org.hibernate.loader.spi.ResultSetProcessingContext;
/**
* @author Steve Ebersole
*/
public class CollectionReturn extends AbstractFetchOwner implements Return, FetchOwner, CollectionReference {
public class CollectionReturn extends AbstractCollectionReference implements Return, 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,
@ -54,14 +48,17 @@ public class CollectionReturn extends AbstractFetchOwner implements Return, Fetc
String ownerProperty,
CollectionAliases collectionAliases,
EntityAliases elementEntityAliases) {
super( sessionFactory, alias, lockMode );
super(
sessionFactory,
alias,
lockMode,
sessionFactory.getCollectionPersister( ownerEntityName + '.' + ownerProperty ),
new PropertyPath(), // its a root
collectionAliases,
elementEntityAliases
);
this.ownerEntityName = ownerEntityName;
this.ownerProperty = ownerProperty;
this.collectionAliases = collectionAliases;
this.elementEntityAliases = elementEntityAliases;
final String role = ownerEntityName + '.' + ownerProperty;
this.persister = sessionFactory.getCollectionPersister( role );
}
/**
@ -83,31 +80,22 @@ public class CollectionReturn extends AbstractFetchOwner implements Return, Fetc
}
@Override
public CollectionAliases getCollectionAliases() {
return collectionAliases;
public void hydrate(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
// todo : anything to do here?
}
@Override
public EntityAliases getElementEntityAliases() {
return elementEntityAliases;
public void resolve(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
// todo : anything to do here?
}
@Override
public CollectionPersister getCollectionPersister() {
return persister;
public Object read(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void validateFetchPlan(FetchStrategy fetchStrategy) {
}
@Override
public EntityPersister retrieveFetchSourcePersister() {
return ( (QueryableCollection) persister ).getElementPersister();
}
@Override
public PropertyPath getPropertyPath() {
return propertyPath;
public String toString() {
return "CollectionReturn(" + getCollectionPersister().getRole() + ")";
}
}

View File

@ -0,0 +1,90 @@
package org.hibernate.loader.plan.spi;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.PropertyPath;
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
/**
* @author Steve Ebersole
*/
public class CompositeElementGraph extends AbstractPlanNode implements FetchOwner {
private final CollectionReference collectionReference;
private final PropertyPath propertyPath;
private final CollectionPersister collectionPersister;
private List<Fetch> fetches;
public CompositeElementGraph(
SessionFactoryImplementor sessionFactory,
CollectionReference collectionReference,
PropertyPath collectionPath) {
super( sessionFactory );
this.collectionReference = collectionReference;
this.collectionPersister = collectionReference.getCollectionPersister();
this.propertyPath = collectionPath.append( "<elements>" );
}
@Override
public void addFetch(Fetch fetch) {
if ( fetches == null ) {
fetches = new ArrayList<Fetch>();
}
fetches.add( fetch );
}
@Override
public Fetch[] getFetches() {
return fetches == null ? NO_FETCHES : fetches.toArray( new Fetch[ fetches.size() ] );
}
@Override
public void validateFetchPlan(FetchStrategy fetchStrategy) {
}
@Override
public EntityPersister retrieveFetchSourcePersister() {
return collectionPersister.getOwnerEntityPersister();
}
@Override
public PropertyPath getPropertyPath() {
return propertyPath;
}
@Override
public CollectionFetch buildCollectionFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
throw new HibernateException( "Collection composite element cannot define collections" );
}
@Override
public EntityFetch buildEntityFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardEntityFetch(
this,
attributeDefinition,
fetchStrategy,
loadPlanBuildingContext
);
}
@Override
public CompositeFetch buildCompositeFetch(
CompositionDefinition attributeDefinition,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardCompositeFetch( this, attributeDefinition, loadPlanBuildingContext );
}
}

View File

@ -23,12 +23,18 @@
*/
package org.hibernate.loader.plan.spi;
import java.sql.ResultSet;
import java.sql.SQLException;
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.loader.spi.ResultSetProcessingContext;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
/**
* @author Steve Ebersole
@ -48,4 +54,36 @@ public class CompositeFetch extends AbstractFetch implements Fetch {
public EntityPersister retrieveFetchSourcePersister() {
return getOwner().retrieveFetchSourcePersister();
}
@Override
public CollectionFetch buildCollectionFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public EntityFetch buildEntityFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public CompositeFetch buildCompositeFetch(
CompositionDefinition attributeDefinition, LoadPlanBuildingContext loadPlanBuildingContext) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void hydrate(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public Object resolve(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
}

View File

@ -0,0 +1,90 @@
package org.hibernate.loader.plan.spi;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.PropertyPath;
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
/**
* @author Steve Ebersole
*/
public class CompositeIndexGraph extends AbstractPlanNode implements FetchOwner {
private final CollectionReference collectionReference;
private final PropertyPath propertyPath;
private final CollectionPersister collectionPersister;
private List<Fetch> fetches;
public CompositeIndexGraph(
SessionFactoryImplementor sessionFactory,
CollectionReference collectionReference,
PropertyPath propertyPath) {
super( sessionFactory );
this.collectionReference = collectionReference;
this.collectionPersister = collectionReference.getCollectionPersister();
this.propertyPath = propertyPath.append( "<index>" );
}
@Override
public void addFetch(Fetch fetch) {
if ( fetches == null ) {
fetches = new ArrayList<Fetch>();
}
fetches.add( fetch );
}
@Override
public Fetch[] getFetches() {
return fetches == null ? NO_FETCHES : fetches.toArray( new Fetch[ fetches.size() ] );
}
@Override
public void validateFetchPlan(FetchStrategy fetchStrategy) {
}
@Override
public EntityPersister retrieveFetchSourcePersister() {
return collectionPersister.getOwnerEntityPersister();
}
@Override
public PropertyPath getPropertyPath() {
return propertyPath;
}
@Override
public CollectionFetch buildCollectionFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
throw new HibernateException( "Composite index cannot define collections" );
}
@Override
public EntityFetch buildEntityFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardEntityFetch(
this,
attributeDefinition,
fetchStrategy,
loadPlanBuildingContext
);
}
@Override
public CompositeFetch buildCompositeFetch(
CompositionDefinition attributeDefinition,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardCompositeFetch( this, attributeDefinition, loadPlanBuildingContext );
}
}

View File

@ -0,0 +1,133 @@
package org.hibernate.loader.plan.spi;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.PropertyPath;
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.type.AssociationType;
/**
* @author Steve Ebersole
*/
public class EntityElementGraph extends AbstractPlanNode implements FetchOwner, EntityReference {
private final CollectionReference collectionReference;
private final CollectionPersister collectionPersister;
private final AssociationType elementType;
private final EntityPersister elementPersister;
private final PropertyPath propertyPath;
private List<Fetch> fetches;
private IdentifierDescription identifierDescription;
public EntityElementGraph(
SessionFactoryImplementor sessionFactory,
CollectionReference collectionReference,
PropertyPath collectionPath) {
super( sessionFactory );
this.collectionReference = collectionReference;
this.collectionPersister = collectionReference.getCollectionPersister();
this.elementType = (AssociationType) collectionPersister.getElementType();
this.elementPersister = (EntityPersister) this.elementType.getAssociatedJoinable( sessionFactory() );
this.propertyPath = collectionPath.append( "<elements>" );
}
@Override
public String getAlias() {
return null;
}
@Override
public LockMode getLockMode() {
return null;
}
@Override
public EntityPersister getEntityPersister() {
return elementPersister;
}
@Override
public IdentifierDescription getIdentifierDescription() {
return identifierDescription;
}
@Override
public void addFetch(Fetch fetch) {
if ( fetches == null ) {
fetches = new ArrayList<Fetch>();
}
fetches.add( fetch );
}
@Override
public Fetch[] getFetches() {
return fetches == null ? NO_FETCHES : fetches.toArray( new Fetch[ fetches.size() ] );
}
@Override
public void validateFetchPlan(FetchStrategy fetchStrategy) {
}
@Override
public EntityPersister retrieveFetchSourcePersister() {
return elementPersister;
}
@Override
public PropertyPath getPropertyPath() {
return propertyPath;
}
@Override
public CollectionFetch buildCollectionFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardCollectionFetch(
this,
attributeDefinition,
fetchStrategy,
loadPlanBuildingContext
);
}
@Override
public EntityFetch buildEntityFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardEntityFetch(
this,
attributeDefinition,
fetchStrategy,
loadPlanBuildingContext
);
}
@Override
public CompositeFetch buildCompositeFetch(
CompositionDefinition attributeDefinition,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardCompositeFetch( this, attributeDefinition, loadPlanBuildingContext );
}
@Override
public void injectIdentifierDescription(IdentifierDescription identifierDescription) {
this.identifierDescription = identifierDescription;
}
@Override
public String toString() {
return "EntityElementGraph(collection=" + collectionPersister.getRole() + ", type=" + elementPersister.getEntityName() + ")";
}
}

View File

@ -23,27 +23,40 @@
*/
package org.hibernate.loader.plan.spi;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.hibernate.LockMode;
import org.hibernate.WrongClassException;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.EntityAliases;
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
import org.hibernate.loader.spi.ResultSetProcessingContext;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.type.EntityType;
/**
* @author Steve Ebersole
*/
public class EntityFetch extends AbstractFetch implements EntityReference {
public class EntityFetch extends AbstractFetch implements EntityReference, FetchOwner {
private final String sqlTableAlias;
private final EntityAliases entityAliases;
private final EntityType associationType;
private final EntityPersister persister;
private IdentifierDescription identifierDescription;
public EntityFetch(
SessionFactoryImplementor sessionFactory,
String alias,
LockMode lockMode,
AbstractFetchOwner owner,
FetchOwner owner,
String ownerProperty,
FetchStrategy fetchStrategy,
String sqlTableAlias,
@ -52,8 +65,8 @@ public class EntityFetch extends AbstractFetch implements EntityReference {
this.sqlTableAlias = sqlTableAlias;
this.entityAliases = entityAliases;
final EntityType type = (EntityType) owner.retrieveFetchSourcePersister().getPropertyType( ownerProperty );
this.persister = sessionFactory.getEntityPersister( type.getAssociatedEntityName() );
this.associationType = (EntityType) owner.retrieveFetchSourcePersister().getPropertyType( ownerProperty );
this.persister = sessionFactory.getEntityPersister( associationType.getAssociatedEntityName() );
}
@Override
@ -62,17 +75,174 @@ public class EntityFetch extends AbstractFetch implements EntityReference {
}
@Override
public EntityAliases getEntityAliases() {
return entityAliases;
}
@Override
public String getSqlTableAlias() {
return sqlTableAlias;
public IdentifierDescription getIdentifierDescription() {
return identifierDescription;
}
@Override
public EntityPersister retrieveFetchSourcePersister() {
return persister;
}
@Override
public CollectionFetch buildCollectionFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardCollectionFetch(
this,
attributeDefinition,
fetchStrategy,
loadPlanBuildingContext
);
}
@Override
public EntityFetch buildEntityFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardEntityFetch(
this,
attributeDefinition,
fetchStrategy,
loadPlanBuildingContext
);
}
@Override
public CompositeFetch buildCompositeFetch(
CompositionDefinition attributeDefinition,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardCompositeFetch( this, attributeDefinition, loadPlanBuildingContext );
}
@Override
public void injectIdentifierDescription(IdentifierDescription identifierDescription) {
this.identifierDescription = identifierDescription;
}
@Override
public void hydrate(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
EntityKey entityKey = context.getDictatedRootEntityKey();
if ( entityKey != null ) {
context.getIdentifierResolutionContext( this ).registerEntityKey( entityKey );
return;
}
identifierDescription.hydrate( resultSet, context );
for ( Fetch fetch : getFetches() ) {
fetch.hydrate( resultSet, context );
}
}
@Override
public EntityKey resolve(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
final ResultSetProcessingContext.IdentifierResolutionContext identifierResolutionContext = context.getIdentifierResolutionContext( this );
EntityKey entityKey = identifierResolutionContext.getEntityKey();
if ( entityKey == null ) {
entityKey = identifierDescription.resolve( resultSet, context );
if ( entityKey == null ) {
// register the non-existence (though only for one-to-one associations)
if ( associationType.isOneToOne() ) {
// first, find our owner's entity-key...
final EntityKey ownersEntityKey = context.getIdentifierResolutionContext( (EntityReference) getOwner() ).getEntityKey();
if ( ownersEntityKey != null ) {
context.getSession().getPersistenceContext()
.addNullProperty( ownersEntityKey, associationType.getPropertyName() );
}
}
}
identifierResolutionContext.registerEntityKey( entityKey );
for ( Fetch fetch : getFetches() ) {
fetch.resolve( resultSet, context );
}
}
return entityKey;
}
public EntityKey resolveInIdentifier(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
// todo : may not need to do this if entitykey is already part of the resolution context
final EntityKey entityKey = resolve( resultSet, context );
final Object existing = context.getSession().getEntityUsingInterceptor( entityKey );
if ( existing != null ) {
if ( !persister.isInstance( existing ) ) {
throw new WrongClassException(
"loaded object was of wrong class " + existing.getClass(),
entityKey.getIdentifier(),
persister.getEntityName()
);
}
if ( getLockMode() != null && getLockMode() != LockMode.NONE ) {
final boolean isVersionCheckNeeded = persister.isVersioned()
&& context.getSession().getPersistenceContext().getEntry( existing ).getLockMode().lessThan( getLockMode() );
// we don't need to worry about existing version being uninitialized because this block isn't called
// by a re-entrant load (re-entrant loads _always_ have lock mode NONE)
if ( isVersionCheckNeeded ) {
//we only check the version when _upgrading_ lock modes
context.checkVersion(
resultSet,
persister,
entityAliases,
entityKey,
existing
);
//we need to upgrade the lock mode to the mode requested
context.getSession().getPersistenceContext().getEntry( existing ).setLockMode( getLockMode() );
}
}
}
else {
final String concreteEntityTypeName = context.getConcreteEntityTypeName(
resultSet,
persister,
entityAliases,
entityKey
);
final Object entityInstance = context.getSession().instantiate(
concreteEntityTypeName,
entityKey.getIdentifier()
);
//need to hydrate it.
// grab its state from the ResultSet and keep it in the Session
// (but don't yet initialize the object itself)
// note that we acquire LockMode.READ even if it was not requested
LockMode acquiredLockMode = getLockMode() == LockMode.NONE ? LockMode.READ : getLockMode();
context.loadFromResultSet(
resultSet,
entityInstance,
concreteEntityTypeName,
entityKey,
entityAliases,
acquiredLockMode,
persister,
getFetchStrategy().getTiming() == FetchTiming.IMMEDIATE,
associationType
);
// materialize associations (and initialize the object) later
context.registerHydratedEntity( persister, entityKey, entityInstance );
}
return entityKey;
}
@Override
public String toString() {
return "EntityFetch(" + getPropertyPath().getFullPath() + " -> " + persister.getEntityName() + ")";
}
}

View File

@ -0,0 +1,150 @@
/*
* 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.loader.plan.spi;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.PropertyPath;
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.type.AssociationType;
/**
* @author Steve Ebersole
*/
public class EntityIndexGraph extends AbstractPlanNode implements FetchOwner, EntityReference {
private final CollectionReference collectionReference;
private final CollectionPersister collectionPersister;
private final AssociationType indexType;
private final EntityPersister indexPersister;
private final PropertyPath propertyPath;
private List<Fetch> fetches;
private IdentifierDescription identifierDescription;
public EntityIndexGraph(
SessionFactoryImplementor sessionFactory,
CollectionReference collectionReference,
PropertyPath collectionPath) {
super( sessionFactory );
this.collectionReference = collectionReference;
this.collectionPersister = collectionReference.getCollectionPersister();
this.indexType = (AssociationType) collectionPersister.getIndexType();
this.indexPersister = (EntityPersister) this.indexType.getAssociatedJoinable( sessionFactory() );
this.propertyPath = collectionPath.append( "<index>" ); // todo : do we want the <index> part?
}
@Override
public String getAlias() {
return null;
}
@Override
public LockMode getLockMode() {
return null;
}
@Override
public EntityPersister getEntityPersister() {
return indexPersister;
}
@Override
public IdentifierDescription getIdentifierDescription() {
return identifierDescription;
}
@Override
public void addFetch(Fetch fetch) {
if ( fetches == null ) {
fetches = new ArrayList<Fetch>();
}
fetches.add( fetch );
}
@Override
public Fetch[] getFetches() {
return fetches == null ? NO_FETCHES : fetches.toArray( new Fetch[ fetches.size() ] );
}
@Override
public void validateFetchPlan(FetchStrategy fetchStrategy) {
}
@Override
public EntityPersister retrieveFetchSourcePersister() {
return indexPersister;
}
@Override
public PropertyPath getPropertyPath() {
return propertyPath;
}
@Override
public CollectionFetch buildCollectionFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardCollectionFetch(
this,
attributeDefinition,
fetchStrategy,
loadPlanBuildingContext
);
}
@Override
public EntityFetch buildEntityFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardEntityFetch(
this,
attributeDefinition,
fetchStrategy,
loadPlanBuildingContext
);
}
@Override
public CompositeFetch buildCompositeFetch(
CompositionDefinition attributeDefinition,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardCompositeFetch( this, attributeDefinition, loadPlanBuildingContext );
}
@Override
public void injectIdentifierDescription(IdentifierDescription identifierDescription) {
this.identifierDescription = identifierDescription;
}
}

View File

@ -24,7 +24,6 @@
package org.hibernate.loader.plan.spi;
import org.hibernate.LockMode;
import org.hibernate.loader.EntityAliases;
import org.hibernate.persister.entity.EntityPersister;
/**
@ -32,7 +31,7 @@ import org.hibernate.persister.entity.EntityPersister;
*
* @author Steve Ebersole
*/
public interface EntityReference {
public interface EntityReference extends IdentifierDescriptionInjectable {
/**
* Retrieve the alias associated with the persister (entity/collection).
*
@ -54,20 +53,5 @@ public interface EntityReference {
*/
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();
public IdentifierDescription getIdentifierDescription();
}

View File

@ -23,12 +23,25 @@
*/
package org.hibernate.loader.plan.spi;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.EntityAliases;
import org.hibernate.loader.PropertyPath;
import org.hibernate.loader.internal.ResultSetProcessorHelper;
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
import org.hibernate.loader.spi.ResultSetProcessingContext;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
import static org.hibernate.loader.spi.ResultSetProcessingContext.IdentifierResolutionContext;
/**
* @author Steve Ebersole
@ -41,6 +54,8 @@ public class EntityReturn extends AbstractFetchOwner implements Return, FetchOwn
private final PropertyPath propertyPath = new PropertyPath(); // its a root
private IdentifierDescription identifierDescription;
public EntityReturn(
SessionFactoryImplementor sessionFactory,
String alias,
@ -71,13 +86,8 @@ public class EntityReturn extends AbstractFetchOwner implements Return, FetchOwn
}
@Override
public EntityAliases getEntityAliases() {
return entityAliases;
}
@Override
public String getSqlTableAlias() {
return sqlTableAlias;
public IdentifierDescription getIdentifierDescription() {
return identifierDescription;
}
@Override
@ -93,4 +103,83 @@ public class EntityReturn extends AbstractFetchOwner implements Return, FetchOwn
public PropertyPath getPropertyPath() {
return propertyPath;
}
@Override
public CollectionFetch buildCollectionFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardCollectionFetch(
this,
attributeDefinition,
fetchStrategy,
loadPlanBuildingContext
);
}
@Override
public EntityFetch buildEntityFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardEntityFetch(
this,
attributeDefinition,
fetchStrategy,
loadPlanBuildingContext
);
}
@Override
public CompositeFetch buildCompositeFetch(
CompositionDefinition attributeDefinition,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardCompositeFetch( this, attributeDefinition, loadPlanBuildingContext );
}
@Override
public void hydrate(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
EntityKey entityKey = context.getDictatedRootEntityKey();
if ( entityKey != null ) {
context.getIdentifierResolutionContext( this ).registerEntityKey( entityKey );
return;
}
identifierDescription.hydrate( resultSet, context );
for ( Fetch fetch : getFetches() ) {
fetch.hydrate( resultSet, context );
}
}
@Override
public void resolve(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
final IdentifierResolutionContext identifierResolutionContext = context.getIdentifierResolutionContext( this );
EntityKey entityKey = identifierResolutionContext.getEntityKey();
if ( entityKey == null ) {
return;
}
entityKey = identifierDescription.resolve( resultSet, context );
identifierResolutionContext.registerEntityKey( entityKey );
for ( Fetch fetch : getFetches() ) {
fetch.resolve( resultSet, context );
}
}
@Override
public Object read(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
return null;
}
@Override
public void injectIdentifierDescription(IdentifierDescription identifierDescription) {
this.identifierDescription = identifierDescription;
}
@Override
public String toString() {
return "EntityReturn(" + persister.getEntityName() + ")";
}
}

View File

@ -23,8 +23,12 @@
*/
package org.hibernate.loader.plan.spi;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.loader.PropertyPath;
import org.hibernate.loader.spi.ResultSetProcessingContext;
/**
* Contract for associations that are being fetched.
@ -33,7 +37,7 @@ import org.hibernate.loader.PropertyPath;
*
* @author Steve Ebersole
*/
public interface Fetch extends FetchOwner {
public interface Fetch {
/**
* Obtain the owner of this fetch.
*
@ -56,4 +60,8 @@ public interface Fetch extends FetchOwner {
* @return The property path
*/
public PropertyPath getPropertyPath();
public void hydrate(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException;
public Object resolve(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException;
}

View File

@ -26,6 +26,8 @@ package org.hibernate.loader.plan.spi;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.loader.PropertyPath;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
/**
* Contract for owners of fetches. Any non-scalar return could be a fetch owner.
@ -38,6 +40,14 @@ public interface FetchOwner {
*/
public static final Fetch[] NO_FETCHES = new Fetch[0];
/**
* Contract to add fetches to this owner. Care should be taken in calling this method; it is intended
* for Hibernate usage
*
* @param fetch The fetch to add
*/
public void addFetch(Fetch fetch);
/**
* Retrieve the fetches owned by this return.
*
@ -65,4 +75,19 @@ public interface FetchOwner {
* @return The property path
*/
public PropertyPath getPropertyPath();
public CollectionFetch buildCollectionFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext);
public EntityFetch buildEntityFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext);
public CompositeFetch buildCompositeFetch(
CompositionDefinition attributeDefinition,
LoadPlanBuildingContext loadPlanBuildingContext);
}

View File

@ -0,0 +1,41 @@
/*
* 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.loader.plan.spi;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.loader.spi.ResultSetProcessingContext;
/**
* @author Steve Ebersole
*/
public interface IdentifierDescription {
public Fetch[] getFetches();
public void hydrate(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException;
public EntityKey resolve(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException;
}

View File

@ -0,0 +1,33 @@
/*
* 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.loader.plan.spi;
/**
* Ugh
*
* @author Steve Ebersole
*/
public interface IdentifierDescriptionInjectable {
public void injectIdentifierDescription(IdentifierDescription identifierDescription);
}

View File

@ -55,6 +55,7 @@ public interface LoadPlan {
public List<Return> 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

View File

@ -0,0 +1,48 @@
/*
* 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.loader.plan.spi;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.loader.EntityAliases;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.CollectionDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.persister.walking.spi.EntityDefinition;
/**
* @author Steve Ebersole
*/
public interface LoadPlanBuildingContext {
public SessionFactoryImplementor getSessionFactory();
public CollectionAliases resolveCollectionColumnAliases(AssociationAttributeDefinition attributeDefinition);
public EntityAliases resolveEntityColumnAliases(AssociationAttributeDefinition attributeDefinition);
public String resolveRootSourceAlias(EntityDefinition definition);
public String resolveRootSourceAlias(CollectionDefinition definition);
public String resolveFetchSourceAlias(AssociationAttributeDefinition attributeDefinition);
public String resolveFetchSourceAlias(CompositionDefinition compositionDefinition);
}

View File

@ -26,16 +26,16 @@ package org.hibernate.loader.plan.spi;
/**
* @author Steve Ebersole
*/
public interface ReturnVisitationStrategy {
public interface LoadPlanVisitationStrategy {
/**
* Notification we are preparing to start visitation.
*/
public void start();
public void start(LoadPlan loadPlan);
/**
* Notification we are finished visitation.
*/
public void finish();
public void finish(LoadPlan loadPlan);
/**
* Notification that a new root return branch is being started. Will be followed by calls to one of the following

View File

@ -0,0 +1,104 @@
/*
* 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.loader.plan.spi;
/**
* @author Steve Ebersole
*/
public class LoadPlanVisitationStrategyAdapter implements LoadPlanVisitationStrategy {
@Override
public void start(LoadPlan loadPlan) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void finish(LoadPlan loadPlan) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void startingRootReturn(Return rootReturn) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void finishingRootReturn(Return rootReturn) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void handleScalarReturn(ScalarReturn scalarReturn) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void handleEntityReturn(EntityReturn rootEntityReturn) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void handleCollectionReturn(CollectionReturn rootCollectionReturn) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void startingFetches(FetchOwner fetchOwner) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void finishingFetches(FetchOwner fetchOwner) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void startingEntityFetch(EntityFetch entityFetch) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void finishingEntityFetch(EntityFetch entityFetch) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void startingCollectionFetch(CollectionFetch collectionFetch) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void finishingCollectionFetch(CollectionFetch collectionFetch) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void startingCompositeFetch(CompositeFetch fetch) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void finishingCompositeFetch(CompositeFetch fetch) {
//To change body of implemented methods use File | Settings | File Templates.
}
}

View File

@ -28,25 +28,25 @@ package org.hibernate.loader.plan.spi;
*
* @author Steve Ebersole
*/
public class ReturnVisitor {
public static void visit(Return[] rootReturns, ReturnVisitationStrategy strategy) {
new ReturnVisitor( strategy ).visitReturns( rootReturns );
public class LoadPlanVisitor {
public static void visit(LoadPlan loadPlan, LoadPlanVisitationStrategy strategy) {
new LoadPlanVisitor( strategy ).visit( loadPlan );
}
private final ReturnVisitationStrategy strategy;
private final LoadPlanVisitationStrategy strategy;
public ReturnVisitor(ReturnVisitationStrategy strategy) {
public LoadPlanVisitor(LoadPlanVisitationStrategy strategy) {
this.strategy = strategy;
}
private void visitReturns(Return[] rootReturns) {
strategy.start();
private void visit(LoadPlan loadPlan) {
strategy.start( loadPlan );
for ( Return rootReturn : rootReturns ) {
for ( Return rootReturn : loadPlan.getReturns() ) {
visitRootReturn( rootReturn );
}
strategy.finish();
strategy.finish( loadPlan );
}
private void visitRootReturn(Return rootReturn) {
@ -69,7 +69,9 @@ public class ReturnVisitor {
}
else if ( CollectionReturn.class.isInstance( rootReturn ) ) {
strategy.handleCollectionReturn( (CollectionReturn) rootReturn );
visitFetches( (CollectionReturn) rootReturn );
final CollectionReturn collectionReturn = (CollectionReturn) rootReturn;
visitFetches( collectionReturn.getIndexGraph() );
visitFetches( collectionReturn.getElementGraph() );
}
else {
throw new IllegalStateException(
@ -92,17 +94,18 @@ public class ReturnVisitor {
private void visitFetch(Fetch fetch) {
if ( EntityFetch.class.isInstance( fetch ) ) {
strategy.startingEntityFetch( (EntityFetch) fetch );
visitFetches( fetch );
visitFetches( (EntityFetch) fetch );
strategy.finishingEntityFetch( (EntityFetch) fetch );
}
else if ( CollectionFetch.class.isInstance( fetch ) ) {
strategy.startingCollectionFetch( (CollectionFetch) fetch );
visitFetches( fetch );
visitFetches( ( (CollectionFetch) fetch ).getIndexGraph() );
visitFetches( ( (CollectionFetch) fetch ).getElementGraph() );
strategy.finishingCollectionFetch( (CollectionFetch) fetch );
}
else if ( CompositeFetch.class.isInstance( fetch ) ) {
strategy.startingCompositeFetch( (CompositeFetch) fetch );
visitFetches( fetch );
visitFetches( (CompositeFetch) fetch );
strategy.finishingCompositeFetch( (CompositeFetch) fetch );
}
else {

View File

@ -23,12 +23,15 @@
*/
package org.hibernate.loader.plan.spi;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.hibernate.loader.spi.ResultSetProcessingContext;
/**
* Represents a return value in the query results. Not the same as a result (column) in the JDBC ResultSet!
* <p/>
* This is merely a unifying contract; it defines no behavior.
* <p/>
* Return is distinctly different from a {@link Fetch}.
* Return is distinctly different from a {@link Fetch} and so modeled as completely separate hierarchy.
*
* @see ScalarReturn
* @see EntityReturn
@ -37,4 +40,28 @@ package org.hibernate.loader.plan.spi;
* @author Steve Ebersole
*/
public interface Return {
public void hydrate(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException;
/**
* Effectively performs first phase of two-phase loading. For scalar results first/second phase is one. For
* entities, first phase is to resolve identifiers; second phase is to resolve the entity instances.
*
* @param resultSet The result set being processed
* @param context The context for the processing
*
* @throws SQLException Indicates a problem access the JDBC result set
*/
public void resolve(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException;
/**
* Essentially performs the second phase of two-phase loading.
*
* @param resultSet The result set being processed
* @param context The context for the processing
*
* @return The read object
*
* @throws SQLException Indicates a problem access the JDBC result set
*/
public Object read(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException;
}

View File

@ -23,7 +23,12 @@
*/
package org.hibernate.loader.plan.spi;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.internal.ResultSetProcessingContextImpl;
import org.hibernate.loader.spi.ResultSetProcessingContext;
import org.hibernate.type.Type;
/**
@ -34,19 +39,30 @@ import org.hibernate.type.Type;
*/
public class ScalarReturn extends AbstractPlanNode implements Return {
private final Type type;
private final String columnAlias;
private final String[] columnAliases;
public ScalarReturn(SessionFactoryImplementor factory, Type type, String columnAlias) {
public ScalarReturn(SessionFactoryImplementor factory, Type type, String[] columnAliases) {
super( factory );
this.type = type;
this.columnAlias = columnAlias;
this.columnAliases = columnAliases;
}
public Type getType() {
return type;
}
public String getColumnAlias() {
return columnAlias;
@Override
public void hydrate(ResultSet resultSet, ResultSetProcessingContext context) {
// nothing to do
}
@Override
public void resolve(ResultSet resultSet, ResultSetProcessingContext context) {
// nothing to do
}
@Override
public Object read(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
return type.nullSafeGet( resultSet, columnAliases, context.getSession(), null );
}
}

View File

@ -0,0 +1,34 @@
/*
* 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.loader.spi;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.persister.entity.Loadable;
/**
* @author Steve Ebersole
*/
public interface AfterLoadAction {
public void afterLoad(SessionImplementor session, Object entity, Loadable persister);
}

View File

@ -33,28 +33,22 @@ import org.hibernate.loader.plan.spi.LoadPlan;
import org.hibernate.transform.ResultTransformer;
/**
* Definition of the Loader contract.
* <p/>
* Capabilities I'd like to see added (todo):<ul>
* <li>
* expose the underlying "query" (although what I see here relies heavily on
* https://github.com/hibernate/hibernate-orm/wiki/Proposal---SQL-generation)
* </li>
* </ul>
*
* Definition of the Loader contract. A Loader is intended to perform loading based on a query and a load-plan.
* Under the covers it uses many delegates to perform that work that might be better used individually in
* different situations. In general, Loader is intended for being fed a set of results and processing through
* all of those result rows in one swoop. For cases that do not fit that template, it is probably better to
* individually use the delegates to perform the work.
*
* @author Gavin King
* @author Steve Ebersole
*/
public interface Loader {
public LoadPlan getLoadPlan();
/**
* Obtain the on-demand form of this loader, if possible.
* Obtain the LoadPlan this Loader is following.
*
* @return The on-demand version of this loader
* @return
*/
public OnDemandLoader asOnDemandLoader();
public LoadPlan getLoadPlan();
public List extractResults(
ResultSet resultSet,

View File

@ -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.loader.spi;
/**
* The context for named parameters.
* <p/>
* NOTE : the hope with the SQL-redesign stuff is that this whole concept goes away, the idea being that
* the parameters are encoded into the query tree and "bind themselves".
*
* @author Steve Ebersole
*/
public interface NamedParameterContext {
public int[] getNamedParameterLocations(String name);
}

View File

@ -1,7 +1,7 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* 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.
@ -25,22 +25,24 @@ package org.hibernate.loader.spi;
import java.sql.ResultSet;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionImplementor;
/**
* Represents an on-demand loading strategy as need for processing single *logical* rows one at a time as required
* for {@link org.hibernate.ScrollableResults} implementations.
* Contract for processing JDBC ResultSets a single logical row at a time. These are intended for use by
* {@link org.hibernate.ScrollableResults} implementations.
*
* NOTE : these methods initially taken directly from {@link org.hibernate.loader.Loader} counterparts in an effort
* to break Loader into manageable pieces, especially in regards to the processing of result sets.
*
* @author Steve Ebersole
*/
public interface OnDemandLoader {
public interface OnDemandResultSetProcessor {
/**
* Given a ResultSet, extract just a single result row.
* Give a ResultSet, extract just a single result row.
*
* Copy of {@link org.hibernate.loader.Loader#loadSingleRow(ResultSet, SessionImplementor, QueryParameters, boolean)}
* Copy of {@link org.hibernate.loader.Loader#loadSingleRow(java.sql.ResultSet, org.hibernate.engine.spi.SessionImplementor, org.hibernate.engine.spi.QueryParameters, boolean)}
* but dropping the 'returnProxies' (that method has only one use in the entire codebase and it always passes in
* false...)
*
@ -50,19 +52,19 @@ public interface OnDemandLoader {
*
* @return The extracted result row
*
* @throws HibernateException Indicates a problem extracting values from the result set.
* @throws org.hibernate.HibernateException Indicates a problem extracting values from the result set.
*/
public Object extractSingleRow(
ResultSet resultSet,
SessionImplementor session,
QueryParameters queryParameters) throws HibernateException;
QueryParameters queryParameters);
/**
* Given a ResultSet extract "sequential rows". This is used in cases where we have multi-row fetches that
* are sequential within the ResultSet due to ordering. Multiple ResultSet rows are read into a single query
* result "row".
*
* Copy of {@link org.hibernate.loader.Loader#loadSequentialRowsForward(ResultSet, SessionImplementor, QueryParameters, boolean)}
* Copy of {@link org.hibernate.loader.Loader#loadSequentialRowsForward(java.sql.ResultSet, org.hibernate.engine.spi.SessionImplementor, org.hibernate.engine.spi.QueryParameters, boolean)}
* but dropping the 'returnProxies' (that method has only one use in the entire codebase and it always passes in
* false...)
*
@ -77,12 +79,12 @@ public interface OnDemandLoader {
public Object extractSequentialRowsForward(
final ResultSet resultSet,
final SessionImplementor session,
final QueryParameters queryParameters) throws HibernateException;
final QueryParameters queryParameters);
/**
* Like {@link #extractSequentialRowsForward} but here moving back through the ResultSet.
*
* Copy of {@link org.hibernate.loader.Loader#loadSequentialRowsReverse(ResultSet, SessionImplementor, QueryParameters, boolean, boolean)}
* Copy of {@link org.hibernate.loader.Loader#loadSequentialRowsReverse(java.sql.ResultSet, org.hibernate.engine.spi.SessionImplementor, org.hibernate.engine.spi.QueryParameters, boolean, boolean)}
* but dropping the 'returnProxies' (that method has only one use in the entire codebase and it always passes in
* false...).
*
@ -101,5 +103,5 @@ public interface OnDemandLoader {
ResultSet resultSet,
SessionImplementor session,
QueryParameters queryParameters,
boolean isLogicallyAfterLast) throws HibernateException;
boolean isLogicallyAfterLast);
}

View File

@ -0,0 +1,7 @@
package org.hibernate.loader.spi;
/**
* @author Steve Ebersole
*/
public class ResultBuilder {
}

View File

@ -0,0 +1,91 @@
/*
* 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.loader.spi;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.hibernate.LockMode;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.loader.EntityAliases;
import org.hibernate.loader.plan.spi.EntityReference;
import org.hibernate.loader.plan.spi.Return;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.AssociationType;
import org.hibernate.type.EntityType;
/**
* @author Steve Ebersole
*/
public interface ResultSetProcessingContext {
public SessionImplementor getSession();
public QueryParameters getQueryParameters();
public EntityKey getDictatedRootEntityKey();
public IdentifierResolutionContext getIdentifierResolutionContext(EntityReference entityReference);
public static interface IdentifierResolutionContext {
public EntityReference getEntityReference();
public void registerHydratedForm(Serializable hydratedForm);
public Serializable getHydratedForm();
public void registerEntityKey(EntityKey entityKey);
public EntityKey getEntityKey();
}
public void registerHydratedEntity(EntityPersister persister, EntityKey entityKey, Object entityInstance);
public void checkVersion(
ResultSet resultSet,
EntityPersister persister,
EntityAliases entityAliases,
EntityKey entityKey,
Object entityInstance) throws SQLException;
public String getConcreteEntityTypeName(
ResultSet resultSet,
EntityPersister persister,
EntityAliases entityAliases,
EntityKey entityKey) throws SQLException;
public void loadFromResultSet(
ResultSet resultSet,
Object entityInstance,
String concreteEntityTypeName,
EntityKey entityKey,
EntityAliases entityAliases,
LockMode acquiredLockMode,
EntityPersister persister,
boolean eagerFetch,
EntityType associationType) throws SQLException;
}

View File

@ -0,0 +1,70 @@
/*
* 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.spi;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.transform.ResultTransformer;
/**
* Contract for processing JDBC ResultSets. Separated because ResultSets can be chained and we'd really like to
* reuse this logic across all result sets.
* <p/>
* todo : investigate having this work with non-JDBC results; maybe just typed as Object? or a special Result contract?
*
* @author Steve Ebersole
*/
public interface ResultSetProcessor {
public OnDemandResultSetProcessor toOnDemandForm();
/**
* Process an entire ResultSet, performing all extractions.
*
* Semi-copy of {@link org.hibernate.loader.Loader#doQuery}, with focus on just the ResultSet processing bit.
*
* @param resultSet The result set being processed.
* @param session The originating session
* @param queryParameters The "parameters" used to build the query
* @param returnProxies Can proxies be returned (not the same as can they be created!)
* @param forcedResultTransformer My old "friend" ResultTransformer...
*
* @return The extracted results list.
*
* @throws java.sql.SQLException Indicates a problem access the JDBC ResultSet
*/
public List extractResults(
ResultSet resultSet,
SessionImplementor session,
QueryParameters queryParameters,
NamedParameterContext namedParameterContext,
boolean returnProxies,
boolean readOnly,
ResultTransformer forcedResultTransformer,
List<AfterLoadAction> afterLoadActions) throws SQLException;
}

View File

@ -82,7 +82,7 @@ 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.CompositionDefinition;
import org.hibernate.persister.walking.spi.EntityDefinition;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.sql.Alias;
@ -1974,7 +1974,7 @@ public abstract class AbstractCollectionPersister
}
@Override
public CompositeDefinition toCompositeDefinition() {
public CompositionDefinition toCompositeDefinition() {
if ( ! getType().isComponentType() ) {
throw new IllegalStateException( "Cannot treat entity collection index type as composite" );
}
@ -2006,7 +2006,7 @@ public abstract class AbstractCollectionPersister
}
@Override
public CompositeDefinition toCompositeDefinition() {
public CompositionDefinition toCompositeDefinition() {
if ( ! getType().isComponentType() ) {
throw new IllegalStateException( "Cannot treat entity collection element type as composite" );
}

View File

@ -110,6 +110,11 @@ 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.persister.walking.spi.AttributeSource;
import org.hibernate.persister.walking.spi.EncapsulatedEntityIdentifierDefinition;
import org.hibernate.persister.walking.spi.EntityDefinition;
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
import org.hibernate.persister.walking.spi.NonEncapsulatedEntityIdentifierDefinition;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.property.BackrefPropertyAccessor;
import org.hibernate.sql.Alias;
@ -5076,11 +5081,12 @@ public abstract class AbstractEntityPersister
// EntityDefinition impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private EntityIdentifierDefinition entityIdentifierDefinition;
private Iterable<AttributeDefinition> embeddedCompositeIdentifierAttributes;
private Iterable<AttributeDefinition> attributeDefinitions;
protected void generateEntityDefinition() {
collectEmbeddedCompositeIdentifierAttributeDefinitions();
prepareEntityIdentifierDefinition();
collectAttributeDefinitions();
}
@ -5090,8 +5096,8 @@ public abstract class AbstractEntityPersister
}
@Override
public Iterable<AttributeDefinition> getEmbeddedCompositeIdentifierAttributes() {
return embeddedCompositeIdentifierAttributes;
public EntityIdentifierDefinition getEntityKeyDefinition() {
return entityIdentifierDefinition;
}
@Override
@ -5099,52 +5105,85 @@ public abstract class AbstractEntityPersister
return attributeDefinitions;
}
private synchronized void collectEmbeddedCompositeIdentifierAttributeDefinitions() {
private void prepareEntityIdentifierDefinition() {
final Type idType = getIdentifierType();
if ( !idType.isComponentType() ) {
entityIdentifierDefinition = buildEncapsulatedIdentifierDefinition();
return;
}
final CompositeType cidType = (CompositeType) idType;
if ( !cidType.isEmbedded() ) {
entityIdentifierDefinition = buildEncapsulatedIdentifierDefinition();
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<AttributeDefinition>() {
@Override
public Iterator<AttributeDefinition> iterator() {
return new Iterator<AttributeDefinition>() {
private final int numberOfAttributes = countSubclassProperties();
private int currentAttributeNumber = 0;
entityIdentifierDefinition = new NonEncapsulatedEntityIdentifierDefinition() {
@Override
public Iterable<AttributeDefinition> getAttributes() {
// todo : implement
throw new NotYetImplementedException();
}
@Override
public boolean hasNext() {
return currentAttributeNumber < numberOfAttributes;
}
@Override
public Class getSeparateIdentifierMappingClass() {
// todo : implement
throw new NotYetImplementedException();
}
@Override
public AttributeDefinition next() {
// todo : implement
throw new NotYetImplementedException();
}
@Override
public boolean isEncapsulated() {
return false;
}
@Override
public void remove() {
throw new UnsupportedOperationException( "Remove operation not supported here" );
}
};
}
};
}
@Override
public EntityDefinition getEntityDefinition() {
return AbstractEntityPersister.this;
}
};
}
private EntityIdentifierDefinition buildEncapsulatedIdentifierDefinition() {
final AttributeDefinition simpleIdentifierAttributeAdapter = new AttributeDefinition() {
@Override
public String getName() {
return entityMetamodel.getIdentifierProperty().getName();
}
@Override
public Type getType() {
return entityMetamodel.getIdentifierProperty().getType();
}
@Override
public AttributeSource getSource() {
return AbstractEntityPersister.this;
}
@Override
public String toString() {
return "<identifier-property:" + getName() + ">";
}
};
return new EncapsulatedEntityIdentifierDefinition() {
@Override
public AttributeDefinition getAttributeDefinition() {
return simpleIdentifierAttributeAdapter;
}
@Override
public boolean isEncapsulated() {
return true;
}
@Override
public EntityDefinition getEntityDefinition() {
return AbstractEntityPersister.this;
}
};
}
private void collectAttributeDefinitions() {

View File

@ -0,0 +1,44 @@
/*
* 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.spi;
/**
* Where to begin... :)
*
* This gets to the internal concept of 2-phase loading of entity data and how specifically it is done. Essentially
* for composite values, the process of hydration results in a tuple array comprising the composition "atomic" values.
* For example, a Name component's hydrated state might look like {@code ["Steve", "L", "Ebersole"]}.
*
* There are times when we need to be able to extract individual pieces out of the hydrated tuple array. For example,
* for an entity with a composite identifier part of which is an association (a key-many-to-one) we often need to
* attempt 2-phase processing on the association portion of the identifier's hydrated tuple array.
*
* This contract allows us access to portions of the hydrated tuple state.
*
* @author Steve Ebersole
*/
public interface HydratedCompoundValueHandler {
public Object extract(Object hydratedState);
public void inject(Object hydratedState, Object value);
}

View File

@ -27,6 +27,7 @@ import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.loader.PropertyPath;
import org.hibernate.persister.spi.HydratedCompoundValueHandler;
/**
* @author Steve Ebersole
@ -43,4 +44,6 @@ public interface AssociationAttributeDefinition extends AttributeDefinition {
public FetchStrategy determineFetchPlan(LoadQueryInfluencers loadQueryInfluencers, PropertyPath propertyPath);
public CascadeStyle determineCascadeStyle();
public HydratedCompoundValueHandler getHydratedCompoundValueExtractor();
}

View File

@ -40,11 +40,20 @@ public interface AssociationVisitationStrategy {
public void startingEntity(EntityDefinition entityDefinition);
public void finishingEntity(EntityDefinition entityDefinition);
public void startingEntityIdentifier(EntityIdentifierDefinition entityIdentifierDefinition);
public void finishingEntityIdentifier(EntityIdentifierDefinition entityIdentifierDefinition);
public void startingCollection(CollectionDefinition collectionDefinition);
public void finishingCollection(CollectionDefinition collectionDefinition);
public void startingComposite(CompositeDefinition compositeDefinition);
public void finishingComposite(CompositeDefinition compositeDefinition);
public void startingCollectionIndex(CollectionIndexDefinition collectionIndexDefinition);
public void finishingCollectionIndex(CollectionIndexDefinition collectionIndexDefinition);
public void startingCollectionElements(CollectionElementDefinition elementDefinition);
public void finishingCollectionElements(CollectionElementDefinition elementDefinition);
public void startingComposite(CompositionDefinition compositionDefinition);
public void finishingComposite(CompositionDefinition compositionDefinition);
public boolean startingAttribute(AttributeDefinition attributeDefinition);
public void finishingAttribute(AttributeDefinition attributeDefinition);

View File

@ -35,5 +35,5 @@ public interface CollectionElementDefinition {
public EntityDefinition toEntityDefinition();
public CompositeDefinition toCompositeDefinition();
public CompositionDefinition toCompositeDefinition();
}

View File

@ -35,5 +35,5 @@ public interface CollectionIndexDefinition {
public EntityDefinition toEntityDefinition();
public CompositeDefinition toCompositeDefinition();
public CompositionDefinition toCompositeDefinition();
}

View File

@ -26,5 +26,5 @@ package org.hibernate.persister.walking.spi;
/**
* @author Steve Ebersole
*/
public interface CompositeDefinition extends AttributeDefinition, AttributeSource {
public interface CompositionDefinition extends AttributeDefinition, AttributeSource {
}

View File

@ -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 EncapsulatedEntityIdentifierDefinition extends EntityIdentifierDefinition {
public AttributeDefinition getAttributeDefinition();
}

View File

@ -32,5 +32,5 @@ import org.hibernate.persister.entity.EntityPersister;
*/
public interface EntityDefinition extends AttributeSource {
public EntityPersister getEntityPersister();
public Iterable<AttributeDefinition> getEmbeddedCompositeIdentifierAttributes();
public EntityIdentifierDefinition getEntityKeyDefinition();
}

View File

@ -0,0 +1,43 @@
/*
* 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;
/**
* Describes aspects of the identifier for an entity
*
* @author Steve Ebersole
*/
public interface EntityIdentifierDefinition {
/**
* Is the entity identifier encapsulated? Meaning, is it represented by a single attribute?
*
* @return {@code true} indicates the identifier is encapsulated (and therefore this is castable to
* {@link EncapsulatedEntityIdentifierDefinition}); {@code false} means it is not encapsulated (and therefore
* castable to {@link NonEncapsulatedEntityIdentifierDefinition}).
*
*/
public boolean isEncapsulated();
public EntityDefinition getEntityDefinition();
}

View File

@ -81,26 +81,26 @@ public class MetadataDrivenModelGraphVisitor {
private void visitEntityDefinition(EntityDefinition entityDefinition) {
strategy.startingEntity( entityDefinition );
try {
visitAttributes( entityDefinition );
optionallyVisitEmbeddedCompositeIdentifier( entityDefinition );
}
finally {
strategy.finishingEntity( entityDefinition );
}
visitAttributes( entityDefinition );
visitIdentifierDefinition( entityDefinition.getEntityKeyDefinition() );
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<AttributeDefinition> embeddedCompositeIdentifierAttributes =
entityDefinition.getEmbeddedCompositeIdentifierAttributes();
if ( embeddedCompositeIdentifierAttributes == null ) {
return;
private void visitIdentifierDefinition(EntityIdentifierDefinition entityIdentifierDefinition) {
strategy.startingEntityIdentifier( entityIdentifierDefinition );
if ( entityIdentifierDefinition.isEncapsulated() ) {
visitAttributeDefinition( ( (EncapsulatedEntityIdentifierDefinition) entityIdentifierDefinition).getAttributeDefinition() );
}
else {
for ( AttributeDefinition attributeDefinition : ( (NonEncapsulatedEntityIdentifierDefinition) entityIdentifierDefinition).getAttributes() ) {
visitAttributeDefinition( attributeDefinition );
}
}
for ( AttributeDefinition attributeDefinition : embeddedCompositeIdentifierAttributes ) {
visitAttributeDefinition( attributeDefinition );
}
strategy.finishingEntityIdentifier( entityIdentifierDefinition );
}
private void visitAttributes(AttributeSource attributeSource) {
@ -122,7 +122,7 @@ public class MetadataDrivenModelGraphVisitor {
visitAssociation( (AssociationAttributeDefinition) attributeDefinition );
}
else if ( attributeDefinition.getType().isComponentType() ) {
visitCompositeDefinition( (CompositeDefinition) attributeDefinition );
visitCompositeDefinition( (CompositionDefinition) attributeDefinition );
}
}
finally {
@ -148,42 +148,34 @@ public class MetadataDrivenModelGraphVisitor {
}
}
private void visitCompositeDefinition(CompositeDefinition compositeDefinition) {
strategy.startingComposite( compositeDefinition );
try {
visitAttributes( compositeDefinition );
}
finally {
strategy.finishingComposite( compositeDefinition );
}
private void visitCompositeDefinition(CompositionDefinition compositionDefinition) {
strategy.startingComposite( compositionDefinition );
visitAttributes( compositionDefinition );
strategy.finishingComposite( compositionDefinition );
}
private void visitCollectionDefinition(CollectionDefinition collectionDefinition) {
strategy.startingCollection( collectionDefinition );
try {
visitCollectionIndex( collectionDefinition.getIndexDefinition() );
visitCollectionIndex( collectionDefinition );
visitCollectionElements( collectionDefinition );
final CollectionElementDefinition elementDefinition = collectionDefinition.getElementDefinition();
if ( elementDefinition.getType().isComponentType() ) {
visitCompositeDefinition( elementDefinition.toCompositeDefinition() );
}
else {
visitEntityDefinition( elementDefinition.toEntityDefinition() );
}
}
finally {
strategy.finishingCollection( collectionDefinition );
}
strategy.finishingCollection( collectionDefinition );
}
private void visitCollectionIndex(CollectionIndexDefinition collectionIndexDefinition) {
private void visitCollectionIndex(CollectionDefinition collectionDefinition) {
final CollectionIndexDefinition collectionIndexDefinition = collectionDefinition.getIndexDefinition();
if ( collectionIndexDefinition == null ) {
return;
}
log.debug( "Visiting collection index : " + currentPropertyPath.getFullPath() );
currentPropertyPath = currentPropertyPath.append( "<key>" );
strategy.startingCollectionIndex( collectionIndexDefinition );
log.debug( "Visiting index for collection : " + currentPropertyPath.getFullPath() );
currentPropertyPath = currentPropertyPath.append( "<index>" );
try {
final Type collectionIndexType = collectionIndexDefinition.getType();
if ( collectionIndexType.isComponentType() ) {
@ -196,6 +188,22 @@ public class MetadataDrivenModelGraphVisitor {
finally {
currentPropertyPath = currentPropertyPath.getParent();
}
strategy.finishingCollectionIndex( collectionIndexDefinition );
}
private void visitCollectionElements(CollectionDefinition collectionDefinition) {
final CollectionElementDefinition elementDefinition = collectionDefinition.getElementDefinition();
strategy.startingCollectionElements( elementDefinition );
if ( elementDefinition.getType().isComponentType() ) {
visitCompositeDefinition( elementDefinition.toCompositeDefinition() );
}
else {
visitEntityDefinition( elementDefinition.toEntityDefinition() );
}
strategy.finishingCollectionElements( elementDefinition );
}

View File

@ -0,0 +1,33 @@
/*
* 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 NonEncapsulatedEntityIdentifierDefinition extends EntityIdentifierDefinition {
public Iterable<AttributeDefinition> getAttributes();
public Class getSeparateIdentifierMappingClass();
}

View File

@ -0,0 +1,41 @@
/*
* 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.HibernateError;
/**
* Indicates a problem walking the domain tree. Almost always this indicates an internal error in Hibernate
*
* @author Steve Ebersole
*/
public class WalkingException extends HibernateError {
public WalkingException(String message) {
super( message );
}
public WalkingException(String message, Throwable root) {
super( message, root );
}
}

View File

@ -37,6 +37,7 @@ import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.loader.custom.CustomLoader;
import org.hibernate.loader.custom.CustomQuery;
import org.hibernate.loader.custom.sql.SQLQueryReturnProcessor;
import org.hibernate.loader.spi.AfterLoadAction;
import org.hibernate.result.NoMoreReturnsException;
import org.hibernate.result.Result;
import org.hibernate.result.Return;

View File

@ -126,8 +126,12 @@ public abstract class AbstractNonIdentifierAttribute extends AbstractAttribute i
return attributeInformation.getFetchMode();
}
protected String loggableMetadata() {
return "non-identifier";
}
@Override
public String toString() {
return "Attribute[non-identifier]( " + getName() + ")";
return "Attribute(name=" + getName() + ", type=" + getType().getName() + " [" + loggableMetadata() + "])";
}
}

View File

@ -54,7 +54,7 @@ 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.EntityBasedCompositionAttribute;
import org.hibernate.tuple.entity.VersionProperty;
import org.hibernate.type.AssociationType;
import org.hibernate.type.CompositeType;
@ -282,7 +282,7 @@ public class PropertyFactory {
);
}
case COMPOSITE: {
return new EntityBasedCompositeAttribute(
return new EntityBasedCompositionAttribute(
persister,
sessionFactory,
attributeNumber,

View File

@ -39,7 +39,7 @@ public abstract class AbstractCompositeBasedAttribute
private final int ownerAttributeNumber;
public AbstractCompositeBasedAttribute(
AbstractCompositeDefinition source,
AbstractCompositionDefinition source,
SessionFactoryImplementor sessionFactory,
int attributeNumber,
String attributeName,
@ -55,7 +55,7 @@ public abstract class AbstractCompositeBasedAttribute
}
@Override
public AbstractCompositeDefinition getSource() {
return (AbstractCompositeDefinition) super.getSource();
public AbstractCompositionDefinition getSource() {
return (AbstractCompositionDefinition) super.getSource();
}
}

View File

@ -32,7 +32,7 @@ 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.CompositionDefinition;
import org.hibernate.persister.walking.spi.EntityDefinition;
import org.hibernate.tuple.AbstractNonIdentifierAttribute;
import org.hibernate.tuple.BaselineAttributeInformation;
@ -48,8 +48,9 @@ import static org.hibernate.engine.internal.JoinHelper.getRHSColumnNames;
/**
* @author Steve Ebersole
*/
public abstract class AbstractCompositeDefinition extends AbstractNonIdentifierAttribute implements CompositeDefinition {
protected AbstractCompositeDefinition(
public abstract class AbstractCompositionDefinition extends AbstractNonIdentifierAttribute implements
CompositionDefinition {
protected AbstractCompositionDefinition(
AttributeSource source,
SessionFactoryImplementor sessionFactory,
int attributeNumber,
@ -119,41 +120,41 @@ public abstract class AbstractCompositeDefinition extends AbstractNonIdentifierA
}
return new CompositeBasedAssociationAttribute(
AbstractCompositeDefinition.this,
AbstractCompositionDefinition.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() )
.setInsertable( AbstractCompositionDefinition.this.isInsertable() )
.setUpdateable( AbstractCompositionDefinition.this.isUpdateable() )
.setInsertGenerated( AbstractCompositionDefinition.this.isInsertGenerated() )
.setUpdateGenerated( AbstractCompositionDefinition.this.isUpdateGenerated() )
.setNullable( getType().getPropertyNullability()[currentAttributeNumber] )
.setDirtyCheckable( true )
.setVersionable( AbstractCompositeDefinition.this.isVersionable() )
.setVersionable( AbstractCompositionDefinition.this.isVersionable() )
.setCascadeStyle( getType().getCascadeStyle( currentAttributeNumber ) )
.setFetchMode( getType().getFetchMode( currentAttributeNumber ) )
.createInformation(),
AbstractCompositeDefinition.this.attributeNumber(),
AbstractCompositionDefinition.this.attributeNumber(),
associationKey
);
}
else if ( type.isComponentType() ) {
return new CompositeBasedCompositeAttribute(
AbstractCompositeDefinition.this,
return new CompositionBasedCompositionAttribute(
AbstractCompositionDefinition.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() )
.setInsertable( AbstractCompositionDefinition.this.isInsertable() )
.setUpdateable( AbstractCompositionDefinition.this.isUpdateable() )
.setInsertGenerated( AbstractCompositionDefinition.this.isInsertGenerated() )
.setUpdateGenerated( AbstractCompositionDefinition.this.isUpdateGenerated() )
.setNullable( getType().getPropertyNullability()[currentAttributeNumber] )
.setDirtyCheckable( true )
.setVersionable( AbstractCompositeDefinition.this.isVersionable() )
.setVersionable( AbstractCompositionDefinition.this.isVersionable() )
.setCascadeStyle( getType().getCascadeStyle( currentAttributeNumber ) )
.setFetchMode( getType().getFetchMode( currentAttributeNumber ) )
.createInformation()
@ -161,19 +162,19 @@ public abstract class AbstractCompositeDefinition extends AbstractNonIdentifierA
}
else {
return new CompositeBasedBasicAttribute(
AbstractCompositeDefinition.this,
AbstractCompositionDefinition.this,
sessionFactory(),
currentAttributeNumber,
name,
type,
new BaselineAttributeInformation.Builder()
.setInsertable( AbstractCompositeDefinition.this.isInsertable() )
.setUpdateable( AbstractCompositeDefinition.this.isUpdateable() )
.setInsertGenerated( AbstractCompositeDefinition.this.isInsertGenerated() )
.setUpdateGenerated( AbstractCompositeDefinition.this.isUpdateGenerated() )
.setInsertable( AbstractCompositionDefinition.this.isInsertable() )
.setUpdateable( AbstractCompositionDefinition.this.isUpdateable() )
.setInsertGenerated( AbstractCompositionDefinition.this.isInsertGenerated() )
.setUpdateGenerated( AbstractCompositionDefinition.this.isUpdateGenerated() )
.setNullable( getType().getPropertyNullability()[currentAttributeNumber] )
.setDirtyCheckable( true )
.setVersionable( AbstractCompositeDefinition.this.isVersionable() )
.setVersionable( AbstractCompositionDefinition.this.isVersionable() )
.setCascadeStyle( getType().getCascadeStyle( currentAttributeNumber ) )
.setFetchMode( getType().getFetchMode( currentAttributeNumber ) )
.createInformation()
@ -195,8 +196,13 @@ public abstract class AbstractCompositeDefinition extends AbstractNonIdentifierA
return ( (EntityDefinition) getSource() ).getEntityPersister();
}
else {
return ( (AbstractCompositeDefinition) getSource() ).locateOwningPersister();
return ( (AbstractCompositionDefinition) getSource() ).locateOwningPersister();
}
}
@Override
protected String loggableMetadata() {
return super.loggableMetadata() + ",composition";
}
}

View File

@ -23,6 +23,8 @@
*/
package org.hibernate.tuple.component;
import java.io.Serializable;
import org.hibernate.FetchMode;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchStyle;
@ -34,6 +36,7 @@ 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.spi.HydratedCompoundValueHandler;
import org.hibernate.persister.walking.internal.Helper;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.AssociationKey;
@ -54,7 +57,7 @@ public class CompositeBasedAssociationAttribute
private Joinable joinable;
public CompositeBasedAssociationAttribute(
AbstractCompositeDefinition source,
AbstractCompositionDefinition source,
SessionFactoryImplementor factory,
int attributeNumber,
String attributeName,
@ -154,4 +157,29 @@ public class CompositeBasedAssociationAttribute
final CompositeType compositeType = (CompositeType) locateOwningPersister().getPropertyType( getName() );
return compositeType.getCascadeStyle( attributeNumber() );
}
private HydratedCompoundValueHandler hydratedCompoundValueHandler;
@Override
public HydratedCompoundValueHandler getHydratedCompoundValueExtractor() {
if ( hydratedCompoundValueHandler == null ) {
hydratedCompoundValueHandler = new HydratedCompoundValueHandler() {
@Override
public Object extract(Object hydratedState) {
return ( (Object[] ) hydratedState )[ attributeNumber() ];
}
@Override
public void inject(Object hydratedState, Object value) {
( (Object[] ) hydratedState )[ attributeNumber() ] = value;
}
};
}
return hydratedCompoundValueHandler;
}
@Override
protected String loggableMetadata() {
return super.loggableMetadata() + ",association";
}
}

View File

@ -24,18 +24,18 @@
package org.hibernate.tuple.component;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.persister.walking.spi.CompositeDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.tuple.BaselineAttributeInformation;
import org.hibernate.type.CompositeType;
/**
* @author Steve Ebersole
*/
public class CompositeBasedCompositeAttribute
extends AbstractCompositeDefinition
implements CompositeDefinition {
public CompositeBasedCompositeAttribute(
CompositeDefinition source,
public class CompositionBasedCompositionAttribute
extends AbstractCompositionDefinition
implements CompositionDefinition {
public CompositionBasedCompositionAttribute(
CompositionDefinition source,
SessionFactoryImplementor sessionFactory,
int attributeNumber,
String attributeName,

View File

@ -33,6 +33,7 @@ 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.spi.HydratedCompoundValueHandler;
import org.hibernate.persister.walking.internal.Helper;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.AssociationKey;
@ -152,4 +153,29 @@ public class EntityBasedAssociationAttribute
public CascadeStyle determineCascadeStyle() {
return getSource().getEntityPersister().getPropertyCascadeStyles()[attributeNumber()];
}
private HydratedCompoundValueHandler hydratedCompoundValueHandler;
@Override
public HydratedCompoundValueHandler getHydratedCompoundValueExtractor() {
if ( hydratedCompoundValueHandler == null ) {
hydratedCompoundValueHandler = new HydratedCompoundValueHandler() {
@Override
public Object extract(Object hydratedState) {
return ( (Object[] ) hydratedState )[ attributeNumber() ];
}
@Override
public void inject(Object hydratedState, Object value) {
( (Object[] ) hydratedState )[ attributeNumber() ] = value;
}
};
}
return hydratedCompoundValueHandler;
}
@Override
protected String loggableMetadata() {
return super.loggableMetadata() + ",association";
}
}

View File

@ -25,19 +25,19 @@ 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.component.AbstractCompositionDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.tuple.BaselineAttributeInformation;
import org.hibernate.type.CompositeType;
/**
* @author Steve Ebersole
*/
public class EntityBasedCompositeAttribute
extends AbstractCompositeDefinition
implements CompositeDefinition {
public class EntityBasedCompositionAttribute
extends AbstractCompositionDefinition
implements CompositionDefinition {
public EntityBasedCompositeAttribute(
public EntityBasedCompositionAttribute(
EntityPersister source,
SessionFactoryImplementor factory,
int attributeNumber,

View File

@ -119,9 +119,9 @@ public class LoadPlanBuilderTest extends BaseCoreFunctionalTestCase {
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];
assertNotNull( collectionReturn.getElementGraph().getFetches() );
assertEquals( 1, collectionReturn.getElementGraph().getFetches().length ); // the collection elements are fetched
Fetch fetch = collectionReturn.getElementGraph().getFetches()[0];
EntityFetch entityFetch = ExtraAssertions.assertTyping( EntityFetch.class, fetch );
assertNotNull( entityFetch.getFetches() );
assertEquals( 0, entityFetch.getFetches().length );
@ -130,8 +130,8 @@ public class LoadPlanBuilderTest extends BaseCoreFunctionalTestCase {
@Entity( name = "Message" )
public static class Message {
@Id
private Integer id;
private String name;
private Integer mid;
private String msgTxt;
@ManyToOne( cascade = CascadeType.MERGE )
@JoinColumn
private Poster poster;
@ -140,7 +140,7 @@ public class LoadPlanBuilderTest extends BaseCoreFunctionalTestCase {
@Entity( name = "Poster" )
public static class Poster {
@Id
private Integer id;
private Integer pid;
private String name;
@OneToMany(mappedBy = "poster")
private List<Message> messages;

View File

@ -35,8 +35,11 @@ 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.CollectionElementDefinition;
import org.hibernate.persister.walking.spi.CollectionIndexDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.persister.walking.spi.EntityDefinition;
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
import org.hibernate.persister.walking.spi.MetadataDrivenModelGraphVisitor;
import org.junit.Test;
@ -91,6 +94,16 @@ public class BasicWalkingTest extends BaseCoreFunctionalTestCase {
);
}
@Override
public void startingEntityIdentifier(EntityIdentifierDefinition entityIdentifierDefinition) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void finishingEntityIdentifier(EntityIdentifierDefinition entityIdentifierDefinition) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void startingCollection(CollectionDefinition collectionDefinition) {
System.out.println(
@ -114,23 +127,43 @@ public class BasicWalkingTest extends BaseCoreFunctionalTestCase {
}
@Override
public void startingComposite(CompositeDefinition compositeDefinition) {
public void startingCollectionIndex(CollectionIndexDefinition collectionIndexDefinition) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void finishingCollectionIndex(CollectionIndexDefinition collectionIndexDefinition) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void startingCollectionElements(CollectionElementDefinition elementDefinition) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void finishingCollectionElements(CollectionElementDefinition elementDefinition) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void startingComposite(CompositionDefinition compositionDefinition) {
System.out.println(
String.format(
"%s Starting composite (%s)",
StringHelper.repeat( ">>", ++depth ),
compositeDefinition.toString()
compositionDefinition.toString()
)
);
}
@Override
public void finishingComposite(CompositeDefinition compositeDefinition) {
public void finishingComposite(CompositionDefinition compositionDefinition) {
System.out.println(
String.format(
"%s Finishing composite (%s)",
StringHelper.repeat( ">>", depth-- ),
compositeDefinition.toString()
compositionDefinition.toString()
)
);
}

View File

@ -58,6 +58,7 @@ 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.persister.walking.spi.EntityIdentifierDefinition;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.tuple.entity.EntityTuplizer;
import org.hibernate.tuple.entity.NonPojoInstrumentationMetadata;
@ -590,8 +591,8 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver {
}
@Override
public Iterable<AttributeDefinition> getEmbeddedCompositeIdentifierAttributes() {
throw new NotYetImplementedException();
public EntityIdentifierDefinition getEntityKeyDefinition() {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override

View File

@ -36,6 +36,7 @@ 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.persister.walking.spi.EntityIdentifierDefinition;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.tuple.entity.EntityTuplizer;
import org.hibernate.tuple.entity.NonPojoInstrumentationMetadata;
@ -680,7 +681,7 @@ public class CustomPersister implements EntityPersister {
}
@Override
public Iterable<AttributeDefinition> getEmbeddedCompositeIdentifierAttributes() {
public EntityIdentifierDefinition getEntityKeyDefinition() {
throw new NotYetImplementedException();
}

View File

@ -9,6 +9,8 @@ log4j.rootLogger=info, stdout
log4j.logger.org.hibernate.tool.hbm2ddl=trace
log4j.logger.org.hibernate.testing.cache=debug
log4j.logger.org.hibernate.loader.plan=trace
# SQL Logging - HHH-6833
log4j.logger.org.hibernate.SQL=debug