merge master

This commit is contained in:
Strong Liu 2013-05-20 11:23:00 -07:00
commit a3184e16cb
110 changed files with 3491 additions and 902 deletions

View File

@ -483,3 +483,5 @@ subprojects { subProject ->
} }
} }
task release(type: Task, dependsOn: 'release:release')

View File

@ -26,7 +26,6 @@ package org.hibernate;
import java.io.Serializable; import java.io.Serializable;
import org.hibernate.procedure.ProcedureCall; import org.hibernate.procedure.ProcedureCall;
import org.hibernate.procedure.ProcedureCallMemento;
/** /**
* Contract methods shared between {@link Session} and {@link StatelessSession}. * Contract methods shared between {@link Session} and {@link StatelessSession}.

View File

@ -61,14 +61,20 @@ public class RegionFactoryInitiator implements StandardServiceInitiator<RegionFa
@Override @Override
@SuppressWarnings({ "unchecked" }) @SuppressWarnings({ "unchecked" })
public RegionFactory initiateService(Map configurationValues, ServiceRegistryImplementor registry) { public RegionFactory initiateService(Map configurationValues, ServiceRegistryImplementor registry) {
Properties p = new Properties(); final Properties p = new Properties();
if (configurationValues != null) { if (configurationValues != null) {
p.putAll( configurationValues ); p.putAll( configurationValues );
} }
boolean useSecondLevelCache = ConfigurationHelper.getBoolean( AvailableSettings.USE_SECOND_LEVEL_CACHE, final boolean useSecondLevelCache = ConfigurationHelper.getBoolean(
configurationValues, true ); AvailableSettings.USE_SECOND_LEVEL_CACHE,
boolean useQueryCache = ConfigurationHelper.getBoolean( AvailableSettings.USE_QUERY_CACHE, configurationValues ); configurationValues,
true
);
final boolean useQueryCache = ConfigurationHelper.getBoolean(
AvailableSettings.USE_QUERY_CACHE,
configurationValues
);
RegionFactory regionFactory = NoCachingRegionFactory.INSTANCE; RegionFactory regionFactory = NoCachingRegionFactory.INSTANCE;
@ -81,16 +87,6 @@ public class RegionFactoryInitiator implements StandardServiceInitiator<RegionFa
try { try {
regionFactory = registry.getService( StrategySelector.class ) regionFactory = registry.getService( StrategySelector.class )
.resolveStrategy( RegionFactory.class, setting ); .resolveStrategy( RegionFactory.class, setting );
// try {
// regionFactory = regionFactoryClass.getConstructor( Properties.class ).newInstance( p );
// }
// catch ( NoSuchMethodException e ) {
// // no constructor accepting Properties found, try no arg constructor
// LOG.debugf(
// "%s did not provide constructor accepting java.util.Properties; attempting no-arg constructor.",
// regionFactoryClass.getSimpleName() );
// regionFactory = regionFactoryClass.getConstructor().newInstance();
// }
} }
catch ( Exception e ) { catch ( Exception e ) {
throw new HibernateException( "could not instantiate RegionFactory [" + setting + "]", e ); throw new HibernateException( "could not instantiate RegionFactory [" + setting + "]", e );

View File

@ -209,6 +209,9 @@ public final class AnnotationBinder {
public static void bindDefaults(Mappings mappings) { public static void bindDefaults(Mappings mappings) {
Map defaults = mappings.getReflectionManager().getDefaults(); Map defaults = mappings.getReflectionManager().getDefaults();
// id generators ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{ {
List<SequenceGenerator> anns = ( List<SequenceGenerator> ) defaults.get( SequenceGenerator.class ); List<SequenceGenerator> anns = ( List<SequenceGenerator> ) defaults.get( SequenceGenerator.class );
if ( anns != null ) { if ( anns != null ) {
@ -231,6 +234,9 @@ public final class AnnotationBinder {
} }
} }
} }
// queries ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{ {
List<NamedQuery> anns = ( List<NamedQuery> ) defaults.get( NamedQuery.class ); List<NamedQuery> anns = ( List<NamedQuery> ) defaults.get( NamedQuery.class );
if ( anns != null ) { if ( anns != null ) {
@ -247,6 +253,9 @@ public final class AnnotationBinder {
} }
} }
} }
// result-set-mappings ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{ {
List<SqlResultSetMapping> anns = ( List<SqlResultSetMapping> ) defaults.get( SqlResultSetMapping.class ); List<SqlResultSetMapping> anns = ( List<SqlResultSetMapping> ) defaults.get( SqlResultSetMapping.class );
if ( anns != null ) { if ( anns != null ) {
@ -256,6 +265,8 @@ public final class AnnotationBinder {
} }
} }
// stored procs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{ {
final List<NamedStoredProcedureQuery> annotations = final List<NamedStoredProcedureQuery> annotations =
(List<NamedStoredProcedureQuery>) defaults.get( NamedStoredProcedureQuery.class ); (List<NamedStoredProcedureQuery>) defaults.get( NamedStoredProcedureQuery.class );
@ -265,7 +276,6 @@ public final class AnnotationBinder {
} }
} }
} }
{ {
final List<NamedStoredProcedureQueries> annotations = final List<NamedStoredProcedureQueries> annotations =
(List<NamedStoredProcedureQueries>) defaults.get( NamedStoredProcedureQueries.class ); (List<NamedStoredProcedureQueries>) defaults.get( NamedStoredProcedureQueries.class );

View File

@ -341,6 +341,7 @@ public class BinderHelper {
*/ */
if ( value instanceof ToOne ) { if ( value instanceof ToOne ) {
( (ToOne) value ).setReferencedPropertyName( syntheticPropertyName ); ( (ToOne) value ).setReferencedPropertyName( syntheticPropertyName );
( (ToOne) value ).setReferenceToPrimaryKey( syntheticPropertyName == null );
mappings.addUniquePropertyReference( ownerEntity.getEntityName(), syntheticPropertyName ); mappings.addUniquePropertyReference( ownerEntity.getEntityName(), syntheticPropertyName );
} }
else if ( value instanceof Collection ) { else if ( value instanceof Collection ) {

View File

@ -84,6 +84,8 @@ import org.hibernate.annotations.common.reflection.java.JavaReflectionManager;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.internal.StandardServiceRegistryImpl; import org.hibernate.boot.registry.internal.StandardServiceRegistryImpl;
import org.hibernate.cache.spi.GeneralDataRegion;
import org.hibernate.cfg.annotations.NamedEntityGraphDefinition;
import org.hibernate.cfg.annotations.NamedProcedureCallDefinition; import org.hibernate.cfg.annotations.NamedProcedureCallDefinition;
import org.hibernate.cfg.annotations.reflection.JPAMetadataProvider; import org.hibernate.cfg.annotations.reflection.JPAMetadataProvider;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver; import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
@ -217,6 +219,7 @@ public class Configuration implements Serializable {
protected Map<String, NamedSQLQueryDefinition> namedSqlQueries; protected Map<String, NamedSQLQueryDefinition> namedSqlQueries;
protected Map<String, NamedProcedureCallDefinition> namedProcedureCallMap; protected Map<String, NamedProcedureCallDefinition> namedProcedureCallMap;
protected Map<String, ResultSetMappingDefinition> sqlResultSetMappings; protected Map<String, ResultSetMappingDefinition> sqlResultSetMappings;
protected Map<String, NamedEntityGraphDefinition> namedEntityGraphMap;
protected Map<String, TypeDef> typeDefs; protected Map<String, TypeDef> typeDefs;
protected Map<String, FilterDefinition> filterDefinitions; protected Map<String, FilterDefinition> filterDefinitions;
@ -299,6 +302,7 @@ public class Configuration implements Serializable {
namedQueries = new HashMap<String,NamedQueryDefinition>(); namedQueries = new HashMap<String,NamedQueryDefinition>();
namedSqlQueries = new HashMap<String,NamedSQLQueryDefinition>(); namedSqlQueries = new HashMap<String,NamedSQLQueryDefinition>();
sqlResultSetMappings = new HashMap<String, ResultSetMappingDefinition>(); sqlResultSetMappings = new HashMap<String, ResultSetMappingDefinition>();
namedEntityGraphMap = new HashMap<String, NamedEntityGraphDefinition>();
typeDefs = new HashMap<String,TypeDef>(); typeDefs = new HashMap<String,TypeDef>();
filterDefinitions = new HashMap<String, FilterDefinition>(); filterDefinitions = new HashMap<String, FilterDefinition>();
@ -2619,6 +2623,12 @@ public class Configuration implements Serializable {
} }
} }
public java.util.Collection<NamedEntityGraphDefinition> getNamedEntityGraphs() {
return namedEntityGraphMap == null
? Collections.<NamedEntityGraphDefinition>emptyList()
: namedEntityGraphMap.values();
}
// Mappings impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Mappings impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -2886,6 +2896,16 @@ public class Configuration implements Serializable {
} }
} }
@Override
public void addNamedEntityGraphDefintion(NamedEntityGraphDefinition definition)
throws DuplicateMappingException {
final String name = definition.getRegisteredName();
final NamedEntityGraphDefinition previous = namedEntityGraphMap.put( name, definition );
if ( previous != null ) {
throw new DuplicateMappingException( "NamedEntityGraph", name );
}
}
public void addDefaultSQLQuery(String name, NamedSQLQueryDefinition query) { public void addDefaultSQLQuery(String name, NamedSQLQueryDefinition query) {
applySQLQuery( name, query ); applySQLQuery( name, query );
defaultNamedNativeQueryNames.add( name ); defaultNamedNativeQueryNames.add( name );

View File

@ -1620,6 +1620,7 @@ public final class HbmBinder {
if ( ukName != null ) { if ( ukName != null ) {
manyToOne.setReferencedPropertyName( ukName.getValue() ); manyToOne.setReferencedPropertyName( ukName.getValue() );
} }
manyToOne.setReferenceToPrimaryKey( manyToOne.getReferencedPropertyName() == null );
manyToOne.setReferencedEntityName( getEntityName( node, mappings ) ); manyToOne.setReferencedEntityName( getEntityName( node, mappings ) );
@ -1702,6 +1703,7 @@ public final class HbmBinder {
Attribute ukName = node.attribute( "property-ref" ); Attribute ukName = node.attribute( "property-ref" );
if ( ukName != null ) oneToOne.setReferencedPropertyName( ukName.getValue() ); if ( ukName != null ) oneToOne.setReferencedPropertyName( ukName.getValue() );
oneToOne.setReferenceToPrimaryKey( oneToOne.getReferencedPropertyName() == null );
oneToOne.setPropertyName( node.attributeValue( "name" ) ); oneToOne.setPropertyName( node.attributeValue( "name" ) );

View File

@ -36,6 +36,7 @@ import org.hibernate.MappingException;
import org.hibernate.annotations.AnyMetaDef; import org.hibernate.annotations.AnyMetaDef;
import org.hibernate.annotations.common.reflection.ReflectionManager; import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.annotations.common.reflection.XClass; import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.cfg.annotations.NamedEntityGraphDefinition;
import org.hibernate.cfg.annotations.NamedProcedureCallDefinition; import org.hibernate.cfg.annotations.NamedProcedureCallDefinition;
import org.hibernate.engine.ResultSetMappingDefinition; import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.spi.FilterDefinition; import org.hibernate.engine.spi.FilterDefinition;
@ -347,6 +348,15 @@ public interface Mappings {
*/ */
public void addNamedProcedureCallDefinition(NamedProcedureCallDefinition definition) throws DuplicateMappingException; public void addNamedProcedureCallDefinition(NamedProcedureCallDefinition definition) throws DuplicateMappingException;
/**
* Adds metadata for a named entity graph to this repository
*
* @param namedEntityGraphDefinition The procedure call information
*
* @throws DuplicateMappingException If an entity graph already exists with that name.
*/
public void addNamedEntityGraphDefintion(NamedEntityGraphDefinition namedEntityGraphDefinition);
/** /**
* Get the metadata for a named SQL result set mapping. * Get the metadata for a named SQL result set mapping.
* *

View File

@ -39,6 +39,7 @@ import org.hibernate.mapping.ManyToOne;
import org.hibernate.mapping.OneToOne; import org.hibernate.mapping.OneToOne;
import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property; import org.hibernate.mapping.Property;
import org.hibernate.mapping.Selectable;
import org.hibernate.mapping.SimpleValue; import org.hibernate.mapping.SimpleValue;
import org.hibernate.type.ForeignKeyDirection; import org.hibernate.type.ForeignKeyDirection;
@ -212,11 +213,9 @@ public class OneToOneSecondPass implements SecondPass {
propertyHolder.addProperty( prop, inferredData.getDeclaringClass() ); propertyHolder.addProperty( prop, inferredData.getDeclaringClass() );
} }
value.setReferencedPropertyName( mappedBy );
// HHH-6813 // HHH-6813
// If otherSide's id is derived, do not set EntityType#uniqueKeyPropertyName.
// EntityType#isReferenceToPrimaryKey() assumes that, if it's set,
// a PK is not referenced. Example:
//
// Foo: @Id long id, @OneToOne(mappedBy="foo") Bar bar // Foo: @Id long id, @OneToOne(mappedBy="foo") Bar bar
// Bar: @Id @OneToOne Foo foo // Bar: @Id @OneToOne Foo foo
boolean referencesDerivedId = false; boolean referencesDerivedId = false;
@ -227,8 +226,14 @@ public class OneToOneSecondPass implements SecondPass {
catch ( MappingException e ) { catch ( MappingException e ) {
// ignore // ignore
} }
String referencedPropertyName = referencesDerivedId ? null : mappedBy; boolean referenceToPrimaryKey = referencesDerivedId || mappedBy == null;
value.setReferencedPropertyName( referencedPropertyName ); value.setReferenceToPrimaryKey( referenceToPrimaryKey );
// If the other side is a derived ID, prevent an infinite
// loop of attempts to resolve identifiers.
if ( referencesDerivedId ) {
( (ManyToOne) otherSideProperty.getValue() ).setReferenceToPrimaryKey( false );
}
String propertyRef = value.getReferencedPropertyName(); String propertyRef = value.getReferencedPropertyName();
if ( propertyRef != null ) { if ( propertyRef != null ) {

View File

@ -1511,6 +1511,7 @@ public abstract class CollectionBinder {
( (ManyToOne) value ).setReferencedPropertyName( referencedPropertyName ); ( (ManyToOne) value ).setReferencedPropertyName( referencedPropertyName );
mappings.addUniquePropertyReference( referencedEntity.getEntityName(), referencedPropertyName ); mappings.addUniquePropertyReference( referencedEntity.getEntityName(), referencedPropertyName );
} }
( (ManyToOne) value ).setReferenceToPrimaryKey( referencedPropertyName == null );
value.createForeignKey(); value.createForeignKey();
} }
else { else {

View File

@ -31,6 +31,8 @@ import javax.persistence.Access;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.JoinTable; import javax.persistence.JoinTable;
import javax.persistence.NamedEntityGraph;
import javax.persistence.NamedEntityGraphs;
import javax.persistence.PrimaryKeyJoinColumn; import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.SecondaryTable; import javax.persistence.SecondaryTable;
import javax.persistence.SecondaryTables; import javax.persistence.SecondaryTables;
@ -83,7 +85,6 @@ import org.hibernate.cfg.ObjectNameSource;
import org.hibernate.cfg.PropertyHolder; import org.hibernate.cfg.PropertyHolder;
import org.hibernate.cfg.UniqueConstraintHolder; import org.hibernate.cfg.UniqueConstraintHolder;
import org.hibernate.engine.OptimisticLockStyle; import org.hibernate.engine.OptimisticLockStyle;
import org.hibernate.engine.internal.Versioning;
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle; import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
import org.hibernate.engine.spi.FilterDefinition; import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
@ -159,8 +160,27 @@ public class EntityBinder {
this.annotatedClass = annotatedClass; this.annotatedClass = annotatedClass;
bindEjb3Annotation( ejb3Ann ); bindEjb3Annotation( ejb3Ann );
bindHibernateAnnotation(); bindHibernateAnnotation();
processNamedEntityGraphs();
} }
private void processNamedEntityGraphs() {
processNamedEntityGraph( annotatedClass.getAnnotation( NamedEntityGraph.class ) );
final NamedEntityGraphs graphs = annotatedClass.getAnnotation( NamedEntityGraphs.class );
if ( graphs != null ) {
for ( NamedEntityGraph graph : graphs.value() ) {
processNamedEntityGraph( graph );
}
}
}
private void processNamedEntityGraph(NamedEntityGraph annotation) {
if ( annotation == null ) {
return;
}
mappings.addNamedEntityGraphDefintion( new NamedEntityGraphDefinition( annotation, name, persistentClass.getEntityName() ) );
}
@SuppressWarnings("SimplifiableConditionalExpression") @SuppressWarnings("SimplifiableConditionalExpression")
private void bindHibernateAnnotation() { private void bindHibernateAnnotation() {
{ {

View File

@ -0,0 +1,59 @@
/*
* 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.cfg.annotations;
import javax.persistence.NamedEntityGraph;
/**
* Models the definition of a {@link NamedEntityGraph} annotation
*
* @author Steve Ebersole
*/
public class NamedEntityGraphDefinition {
private final NamedEntityGraph annotation;
private final String jpaEntityName;
private final String entityName;
public NamedEntityGraphDefinition(NamedEntityGraph annotation, String jpaEntityName, String entityName) {
this.annotation = annotation;
this.jpaEntityName = jpaEntityName;
this.entityName = entityName;
}
public String getRegisteredName() {
return jpaEntityName;
}
public String getJpaEntityName() {
return jpaEntityName;
}
public String getEntityName() {
return entityName;
}
public NamedEntityGraph getAnnotation() {
return annotation;
}
}

View File

@ -299,6 +299,12 @@ public abstract class Dialect implements ConversionContext {
// database type mapping support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // database type mapping support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* Allows the Dialect to contribute additional types
*
* @param typeContributions Callback to contribute the types
* @param serviceRegistry The service registry
*/
public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
// by default, nothing to do // by default, nothing to do
} }
@ -1362,7 +1368,7 @@ public abstract class Dialect implements ConversionContext {
* @param lockOptions the lock options to apply * @param lockOptions the lock options to apply
* @return The appropriate <tt>FOR UPDATE OF column_list</tt> clause string. * @return The appropriate <tt>FOR UPDATE OF column_list</tt> clause string.
*/ */
@SuppressWarnings( {"unchecked"}) @SuppressWarnings({"unchecked", "UnusedParameters"})
public String getForUpdateString(String aliases, LockOptions lockOptions) { public String getForUpdateString(String aliases, LockOptions lockOptions) {
LockMode lockMode = lockOptions.getLockMode(); LockMode lockMode = lockOptions.getLockMode();
final Iterator<Map.Entry<String, LockMode>> itr = lockOptions.getAliasLockIterator(); final Iterator<Map.Entry<String, LockMode>> itr = lockOptions.getAliasLockIterator();
@ -1612,6 +1618,7 @@ public abstract class Dialect implements ConversionContext {
* *
* @throws SQLException Indicates problems registering the param. * @throws SQLException Indicates problems registering the param.
*/ */
@SuppressWarnings("UnusedParameters")
public int registerResultSetOutParameter(CallableStatement statement, String name) throws SQLException { public int registerResultSetOutParameter(CallableStatement statement, String name) throws SQLException {
throw new UnsupportedOperationException( throw new UnsupportedOperationException(
getClass().getName() + getClass().getName() +
@ -1644,6 +1651,7 @@ public abstract class Dialect implements ConversionContext {
* *
* @throws SQLException Indicates problems extracting the result set. * @throws SQLException Indicates problems extracting the result set.
*/ */
@SuppressWarnings("UnusedParameters")
public ResultSet getResultSet(CallableStatement statement, int position) throws SQLException { public ResultSet getResultSet(CallableStatement statement, int position) throws SQLException {
throw new UnsupportedOperationException( throw new UnsupportedOperationException(
getClass().getName() + " does not support resultsets via stored procedures" getClass().getName() + " does not support resultsets via stored procedures"
@ -1661,6 +1669,7 @@ public abstract class Dialect implements ConversionContext {
* *
* @throws SQLException Indicates problems extracting the result set. * @throws SQLException Indicates problems extracting the result set.
*/ */
@SuppressWarnings("UnusedParameters")
public ResultSet getResultSet(CallableStatement statement, String name) throws SQLException { public ResultSet getResultSet(CallableStatement statement, String name) throws SQLException {
throw new UnsupportedOperationException( throw new UnsupportedOperationException(
getClass().getName() + " does not support resultsets via stored procedures" getClass().getName() + " does not support resultsets via stored procedures"

View File

@ -40,7 +40,11 @@ import org.hibernate.service.spi.ServiceRegistryImplementor;
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@SuppressWarnings("deprecation")
public class DialectResolverInitiator implements StandardServiceInitiator<DialectResolver> { public class DialectResolverInitiator implements StandardServiceInitiator<DialectResolver> {
/**
* Singleton access
*/
public static final DialectResolverInitiator INSTANCE = new DialectResolverInitiator(); public static final DialectResolverInitiator INSTANCE = new DialectResolverInitiator();
@Override @Override

View File

@ -45,9 +45,9 @@ import org.hibernate.engine.jdbc.env.spi.QualifiedObjectNameSupport;
import org.hibernate.engine.jdbc.env.spi.SQLStateType; import org.hibernate.engine.jdbc.env.spi.SQLStateType;
import org.hibernate.engine.jdbc.env.spi.SchemaNameResolver; import org.hibernate.engine.jdbc.env.spi.SchemaNameResolver;
import org.hibernate.engine.jdbc.env.spi.StandardQualifiedObjectNameSupportImpl; import org.hibernate.engine.jdbc.env.spi.StandardQualifiedObjectNameSupportImpl;
import org.hibernate.engine.jdbc.internal.TypeInfo;
import org.hibernate.engine.jdbc.internal.TypeInfoExtracter; import org.hibernate.engine.jdbc.internal.TypeInfoExtracter;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper; import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.engine.jdbc.spi.TypeInfo;
import org.hibernate.exception.internal.SQLExceptionTypeDelegate; import org.hibernate.exception.internal.SQLExceptionTypeDelegate;
import org.hibernate.exception.internal.SQLStateConversionDelegate; import org.hibernate.exception.internal.SQLStateConversionDelegate;
import org.hibernate.exception.internal.StandardSQLExceptionConverter; import org.hibernate.exception.internal.StandardSQLExceptionConverter;

View File

@ -26,8 +26,8 @@ package org.hibernate.engine.jdbc.env.spi;
import java.util.Set; import java.util.Set;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.internal.TypeInfo;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper; import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.engine.jdbc.spi.TypeInfo;
import org.hibernate.metamodel.spi.relational.Identifier; import org.hibernate.metamodel.spi.relational.Identifier;
import org.hibernate.service.Service; import org.hibernate.service.Service;

View File

@ -70,7 +70,6 @@ public class JdbcServicesImpl implements JdbcServices, ServiceRegistryAwareServi
@Override @Override
public void configure(Map configValues) { public void configure(Map configValues) {
this.jdbcEnvironment = serviceRegistry.getService( JdbcEnvironment.class ); this.jdbcEnvironment = serviceRegistry.getService( JdbcEnvironment.class );
this.connectionProvider = serviceRegistry.getService( ConnectionProvider.class ); this.connectionProvider = serviceRegistry.getService( ConnectionProvider.class );
final boolean showSQL = ConfigurationHelper.getBoolean( Environment.SHOW_SQL, configValues, false ); final boolean showSQL = ConfigurationHelper.getBoolean( Environment.SHOW_SQL, configValues, false );
final boolean formatSQL = ConfigurationHelper.getBoolean( Environment.FORMAT_SQL, configValues, false ); final boolean formatSQL = ConfigurationHelper.getBoolean( Environment.FORMAT_SQL, configValues, false );

View File

@ -30,6 +30,9 @@ import java.util.LinkedHashSet;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.hibernate.engine.jdbc.spi.TypeInfo;
import org.hibernate.engine.jdbc.spi.TypeNullability;
import org.hibernate.engine.jdbc.spi.TypeSearchability;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.collections.ArrayHelper; import org.hibernate.internal.util.collections.ArrayHelper;

View File

@ -26,6 +26,8 @@ package org.hibernate.engine.jdbc.spi;
import java.sql.Connection; import java.sql.Connection;
/** /**
* A no-op adapter for ConnectionObserver.
*
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class ConnectionObserverAdapter implements ConnectionObserver { public class ConnectionObserverAdapter implements ConnectionObserver {

View File

@ -154,6 +154,7 @@ public interface JdbcCoordinator extends Serializable {
* @throws org.hibernate.TransactionException Indicates the time out period has already been exceeded. * @throws org.hibernate.TransactionException Indicates the time out period has already been exceeded.
*/ */
public int determineRemainingTransactionTimeOutPeriod(); public int determineRemainingTransactionTimeOutPeriod();
/** /**
* Register a JDBC statement. * Register a JDBC statement.
* *
@ -200,8 +201,14 @@ public interface JdbcCoordinator extends Serializable {
*/ */
public void releaseResources(); public void releaseResources();
/**
* Enable connection releases
*/
public void enableReleases(); public void enableReleases();
/**
* Disable connection releases
*/
public void disableReleases(); public void disableReleases();
/** /**
@ -211,5 +218,10 @@ public interface JdbcCoordinator extends Serializable {
*/ */
public void registerLastQuery(Statement statement); public void registerLastQuery(Statement statement);
/**
* Can this coordinator be serialized?
*
* @return {@code true} indicates the coordinator can be serialized.
*/
public boolean isReadyForSerialization(); public boolean isReadyForSerialization();
} }

View File

@ -23,8 +23,6 @@
*/ */
package org.hibernate.engine.jdbc.spi; package org.hibernate.engine.jdbc.spi;
import java.sql.ResultSet;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.LobCreationContext; import org.hibernate.engine.jdbc.LobCreationContext;
import org.hibernate.engine.jdbc.LobCreator; import org.hibernate.engine.jdbc.LobCreator;
@ -90,7 +88,7 @@ public interface JdbcServices extends Service {
public LobCreator getLobCreator(LobCreationContext lobCreationContext); public LobCreator getLobCreator(LobCreationContext lobCreationContext);
/** /**
* Obtain service for wrapping a {@link ResultSet} in a "column name cache" wrapper. * Obtain service for wrapping a {@link java.sql.ResultSet} in a "column name cache" wrapper.
* @return The ResultSet wrapper. * @return The ResultSet wrapper.
*/ */
public ResultSetWrapper getResultSetWrapper(); public ResultSetWrapper getResultSetWrapper();

View File

@ -79,13 +79,34 @@ public interface LogicalConnectionImplementor extends LogicalConnection {
*/ */
public void manualReconnect(Connection suppliedConnection); public void manualReconnect(Connection suppliedConnection);
/**
* Perform an aggressive release
*/
public void aggressiveRelease(); public void aggressiveRelease();
/**
* Release any held connection.
*
* @throws JDBCException Indicates a problem releasing the connection
*/
public void releaseConnection() throws JDBCException; public void releaseConnection() throws JDBCException;
/**
* Is this logical connection in auto-commit mode?
*
* @return {@code true} if auto-commit
*/
public boolean isAutoCommit(); public boolean isAutoCommit();
/**
* Callback to notify all registered observers of a connection being prepared.
*/
public void notifyObserversStatementPrepared(); public void notifyObserversStatementPrepared();
/**
* Does this logical connection wrap a user/application supplied connection?
*
* @return {@code true} if the underlying connection was user supplied.
*/
public boolean isUserSuppliedConnection(); public boolean isUserSuppliedConnection();
} }

View File

@ -35,74 +35,83 @@ import java.sql.Statement;
* TODO: This could eventually utilize the new Return interface. It would be * TODO: This could eventually utilize the new Return interface. It would be
* great to have a common API shared. * great to have a common API shared.
* *
* Generally the methods here dealing with CallableStatement are extremely limited, relying on the legacy
*
*
* @author Brett Meyer * @author Brett Meyer
* @author Steve Ebersole
*/ */
public interface ResultSetReturn { public interface ResultSetReturn {
/** /**
* Extract the ResultSet from the statement. If user passes {@link CallableStatement} * Extract the ResultSet from the PreparedStatement.
* reference, method calls {@link #extract(CallableStatement)} internally. * <p/>
* If user passes {@link CallableStatement} reference, this method calls {@link #extract(CallableStatement)}
* internally. Otherwise, generally speaking, {@link java.sql.PreparedStatement#executeQuery()} is called
* *
* @param statement * @param statement The PreparedStatement from which to extract the ResultSet
* *
* @return the ResultSet * @return The extracted ResultSet
*/ */
public ResultSet extract(PreparedStatement statement); public ResultSet extract(PreparedStatement statement);
/** /**
* Extract the ResultSet from the statement. * Extract the ResultSet from the CallableStatement. Note that this is the limited legacy form which delegates to
* {@link org.hibernate.dialect.Dialect#getResultSet}. Better option is to integrate
* {@link org.hibernate.procedure.ProcedureCall}-like hooks
* *
* @param statement * @param callableStatement The CallableStatement from which to extract the ResultSet
* *
* @return the ResultSet * @return The extracted ResultSet
*/ */
public ResultSet extract( CallableStatement statement ); public ResultSet extract(CallableStatement callableStatement);
/** /**
* Extract the ResultSet from the statement. * Performs the given SQL statement, expecting a ResultSet in return
* *
* @param statement * @param statement The JDBC Statement object to use
* @param sql * @param sql The SQL to execute
* *
* @return the ResultSet * @return The resulting ResultSet
*/ */
public ResultSet extract(Statement statement, String sql); public ResultSet extract(Statement statement, String sql);
/** /**
* Execute the Statement query and, if results in a ResultSet, extract it. * Execute the PreparedStatement return its first ResultSet, if any. If there is no ResultSet, returns {@code null}
* *
* @param statement * @param statement The PreparedStatement to execute
* *
* @return the ResultSet * @return The extracted ResultSet, or {@code null}
*/ */
public ResultSet execute(PreparedStatement statement); public ResultSet execute(PreparedStatement statement);
/** /**
* Execute the Statement query and, if results in a ResultSet, extract it. * Performs the given SQL statement, returning its first ResultSet, if any. If there is no ResultSet,
* returns {@code null}
* *
* @param statement * @param statement The JDBC Statement object to use
* @param sql * @param sql The SQL to execute
* *
* @return the ResultSet * @return The extracted ResultSet, or {@code null}
*/ */
public ResultSet execute(Statement statement, String sql); public ResultSet execute(Statement statement, String sql);
/** /**
* Execute the Statement queryUpdate. * Execute the PreparedStatement, returning its "affected row count".
* *
* @param statement * @param statement The PreparedStatement to execute
* *
* @return int * @return The {@link java.sql.PreparedStatement#executeUpdate()} result
*/ */
public int executeUpdate(PreparedStatement statement); public int executeUpdate(PreparedStatement statement);
/** /**
* Execute the Statement query and, if results in a ResultSet, extract it. * Execute the given SQL statement returning its "affected row count".
* *
* @param statement * @param statement The JDBC Statement object to use
* @param sql * @param sql The SQL to execute
* *
* @return the ResultSet * @return The {@link java.sql.PreparedStatement#executeUpdate(String)} result
*/ */
public int executeUpdate(Statement statement, String sql); public int executeUpdate(Statement statement, String sql);
} }

View File

@ -97,6 +97,12 @@ public class SqlStatementLogger {
logStatement( statement, FormatStyle.BASIC.getFormatter() ); logStatement( statement, FormatStyle.BASIC.getFormatter() );
} }
/**
* Log a SQL statement string using the specified formatter
*
* @param statement The SQL statement.
* @param formatter The formatter to use.
*/
public void logStatement(String statement, Formatter formatter) { public void logStatement(String statement, Formatter formatter) {
if ( format ) { if ( format ) {
if ( logToStdout || LOG.isDebugEnabled() ) { if ( logToStdout || LOG.isDebugEnabled() ) {

View File

@ -38,8 +38,6 @@ public interface StatementPreparer {
/** /**
* Create a statement. * Create a statement.
* *
* @param sql The SQL the statement to be created
*
* @return the statement * @return the statement
*/ */
public Statement createStatement(); public Statement createStatement();
@ -64,14 +62,15 @@ public interface StatementPreparer {
public PreparedStatement prepareStatement(String sql, boolean isCallable); public PreparedStatement prepareStatement(String sql, boolean isCallable);
/** /**
* Get a prepared statement to use for inserting using JDBC3 * Prepare an INSERT statement, specifying how auto-generated (by the database) keys should be handled. Really this
* {@link java.sql.PreparedStatement#getGeneratedKeys getGeneratedKeys} processing. * is a boolean, but JDBC opted to define it instead using 2 int constants:<ul>
*
* @param sql - the SQL for the statement to be prepared
* @param autoGeneratedKeys - a flag indicating whether auto-generated keys should be returned; one of<ul>
* <li>{@link PreparedStatement#RETURN_GENERATED_KEYS}</li> * <li>{@link PreparedStatement#RETURN_GENERATED_KEYS}</li>
* <li>{@link PreparedStatement#NO_GENERATED_KEYS}</li> * <li>{@link PreparedStatement#NO_GENERATED_KEYS}</li>
* </li> * </ul>
* Generated keys are accessed afterwards via {@link java.sql.PreparedStatement#getGeneratedKeys}
*
* @param sql The INSERT SQL
* @param autoGeneratedKeys The autoGeneratedKeys flag
* *
* @return the prepared statement * @return the prepared statement
* *
@ -79,10 +78,9 @@ public interface StatementPreparer {
*/ */
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys); public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys);
/** /**
* Get a prepared statement to use for inserting using JDBC3 * Prepare an INSERT statement, specifying columns which are auto-generated values to be returned.
* {@link java.sql.PreparedStatement#getGeneratedKeys getGeneratedKeys} processing. * Generated keys are accessed afterwards via {@link java.sql.PreparedStatement#getGeneratedKeys}
* *
* @param sql - the SQL for the statement to be prepared * @param sql - the SQL for the statement to be prepared
* @param columnNames The name of the columns to be returned in the generated keys result set. * @param columnNames The name of the columns to be returned in the generated keys result set.

View File

@ -21,15 +21,30 @@
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.engine.jdbc.internal; package org.hibernate.engine.jdbc.spi;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedHashSet;
import org.jboss.logging.Logger;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.collections.ArrayHelper;
/** /**
* Models type info extracted from {@link java.sql.DatabaseMetaData#getTypeInfo()} * Models type info extracted from {@link java.sql.DatabaseMetaData#getTypeInfo()}
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@SuppressWarnings("UnusedDeclaration")
public class TypeInfo { public class TypeInfo {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
TypeInfo.class.getName()
);
private final String typeName; private final String typeName;
private final int jdbcTypeCode; private final int jdbcTypeCode;
private final String[] createParams; private final String[] createParams;
@ -73,6 +88,64 @@ public class TypeInfo {
this.nullability = nullability; this.nullability = nullability;
} }
/**
* Extract the type information from the JDBC driver's DatabaseMetaData
*
* @param metaData The JDBC metadata
*
* @return The extracted type info
*/
public static LinkedHashSet<TypeInfo> extractTypeInfo(DatabaseMetaData metaData) {
final LinkedHashSet<TypeInfo> typeInfoSet = new LinkedHashSet<TypeInfo>();
try {
final ResultSet resultSet = metaData.getTypeInfo();
try {
while ( resultSet.next() ) {
typeInfoSet.add(
new TypeInfo(
resultSet.getString( "TYPE_NAME" ),
resultSet.getInt( "DATA_TYPE" ),
interpretCreateParams( resultSet.getString( "CREATE_PARAMS" ) ),
resultSet.getBoolean( "UNSIGNED_ATTRIBUTE" ),
resultSet.getInt( "PRECISION" ),
resultSet.getShort( "MINIMUM_SCALE" ),
resultSet.getShort( "MAXIMUM_SCALE" ),
resultSet.getBoolean( "FIXED_PREC_SCALE" ),
resultSet.getString( "LITERAL_PREFIX" ),
resultSet.getString( "LITERAL_SUFFIX" ),
resultSet.getBoolean( "CASE_SENSITIVE" ),
TypeSearchability.interpret( resultSet.getShort( "SEARCHABLE" ) ),
TypeNullability.interpret( resultSet.getShort( "NULLABLE" ) )
)
);
}
}
catch ( SQLException e ) {
LOG.unableToAccessTypeInfoResultSet( e.toString() );
}
finally {
try {
resultSet.close();
}
catch ( SQLException e ) {
LOG.unableToReleaseTypeInfoResultSet();
}
}
}
catch ( SQLException e ) {
LOG.unableToRetrieveTypeInfoResultSet( e.toString() );
}
return typeInfoSet;
}
private static String[] interpretCreateParams(String value) {
if ( value == null || value.length() == 0 ) {
return ArrayHelper.EMPTY_STRING_ARRAY;
}
return value.split( "," );
}
public String getTypeName() { public String getTypeName() {
return typeName; return typeName;
} }

View File

@ -21,7 +21,7 @@
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.engine.jdbc.internal; package org.hibernate.engine.jdbc.spi;
import java.sql.DatabaseMetaData; import java.sql.DatabaseMetaData;

View File

@ -21,7 +21,7 @@
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.engine.jdbc.internal; package org.hibernate.engine.jdbc.spi;
import java.sql.DatabaseMetaData; import java.sql.DatabaseMetaData;

View File

@ -30,7 +30,13 @@ import org.hibernate.HibernateException;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class JndiException extends HibernateException { public class JndiException extends HibernateException {
public JndiException(String string, Throwable root) { /**
super( string, root ); * Constructs a JndiException
*
* @param message Message explaining the exception condition
* @param cause The underlying cause
*/
public JndiException(String message, Throwable cause) {
super( message, cause );
} }
} }

View File

@ -31,7 +31,13 @@ import org.hibernate.HibernateException;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class JndiNameException extends HibernateException { public class JndiNameException extends HibernateException {
public JndiNameException(String string, Throwable root) { /**
super( string, root ); * Constructs a JndiNameException
*
* @param message Message explaining the exception condition
* @param cause The underlying cause.
*/
public JndiNameException(String message, Throwable cause) {
super( message, cause );
} }
} }

View File

@ -25,6 +25,8 @@ package org.hibernate.engine.jndi.internal;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.Map; import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.naming.Context; import javax.naming.Context;
import javax.naming.InitialContext; import javax.naming.InitialContext;
import javax.naming.InvalidNameException; import javax.naming.InvalidNameException;
@ -36,11 +38,11 @@ import javax.naming.event.NamespaceChangeListener;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.hibernate.cfg.Environment;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.engine.jndi.JndiException; import org.hibernate.engine.jndi.JndiException;
import org.hibernate.engine.jndi.JndiNameException; import org.hibernate.engine.jndi.JndiNameException;
import org.hibernate.engine.jndi.spi.JndiService; import org.hibernate.engine.jndi.spi.JndiService;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.jndi.JndiHelper;
/** /**
* Standard implementation of JNDI services. * Standard implementation of JNDI services.
@ -48,19 +50,66 @@ import org.hibernate.internal.util.jndi.JndiHelper;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class JndiServiceImpl implements JndiService { public class JndiServiceImpl implements JndiService {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, JndiServiceImpl.class.getName()); CoreMessageLogger.class,
JndiServiceImpl.class.getName()
);
private final Hashtable initialContextSettings; private final Hashtable initialContextSettings;
/**
* Constructs a JndiServiceImpl
*
* @param configurationValues Map of configuration settings, some of which apply to JNDI support.
*/
public JndiServiceImpl(Map configurationValues) { public JndiServiceImpl(Map configurationValues) {
this.initialContextSettings = JndiHelper.extractJndiProperties( configurationValues ); this.initialContextSettings = extractJndiProperties( configurationValues );
}
/**
* Given a hodgepodge of properties, extract out the ones relevant for JNDI interaction.
*
* @param configurationValues The map of config values
*
* @return The extracted JNDI specific properties.
*/
@SuppressWarnings({ "unchecked" })
public static Properties extractJndiProperties(Map configurationValues) {
final Properties jndiProperties = new Properties();
for ( Map.Entry entry : (Set<Map.Entry>) configurationValues.entrySet() ) {
if ( !String.class.isInstance( entry.getKey() ) ) {
continue;
}
final String propertyName = (String) entry.getKey();
final Object propertyValue = entry.getValue();
if ( propertyName.startsWith( Environment.JNDI_PREFIX ) ) {
// write the IntialContextFactory class and provider url to the result only if they are
// non-null; this allows the environmental defaults (if any) to remain in effect
if ( Environment.JNDI_CLASS.equals( propertyName ) ) {
if ( propertyValue != null ) {
jndiProperties.put( Context.INITIAL_CONTEXT_FACTORY, propertyValue );
}
}
else if ( Environment.JNDI_URL.equals( propertyName ) ) {
if ( propertyValue != null ) {
jndiProperties.put( Context.PROVIDER_URL, propertyValue );
}
}
else {
final String passThruPropertyname = propertyName.substring( Environment.JNDI_PREFIX.length() + 1 );
jndiProperties.put( passThruPropertyname, propertyValue );
}
}
}
return jndiProperties;
} }
@Override @Override
public Object locate(String jndiName) { public Object locate(String jndiName) {
InitialContext initialContext = buildInitialContext(); final InitialContext initialContext = buildInitialContext();
Name name = parseName( jndiName, initialContext ); final Name name = parseName( jndiName, initialContext );
try { try {
return initialContext.lookup( name ); return initialContext.lookup( name );
} }
@ -104,8 +153,8 @@ public class JndiServiceImpl implements JndiService {
@Override @Override
public void bind(String jndiName, Object value) { public void bind(String jndiName, Object value) {
InitialContext initialContext = buildInitialContext(); final InitialContext initialContext = buildInitialContext();
Name name = parseName( jndiName, initialContext ); final Name name = parseName( jndiName, initialContext );
try { try {
bind( name, value, initialContext ); bind( name, value, initialContext );
} }
@ -172,8 +221,8 @@ public class JndiServiceImpl implements JndiService {
@Override @Override
public void unbind(String jndiName) { public void unbind(String jndiName) {
InitialContext initialContext = buildInitialContext(); final InitialContext initialContext = buildInitialContext();
Name name = parseName( jndiName, initialContext ); final Name name = parseName( jndiName, initialContext );
try { try {
initialContext.unbind( name ); initialContext.unbind( name );
} }
@ -187,8 +236,8 @@ public class JndiServiceImpl implements JndiService {
@Override @Override
public void addListener(String jndiName, NamespaceChangeListener listener) { public void addListener(String jndiName, NamespaceChangeListener listener) {
InitialContext initialContext = buildInitialContext(); final InitialContext initialContext = buildInitialContext();
Name name = parseName( jndiName, initialContext ); final Name name = parseName( jndiName, initialContext );
try { try {
( (EventContext) initialContext ).addNamingListener( name, EventContext.OBJECT_SCOPE, listener ); ( (EventContext) initialContext ).addNamingListener( name, EventContext.OBJECT_SCOPE, listener );
} }

View File

@ -35,6 +35,9 @@ import org.hibernate.service.spi.ServiceRegistryImplementor;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class JndiServiceInitiator implements StandardServiceInitiator<JndiService> { public class JndiServiceInitiator implements StandardServiceInitiator<JndiService> {
/**
* Singleton access
*/
public static final JndiServiceInitiator INSTANCE = new JndiServiceInitiator(); public static final JndiServiceInitiator INSTANCE = new JndiServiceInitiator();
@Override @Override

View File

@ -0,0 +1,4 @@
/**
* Internal contracts defining the JNDI support within Hibernate
*/
package org.hibernate.engine.jndi.internal;

View File

@ -0,0 +1,4 @@
/**
* Support for JNDI within Hibernate
*/
package org.hibernate.engine.jndi;

View File

@ -0,0 +1,4 @@
/**
* The SPI contracts for Hibernate JNDI support
*/
package org.hibernate.engine.jndi.spi;

View File

@ -27,6 +27,7 @@ import javax.transaction.SystemException;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.hibernate.HibernateException;
import org.hibernate.TransactionException; import org.hibernate.TransactionException;
import org.hibernate.cfg.Settings; import org.hibernate.cfg.Settings;
import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper; import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper;
@ -56,9 +57,9 @@ public class SynchronizationCallbackCoordinatorImpl implements SynchronizationCa
private AfterCompletionAction afterCompletionAction; private AfterCompletionAction afterCompletionAction;
private ExceptionMapper exceptionMapper; private ExceptionMapper exceptionMapper;
private long registrationThreadId; private volatile long registrationThreadId;
private final int NO_STATUS = -1; private final int NO_STATUS = -1;
private int delayedCompletionHandlingStatus; private volatile int delayedCompletionHandlingStatus;
public SynchronizationCallbackCoordinatorImpl(TransactionCoordinator transactionCoordinator) { public SynchronizationCallbackCoordinatorImpl(TransactionCoordinator transactionCoordinator) {
this.transactionCoordinator = transactionCoordinator; this.transactionCoordinator = transactionCoordinator;
@ -154,11 +155,12 @@ public class SynchronizationCallbackCoordinatorImpl implements SynchronizationCa
if ( delayedCompletionHandlingStatus != NO_STATUS ) { if ( delayedCompletionHandlingStatus != NO_STATUS ) {
doAfterCompletion( delayedCompletionHandlingStatus ); doAfterCompletion( delayedCompletionHandlingStatus );
delayedCompletionHandlingStatus = NO_STATUS; delayedCompletionHandlingStatus = NO_STATUS;
throw new HibernateException("Transaction was rolled back in a different thread!");
} }
} }
private void doAfterCompletion(int status) { private void doAfterCompletion(int status) {
LOG.tracev( "Transaction after completion callback [status={0}]", status ); LOG.tracev( "Transaction afterCompletion callback [status={0}]", status );
try { try {
afterCompletionAction.doAction( transactionCoordinator, status ); afterCompletionAction.doAction( transactionCoordinator, status );

View File

@ -74,9 +74,11 @@ public class DefaultInitializeCollectionEventListener implements InitializeColle
source source
); );
if ( foundInCache && traceEnabled ) { if ( foundInCache ) {
if ( traceEnabled ) {
LOG.trace( "Collection initialized from cache" ); LOG.trace( "Collection initialized from cache" );
} }
}
else { else {
if ( traceEnabled ) { if ( traceEnabled ) {
LOG.trace( "Collection not cached" ); LOG.trace( "Collection not cached" );

View File

@ -94,6 +94,8 @@ public class JoinProcessor implements SqlTokenTypes {
return JoinType.INNER_JOIN; return JoinType.INNER_JOIN;
case RIGHT_OUTER: case RIGHT_OUTER:
return JoinType.RIGHT_OUTER_JOIN; return JoinType.RIGHT_OUTER_JOIN;
case FULL:
return JoinType.FULL_JOIN;
default: default:
throw new AssertionFailure( "undefined join type " + astJoinType ); throw new AssertionFailure( "undefined join type " + astJoinType );
} }

View File

@ -23,17 +23,16 @@
*/ */
package org.hibernate.internal.util.jndi; package org.hibernate.internal.util.jndi;
import java.util.Hashtable;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.naming.Context; import javax.naming.Context;
import javax.naming.InitialContext; import javax.naming.InitialContext;
import javax.naming.Name; import javax.naming.Name;
import javax.naming.NameNotFoundException; import javax.naming.NameNotFoundException;
import javax.naming.NamingException; import javax.naming.NamingException;
import java.util.Hashtable;
import java.util.Map;
import java.util.Properties;
import org.hibernate.cfg.Environment; import org.hibernate.engine.jndi.internal.JndiServiceImpl;
/** /**
* Helper for dealing with JNDI. * Helper for dealing with JNDI.
@ -54,42 +53,12 @@ public final class JndiHelper {
*/ */
@SuppressWarnings({ "unchecked" }) @SuppressWarnings({ "unchecked" })
public static Properties extractJndiProperties(Map configurationValues) { public static Properties extractJndiProperties(Map configurationValues) {
final Properties jndiProperties = new Properties(); return JndiServiceImpl.extractJndiProperties( configurationValues );
for ( Map.Entry entry : (Set<Map.Entry>) configurationValues.entrySet() ) {
if ( !String.class.isInstance( entry.getKey() ) ) {
continue;
}
final String propertyName = (String) entry.getKey();
final Object propertyValue = entry.getValue();
if ( propertyName.startsWith( Environment.JNDI_PREFIX ) ) {
// write the IntialContextFactory class and provider url to the result only if they are
// non-null; this allows the environmental defaults (if any) to remain in effect
if ( Environment.JNDI_CLASS.equals( propertyName ) ) {
if ( propertyValue != null ) {
jndiProperties.put( Context.INITIAL_CONTEXT_FACTORY, propertyValue );
}
}
else if ( Environment.JNDI_URL.equals( propertyName ) ) {
if ( propertyValue != null ) {
jndiProperties.put( Context.PROVIDER_URL, propertyValue );
}
}
else {
final String passThruPropertyname = propertyName.substring( Environment.JNDI_PREFIX.length() + 1 );
jndiProperties.put( passThruPropertyname, propertyValue );
}
}
}
return jndiProperties;
} }
public static InitialContext getInitialContext(Properties props) throws NamingException { public static InitialContext getInitialContext(Properties props) throws NamingException {
Hashtable hash = extractJndiProperties(props); final Hashtable hash = extractJndiProperties( props );
return hash.size()==0 ? return hash.size() == 0 ? new InitialContext() : new InitialContext( hash );
new InitialContext() :
new InitialContext(hash);
} }
/** /**
@ -108,7 +77,7 @@ public final class JndiHelper {
catch (Exception e) { catch (Exception e) {
Name n = ctx.getNameParser( "" ).parse( name ); Name n = ctx.getNameParser( "" ).parse( name );
while ( n.size() > 1 ) { while ( n.size() > 1 ) {
String ctxName = n.get(0); final String ctxName = n.get( 0 );
Context subctx = null; Context subctx = null;
try { try {

View File

@ -59,11 +59,8 @@ public abstract class AbstractJoinableAssociationImpl implements JoinableAssocia
boolean hasRestriction, boolean hasRestriction,
Map<String, Filter> enabledFilters) throws MappingException { Map<String, Filter> enabledFilters) throws MappingException {
this.propertyPath = currentFetch.getPropertyPath(); this.propertyPath = currentFetch.getPropertyPath();
final OuterJoinLoadable ownerPersister = (OuterJoinLoadable) currentFetch.getOwner().retrieveFetchSourcePersister();
final int propertyNumber = ownerPersister.getEntityMetamodel().getPropertyIndex( currentFetch.getOwnerPropertyName() );
final boolean isNullable = ownerPersister.isSubclassPropertyNullable( propertyNumber );
if ( currentFetch.getFetchStrategy().getStyle() == FetchStyle.JOIN ) { if ( currentFetch.getFetchStrategy().getStyle() == FetchStyle.JOIN ) {
joinType = isNullable ? JoinType.LEFT_OUTER_JOIN : JoinType.INNER_JOIN; joinType = currentFetch.isNullable() ? JoinType.LEFT_OUTER_JOIN : JoinType.INNER_JOIN;
} }
else { else {
joinType = JoinType.NONE; joinType = JoinType.NONE;

View File

@ -27,7 +27,6 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.hibernate.cfg.NotYetImplementedException; import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.engine.internal.JoinHelper;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.hibernate.loader.CollectionAliases; import org.hibernate.loader.CollectionAliases;
@ -36,6 +35,8 @@ import org.hibernate.loader.EntityAliases;
import org.hibernate.loader.GeneratedCollectionAliases; import org.hibernate.loader.GeneratedCollectionAliases;
import org.hibernate.loader.plan.spi.CollectionReference; import org.hibernate.loader.plan.spi.CollectionReference;
import org.hibernate.loader.plan.spi.CollectionReturn; import org.hibernate.loader.plan.spi.CollectionReturn;
import org.hibernate.loader.plan.spi.CompositeElementGraph;
import org.hibernate.loader.plan.spi.CompositeIndexGraph;
import org.hibernate.loader.plan.spi.EntityReference; import org.hibernate.loader.plan.spi.EntityReference;
import org.hibernate.loader.plan.spi.EntityReturn; import org.hibernate.loader.plan.spi.EntityReturn;
import org.hibernate.loader.plan.spi.Fetch; import org.hibernate.loader.plan.spi.Fetch;
@ -46,7 +47,6 @@ import org.hibernate.loader.spi.LoadQueryAliasResolutionContext;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Loadable; import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.type.EntityType; import org.hibernate.type.EntityType;
/** /**
@ -214,9 +214,18 @@ public class LoadQueryAliasResolutionContextImpl implements LoadQueryAliasResolu
if ( EntityReference.class.isInstance( currentFetch.getOwner() ) ) { if ( EntityReference.class.isInstance( currentFetch.getOwner() ) ) {
lhsAlias = resolveEntityTableAlias( (EntityReference) currentFetch.getOwner() ); lhsAlias = resolveEntityTableAlias( (EntityReference) currentFetch.getOwner() );
} }
else { else if ( CompositeElementGraph.class.isInstance( currentFetch.getOwner() ) ) {
throw new NotYetImplementedException( "Cannot determine LHS alias for a FetchOwner that is not an EntityReference yet." ); CompositeElementGraph compositeElementGraph = (CompositeElementGraph) currentFetch.getOwner();
lhsAlias = resolveCollectionTableAlias( compositeElementGraph.getCollectionReference() );
} }
else if ( CompositeIndexGraph.class.isInstance( currentFetch.getOwner() ) ) {
CompositeIndexGraph compositeIndexGraph = (CompositeIndexGraph) currentFetch.getOwner();
lhsAlias = resolveCollectionTableAlias( compositeIndexGraph.getCollectionReference() );
}
else {
throw new NotYetImplementedException( "Cannot determine LHS alias for FetchOwner." );
}
final String[] aliasedLhsColumnNames = StringHelper.qualify( lhsAlias, currentFetch.getColumnNames() );
final String rhsAlias; final String rhsAlias;
if ( EntityReference.class.isInstance( currentFetch ) ) { if ( EntityReference.class.isInstance( currentFetch ) ) {
rhsAlias = resolveEntityTableAlias( (EntityReference) currentFetch ); rhsAlias = resolveEntityTableAlias( (EntityReference) currentFetch );
@ -229,15 +238,6 @@ public class LoadQueryAliasResolutionContextImpl implements LoadQueryAliasResolu
} }
// TODO: can't this be found in CollectionAliases or EntityAliases? should be moved to LoadQueryAliasResolutionContextImpl // TODO: can't this be found in CollectionAliases or EntityAliases? should be moved to LoadQueryAliasResolutionContextImpl
final OuterJoinLoadable fetchSourcePersister = (OuterJoinLoadable) currentFetch.getOwner().retrieveFetchSourcePersister();
final int propertyNumber = fetchSourcePersister.getEntityMetamodel().getPropertyIndex( currentFetch.getOwnerPropertyName() );
final String[] aliasedLhsColumnNames = JoinHelper.getAliasedLHSColumnNames(
joinableAssociation.getAssociationType(),
lhsAlias,
propertyNumber,
fetchSourcePersister,
sessionFactory
);
aliases = new JoinableAssociationAliasesImpl( lhsAlias, aliasedLhsColumnNames, rhsAlias ); aliases = new JoinableAssociationAliasesImpl( lhsAlias, aliasedLhsColumnNames, rhsAlias );
aliasesByJoinableAssociation.put( joinableAssociation, aliases ); aliasesByJoinableAssociation.put( joinableAssociation, aliases );

View File

@ -33,6 +33,7 @@ import org.hibernate.loader.plan.spi.FetchOwner;
import org.hibernate.loader.plan.spi.build.LoadPlanBuildingContext; import org.hibernate.loader.plan.spi.build.LoadPlanBuildingContext;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition; import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition; import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.type.EntityType;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
@ -63,6 +64,7 @@ public class LoadPlanBuildingHelper {
LockMode.NONE, // todo : for now LockMode.NONE, // todo : for now
fetchOwner, fetchOwner,
attributeDefinition.getName(), attributeDefinition.getName(),
(EntityType) attributeDefinition.getType(),
fetchStrategy fetchStrategy
); );
} }
@ -73,7 +75,7 @@ public class LoadPlanBuildingHelper {
LoadPlanBuildingContext loadPlanBuildingContext) { LoadPlanBuildingContext loadPlanBuildingContext) {
return new CompositeFetch( return new CompositeFetch(
loadPlanBuildingContext.getSessionFactory(), loadPlanBuildingContext.getSessionFactory(),
(AbstractFetchOwner) fetchOwner, fetchOwner,
attributeDefinition.getName() attributeDefinition.getName()
); );
} }

View File

@ -27,20 +27,24 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.hibernate.LockMode; import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
import org.hibernate.loader.plan.spi.build.LoadPlanBuildingContext;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.type.Type;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
* @author Gail Badner
*/ */
public abstract class AbstractFetchOwner extends AbstractPlanNode implements FetchOwner { public abstract class AbstractFetchOwner extends AbstractPlanNode implements FetchOwner {
private final LockMode lockMode;
private List<Fetch> fetches; private List<Fetch> fetches;
public AbstractFetchOwner(SessionFactoryImplementor factory, LockMode lockMode) { public AbstractFetchOwner(SessionFactoryImplementor factory) {
super( factory ); super( factory );
this.lockMode = lockMode;
validate(); validate();
} }
@ -50,11 +54,10 @@ public abstract class AbstractFetchOwner extends AbstractPlanNode implements Fet
/** /**
* A "copy" constructor. Used while making clones/copies of this. * A "copy" constructor. Used while making clones/copies of this.
* *
* @param original * @param original - the original object to copy.
*/ */
protected AbstractFetchOwner(AbstractFetchOwner original, CopyContext copyContext) { protected AbstractFetchOwner(AbstractFetchOwner original, CopyContext copyContext) {
super( original ); super( original );
this.lockMode = original.lockMode;
validate(); validate();
copyContext.getReturnGraphVisitationStrategy().startingFetches( original ); copyContext.getReturnGraphVisitationStrategy().startingFetches( original );
@ -62,6 +65,7 @@ public abstract class AbstractFetchOwner extends AbstractPlanNode implements Fet
this.fetches = Collections.emptyList(); this.fetches = Collections.emptyList();
} }
else { else {
// TODO: don't think this is correct...
List<Fetch> fetchesCopy = new ArrayList<Fetch>(); List<Fetch> fetchesCopy = new ArrayList<Fetch>();
for ( Fetch fetch : fetches ) { for ( Fetch fetch : fetches ) {
fetchesCopy.add( fetch.makeCopy( copyContext, this ) ); fetchesCopy.add( fetch.makeCopy( copyContext, this ) );
@ -71,11 +75,6 @@ public abstract class AbstractFetchOwner extends AbstractPlanNode implements Fet
copyContext.getReturnGraphVisitationStrategy().finishingFetches( original ); copyContext.getReturnGraphVisitationStrategy().finishingFetches( original );
} }
public LockMode getLockMode() {
return lockMode;
}
@Override
public void addFetch(Fetch fetch) { public void addFetch(Fetch fetch) {
if ( fetch.getOwner() != this ) { if ( fetch.getOwner() != this ) {
throw new IllegalArgumentException( "Fetch and owner did not match" ); throw new IllegalArgumentException( "Fetch and owner did not match" );
@ -92,4 +91,55 @@ public abstract class AbstractFetchOwner extends AbstractPlanNode implements Fet
public Fetch[] getFetches() { public Fetch[] getFetches() {
return fetches == null ? NO_FETCHES : fetches.toArray( new Fetch[ fetches.size() ] ); return fetches == null ? NO_FETCHES : fetches.toArray( new Fetch[ fetches.size() ] );
} }
protected abstract FetchOwnerDelegate getFetchOwnerDelegate();
@Override
public boolean isNullable(Fetch fetch) {
return getFetchOwnerDelegate().isNullable( fetch );
}
@Override
public Type getType(Fetch fetch) {
return getFetchOwnerDelegate().getType( fetch );
}
@Override
public String[] getColumnNames(Fetch fetch) {
return getFetchOwnerDelegate().getColumnNames( fetch );
}
@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 );
}
} }

View File

@ -24,7 +24,6 @@
package org.hibernate.loader.plan.spi; package org.hibernate.loader.plan.spi;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchStrategy; import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
@ -42,11 +41,10 @@ public abstract class AbstractSingularAttributeFetch extends AbstractFetchOwner
public AbstractSingularAttributeFetch( public AbstractSingularAttributeFetch(
SessionFactoryImplementor factory, SessionFactoryImplementor factory,
LockMode lockMode,
FetchOwner owner, FetchOwner owner,
String ownerProperty, String ownerProperty,
FetchStrategy fetchStrategy) { FetchStrategy fetchStrategy) {
super( factory, lockMode ); super( factory );
this.owner = owner; this.owner = owner;
this.ownerProperty = ownerProperty; this.ownerProperty = ownerProperty;
this.fetchStrategy = fetchStrategy; this.fetchStrategy = fetchStrategy;
@ -77,6 +75,16 @@ public abstract class AbstractSingularAttributeFetch extends AbstractFetchOwner
return ownerProperty; return ownerProperty;
} }
@Override
public boolean isNullable() {
return owner.isNullable( this );
}
@Override
public String[] getColumnNames() {
return owner.getColumnNames( this );
}
@Override @Override
public FetchStrategy getFetchStrategy() { public FetchStrategy getFetchStrategy() {
return fetchStrategy; return fetchStrategy;

View File

@ -28,8 +28,10 @@ import java.sql.SQLException;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.engine.FetchStrategy; import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.internal.JoinHelper;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.spi.ResultSetProcessingContext; import org.hibernate.loader.spi.ResultSetProcessingContext;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.type.CollectionType; import org.hibernate.type.CollectionType;
/** /**
@ -74,6 +76,16 @@ public class CollectionFetch extends AbstractCollectionReference implements Fetc
return getPropertyPath().getProperty(); return getPropertyPath().getProperty();
} }
@Override
public boolean isNullable() {
return true;
}
@Override
public String[] getColumnNames() {
return getOwner().getColumnNames( this );
}
@Override @Override
public FetchStrategy getFetchStrategy() { public FetchStrategy getFetchStrategy() {
return fetchStrategy; return fetchStrategy;

View File

@ -1,29 +1,24 @@
package org.hibernate.loader.plan.spi; package org.hibernate.loader.plan.spi;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.engine.FetchStrategy; import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.PropertyPath; import org.hibernate.loader.PropertyPath;
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
import org.hibernate.loader.plan.spi.build.LoadPlanBuildingContext; import org.hibernate.loader.plan.spi.build.LoadPlanBuildingContext;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition; import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition; import org.hibernate.type.CompositeType;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class CompositeElementGraph extends AbstractPlanNode implements FetchableCollectionElement { public class CompositeElementGraph extends AbstractFetchOwner implements FetchableCollectionElement {
private final CollectionReference collectionReference; private final CollectionReference collectionReference;
private final PropertyPath propertyPath; private final PropertyPath propertyPath;
private final CollectionPersister collectionPersister; private final CollectionPersister collectionPersister;
private final FetchOwnerDelegate fetchOwnerDelegate;
private List<Fetch> fetches;
public CompositeElementGraph( public CompositeElementGraph(
SessionFactoryImplementor sessionFactory, SessionFactoryImplementor sessionFactory,
@ -34,39 +29,24 @@ public class CompositeElementGraph extends AbstractPlanNode implements Fetchable
this.collectionReference = collectionReference; this.collectionReference = collectionReference;
this.collectionPersister = collectionReference.getCollectionPersister(); this.collectionPersister = collectionReference.getCollectionPersister();
this.propertyPath = collectionPath.append( "<elements>" ); this.propertyPath = collectionPath.append( "<elements>" );
this.fetchOwnerDelegate = new CompositeFetchOwnerDelegate(
sessionFactory,
(CompositeType) collectionPersister.getElementType(),
( (QueryableCollection) collectionPersister ).getElementColumnNames()
);
} }
public CompositeElementGraph(CompositeElementGraph original, CopyContext copyContext) { public CompositeElementGraph(CompositeElementGraph original, CopyContext copyContext) {
super( original ); super( original, copyContext );
this.collectionReference = original.collectionReference; this.collectionReference = original.collectionReference;
this.collectionPersister = original.collectionPersister; this.collectionPersister = original.collectionPersister;
this.propertyPath = original.propertyPath; this.propertyPath = original.propertyPath;
this.fetchOwnerDelegate = original.fetchOwnerDelegate;
copyContext.getReturnGraphVisitationStrategy().startingFetches( original );
if ( fetches == null || fetches.size() == 0 ) {
this.fetches = Collections.emptyList();
}
else {
List<Fetch> fetchesCopy = new ArrayList<Fetch>();
for ( Fetch fetch : fetches ) {
fetchesCopy.add( fetch.makeCopy( copyContext, this ) );
}
this.fetches = fetchesCopy;
}
copyContext.getReturnGraphVisitationStrategy().finishingFetches( original );
} }
@Override @Override
public void addFetch(Fetch fetch) { public CollectionReference getCollectionReference() {
if ( fetches == null ) { return collectionReference;
fetches = new ArrayList<Fetch>();
}
fetches.add( fetch );
}
@Override
public Fetch[] getFetches() {
return fetches == null ? NO_FETCHES : fetches.toArray( new Fetch[ fetches.size() ] );
} }
@Override @Override
@ -83,6 +63,16 @@ public class CompositeElementGraph extends AbstractPlanNode implements Fetchable
return propertyPath; return propertyPath;
} }
@Override
public CompositeElementGraph makeCopy(CopyContext copyContext) {
return new CompositeElementGraph( this, copyContext );
}
@Override
protected FetchOwnerDelegate getFetchOwnerDelegate() {
return fetchOwnerDelegate;
}
@Override @Override
public CollectionFetch buildCollectionFetch( public CollectionFetch buildCollectionFetch(
AssociationAttributeDefinition attributeDefinition, AssociationAttributeDefinition attributeDefinition,
@ -90,29 +80,4 @@ public class CompositeElementGraph extends AbstractPlanNode implements Fetchable
LoadPlanBuildingContext loadPlanBuildingContext) { LoadPlanBuildingContext loadPlanBuildingContext) {
throw new HibernateException( "Collection composite element cannot define collections" ); 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 );
}
@Override
public CompositeElementGraph makeCopy(CopyContext copyContext) {
return new CompositeElementGraph( this, copyContext );
}
} }

View File

@ -25,17 +25,17 @@ package org.hibernate.loader.plan.spi;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchStrategy; import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming; import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
import org.hibernate.loader.plan.spi.build.LoadPlanBuildingContext; import org.hibernate.loader.plan.spi.build.LoadPlanBuildingContext;
import org.hibernate.loader.spi.ResultSetProcessingContext; import org.hibernate.loader.spi.ResultSetProcessingContext;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition; import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition; import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.type.CompositeType;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
@ -43,15 +43,28 @@ import org.hibernate.persister.walking.spi.CompositionDefinition;
public class CompositeFetch extends AbstractSingularAttributeFetch { public class CompositeFetch extends AbstractSingularAttributeFetch {
public static final FetchStrategy FETCH_PLAN = new FetchStrategy( FetchTiming.IMMEDIATE, FetchStyle.JOIN ); public static final FetchStrategy FETCH_PLAN = new FetchStrategy( FetchTiming.IMMEDIATE, FetchStyle.JOIN );
private final FetchOwnerDelegate delegate;
public CompositeFetch( public CompositeFetch(
SessionFactoryImplementor sessionFactory, SessionFactoryImplementor sessionFactory,
FetchOwner owner, FetchOwner owner,
String ownerProperty) { String ownerProperty) {
super( sessionFactory, LockMode.NONE, owner, ownerProperty, FETCH_PLAN ); super( sessionFactory, owner, ownerProperty, FETCH_PLAN );
this.delegate = new CompositeFetchOwnerDelegate(
sessionFactory,
(CompositeType) getOwner().getType( this ),
getOwner().getColumnNames( this )
);
} }
public CompositeFetch(CompositeFetch original, CopyContext copyContext, FetchOwner fetchOwnerCopy) { public CompositeFetch(CompositeFetch original, CopyContext copyContext, FetchOwner fetchOwnerCopy) {
super( original, copyContext, fetchOwnerCopy ); super( original, copyContext, fetchOwnerCopy );
this.delegate = original.getFetchOwnerDelegate();
}
@Override
protected FetchOwnerDelegate getFetchOwnerDelegate() {
return delegate;
} }
@Override @Override
@ -72,13 +85,18 @@ public class CompositeFetch extends AbstractSingularAttributeFetch {
AssociationAttributeDefinition attributeDefinition, AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy, FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) { LoadPlanBuildingContext loadPlanBuildingContext) {
return null; //To change body of implemented methods use File | Settings | File Templates. return LoadPlanBuildingHelper.buildStandardEntityFetch(
this,
attributeDefinition,
fetchStrategy,
loadPlanBuildingContext
);
} }
@Override @Override
public CompositeFetch buildCompositeFetch( public CompositeFetch buildCompositeFetch(
CompositionDefinition attributeDefinition, LoadPlanBuildingContext loadPlanBuildingContext) { CompositionDefinition attributeDefinition, LoadPlanBuildingContext loadPlanBuildingContext) {
return null; //To change body of implemented methods use File | Settings | File Templates. return LoadPlanBuildingHelper.buildStandardCompositeFetch( this, attributeDefinition, loadPlanBuildingContext );
} }
@Override @Override

View File

@ -0,0 +1,98 @@
/*
* 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.Arrays;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.persister.walking.spi.WalkingException;
import org.hibernate.type.CompositeType;
import org.hibernate.type.Type;
/**
* @author Gail Badner
*/
public class CompositeFetchOwnerDelegate implements FetchOwnerDelegate {
private final SessionFactoryImplementor sessionFactory;
private final CompositeType compositeType;
private final String[] columnNames;
public CompositeFetchOwnerDelegate(
SessionFactoryImplementor sessionFactory,
CompositeType compositeType,
String[] columnNames) {
this.sessionFactory = sessionFactory;
this.compositeType = compositeType;
this.columnNames = columnNames;
}
@Override
public boolean isNullable(Fetch fetch) {
return compositeType.getPropertyNullability()[ determinePropertyIndex( fetch ) ];
}
@Override
public Type getType(Fetch fetch) {
return compositeType.getSubtypes()[ determinePropertyIndex( fetch ) ];
}
@Override
public String[] getColumnNames(Fetch fetch) {
// TODO: probably want to cache this
int begin = 0;
String[] subColumnNames = null;
for ( int i = 0; i < compositeType.getSubtypes().length; i++ ) {
final int columnSpan = compositeType.getSubtypes()[i].getColumnSpan( sessionFactory );
subColumnNames = ArrayHelper.slice( columnNames, begin, columnSpan );
if ( compositeType.getPropertyNames()[ i ].equals( fetch.getOwnerPropertyName() ) ) {
break;
}
begin += columnSpan;
}
return subColumnNames;
}
private int determinePropertyIndex(Fetch fetch) {
// TODO: probably want to cache this
final String[] subAttributeNames = compositeType.getPropertyNames();
int subAttributeIndex = -1;
for ( int i = 0; i < subAttributeNames.length ; i++ ) {
if ( subAttributeNames[ i ].equals( fetch.getOwnerPropertyName() ) ) {
subAttributeIndex = i;
break;
}
}
if ( subAttributeIndex == -1 ) {
throw new WalkingException(
String.format(
"Owner property [%s] not found in composite properties [%s]",
fetch.getOwnerPropertyName(),
Arrays.asList( subAttributeNames )
)
);
}
return subAttributeIndex;
}
}

View File

@ -1,29 +1,24 @@
package org.hibernate.loader.plan.spi; package org.hibernate.loader.plan.spi;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.engine.FetchStrategy; import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.PropertyPath; import org.hibernate.loader.PropertyPath;
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
import org.hibernate.loader.plan.spi.build.LoadPlanBuildingContext; import org.hibernate.loader.plan.spi.build.LoadPlanBuildingContext;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition; import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition; import org.hibernate.type.CompositeType;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class CompositeIndexGraph extends AbstractPlanNode implements FetchableCollectionIndex { public class CompositeIndexGraph extends AbstractFetchOwner implements FetchableCollectionIndex {
private final CollectionReference collectionReference; private final CollectionReference collectionReference;
private final PropertyPath propertyPath; private final PropertyPath propertyPath;
private final CollectionPersister collectionPersister; private final CollectionPersister collectionPersister;
private final FetchOwnerDelegate fetchOwnerDelegate;
private List<Fetch> fetches;
public CompositeIndexGraph( public CompositeIndexGraph(
SessionFactoryImplementor sessionFactory, SessionFactoryImplementor sessionFactory,
@ -33,39 +28,19 @@ public class CompositeIndexGraph extends AbstractPlanNode implements FetchableCo
this.collectionReference = collectionReference; this.collectionReference = collectionReference;
this.collectionPersister = collectionReference.getCollectionPersister(); this.collectionPersister = collectionReference.getCollectionPersister();
this.propertyPath = propertyPath.append( "<index>" ); this.propertyPath = propertyPath.append( "<index>" );
this.fetchOwnerDelegate = new CompositeFetchOwnerDelegate(
sessionFactory,
(CompositeType) collectionPersister.getIndexType(),
( (QueryableCollection) collectionPersister ).getIndexColumnNames()
);
} }
protected CompositeIndexGraph(CompositeIndexGraph original, CopyContext copyContext) { protected CompositeIndexGraph(CompositeIndexGraph original, CopyContext copyContext) {
super( original ); super( original, copyContext );
this.collectionReference = original.collectionReference; this.collectionReference = original.collectionReference;
this.collectionPersister = original.collectionPersister; this.collectionPersister = original.collectionPersister;
this.propertyPath = original.propertyPath; this.propertyPath = original.propertyPath;
this.fetchOwnerDelegate = original.fetchOwnerDelegate;
copyContext.getReturnGraphVisitationStrategy().startingFetches( original );
if ( fetches == null || fetches.size() == 0 ) {
this.fetches = Collections.emptyList();
}
else {
List<Fetch> fetchesCopy = new ArrayList<Fetch>();
for ( Fetch fetch : fetches ) {
fetchesCopy.add( fetch.makeCopy( copyContext, this ) );
}
this.fetches = fetchesCopy;
}
copyContext.getReturnGraphVisitationStrategy().finishingFetches( original );
}
@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 @Override
@ -77,12 +52,25 @@ public class CompositeIndexGraph extends AbstractPlanNode implements FetchableCo
return collectionPersister.getOwnerEntityPersister(); return collectionPersister.getOwnerEntityPersister();
} }
public CollectionReference getCollectionReference() {
return collectionReference;
}
@Override @Override
public PropertyPath getPropertyPath() { public PropertyPath getPropertyPath() {
return propertyPath; return propertyPath;
} }
@Override @Override
public CompositeIndexGraph makeCopy(CopyContext copyContext) {
return new CompositeIndexGraph( this, copyContext );
}
@Override
protected FetchOwnerDelegate getFetchOwnerDelegate() {
return fetchOwnerDelegate;
}
public CollectionFetch buildCollectionFetch( public CollectionFetch buildCollectionFetch(
AssociationAttributeDefinition attributeDefinition, AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy, FetchStrategy fetchStrategy,
@ -90,28 +78,4 @@ public class CompositeIndexGraph extends AbstractPlanNode implements FetchableCo
throw new HibernateException( "Composite index cannot define collections" ); 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 );
}
@Override
public CompositeIndexGraph makeCopy(CopyContext copyContext) {
return new CompositeIndexGraph( this, copyContext );
}
} }

View File

@ -1,32 +1,23 @@
package org.hibernate.loader.plan.spi; package org.hibernate.loader.plan.spi;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.engine.FetchStrategy; import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.PropertyPath; import org.hibernate.loader.PropertyPath;
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
import org.hibernate.loader.plan.spi.build.LoadPlanBuildingContext;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister; 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; import org.hibernate.type.AssociationType;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class EntityElementGraph extends AbstractPlanNode implements FetchableCollectionElement, EntityReference { public class EntityElementGraph extends AbstractFetchOwner implements FetchableCollectionElement, EntityReference {
private final CollectionReference collectionReference; private final CollectionReference collectionReference;
private final CollectionPersister collectionPersister; private final CollectionPersister collectionPersister;
private final AssociationType elementType; private final AssociationType elementType;
private final EntityPersister elementPersister; private final EntityPersister elementPersister;
private final PropertyPath propertyPath; private final PropertyPath propertyPath;
private final FetchOwnerDelegate fetchOwnerDelegate;
private List<Fetch> fetches;
private IdentifierDescription identifierDescription; private IdentifierDescription identifierDescription;
@ -40,30 +31,19 @@ public class EntityElementGraph extends AbstractPlanNode implements FetchableCol
this.collectionPersister = collectionReference.getCollectionPersister(); this.collectionPersister = collectionReference.getCollectionPersister();
this.elementType = (AssociationType) collectionPersister.getElementType(); this.elementType = (AssociationType) collectionPersister.getElementType();
this.elementPersister = (EntityPersister) this.elementType.getAssociatedJoinable( sessionFactory() ); this.elementPersister = (EntityPersister) this.elementType.getAssociatedJoinable( sessionFactory() );
this.propertyPath = collectionPath.append( "<elements>" ); this.propertyPath = collectionPath;
this.fetchOwnerDelegate = new EntityFetchOwnerDelegate( elementPersister );
} }
public EntityElementGraph(EntityElementGraph original, CopyContext copyContext) { public EntityElementGraph(EntityElementGraph original, CopyContext copyContext) {
super( original ); super( original, copyContext );
this.collectionReference = original.collectionReference; this.collectionReference = original.collectionReference;
this.collectionPersister = original.collectionReference.getCollectionPersister(); this.collectionPersister = original.collectionReference.getCollectionPersister();
this.elementType = original.elementType; this.elementType = original.elementType;
this.elementPersister = original.elementPersister; this.elementPersister = original.elementPersister;
this.propertyPath = original.propertyPath; this.propertyPath = original.propertyPath;
this.fetchOwnerDelegate = original.fetchOwnerDelegate;
copyContext.getReturnGraphVisitationStrategy().startingFetches( original );
if ( fetches == null || fetches.size() == 0 ) {
this.fetches = Collections.emptyList();
}
else {
List<Fetch> fetchesCopy = new ArrayList<Fetch>();
for ( Fetch fetch : fetches ) {
fetchesCopy.add( fetch.makeCopy( copyContext, this ) );
}
this.fetches = fetchesCopy;
}
copyContext.getReturnGraphVisitationStrategy().finishingFetches( original );
} }
@Override @Override
@ -86,19 +66,6 @@ public class EntityElementGraph extends AbstractPlanNode implements FetchableCol
return identifierDescription; 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 @Override
public void validateFetchPlan(FetchStrategy fetchStrategy) { public void validateFetchPlan(FetchStrategy fetchStrategy) {
} }
@ -113,39 +80,6 @@ public class EntityElementGraph extends AbstractPlanNode implements FetchableCol
return propertyPath; 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 @Override
public void injectIdentifierDescription(IdentifierDescription identifierDescription) { public void injectIdentifierDescription(IdentifierDescription identifierDescription) {
this.identifierDescription = identifierDescription; this.identifierDescription = identifierDescription;
@ -156,8 +90,18 @@ public class EntityElementGraph extends AbstractPlanNode implements FetchableCol
return new EntityElementGraph( this, copyContext ); return new EntityElementGraph( this, copyContext );
} }
@Override
public CollectionReference getCollectionReference() {
return collectionReference;
}
@Override @Override
public String toString() { public String toString() {
return "EntityElementGraph(collection=" + collectionPersister.getRole() + ", type=" + elementPersister.getEntityName() + ")"; return "EntityElementGraph(collection=" + collectionPersister.getRole() + ", type=" + elementPersister.getEntityName() + ")";
} }
@Override
protected FetchOwnerDelegate getFetchOwnerDelegate() {
return fetchOwnerDelegate;
}
} }

View File

@ -32,21 +32,19 @@ import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchTiming; import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
import org.hibernate.loader.plan.spi.build.LoadPlanBuildingContext;
import org.hibernate.loader.spi.ResultSetProcessingContext; import org.hibernate.loader.spi.ResultSetProcessingContext;
import org.hibernate.persister.entity.EntityPersister; 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; import org.hibernate.type.EntityType;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class EntityFetch extends AbstractSingularAttributeFetch implements EntityReference { public class EntityFetch extends AbstractSingularAttributeFetch implements EntityReference, Fetch {
private final EntityType associationType; private final EntityType associationType;
private final EntityPersister persister; private final EntityPersister persister;
private final LockMode lockMode;
private final FetchOwnerDelegate fetchOwnerDelegate;
private IdentifierDescription identifierDescription; private IdentifierDescription identifierDescription;
@ -55,11 +53,14 @@ public class EntityFetch extends AbstractSingularAttributeFetch implements Entit
LockMode lockMode, LockMode lockMode,
FetchOwner owner, FetchOwner owner,
String ownerProperty, String ownerProperty,
EntityType entityType,
FetchStrategy fetchStrategy) { FetchStrategy fetchStrategy) {
super( sessionFactory, lockMode, owner, ownerProperty, fetchStrategy ); super( sessionFactory, owner, ownerProperty, fetchStrategy );
this.associationType = (EntityType) owner.retrieveFetchSourcePersister().getPropertyType( ownerProperty ); this.associationType = entityType;
this.persister = sessionFactory.getEntityPersister( associationType.getAssociatedEntityName() ); this.persister = sessionFactory.getEntityPersister( associationType.getAssociatedEntityName() );
this.lockMode = lockMode;
this.fetchOwnerDelegate = new EntityFetchOwnerDelegate( persister );
} }
/** /**
@ -72,6 +73,8 @@ public class EntityFetch extends AbstractSingularAttributeFetch implements Entit
super( original, copyContext, fetchOwnerCopy ); super( original, copyContext, fetchOwnerCopy );
this.associationType = original.associationType; this.associationType = original.associationType;
this.persister = original.persister; this.persister = original.persister;
this.lockMode = original.lockMode;
this.fetchOwnerDelegate = original.fetchOwnerDelegate;
} }
public EntityType getAssociationType() { public EntityType getAssociationType() {
@ -93,45 +96,16 @@ public class EntityFetch extends AbstractSingularAttributeFetch implements Entit
return identifierDescription; return identifierDescription;
} }
@Override
public LockMode getLockMode() {
return lockMode;
}
@Override @Override
public EntityPersister retrieveFetchSourcePersister() { public EntityPersister retrieveFetchSourcePersister() {
return persister; 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 @Override
public void injectIdentifierDescription(IdentifierDescription identifierDescription) { public void injectIdentifierDescription(IdentifierDescription identifierDescription) {
this.identifierDescription = identifierDescription; this.identifierDescription = identifierDescription;
@ -267,4 +241,9 @@ public class EntityFetch extends AbstractSingularAttributeFetch implements Entit
copyContext.getReturnGraphVisitationStrategy().finishingEntityFetch( this ); copyContext.getReturnGraphVisitationStrategy().finishingEntityFetch( this );
return copy; return copy;
} }
@Override
protected FetchOwnerDelegate getFetchOwnerDelegate() {
return fetchOwnerDelegate;
}
} }

View File

@ -0,0 +1,72 @@
/*
* 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.internal.JoinHelper;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.type.AssociationType;
import org.hibernate.type.Type;
/**
* @author Gail Badner
*/
public class EntityFetchOwnerDelegate implements FetchOwnerDelegate {
private final EntityPersister entityPersister;
public EntityFetchOwnerDelegate(EntityPersister entityPersister) {
this.entityPersister = entityPersister;
}
@Override
public boolean isNullable(Fetch fetch) {
return entityPersister.getPropertyNullability()[ determinePropertyIndex( fetch ) ];
}
@Override
public Type getType(Fetch fetch) {
return entityPersister.getPropertyTypes()[ determinePropertyIndex( fetch ) ];
}
@Override
public String[] getColumnNames(Fetch fetch) {
final OuterJoinLoadable outerJoinLoadable = (OuterJoinLoadable) entityPersister;
Type fetchType = getType( fetch );
if ( fetchType.isAssociationType() ) {
return JoinHelper.getLHSColumnNames(
(AssociationType) fetchType,
determinePropertyIndex( fetch ),
outerJoinLoadable,
outerJoinLoadable.getFactory()
);
}
else {
return outerJoinLoadable.getPropertyColumnNames( determinePropertyIndex( fetch ) );
}
}
private int determinePropertyIndex(Fetch fetch) {
return entityPersister.getEntityMetamodel().getPropertyIndex( fetch.getOwnerPropertyName() );
}
}

View File

@ -23,33 +23,24 @@
*/ */
package org.hibernate.loader.plan.spi; package org.hibernate.loader.plan.spi;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.engine.FetchStrategy; import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.PropertyPath; import org.hibernate.loader.PropertyPath;
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
import org.hibernate.loader.plan.spi.build.LoadPlanBuildingContext;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister; 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; import org.hibernate.type.AssociationType;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class EntityIndexGraph extends AbstractPlanNode implements FetchableCollectionIndex, EntityReference { public class EntityIndexGraph extends AbstractFetchOwner implements FetchableCollectionIndex, EntityReference {
private final CollectionReference collectionReference; private final CollectionReference collectionReference;
private final CollectionPersister collectionPersister; private final CollectionPersister collectionPersister;
private final AssociationType indexType; private final AssociationType indexType;
private final EntityPersister indexPersister; private final EntityPersister indexPersister;
private final PropertyPath propertyPath; private final PropertyPath propertyPath;
private final FetchOwnerDelegate fetchOwnerDelegate;
private List<Fetch> fetches;
private IdentifierDescription identifierDescription; private IdentifierDescription identifierDescription;
@ -63,28 +54,17 @@ public class EntityIndexGraph extends AbstractPlanNode implements FetchableColle
this.indexType = (AssociationType) collectionPersister.getIndexType(); this.indexType = (AssociationType) collectionPersister.getIndexType();
this.indexPersister = (EntityPersister) this.indexType.getAssociatedJoinable( sessionFactory() ); this.indexPersister = (EntityPersister) this.indexType.getAssociatedJoinable( sessionFactory() );
this.propertyPath = collectionPath.append( "<index>" ); // todo : do we want the <index> part? this.propertyPath = collectionPath.append( "<index>" ); // todo : do we want the <index> part?
this.fetchOwnerDelegate = new EntityFetchOwnerDelegate( indexPersister );
} }
public EntityIndexGraph(EntityIndexGraph original, CopyContext copyContext) { public EntityIndexGraph(EntityIndexGraph original, CopyContext copyContext) {
super( original ); super( original, copyContext );
this.collectionReference = original.collectionReference; this.collectionReference = original.collectionReference;
this.collectionPersister = original.collectionReference.getCollectionPersister(); this.collectionPersister = original.collectionReference.getCollectionPersister();
this.indexType = original.indexType; this.indexType = original.indexType;
this.indexPersister = original.indexPersister; this.indexPersister = original.indexPersister;
this.propertyPath = original.propertyPath; this.propertyPath = original.propertyPath;
this.fetchOwnerDelegate = original.fetchOwnerDelegate;
copyContext.getReturnGraphVisitationStrategy().startingFetches( original );
if ( fetches == null || fetches.size() == 0 ) {
this.fetches = Collections.emptyList();
}
else {
List<Fetch> fetchesCopy = new ArrayList<Fetch>();
for ( Fetch fetch : fetches ) {
fetchesCopy.add( fetch.makeCopy( copyContext, this ) );
}
this.fetches = fetchesCopy;
}
copyContext.getReturnGraphVisitationStrategy().finishingFetches( original );
} }
@Override @Override
@ -107,19 +87,6 @@ public class EntityIndexGraph extends AbstractPlanNode implements FetchableColle
return identifierDescription; 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 @Override
public void validateFetchPlan(FetchStrategy fetchStrategy) { public void validateFetchPlan(FetchStrategy fetchStrategy) {
} }
@ -134,39 +101,6 @@ public class EntityIndexGraph extends AbstractPlanNode implements FetchableColle
return propertyPath; 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 @Override
public void injectIdentifierDescription(IdentifierDescription identifierDescription) { public void injectIdentifierDescription(IdentifierDescription identifierDescription) {
this.identifierDescription = identifierDescription; this.identifierDescription = identifierDescription;
@ -176,4 +110,9 @@ public class EntityIndexGraph extends AbstractPlanNode implements FetchableColle
public EntityIndexGraph makeCopy(CopyContext copyContext) { public EntityIndexGraph makeCopy(CopyContext copyContext) {
return new EntityIndexGraph( this, copyContext ); return new EntityIndexGraph( this, copyContext );
} }
@Override
protected FetchOwnerDelegate getFetchOwnerDelegate() {
return fetchOwnerDelegate;
}
} }

View File

@ -32,12 +32,8 @@ import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.PropertyPath; import org.hibernate.loader.PropertyPath;
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
import org.hibernate.loader.plan.spi.build.LoadPlanBuildingContext;
import org.hibernate.loader.spi.ResultSetProcessingContext; import org.hibernate.loader.spi.ResultSetProcessingContext;
import org.hibernate.persister.entity.EntityPersister; 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; import static org.hibernate.loader.spi.ResultSetProcessingContext.IdentifierResolutionContext;
@ -50,24 +46,32 @@ public class EntityReturn extends AbstractFetchOwner implements Return, EntityRe
private final PropertyPath propertyPath = new PropertyPath(); // its a root private final PropertyPath propertyPath = new PropertyPath(); // its a root
private final LockMode lockMode;
private final FetchOwnerDelegate fetchOwnerDelegate;
private IdentifierDescription identifierDescription; private IdentifierDescription identifierDescription;
public EntityReturn( public EntityReturn(
SessionFactoryImplementor sessionFactory, SessionFactoryImplementor sessionFactory,
LockMode lockMode, LockMode lockMode,
String entityName) { String entityName) {
super( sessionFactory, lockMode ); super( sessionFactory );
this.persister = sessionFactory.getEntityPersister( entityName ); this.persister = sessionFactory.getEntityPersister( entityName );
this.lockMode = lockMode;
this.fetchOwnerDelegate = new EntityFetchOwnerDelegate( persister );
} }
protected EntityReturn(EntityReturn original, CopyContext copyContext) { protected EntityReturn(EntityReturn original, CopyContext copyContext) {
super( original, copyContext ); super( original, copyContext );
this.persister = original.persister; this.persister = original.persister;
this.lockMode = original.lockMode;
this.fetchOwnerDelegate = original.fetchOwnerDelegate;
} }
@Override @Override
public LockMode getLockMode() { public LockMode getLockMode() {
return super.getLockMode(); return lockMode;
} }
@Override @Override
@ -99,42 +103,9 @@ public class EntityReturn extends AbstractFetchOwner implements Return, EntityRe
return propertyPath; 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 @Override
public void hydrate(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException { public void hydrate(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
EntityKey entityKey = context.getDictatedRootEntityKey(); EntityKey entityKey = getEntityKeyFromContext( context );
if ( entityKey != null ) { if ( entityKey != null ) {
context.getIdentifierResolutionContext( this ).registerEntityKey( entityKey ); context.getIdentifierResolutionContext( this ).registerEntityKey( entityKey );
return; return;
@ -147,6 +118,19 @@ public class EntityReturn extends AbstractFetchOwner implements Return, EntityRe
} }
} }
private EntityKey getEntityKeyFromContext(ResultSetProcessingContext context) {
if ( context.getDictatedRootEntityKey() != null ) {
return context.getDictatedRootEntityKey();
}
else if ( context.getQueryParameters().getOptionalId() != null ) {
return context.getSession().generateEntityKey(
context.getQueryParameters().getOptionalId(),
getEntityPersister()
);
}
return null;
}
@Override @Override
public void resolve(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException { public void resolve(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
final IdentifierResolutionContext identifierResolutionContext = context.getIdentifierResolutionContext( this ); final IdentifierResolutionContext identifierResolutionContext = context.getIdentifierResolutionContext( this );
@ -194,4 +178,9 @@ public class EntityReturn extends AbstractFetchOwner implements Return, EntityRe
public EntityReturn makeCopy(CopyContext copyContext) { public EntityReturn makeCopy(CopyContext copyContext) {
return new EntityReturn( this, copyContext ); return new EntityReturn( this, copyContext );
} }
@Override
protected FetchOwnerDelegate getFetchOwnerDelegate() {
return fetchOwnerDelegate;
}
} }

View File

@ -52,6 +52,10 @@ public interface Fetch extends CopyableFetch {
*/ */
public String getOwnerPropertyName(); public String getOwnerPropertyName();
public boolean isNullable();
public String[] getColumnNames();
public FetchStrategy getFetchStrategy(); public FetchStrategy getFetchStrategy();
/** /**

View File

@ -29,6 +29,7 @@ import org.hibernate.loader.plan.spi.build.LoadPlanBuildingContext;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition; import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition; import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.type.Type;
/** /**
* Contract for owners of fetches. Any non-scalar return could be a fetch owner. * Contract for owners of fetches. Any non-scalar return could be a fetch owner.
@ -56,6 +57,12 @@ public interface FetchOwner {
*/ */
public Fetch[] getFetches(); public Fetch[] getFetches();
public Type getType(Fetch fetch);
public boolean isNullable(Fetch fetch);
public String[] getColumnNames(Fetch fetch);
/** /**
* Is the asserted plan valid from this owner to a fetch? * Is the asserted plan valid from this owner to a fetch?
* *

View File

@ -0,0 +1,38 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.loader.plan.spi;
import org.hibernate.type.Type;
/**
* @author Gail Badner
*/
public interface FetchOwnerDelegate {
public boolean isNullable(Fetch fetch);
public Type getType(Fetch fetch);
public String[] getColumnNames(Fetch fetch);
}

View File

@ -23,10 +23,14 @@
*/ */
package org.hibernate.loader.plan.spi; package org.hibernate.loader.plan.spi;
import org.hibernate.persister.collection.CollectionPersister;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface FetchableCollectionElement extends FetchOwner, CopyableReturn { public interface FetchableCollectionElement extends FetchOwner, CopyableReturn {
@Override @Override
public FetchableCollectionElement makeCopy(CopyContext copyContext); public FetchableCollectionElement makeCopy(CopyContext copyContext);
public CollectionReference getCollectionReference();
} }

View File

@ -37,6 +37,7 @@ import org.jboss.logging.MDC;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.engine.FetchStrategy; import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchTiming; import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.EntityKey;
@ -44,19 +45,24 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.hibernate.loader.PropertyPath; import org.hibernate.loader.PropertyPath;
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper; import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
import org.hibernate.loader.plan.spi.AbstractSingularAttributeFetch;
import org.hibernate.loader.plan.spi.CollectionFetch; import org.hibernate.loader.plan.spi.CollectionFetch;
import org.hibernate.loader.plan.spi.CollectionReference; import org.hibernate.loader.plan.spi.CollectionReference;
import org.hibernate.loader.plan.spi.CollectionReturn; import org.hibernate.loader.plan.spi.CollectionReturn;
import org.hibernate.loader.plan.spi.CompositeElementGraph;
import org.hibernate.loader.plan.spi.CompositeFetch; import org.hibernate.loader.plan.spi.CompositeFetch;
import org.hibernate.loader.plan.spi.CompositeFetchOwnerDelegate;
import org.hibernate.loader.plan.spi.EntityFetch; import org.hibernate.loader.plan.spi.EntityFetch;
import org.hibernate.loader.plan.spi.EntityReference; import org.hibernate.loader.plan.spi.EntityReference;
import org.hibernate.loader.plan.spi.EntityReturn; import org.hibernate.loader.plan.spi.EntityReturn;
import org.hibernate.loader.plan.spi.Fetch; import org.hibernate.loader.plan.spi.Fetch;
import org.hibernate.loader.plan.spi.FetchOwner; import org.hibernate.loader.plan.spi.FetchOwner;
import org.hibernate.loader.plan.spi.FetchOwnerDelegate;
import org.hibernate.loader.plan.spi.IdentifierDescription; import org.hibernate.loader.plan.spi.IdentifierDescription;
import org.hibernate.loader.plan.spi.Return; import org.hibernate.loader.plan.spi.Return;
import org.hibernate.loader.spi.ResultSetProcessingContext; import org.hibernate.loader.spi.ResultSetProcessingContext;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.spi.HydratedCompoundValueHandler; import org.hibernate.persister.spi.HydratedCompoundValueHandler;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition; import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.AttributeDefinition; import org.hibernate.persister.walking.spi.AttributeDefinition;
@ -64,9 +70,11 @@ import org.hibernate.persister.walking.spi.CollectionDefinition;
import org.hibernate.persister.walking.spi.CollectionElementDefinition; import org.hibernate.persister.walking.spi.CollectionElementDefinition;
import org.hibernate.persister.walking.spi.CollectionIndexDefinition; import org.hibernate.persister.walking.spi.CollectionIndexDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition; import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.persister.walking.spi.CompositionElementDefinition;
import org.hibernate.persister.walking.spi.EntityDefinition; import org.hibernate.persister.walking.spi.EntityDefinition;
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition; import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
import org.hibernate.persister.walking.spi.WalkingException; import org.hibernate.persister.walking.spi.WalkingException;
import org.hibernate.type.CompositeType;
import org.hibernate.type.Type; import org.hibernate.type.Type;
import static org.hibernate.loader.spi.ResultSetProcessingContext.IdentifierResolutionContext; import static org.hibernate.loader.spi.ResultSetProcessingContext.IdentifierResolutionContext;
@ -190,8 +198,13 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
final FetchOwner identifierAttributeCollector; final FetchOwner identifierAttributeCollector;
if ( entityIdentifierDefinition.isEncapsulated() ) { if ( entityIdentifierDefinition.isEncapsulated() ) {
if ( entityIdentifierDefinition.getEntityDefinition().getEntityPersister().getIdentifierType().isComponentType() ) {
identifierAttributeCollector = new EncapsulatedCompositeIdentifierAttributeCollector( entityReference );
}
else {
identifierAttributeCollector = new EncapsulatedIdentifierAttributeCollector( entityReference ); identifierAttributeCollector = new EncapsulatedIdentifierAttributeCollector( entityReference );
} }
}
else { else {
identifierAttributeCollector = new NonEncapsulatedIdentifierAttributeCollector( entityReference ); identifierAttributeCollector = new NonEncapsulatedIdentifierAttributeCollector( entityReference );
} }
@ -305,6 +318,35 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
// - the element graph pushed while starting would be popped in finishing/Entity/finishingComposite // - the element graph pushed while starting would be popped in finishing/Entity/finishingComposite
} }
@Override
public void startingCompositeElement(CompositionElementDefinition compositeElementDefinition) {
System.out.println(
String.format(
"%s Starting composite collection element for (%s)",
StringHelper.repeat( ">>", fetchOwnerStack.size() ),
compositeElementDefinition.getCollectionDefinition().getCollectionPersister().getRole()
)
);
}
@Override
public void finishingCompositeElement(CompositionElementDefinition compositeElementDefinition) {
// pop the current fetch owner, and make sure what we just popped represents this composition
final FetchOwner poppedFetchOwner = popFromStack();
if ( ! CompositeElementGraph.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 composite element for : %s",
StringHelper.repeat( "<<", fetchOwnerStack.size() ),
compositeElementDefinition.getCollectionDefinition().getCollectionPersister().getRole()
);
}
@Override @Override
public void finishingCollection(CollectionDefinition collectionDefinition) { public void finishingCollection(CollectionDefinition collectionDefinition) {
// pop the current fetch owner, and make sure what we just popped represents this collection // pop the current fetch owner, and make sure what we just popped represents this collection
@ -487,15 +529,13 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
implements FetchOwner, EntityReference, FetchStackAware { implements FetchOwner, EntityReference, FetchStackAware {
protected final EntityReference entityReference; protected final EntityReference entityReference;
private final PropertyPath propertyPath;
protected final List<EntityFetch> identifierFetches = new ArrayList<EntityFetch>(); protected final List<AbstractSingularAttributeFetch> identifierFetches = new ArrayList<AbstractSingularAttributeFetch>();
protected final Map<EntityFetch,HydratedCompoundValueHandler> fetchToHydratedStateExtractorMap protected final Map<AbstractSingularAttributeFetch,HydratedCompoundValueHandler> fetchToHydratedStateExtractorMap
= new HashMap<EntityFetch, HydratedCompoundValueHandler>(); = new HashMap<AbstractSingularAttributeFetch, HydratedCompoundValueHandler>();
public AbstractIdentifierAttributeCollector(EntityReference entityReference) { public AbstractIdentifierAttributeCollector(EntityReference entityReference) {
this.entityReference = entityReference; this.entityReference = entityReference;
this.propertyPath = ( (FetchOwner) entityReference ).getPropertyPath().append( "<id>" );
} }
@Override @Override
@ -513,6 +553,11 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
return entityReference.getEntityPersister(); return entityReference.getEntityPersister();
} }
@Override
public boolean isNullable(Fetch fetch) {
return false;
}
@Override @Override
public IdentifierDescription getIdentifierDescription() { public IdentifierDescription getIdentifierDescription() {
return entityReference.getIdentifierDescription(); return entityReference.getIdentifierDescription();
@ -533,7 +578,7 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
LoadPlanBuildingContext loadPlanBuildingContext) { LoadPlanBuildingContext loadPlanBuildingContext) {
// we have a key-many-to-one // 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 NOTE: we pass ourselves as the FetchOwner which will route the fetch back through our #addFetch
// impl. We collect them there and later build the IdentifierDescription // impl. We collect them there and later build the IdentifierDescription
final EntityFetch fetch = LoadPlanBuildingHelper.buildStandardEntityFetch( final EntityFetch fetch = LoadPlanBuildingHelper.buildStandardEntityFetch(
this, this,
@ -551,7 +596,7 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
CompositionDefinition attributeDefinition, LoadPlanBuildingContext loadPlanBuildingContext) { CompositionDefinition attributeDefinition, LoadPlanBuildingContext loadPlanBuildingContext) {
// nested composition. Unusual, but not disallowed. // nested composition. Unusual, but not disallowed.
// //
// IMPL NOTE: we pass ourselves as the FetchOwner which will route the fetch back throw our #addFetch // IMPL NOTE: we pass ourselves as the FetchOwner which will route the fetch back through our #addFetch
// impl. We collect them there and later build the IdentifierDescription // impl. We collect them there and later build the IdentifierDescription
return LoadPlanBuildingHelper.buildStandardCompositeFetch( return LoadPlanBuildingHelper.buildStandardCompositeFetch(
this, this,
@ -570,7 +615,7 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
@Override @Override
public void addFetch(Fetch fetch) { public void addFetch(Fetch fetch) {
identifierFetches.add( (EntityFetch) fetch ); identifierFetches.add( (AbstractSingularAttributeFetch) fetch );
} }
@Override @Override
@ -588,11 +633,6 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
return ( (FetchOwner) entityReference ).retrieveFetchSourcePersister(); return ( (FetchOwner) entityReference ).retrieveFetchSourcePersister();
} }
@Override
public PropertyPath getPropertyPath() {
return propertyPath;
}
@Override @Override
public void injectIdentifierDescription(IdentifierDescription identifierDescription) { public void injectIdentifierDescription(IdentifierDescription identifierDescription) {
throw new WalkingException( throw new WalkingException(
@ -601,44 +641,144 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
} }
} }
protected static abstract class AbstractCompositeIdentifierAttributeCollector extends AbstractIdentifierAttributeCollector {
public AbstractCompositeIdentifierAttributeCollector(EntityReference entityReference) {
super( entityReference );
}
}
protected static class EncapsulatedIdentifierAttributeCollector extends AbstractIdentifierAttributeCollector { protected static class EncapsulatedIdentifierAttributeCollector extends AbstractIdentifierAttributeCollector {
private final PropertyPath propertyPath;
public EncapsulatedIdentifierAttributeCollector(EntityReference entityReference) { public EncapsulatedIdentifierAttributeCollector(EntityReference entityReference) {
super( entityReference ); super( entityReference );
this.propertyPath = ( (FetchOwner) entityReference ).getPropertyPath();
} }
@Override @Override
protected IdentifierDescription buildIdentifierDescription() { protected IdentifierDescription buildIdentifierDescription() {
return new IdentifierDescriptionImpl( return new IdentifierDescriptionImpl(
entityReference, entityReference,
identifierFetches.toArray( new EntityFetch[ identifierFetches.size() ] ), identifierFetches.toArray( new AbstractSingularAttributeFetch[ identifierFetches.size() ] ),
null null
); );
} }
@Override
public Type getType(Fetch fetch) {
return null; //To change body of implemented methods use File | Settings | File Templates.
} }
protected static class NonEncapsulatedIdentifierAttributeCollector extends AbstractIdentifierAttributeCollector { @Override
public NonEncapsulatedIdentifierAttributeCollector(EntityReference entityReference) { public String[] getColumnNames(Fetch fetch) {
return ( (Loadable) entityReference.getEntityPersister() ).getIdentifierColumnNames();
}
@Override
public PropertyPath getPropertyPath() {
return propertyPath;
}
}
protected static class EncapsulatedCompositeIdentifierAttributeCollector extends AbstractCompositeIdentifierAttributeCollector {
private final PropertyPath propertyPath;
public EncapsulatedCompositeIdentifierAttributeCollector(EntityReference entityReference) {
super( entityReference ); super( entityReference );
this.propertyPath = ( (FetchOwner) entityReference ).getPropertyPath();
} }
@Override @Override
protected IdentifierDescription buildIdentifierDescription() { protected IdentifierDescription buildIdentifierDescription() {
return new IdentifierDescriptionImpl( return new IdentifierDescriptionImpl(
entityReference, entityReference,
identifierFetches.toArray( new EntityFetch[ identifierFetches.size() ] ), identifierFetches.toArray( new AbstractSingularAttributeFetch[ identifierFetches.size() ] ),
null
);
}
@Override
public PropertyPath getPropertyPath() {
return propertyPath;
}
@Override
public Type getType(Fetch fetch) {
if ( !fetch.getOwnerPropertyName().equals( entityReference.getEntityPersister().getIdentifierPropertyName() ) ) {
throw new IllegalArgumentException(
String.format(
"Fetch owner property name [%s] is not the same as the identifier property name [%s].",
fetch.getOwnerPropertyName(),
entityReference.getEntityPersister().getIdentifierPropertyName()
)
);
}
return entityReference.getEntityPersister().getIdentifierType();
}
@Override
public String[] getColumnNames(Fetch fetch) {
return ( (Loadable) entityReference.getEntityPersister() ).getIdentifierColumnNames();
}
}
protected static class NonEncapsulatedIdentifierAttributeCollector extends AbstractCompositeIdentifierAttributeCollector {
private final PropertyPath propertyPath;
private final FetchOwnerDelegate fetchOwnerDelegate;
public NonEncapsulatedIdentifierAttributeCollector(EntityReference entityReference) {
super( entityReference );
this.propertyPath = ( (FetchOwner) entityReference ).getPropertyPath().append( "<id>" );
this.fetchOwnerDelegate = new CompositeFetchOwnerDelegate(
entityReference.getEntityPersister().getFactory(),
(CompositeType) entityReference.getEntityPersister().getIdentifierType(),
( (Loadable) entityReference.getEntityPersister() ).getIdentifierColumnNames()
);
}
@Override
protected IdentifierDescription buildIdentifierDescription() {
return new IdentifierDescriptionImpl(
entityReference,
identifierFetches.toArray( new AbstractSingularAttributeFetch[ identifierFetches.size() ] ),
fetchToHydratedStateExtractorMap fetchToHydratedStateExtractorMap
); );
} }
@Override
public PropertyPath getPropertyPath() {
return propertyPath;
}
public Type getType(Fetch fetch) {
if ( !fetch.getOwnerPropertyName().equals( entityReference.getEntityPersister().getIdentifierPropertyName() ) ) {
throw new IllegalArgumentException(
String.format(
"Fetch owner property name [%s] is not the same as the identifier property name [%s].",
fetch.getOwnerPropertyName(),
entityReference.getEntityPersister().getIdentifierPropertyName()
)
);
}
return fetchOwnerDelegate.getType( fetch );
}
public String[] getColumnNames(Fetch fetch) {
return fetchOwnerDelegate.getColumnNames( fetch );
}
} }
private static class IdentifierDescriptionImpl implements IdentifierDescription { private static class IdentifierDescriptionImpl implements IdentifierDescription {
private final EntityReference entityReference; private final EntityReference entityReference;
private final EntityFetch[] identifierFetches; private final AbstractSingularAttributeFetch[] identifierFetches;
private final Map<EntityFetch,HydratedCompoundValueHandler> fetchToHydratedStateExtractorMap; private final Map<AbstractSingularAttributeFetch,HydratedCompoundValueHandler> fetchToHydratedStateExtractorMap;
private IdentifierDescriptionImpl( private IdentifierDescriptionImpl(
EntityReference entityReference, EntityFetch[] identifierFetches, EntityReference entityReference,
Map<EntityFetch, HydratedCompoundValueHandler> fetchToHydratedStateExtractorMap) { AbstractSingularAttributeFetch[] identifierFetches,
Map<AbstractSingularAttributeFetch, HydratedCompoundValueHandler> fetchToHydratedStateExtractorMap) {
this.entityReference = entityReference; this.entityReference = entityReference;
this.identifierFetches = identifierFetches; this.identifierFetches = identifierFetches;
this.fetchToHydratedStateExtractorMap = fetchToHydratedStateExtractorMap; this.fetchToHydratedStateExtractorMap = fetchToHydratedStateExtractorMap;
@ -656,14 +796,14 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
final Object ownerIdentifierHydratedState = ownerIdentifierResolutionContext.getHydratedForm(); final Object ownerIdentifierHydratedState = ownerIdentifierResolutionContext.getHydratedForm();
if ( ownerIdentifierHydratedState != null ) { if ( ownerIdentifierHydratedState != null ) {
for ( EntityFetch fetch : identifierFetches ) { for ( AbstractSingularAttributeFetch fetch : identifierFetches ) {
if ( fetch instanceof EntityFetch ) {
final IdentifierResolutionContext identifierResolutionContext = final IdentifierResolutionContext identifierResolutionContext =
context.getIdentifierResolutionContext( fetch ); context.getIdentifierResolutionContext( (EntityFetch) fetch );
// if the identifier was already hydrated, nothing to do // if the identifier was already hydrated, nothing to do
if ( identifierResolutionContext.getHydratedForm() != null ) { if ( identifierResolutionContext.getHydratedForm() != null ) {
continue; continue;
} }
// try to extract the sub-hydrated value from the owners tuple array // try to extract the sub-hydrated value from the owners tuple array
if ( fetchToHydratedStateExtractorMap != null && ownerIdentifierHydratedState != null ) { if ( fetchToHydratedStateExtractorMap != null && ownerIdentifierHydratedState != null ) {
Serializable extracted = (Serializable) fetchToHydratedStateExtractorMap.get( fetch ) Serializable extracted = (Serializable) fetchToHydratedStateExtractorMap.get( fetch )
@ -675,6 +815,10 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
// if we can't, then read from result set // if we can't, then read from result set
fetch.hydrate( resultSet, context ); fetch.hydrate( resultSet, context );
} }
else {
throw new NotYetImplementedException( "Cannot hydrate identifier Fetch that is not an EntityFetch" );
}
}
return; return;
} }
@ -689,15 +833,8 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
@Override @Override
public EntityKey resolve(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException { public EntityKey resolve(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
for ( EntityFetch fetch : identifierFetches ) { for ( AbstractSingularAttributeFetch fetch : identifierFetches ) {
final IdentifierResolutionContext identifierResolutionContext = resolveIdentifierFetch( resultSet, context, fetch );
context.getIdentifierResolutionContext( fetch );
if ( identifierResolutionContext.getEntityKey() != null ) {
continue;
}
EntityKey fetchKey = fetch.resolveInIdentifier( resultSet, context );
identifierResolutionContext.registerEntityKey( fetchKey );
} }
final IdentifierResolutionContext ownerIdentifierResolutionContext = final IdentifierResolutionContext ownerIdentifierResolutionContext =
@ -710,6 +847,28 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
} }
} }
private static void resolveIdentifierFetch(
ResultSet resultSet,
ResultSetProcessingContext context,
AbstractSingularAttributeFetch fetch) throws SQLException {
if ( fetch instanceof EntityFetch ) {
EntityFetch entityFetch = (EntityFetch) fetch;
final IdentifierResolutionContext identifierResolutionContext =
context.getIdentifierResolutionContext( entityFetch );
if ( identifierResolutionContext.getEntityKey() != null ) {
return;
}
EntityKey fetchKey = entityFetch.resolveInIdentifier( resultSet, context );
identifierResolutionContext.registerEntityKey( fetchKey );
}
else if ( fetch instanceof CompositeFetch ) {
for ( Fetch subFetch : fetch.getFetches() ) {
resolveIdentifierFetch( resultSet, context, (AbstractSingularAttributeFetch) subFetch );
}
}
}
public static class MDCStack { public static class MDCStack {
private ArrayDeque<PropertyPath> pathStack = new ArrayDeque<PropertyPath>(); private ArrayDeque<PropertyPath> pathStack = new ArrayDeque<PropertyPath>();

View File

@ -46,6 +46,7 @@ public class ManyToOne extends ToOne {
public Type getType() throws MappingException { public Type getType() throws MappingException {
return getMappings().getTypeResolver().getTypeFactory().manyToOne( return getMappings().getTypeResolver().getTypeFactory().manyToOne(
getReferencedEntityName(), getReferencedEntityName(),
referenceToPrimaryKey,
getReferencedPropertyName(), getReferencedPropertyName(),
isLazy(), isLazy(),
isUnwrapProxy(), isUnwrapProxy(),

View File

@ -47,6 +47,7 @@ public class OneToMany implements Value {
private EntityType getEntityType() { private EntityType getEntityType() {
return mappings.getTypeResolver().getTypeFactory().manyToOne( return mappings.getTypeResolver().getTypeFactory().manyToOne(
getReferencedEntityName(), getReferencedEntityName(),
true,
null, null,
false, false,
false, false,

View File

@ -70,6 +70,7 @@ public class OneToOne extends ToOne {
return getMappings().getTypeResolver().getTypeFactory().specialOneToOne( return getMappings().getTypeResolver().getTypeFactory().specialOneToOne(
getReferencedEntityName(), getReferencedEntityName(),
foreignKeyType, foreignKeyType,
referenceToPrimaryKey,
referencedPropertyName, referencedPropertyName,
isLazy(), isLazy(),
isUnwrapProxy(), isUnwrapProxy(),
@ -81,6 +82,7 @@ public class OneToOne extends ToOne {
return getMappings().getTypeResolver().getTypeFactory().oneToOne( return getMappings().getTypeResolver().getTypeFactory().oneToOne(
getReferencedEntityName(), getReferencedEntityName(),
foreignKeyType, foreignKeyType,
referenceToPrimaryKey,
referencedPropertyName, referencedPropertyName,
isLazy(), isLazy(),
isUnwrapProxy(), isUnwrapProxy(),

View File

@ -40,6 +40,7 @@ public abstract class ToOne extends SimpleValue implements Fetchable {
private String referencedEntityName; private String referencedEntityName;
private boolean lazy = true; private boolean lazy = true;
protected boolean unwrapProxy; protected boolean unwrapProxy;
protected boolean referenceToPrimaryKey = true;
protected ToOne(Mappings mappings, Table table) { protected ToOne(Mappings mappings, Table table) {
super( mappings, table ); super( mappings, table );
@ -111,4 +112,12 @@ public abstract class ToOne extends SimpleValue implements Fetchable {
this.unwrapProxy = unwrapProxy; this.unwrapProxy = unwrapProxy;
} }
public boolean isReferenceToPrimaryKey() {
return referenceToPrimaryKey;
}
public void setReferenceToPrimaryKey(boolean referenceToPrimaryKey) {
this.referenceToPrimaryKey = referenceToPrimaryKey;
}
} }

View File

@ -35,6 +35,7 @@ import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.cache.spi.access.AccessType; import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cfg.NamingStrategy; import org.hibernate.cfg.NamingStrategy;
import org.hibernate.cfg.annotations.NamedEntityGraphDefinition;
import org.hibernate.engine.ResultSetMappingDefinition; import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.spi.FilterDefinition; import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.engine.spi.NamedQueryDefinition; import org.hibernate.engine.spi.NamedQueryDefinition;
@ -115,6 +116,8 @@ public interface Metadata {
public Iterable<NamedQueryDefinition> getNamedQueryDefinitions(); public Iterable<NamedQueryDefinition> getNamedQueryDefinitions();
public Map<String, NamedEntityGraphDefinition> getNamedEntityGraphMap();
public Iterable<NamedSQLQueryDefinition> getNamedNativeQueryDefinitions(); public Iterable<NamedSQLQueryDefinition> getNamedNativeQueryDefinitions();
public Map<String, ResultSetMappingDefinition> getResultSetMappingDefinitions(); public Map<String, ResultSetMappingDefinition> getResultSetMappingDefinitions();

View File

@ -47,6 +47,7 @@ import org.hibernate.boot.spi.CacheRegionDefinition;
import org.hibernate.cache.spi.access.AccessType; import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cfg.NamingStrategy; import org.hibernate.cfg.NamingStrategy;
import org.hibernate.cfg.ObjectNameNormalizer; import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.cfg.annotations.NamedEntityGraphDefinition;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.engine.ResultSetMappingDefinition; import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.jdbc.spi.JdbcServices;
@ -134,7 +135,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
private final MappingDefaults mappingDefaults; private final MappingDefaults mappingDefaults;
private final ObjectNameNormalizer nameNormalizer; private final ObjectNameNormalizer nameNormalizer;
private Map<String, TypeDefinition> typeDefinitionMap = new HashMap<String, TypeDefinition>(); private final Map<String, TypeDefinition> typeDefinitionMap = new HashMap<String, TypeDefinition>();
private Map<String, FilterDefinition> filterDefinitionMap = new HashMap<String, FilterDefinition>(); private Map<String, FilterDefinition> filterDefinitionMap = new HashMap<String, FilterDefinition>();
private Map<String, EntityBinding> entityBindingMap = new HashMap<String, EntityBinding>(); private Map<String, EntityBinding> entityBindingMap = new HashMap<String, EntityBinding>();
@ -145,6 +146,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
private Map<String, NamedQueryDefinition> namedQueryDefs = new HashMap<String, NamedQueryDefinition>(); private Map<String, NamedQueryDefinition> namedQueryDefs = new HashMap<String, NamedQueryDefinition>();
private Map<String, NamedSQLQueryDefinition> namedNativeQueryDefs = new HashMap<String, NamedSQLQueryDefinition>(); private Map<String, NamedSQLQueryDefinition> namedNativeQueryDefs = new HashMap<String, NamedSQLQueryDefinition>();
private Map<String, ResultSetMappingDefinition> resultSetMappings = new HashMap<String, ResultSetMappingDefinition>(); private Map<String, ResultSetMappingDefinition> resultSetMappings = new HashMap<String, ResultSetMappingDefinition>();
private final Map<String, NamedEntityGraphDefinition> namedEntityGraphMap = new HashMap<String, NamedEntityGraphDefinition>( );
private boolean globallyQuotedIdentifiers = false; private boolean globallyQuotedIdentifiers = false;
@ -375,6 +377,19 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
return typeDefinitionMap.get( registrationKey ); return typeDefinitionMap.get( registrationKey );
} }
@Override
public void addNamedEntityGraph(NamedEntityGraphDefinition definition) {
final String name = definition.getRegisteredName();
final NamedEntityGraphDefinition previous = namedEntityGraphMap.put( name, definition );
if ( previous != null ) {
throw new DuplicateMappingException( "NamedEntityGraph", name );
}
}
@Override
public Map<String, NamedEntityGraphDefinition> getNamedEntityGraphMap() {
return namedEntityGraphMap;
}
// filter definitions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // filter definitions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -24,6 +24,7 @@
package org.hibernate.metamodel.spi; package org.hibernate.metamodel.spi;
import org.hibernate.cfg.ObjectNameNormalizer; import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.cfg.annotations.NamedEntityGraphDefinition;
import org.hibernate.engine.ResultSetMappingDefinition; import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.spi.FilterDefinition; import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.engine.spi.Mapping; import org.hibernate.engine.spi.Mapping;
@ -69,6 +70,8 @@ public interface MetadataImplementor extends Metadata, BindingContext, Mapping {
public void addNamedNativeQuery(NamedSQLQueryDefinition def); public void addNamedNativeQuery(NamedSQLQueryDefinition def);
public void addNamedEntityGraph(NamedEntityGraphDefinition def);
public void addNamedQuery(NamedQueryDefinition def); public void addNamedQuery(NamedQueryDefinition def);
public void addResultSetMapping(ResultSetMappingDefinition resultSetMappingDefinition); public void addResultSetMapping(ResultSetMappingDefinition resultSetMappingDefinition);

View File

@ -101,10 +101,14 @@ import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Loadable; import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.entity.PropertyMapping; import org.hibernate.persister.entity.PropertyMapping;
import org.hibernate.persister.entity.Queryable; import org.hibernate.persister.entity.Queryable;
import org.hibernate.persister.walking.internal.CompositionSingularSubAttributesHelper;
import org.hibernate.persister.walking.spi.AttributeDefinition;
import org.hibernate.persister.walking.spi.AttributeSource;
import org.hibernate.persister.walking.spi.CollectionDefinition; import org.hibernate.persister.walking.spi.CollectionDefinition;
import org.hibernate.persister.walking.spi.CollectionElementDefinition; import org.hibernate.persister.walking.spi.CollectionElementDefinition;
import org.hibernate.persister.walking.spi.CollectionIndexDefinition; import org.hibernate.persister.walking.spi.CollectionIndexDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition; import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.persister.walking.spi.CompositionElementDefinition;
import org.hibernate.persister.walking.spi.EntityDefinition; import org.hibernate.persister.walking.spi.EntityDefinition;
import org.hibernate.pretty.MessageHelper; import org.hibernate.pretty.MessageHelper;
import org.hibernate.sql.Alias; import org.hibernate.sql.Alias;
@ -2342,7 +2346,6 @@ public abstract class AbstractCollectionPersister
public abstract FilterAliasGenerator getFilterAliasGenerator(final String rootAlias); public abstract FilterAliasGenerator getFilterAliasGenerator(final String rootAlias);
// ColectionDefinition impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ColectionDefinition impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override @Override
@ -2408,12 +2411,42 @@ public abstract class AbstractCollectionPersister
} }
@Override @Override
public CompositionDefinition toCompositeDefinition() { public CompositionElementDefinition toCompositeElementDefinition() {
final String propertyName = role.substring( entityName.length() + 1 );
final int propertyIndex = ownerPersister.getEntityMetamodel().getPropertyIndex( propertyName );
if ( ! getType().isComponentType() ) { if ( ! getType().isComponentType() ) {
throw new IllegalStateException( "Cannot treat entity collection element type as composite" ); throw new IllegalStateException( "Cannot treat entity collection element type as composite" );
} }
// todo : implement
throw new NotYetImplementedException(); return new CompositionElementDefinition() {
@Override
public String getName() {
return "";
}
@Override
public Type getType() {
return getElementType();
}
@Override
public AttributeSource getSource() {
// TODO: what if this is a collection w/in an encapsulated composition attribute?
// should return the encapsulated composition attribute instead???
return getOwnerEntityPersister();
}
@Override
public Iterable<AttributeDefinition> getAttributes() {
return CompositionSingularSubAttributesHelper.getCompositionElementSubAttributes( this );
}
@Override
public CollectionDefinition getCollectionDefinition() {
return AbstractCollectionPersister.this;
}
};
} }
}; };
} }

View File

@ -62,7 +62,6 @@ import org.hibernate.cache.spi.entry.ReferenceCacheEntryImpl;
import org.hibernate.cache.spi.entry.StandardCacheEntryImpl; import org.hibernate.cache.spi.entry.StandardCacheEntryImpl;
import org.hibernate.cache.spi.entry.StructuredCacheEntry; import org.hibernate.cache.spi.entry.StructuredCacheEntry;
import org.hibernate.cache.spi.entry.UnstructuredCacheEntry; import org.hibernate.cache.spi.entry.UnstructuredCacheEntry;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.dialect.lock.LockingStrategy; import org.hibernate.dialect.lock.LockingStrategy;
import org.hibernate.engine.OptimisticLockStyle; import org.hibernate.engine.OptimisticLockStyle;
import org.hibernate.engine.internal.StatefulPersistenceContext; import org.hibernate.engine.internal.StatefulPersistenceContext;
@ -120,12 +119,9 @@ import org.hibernate.metamodel.spi.relational.DerivedValue;
import org.hibernate.metamodel.spi.relational.Table; import org.hibernate.metamodel.spi.relational.Table;
import org.hibernate.metamodel.spi.relational.TableSpecification; import org.hibernate.metamodel.spi.relational.TableSpecification;
import org.hibernate.metamodel.spi.relational.Value; import org.hibernate.metamodel.spi.relational.Value;
import org.hibernate.persister.walking.internal.EntityIdentifierDefinitionHelper;
import org.hibernate.persister.walking.spi.AttributeDefinition; 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.EntityIdentifierDefinition;
import org.hibernate.persister.walking.spi.NonEncapsulatedEntityIdentifierDefinition;
import org.hibernate.pretty.MessageHelper; import org.hibernate.pretty.MessageHelper;
import org.hibernate.property.BackrefPropertyAccessor; import org.hibernate.property.BackrefPropertyAccessor;
import org.hibernate.sql.Alias; import org.hibernate.sql.Alias;
@ -5290,80 +5286,20 @@ public abstract class AbstractEntityPersister
final Type idType = getIdentifierType(); final Type idType = getIdentifierType();
if ( !idType.isComponentType() ) { if ( !idType.isComponentType() ) {
entityIdentifierDefinition = buildEncapsulatedIdentifierDefinition(); entityIdentifierDefinition =
EntityIdentifierDefinitionHelper.buildSimpleEncapsulatedIdentifierDefinition( this );
return; return;
} }
final CompositeType cidType = (CompositeType) idType; final CompositeType cidType = (CompositeType) idType;
if ( !cidType.isEmbedded() ) { if ( !cidType.isEmbedded() ) {
entityIdentifierDefinition = buildEncapsulatedIdentifierDefinition(); entityIdentifierDefinition =
EntityIdentifierDefinitionHelper.buildEncapsulatedCompositeIdentifierDefinition( this );
return; return;
} }
entityIdentifierDefinition = new NonEncapsulatedEntityIdentifierDefinition() { entityIdentifierDefinition =
@Override EntityIdentifierDefinitionHelper.buildNonEncapsulatedCompositeIdentifierDefinition( this );
public Iterable<AttributeDefinition> getAttributes() {
// todo : implement
throw new NotYetImplementedException();
}
@Override
public Class getSeparateIdentifierMappingClass() {
// todo : implement
throw new NotYetImplementedException();
}
@Override
public boolean isEncapsulated() {
return false;
}
@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() { private void collectAttributeDefinitions() {

View File

@ -0,0 +1,212 @@
package org.hibernate.persister.walking.internal;
import java.util.Iterator;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.engine.spi.CascadeStyles;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.PropertyPath;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.persister.spi.HydratedCompoundValueHandler;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
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.CollectionDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.persister.walking.spi.CompositionElementDefinition;
import org.hibernate.persister.walking.spi.EntityDefinition;
import org.hibernate.persister.walking.spi.WalkingException;
import org.hibernate.type.AssociationType;
import org.hibernate.type.CompositeType;
import org.hibernate.type.Type;
/**
* @author Gail Badner
*/
public class CompositionSingularSubAttributesHelper {
public static Iterable<AttributeDefinition> getIdentifierSubAttributes(
final AbstractEntityPersister entityPersister) {
return getSingularSubAttributes(
entityPersister,
entityPersister,
(CompositeType) entityPersister.getIdentifierType(),
entityPersister.getTableName(),
entityPersister.getRootTableIdentifierColumnNames()
);
}
public static Iterable<AttributeDefinition> getCompositionElementSubAttributes(
CompositionElementDefinition compositionElementDefinition) {
final QueryableCollection collectionPersister =
(QueryableCollection) compositionElementDefinition.getCollectionDefinition().getCollectionPersister();
return getSingularSubAttributes(
compositionElementDefinition.getSource(),
(OuterJoinLoadable) collectionPersister.getOwnerEntityPersister(),
(CompositeType) collectionPersister.getElementType(),
collectionPersister.getTableName(),
collectionPersister.getElementColumnNames()
);
}
private static Iterable<AttributeDefinition> getSingularSubAttributes(
final AttributeSource source,
final OuterJoinLoadable ownerEntityPersister,
final CompositeType compositeType,
final String lhsTableName,
final String[] lhsColumns) {
return new Iterable<AttributeDefinition>() {
@Override
public Iterator<AttributeDefinition> iterator() {
return new Iterator<AttributeDefinition>() {
private final int numberOfAttributes = compositeType.getSubtypes().length;
private int currentSubAttributeNumber = 0;
private int currentColumnPosition = 0;
@Override
public boolean hasNext() {
return currentSubAttributeNumber < numberOfAttributes;
}
@Override
public AttributeDefinition next() {
final int subAttributeNumber = currentSubAttributeNumber;
currentSubAttributeNumber++;
final String name = compositeType.getPropertyNames()[subAttributeNumber];
final Type type = compositeType.getSubtypes()[subAttributeNumber];
final int columnPosition = currentColumnPosition;
final int columnSpan = type.getColumnSpan( ownerEntityPersister.getFactory() );
final String[] subAttributeLhsColumns = ArrayHelper.slice( lhsColumns, columnPosition, columnSpan );
currentColumnPosition += columnSpan;
if ( type.isAssociationType() ) {
final AssociationType aType = (AssociationType) type;
return new AssociationAttributeDefinition() {
@Override
public AssociationKey getAssociationKey() {
/* TODO: is this always correct? */
//return new AssociationKey(
// joinable.getTableName(),
// JoinHelper.getRHSColumnNames( aType, getEntityPersister().getFactory() )
//);
return new AssociationKey(
lhsTableName,
subAttributeLhsColumns
);
}
@Override
public boolean isCollection() {
return false;
}
@Override
public EntityDefinition toEntityDefinition() {
return (EntityPersister) aType.getAssociatedJoinable( ownerEntityPersister.getFactory() );
}
@Override
public CollectionDefinition toCollectionDefinition() {
throw new WalkingException( "A collection cannot be mapped to a composite ID sub-attribute." );
}
@Override
public FetchStrategy determineFetchPlan(LoadQueryInfluencers loadQueryInfluencers, PropertyPath propertyPath) {
return new FetchStrategy( FetchTiming.IMMEDIATE, FetchStyle.JOIN );
}
@Override
public CascadeStyle determineCascadeStyle() {
return CascadeStyles.NONE;
}
@Override
public HydratedCompoundValueHandler getHydratedCompoundValueExtractor() {
return null;
}
@Override
public String getName() {
return name;
}
@Override
public Type getType() {
return type;
}
@Override
public AttributeSource getSource() {
return source;
}
};
}
else if ( type.isComponentType() ) {
return new CompositionDefinition() {
@Override
public String getName() {
return name;
}
@Override
public Type getType() {
return type;
}
@Override
public AttributeSource getSource() {
return this;
}
@Override
public Iterable<AttributeDefinition> getAttributes() {
return CompositionSingularSubAttributesHelper.getSingularSubAttributes(
this,
ownerEntityPersister,
(CompositeType) type,
lhsTableName,
subAttributeLhsColumns
);
}
};
}
else {
return new AttributeDefinition() {
@Override
public String getName() {
return name;
}
@Override
public Type getType() {
return type;
}
@Override
public AttributeSource getSource() {
return source;
}
};
}
}
@Override
public void remove() {
throw new UnsupportedOperationException( "Remove operation not supported here" );
}
};
}
};
}
}

View File

@ -0,0 +1,153 @@
/*
* 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.internal;
import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.persister.walking.spi.AttributeDefinition;
import org.hibernate.persister.walking.spi.AttributeSource;
import org.hibernate.persister.walking.spi.CompositionDefinition;
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.type.Type;
/**
* @author Gail Badner
*/
public class EntityIdentifierDefinitionHelper {
public static EntityIdentifierDefinition buildSimpleEncapsulatedIdentifierDefinition(final AbstractEntityPersister entityPersister) {
return new EncapsulatedEntityIdentifierDefinition() {
@Override
public AttributeDefinition getAttributeDefinition() {
return new AttributeDefinitionAdapter( entityPersister);
}
@Override
public boolean isEncapsulated() {
return true;
}
@Override
public EntityDefinition getEntityDefinition() {
return entityPersister;
}
};
}
public static EntityIdentifierDefinition buildEncapsulatedCompositeIdentifierDefinition(
final AbstractEntityPersister entityPersister) {
return new EncapsulatedEntityIdentifierDefinition() {
@Override
public AttributeDefinition getAttributeDefinition() {
return new CompositionDefinitionAdapter( entityPersister );
}
@Override
public boolean isEncapsulated() {
return true;
}
@Override
public EntityDefinition getEntityDefinition() {
return entityPersister;
}
};
}
public static EntityIdentifierDefinition buildNonEncapsulatedCompositeIdentifierDefinition(final AbstractEntityPersister entityPersister) {
return new NonEncapsulatedEntityIdentifierDefinition() {
@Override
public Iterable<AttributeDefinition> getAttributes() {
return CompositionSingularSubAttributesHelper.getIdentifierSubAttributes( entityPersister );
}
@Override
public Class getSeparateIdentifierMappingClass() {
return entityPersister.getEntityMetamodel().getIdentifierProperty().getType().getReturnedClass();
}
@Override
public boolean isEncapsulated() {
return false;
}
@Override
public EntityDefinition getEntityDefinition() {
return entityPersister;
}
};
}
private static class AttributeDefinitionAdapter implements AttributeDefinition {
private final AbstractEntityPersister entityPersister;
AttributeDefinitionAdapter(AbstractEntityPersister entityPersister) {
this.entityPersister = entityPersister;
}
@Override
public String getName() {
return entityPersister.getEntityMetamodel().getIdentifierProperty().getName();
}
@Override
public Type getType() {
return entityPersister.getEntityMetamodel().getIdentifierProperty().getType();
}
@Override
public AttributeSource getSource() {
return entityPersister;
}
@Override
public String toString() {
return "<identifier-property:" + getName() + ">";
}
protected AbstractEntityPersister getEntityPersister() {
return entityPersister;
}
}
private static class CompositionDefinitionAdapter extends AttributeDefinitionAdapter implements CompositionDefinition {
CompositionDefinitionAdapter(AbstractEntityPersister entityPersister) {
super( entityPersister );
}
@Override
public String toString() {
return "<identifier-property:" + getName() + ">";
}
@Override
public Iterable<AttributeDefinition> getAttributes() {
return CompositionSingularSubAttributesHelper.getIdentifierSubAttributes( getEntityPersister() );
}
}
}

View File

@ -42,7 +42,7 @@ import org.hibernate.type.AssociationType;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class Helper { public class FetchStrategyHelper {
/** /**
* Determine the fetch-style (if one) explicitly set for this association via fetch profiles. * Determine the fetch-style (if one) explicitly set for this association via fetch profiles.
* <p/> * <p/>

View File

@ -55,6 +55,9 @@ public interface AssociationVisitationStrategy {
public void startingComposite(CompositionDefinition compositionDefinition); public void startingComposite(CompositionDefinition compositionDefinition);
public void finishingComposite(CompositionDefinition compositionDefinition); public void finishingComposite(CompositionDefinition compositionDefinition);
public void startingCompositeElement(CompositionElementDefinition compositionElementDefinition);
public void finishingCompositeElement(CompositionElementDefinition compositionElementDefinition);
public boolean startingAttribute(AttributeDefinition attributeDefinition); public boolean startingAttribute(AttributeDefinition attributeDefinition);
public void finishingAttribute(AttributeDefinition attributeDefinition); public void finishingAttribute(AttributeDefinition attributeDefinition);
} }

View File

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

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 Gail Badner
*/
public interface CompositionElementDefinition extends CompositionDefinition{
public CollectionDefinition getCollectionDefinition();
}

View File

@ -114,10 +114,10 @@ public class MetadataDrivenModelGraphVisitor {
log.debug( "Visiting attribute path : " + subPath.getFullPath() ); log.debug( "Visiting attribute path : " + subPath.getFullPath() );
final boolean continueWalk; final boolean continueWalk;
if ( attributeDefinition.getType().isAssociationType() ) { if ( attributeDefinition.getType().isAssociationType() &&
continueWalk = isDuplicateAssociationKey( ( (AssociationAttributeDefinition) attributeDefinition ).getAssociationKey() ) ) {
! isDuplicateAssociation( ( (AssociationAttributeDefinition) attributeDefinition ).getAssociationKey() ) && log.debug( "Property path deemed to be circular : " + subPath.getFullPath() );
strategy.startingAttribute( attributeDefinition ); continueWalk = false;
} }
else { else {
continueWalk = strategy.startingAttribute( attributeDefinition ); continueWalk = strategy.startingAttribute( attributeDefinition );
@ -143,6 +143,8 @@ public class MetadataDrivenModelGraphVisitor {
private void visitAssociation(AssociationAttributeDefinition attribute) { private void visitAssociation(AssociationAttributeDefinition attribute) {
// todo : do "too deep" checks; but see note about adding depth to PropertyPath // todo : do "too deep" checks; but see note about adding depth to PropertyPath
addAssociationKey( attribute.getAssociationKey() );
if ( attribute.isCollection() ) { if ( attribute.isCollection() ) {
visitCollectionDefinition( attribute.toCollectionDefinition() ); visitCollectionDefinition( attribute.toCollectionDefinition() );
} }
@ -200,7 +202,7 @@ public class MetadataDrivenModelGraphVisitor {
strategy.startingCollectionElements( elementDefinition ); strategy.startingCollectionElements( elementDefinition );
if ( elementDefinition.getType().isComponentType() ) { if ( elementDefinition.getType().isComponentType() ) {
visitCompositeDefinition( elementDefinition.toCompositeDefinition() ); visitCompositeElementDefinition( elementDefinition.toCompositeElementDefinition() );
} }
else if ( elementDefinition.getType().isEntityType() ) { else if ( elementDefinition.getType().isEntityType() ) {
visitEntityDefinition( elementDefinition.toEntityDefinition() ); visitEntityDefinition( elementDefinition.toEntityDefinition() );
@ -209,18 +211,37 @@ public class MetadataDrivenModelGraphVisitor {
strategy.finishingCollectionElements( elementDefinition ); strategy.finishingCollectionElements( elementDefinition );
} }
private void visitCompositeElementDefinition(CompositionElementDefinition compositionElementDefinition) {
strategy.startingCompositeElement( compositionElementDefinition );
visitAttributes( compositionElementDefinition );
strategy.finishingCompositeElement( compositionElementDefinition );
}
private final Set<AssociationKey> visitedAssociationKeys = new HashSet<AssociationKey>(); private final Set<AssociationKey> visitedAssociationKeys = new HashSet<AssociationKey>();
protected boolean isDuplicateAssociation(AssociationKey associationKey) { /**
boolean isDuplicate = !visitedAssociationKeys.add( associationKey ); * Add association key to indicate the association is being visited.
if ( isDuplicate ) { * @param associationKey - the association key.
log.debug( "Property path deemed to be circular : " + currentPropertyPath.getFullPath() ); * @throws WalkingException if the association with the specified association key
return true; * has already been visited.
} */
else { protected void addAssociationKey(AssociationKey associationKey) {
return false; if ( ! visitedAssociationKeys.add( associationKey ) ) {
throw new WalkingException(
String.format( "Association has already been visited: %s", associationKey )
);
} }
} }
/**
* Has an association with the specified key been visited already?
* @param associationKey - the association key.
* @return true, if the association with the specified association key has already been visited;
* false, otherwise.
*/
protected boolean isDuplicateAssociationKey(AssociationKey associationKey) {
return visitedAssociationKeys.contains( associationKey );
}
} }

View File

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

View File

@ -48,9 +48,9 @@ import static org.hibernate.engine.internal.JoinHelper.getRHSColumnNames;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public abstract class AbstractCompositionDefinition extends AbstractNonIdentifierAttribute implements public abstract class AbstractCompositionAttribute extends AbstractNonIdentifierAttribute implements
CompositionDefinition { CompositionDefinition {
protected AbstractCompositionDefinition( protected AbstractCompositionAttribute(
AttributeSource source, AttributeSource source,
SessionFactoryImplementor sessionFactory, SessionFactoryImplementor sessionFactory,
int attributeNumber, int attributeNumber,
@ -72,21 +72,21 @@ public abstract class AbstractCompositionDefinition extends AbstractNonIdentifie
public Iterator<AttributeDefinition> iterator() { public Iterator<AttributeDefinition> iterator() {
return new Iterator<AttributeDefinition>() { return new Iterator<AttributeDefinition>() {
private final int numberOfAttributes = getType().getSubtypes().length; private final int numberOfAttributes = getType().getSubtypes().length;
private int currentAttributeNumber = 0; private int currentSubAttributeNumber = 0;
private int currentColumnPosition = 0; private int currentColumnPosition = 0;
@Override @Override
public boolean hasNext() { public boolean hasNext() {
return currentAttributeNumber < numberOfAttributes; return currentSubAttributeNumber < numberOfAttributes;
} }
@Override @Override
public AttributeDefinition next() { public AttributeDefinition next() {
final int attributeNumber = currentAttributeNumber; final int subAttributeNumber = currentSubAttributeNumber;
currentAttributeNumber++; currentSubAttributeNumber++;
final String name = getType().getPropertyNames()[attributeNumber]; final String name = getType().getPropertyNames()[subAttributeNumber];
final Type type = getType().getSubtypes()[attributeNumber]; final Type type = getType().getSubtypes()[subAttributeNumber];
int columnPosition = currentColumnPosition; int columnPosition = currentColumnPosition;
currentColumnPosition += type.getColumnSpan( sessionFactory() ); currentColumnPosition += type.getColumnSpan( sessionFactory() );
@ -101,13 +101,13 @@ public abstract class AbstractCompositionDefinition extends AbstractNonIdentifie
getLHSTableName( getLHSTableName(
aType, aType,
attributeNumber(), attributeNumber(),
(OuterJoinLoadable) joinable (OuterJoinLoadable) locateOwningPersister()
), ),
getLHSColumnNames( getLHSColumnNames(
aType, aType,
attributeNumber(), attributeNumber(),
columnPosition, columnPosition,
(OuterJoinLoadable) joinable, (OuterJoinLoadable) locateOwningPersister(),
sessionFactory() sessionFactory()
) )
); );
@ -120,63 +120,63 @@ public abstract class AbstractCompositionDefinition extends AbstractNonIdentifie
} }
return new CompositeBasedAssociationAttribute( return new CompositeBasedAssociationAttribute(
AbstractCompositionDefinition.this, AbstractCompositionAttribute.this,
sessionFactory(), sessionFactory(),
currentAttributeNumber, subAttributeNumber,
name, name,
(AssociationType) type, (AssociationType) type,
new BaselineAttributeInformation.Builder() new BaselineAttributeInformation.Builder()
.setInsertable( AbstractCompositionDefinition.this.isInsertable() ) .setInsertable( AbstractCompositionAttribute.this.isInsertable() )
.setUpdateable( AbstractCompositionDefinition.this.isUpdateable() ) .setUpdateable( AbstractCompositionAttribute.this.isUpdateable() )
.setInsertGenerated( AbstractCompositionDefinition.this.isInsertGenerated() ) .setInsertGenerated( AbstractCompositionAttribute.this.isInsertGenerated() )
.setUpdateGenerated( AbstractCompositionDefinition.this.isUpdateGenerated() ) .setUpdateGenerated( AbstractCompositionAttribute.this.isUpdateGenerated() )
.setNullable( getType().getPropertyNullability()[currentAttributeNumber] ) .setNullable( getType().getPropertyNullability()[subAttributeNumber] )
.setDirtyCheckable( true ) .setDirtyCheckable( true )
.setVersionable( AbstractCompositionDefinition.this.isVersionable() ) .setVersionable( AbstractCompositionAttribute.this.isVersionable() )
.setCascadeStyle( getType().getCascadeStyle( currentAttributeNumber ) ) .setCascadeStyle( getType().getCascadeStyle( subAttributeNumber ) )
.setFetchMode( getType().getFetchMode( currentAttributeNumber ) ) .setFetchMode( getType().getFetchMode( subAttributeNumber ) )
.createInformation(), .createInformation(),
AbstractCompositionDefinition.this.attributeNumber(), AbstractCompositionAttribute.this.attributeNumber(),
associationKey associationKey
); );
} }
else if ( type.isComponentType() ) { else if ( type.isComponentType() ) {
return new CompositionBasedCompositionAttribute( return new CompositionBasedCompositionAttribute(
AbstractCompositionDefinition.this, AbstractCompositionAttribute.this,
sessionFactory(), sessionFactory(),
currentAttributeNumber, subAttributeNumber,
name, name,
(CompositeType) type, (CompositeType) type,
new BaselineAttributeInformation.Builder() new BaselineAttributeInformation.Builder()
.setInsertable( AbstractCompositionDefinition.this.isInsertable() ) .setInsertable( AbstractCompositionAttribute.this.isInsertable() )
.setUpdateable( AbstractCompositionDefinition.this.isUpdateable() ) .setUpdateable( AbstractCompositionAttribute.this.isUpdateable() )
.setInsertGenerated( AbstractCompositionDefinition.this.isInsertGenerated() ) .setInsertGenerated( AbstractCompositionAttribute.this.isInsertGenerated() )
.setUpdateGenerated( AbstractCompositionDefinition.this.isUpdateGenerated() ) .setUpdateGenerated( AbstractCompositionAttribute.this.isUpdateGenerated() )
.setNullable( getType().getPropertyNullability()[currentAttributeNumber] ) .setNullable( getType().getPropertyNullability()[subAttributeNumber] )
.setDirtyCheckable( true ) .setDirtyCheckable( true )
.setVersionable( AbstractCompositionDefinition.this.isVersionable() ) .setVersionable( AbstractCompositionAttribute.this.isVersionable() )
.setCascadeStyle( getType().getCascadeStyle( currentAttributeNumber ) ) .setCascadeStyle( getType().getCascadeStyle( subAttributeNumber ) )
.setFetchMode( getType().getFetchMode( currentAttributeNumber ) ) .setFetchMode( getType().getFetchMode( subAttributeNumber ) )
.createInformation() .createInformation()
); );
} }
else { else {
return new CompositeBasedBasicAttribute( return new CompositeBasedBasicAttribute(
AbstractCompositionDefinition.this, AbstractCompositionAttribute.this,
sessionFactory(), sessionFactory(),
currentAttributeNumber, subAttributeNumber,
name, name,
type, type,
new BaselineAttributeInformation.Builder() new BaselineAttributeInformation.Builder()
.setInsertable( AbstractCompositionDefinition.this.isInsertable() ) .setInsertable( AbstractCompositionAttribute.this.isInsertable() )
.setUpdateable( AbstractCompositionDefinition.this.isUpdateable() ) .setUpdateable( AbstractCompositionAttribute.this.isUpdateable() )
.setInsertGenerated( AbstractCompositionDefinition.this.isInsertGenerated() ) .setInsertGenerated( AbstractCompositionAttribute.this.isInsertGenerated() )
.setUpdateGenerated( AbstractCompositionDefinition.this.isUpdateGenerated() ) .setUpdateGenerated( AbstractCompositionAttribute.this.isUpdateGenerated() )
.setNullable( getType().getPropertyNullability()[currentAttributeNumber] ) .setNullable( getType().getPropertyNullability()[subAttributeNumber] )
.setDirtyCheckable( true ) .setDirtyCheckable( true )
.setVersionable( AbstractCompositionDefinition.this.isVersionable() ) .setVersionable( AbstractCompositionAttribute.this.isVersionable() )
.setCascadeStyle( getType().getCascadeStyle( currentAttributeNumber ) ) .setCascadeStyle( getType().getCascadeStyle( subAttributeNumber ) )
.setFetchMode( getType().getFetchMode( currentAttributeNumber ) ) .setFetchMode( getType().getFetchMode( subAttributeNumber ) )
.createInformation() .createInformation()
); );
} }
@ -196,7 +196,7 @@ public abstract class AbstractCompositionDefinition extends AbstractNonIdentifie
return ( (EntityDefinition) getSource() ).getEntityPersister(); return ( (EntityDefinition) getSource() ).getEntityPersister();
} }
else { else {
return ( (AbstractCompositionDefinition) getSource() ).locateOwningPersister(); return ( (AbstractCompositionAttribute) getSource() ).locateOwningPersister();
} }
} }

View File

@ -35,7 +35,7 @@ import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Joinable; import org.hibernate.persister.entity.Joinable;
import org.hibernate.persister.spi.HydratedCompoundValueHandler; import org.hibernate.persister.spi.HydratedCompoundValueHandler;
import org.hibernate.persister.walking.internal.Helper; import org.hibernate.persister.walking.internal.FetchStrategyHelper;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition; import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.AssociationKey; import org.hibernate.persister.walking.spi.AssociationKey;
import org.hibernate.persister.walking.spi.CollectionDefinition; import org.hibernate.persister.walking.spi.CollectionDefinition;
@ -55,7 +55,7 @@ public class CompositeBasedAssociationAttribute
private Joinable joinable; private Joinable joinable;
public CompositeBasedAssociationAttribute( public CompositeBasedAssociationAttribute(
AbstractCompositionDefinition source, AbstractCompositionAttribute source,
SessionFactoryImplementor factory, SessionFactoryImplementor factory,
int attributeNumber, int attributeNumber,
String attributeName, String attributeName,
@ -130,7 +130,7 @@ public class CompositeBasedAssociationAttribute
EntityPersister owningPersister, EntityPersister owningPersister,
PropertyPath propertyPath, PropertyPath propertyPath,
int ownerAttributeNumber) { int ownerAttributeNumber) {
return Helper.determineFetchStyleByProfile( return FetchStrategyHelper.determineFetchStyleByProfile(
loadQueryInfluencers, loadQueryInfluencers,
owningPersister, owningPersister,
propertyPath, propertyPath,
@ -139,11 +139,11 @@ public class CompositeBasedAssociationAttribute
} }
protected FetchStyle determineFetchStyleByMetadata(FetchMode fetchMode, AssociationType type) { protected FetchStyle determineFetchStyleByMetadata(FetchMode fetchMode, AssociationType type) {
return Helper.determineFetchStyleByMetadata( fetchMode, type, sessionFactory() ); return FetchStrategyHelper.determineFetchStyleByMetadata( fetchMode, type, sessionFactory() );
} }
private FetchTiming determineFetchTiming(FetchStyle style) { private FetchTiming determineFetchTiming(FetchStyle style) {
return Helper.determineFetchTiming( style, getType(), sessionFactory() ); return FetchStrategyHelper.determineFetchTiming( style, getType(), sessionFactory() );
} }
private EntityPersister locateOwningPersister() { private EntityPersister locateOwningPersister() {

View File

@ -32,7 +32,7 @@ import org.hibernate.type.CompositeType;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class CompositionBasedCompositionAttribute public class CompositionBasedCompositionAttribute
extends AbstractCompositionDefinition extends AbstractCompositionAttribute
implements CompositionDefinition { implements CompositionDefinition {
public CompositionBasedCompositionAttribute( public CompositionBasedCompositionAttribute(
CompositionDefinition source, CompositionDefinition source,

View File

@ -34,7 +34,7 @@ import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Joinable; import org.hibernate.persister.entity.Joinable;
import org.hibernate.persister.entity.OuterJoinLoadable; import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.persister.spi.HydratedCompoundValueHandler; import org.hibernate.persister.spi.HydratedCompoundValueHandler;
import org.hibernate.persister.walking.internal.Helper; import org.hibernate.persister.walking.internal.FetchStrategyHelper;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition; import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.AssociationKey; import org.hibernate.persister.walking.spi.AssociationKey;
import org.hibernate.persister.walking.spi.CollectionDefinition; import org.hibernate.persister.walking.spi.CollectionDefinition;
@ -129,14 +129,14 @@ public class EntityBasedAssociationAttribute
public FetchStrategy determineFetchPlan(LoadQueryInfluencers loadQueryInfluencers, PropertyPath propertyPath) { public FetchStrategy determineFetchPlan(LoadQueryInfluencers loadQueryInfluencers, PropertyPath propertyPath) {
final EntityPersister owningPersister = getSource().getEntityPersister(); final EntityPersister owningPersister = getSource().getEntityPersister();
FetchStyle style = Helper.determineFetchStyleByProfile( FetchStyle style = FetchStrategyHelper.determineFetchStyleByProfile(
loadQueryInfluencers, loadQueryInfluencers,
owningPersister, owningPersister,
propertyPath, propertyPath,
attributeNumber() attributeNumber()
); );
if ( style == null ) { if ( style == null ) {
style = Helper.determineFetchStyleByMetadata( style = FetchStrategyHelper.determineFetchStyleByMetadata(
( (OuterJoinLoadable) getSource().getEntityPersister() ).getFetchMode( attributeNumber() ), ( (OuterJoinLoadable) getSource().getEntityPersister() ).getFetchMode( attributeNumber() ),
getType(), getType(),
sessionFactory() sessionFactory()
@ -144,7 +144,7 @@ public class EntityBasedAssociationAttribute
} }
return new FetchStrategy( return new FetchStrategy(
Helper.determineFetchTiming( style, getType(), sessionFactory() ), FetchStrategyHelper.determineFetchTiming( style, getType(), sessionFactory() ),
style style
); );
} }

View File

@ -25,7 +25,7 @@ package org.hibernate.tuple.entity;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.tuple.component.AbstractCompositionDefinition; import org.hibernate.tuple.component.AbstractCompositionAttribute;
import org.hibernate.persister.walking.spi.CompositionDefinition; import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.tuple.BaselineAttributeInformation; import org.hibernate.tuple.BaselineAttributeInformation;
import org.hibernate.type.CompositeType; import org.hibernate.type.CompositeType;
@ -34,7 +34,7 @@ import org.hibernate.type.CompositeType;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class EntityBasedCompositionAttribute public class EntityBasedCompositionAttribute
extends AbstractCompositionDefinition extends AbstractCompositionAttribute
implements CompositionDefinition { implements CompositionDefinition {
public EntityBasedCompositionAttribute( public EntityBasedCompositionAttribute(

View File

@ -23,6 +23,7 @@
*/ */
package org.hibernate.type; package org.hibernate.type;
import java.io.Serializable; import java.io.Serializable;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
@ -34,7 +35,11 @@ import org.hibernate.Filter;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.engine.internal.ForeignKeys; import org.hibernate.engine.internal.ForeignKeys;
import org.hibernate.engine.spi.*; import org.hibernate.engine.spi.EntityUniqueKey;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.internal.util.ReflectHelper; import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Joinable; import org.hibernate.persister.entity.Joinable;
@ -53,6 +58,7 @@ public abstract class EntityType extends AbstractType implements AssociationType
protected final String uniqueKeyPropertyName; protected final String uniqueKeyPropertyName;
private final boolean eager; private final boolean eager;
private final boolean unwrapProxy; private final boolean unwrapProxy;
private final boolean referenceToPrimaryKey;
private transient Class returnedClass; private transient Class returnedClass;
@ -67,29 +73,46 @@ public abstract class EntityType extends AbstractType implements AssociationType
* @param unwrapProxy Is unwrapping of proxies allowed for this association; unwrapping * @param unwrapProxy Is unwrapping of proxies allowed for this association; unwrapping
* says to return the "implementation target" of lazy prooxies; typically only possible * says to return the "implementation target" of lazy prooxies; typically only possible
* with lazy="no-proxy". * with lazy="no-proxy".
*
* @deprecated Use {@link #EntityType(org.hibernate.type.TypeFactory.TypeScope, String, boolean, String, boolean, boolean)} instead.
* See Jira issue: <a href="https://hibernate.onjira.com/browse/HHH-7771">HHH-7771</a>
*/ */
@Deprecated
protected EntityType( protected EntityType(
TypeFactory.TypeScope scope, TypeFactory.TypeScope scope,
String entityName, String entityName,
String uniqueKeyPropertyName, String uniqueKeyPropertyName,
boolean eager, boolean eager,
boolean unwrapProxy) { boolean unwrapProxy) {
this(scope, entityName, uniqueKeyPropertyName, eager, unwrapProxy, null); this( scope, entityName, uniqueKeyPropertyName == null, uniqueKeyPropertyName, eager, unwrapProxy );
} }
/**
* Constructs the requested entity type mapping.
*
* @param scope The type scope
* @param entityName The name of the associated entity.
* @param referenceToPrimaryKey True if association references a primary key.
* @param uniqueKeyPropertyName The property-ref name, or null if we
* reference the PK of the associated entity.
* @param eager Is eager fetching enabled.
* @param unwrapProxy Is unwrapping of proxies allowed for this association; unwrapping
* says to return the "implementation target" of lazy prooxies; typically only possible
* with lazy="no-proxy".
*/
protected EntityType( protected EntityType(
TypeFactory.TypeScope scope, TypeFactory.TypeScope scope,
String entityName, String entityName,
boolean referenceToPrimaryKey,
String uniqueKeyPropertyName, String uniqueKeyPropertyName,
boolean eager, boolean eager,
boolean unwrapProxy, boolean unwrapProxy) {
Class returnedClass) {
this.scope = scope; this.scope = scope;
this.associatedEntityName = entityName; this.associatedEntityName = entityName;
this.uniqueKeyPropertyName = uniqueKeyPropertyName; this.uniqueKeyPropertyName = uniqueKeyPropertyName;
this.eager = eager; this.eager = eager;
this.unwrapProxy = unwrapProxy; this.unwrapProxy = unwrapProxy;
this.returnedClass = returnedClass; this.referenceToPrimaryKey = referenceToPrimaryKey;
} }
@ -146,11 +169,13 @@ public abstract class EntityType extends AbstractType implements AssociationType
* @return True if this association reference the PK of the associated entity. * @return True if this association reference the PK of the associated entity.
*/ */
public boolean isReferenceToPrimaryKey() { public boolean isReferenceToPrimaryKey() {
return uniqueKeyPropertyName==null; return referenceToPrimaryKey;
} }
public String getRHSUniqueKeyPropertyName() { public String getRHSUniqueKeyPropertyName() {
return uniqueKeyPropertyName; // Return null if this type references a PK. This is important for
// associations' use of mappedBy referring to a derived ID.
return referenceToPrimaryKey ? null : uniqueKeyPropertyName;
} }
public String getLHSPropertyName() { public String getLHSPropertyName() {
@ -397,14 +422,15 @@ public abstract class EntityType extends AbstractType implements AssociationType
if ( isNull( owner, session ) ) { if ( isNull( owner, session ) ) {
return null; //EARLY EXIT! return null; //EARLY EXIT!
} }
if ( isReferenceToPrimaryKey() ) { if ( isReferenceToPrimaryKey() ) {
return resolveIdentifier( (Serializable) value, session ); return resolveIdentifier( (Serializable) value, session );
} }
else { else if ( uniqueKeyPropertyName != null ) {
return loadByUniqueKey( getAssociatedEntityName(), uniqueKeyPropertyName, value, session ); return loadByUniqueKey( getAssociatedEntityName(), uniqueKeyPropertyName, value, session );
} }
} }
return null;
} }
public Type getSemiResolvedType(SessionFactoryImplementor factory) { public Type getSemiResolvedType(SessionFactoryImplementor factory) {
@ -412,7 +438,7 @@ public abstract class EntityType extends AbstractType implements AssociationType
} }
protected final Object getIdentifier(Object value, SessionImplementor session) throws HibernateException { protected final Object getIdentifier(Object value, SessionImplementor session) throws HibernateException {
if ( isReferenceToPrimaryKey() ) { if ( isReferenceToPrimaryKey() || uniqueKeyPropertyName == null) {
return ForeignKeys.getEntityIdentifierIfNotUnsaved( getAssociatedEntityName(), value, session ); //tolerates nulls return ForeignKeys.getEntityIdentifierIfNotUnsaved( getAssociatedEntityName(), value, session ); //tolerates nulls
} }
else if ( value == null ) { else if ( value == null ) {
@ -516,7 +542,7 @@ public abstract class EntityType extends AbstractType implements AssociationType
* or unique key property name. * or unique key property name.
*/ */
public final Type getIdentifierOrUniqueKeyType(Mapping factory) throws MappingException { public final Type getIdentifierOrUniqueKeyType(Mapping factory) throws MappingException {
if ( isReferenceToPrimaryKey() ) { if ( isReferenceToPrimaryKey() || uniqueKeyPropertyName == null ) {
return getIdentifierType(factory); return getIdentifierType(factory);
} }
else { else {
@ -538,7 +564,7 @@ public abstract class EntityType extends AbstractType implements AssociationType
*/ */
public final String getIdentifierOrUniqueKeyPropertyName(Mapping factory) public final String getIdentifierOrUniqueKeyPropertyName(Mapping factory)
throws MappingException { throws MappingException {
if ( isReferenceToPrimaryKey() ) { if ( isReferenceToPrimaryKey() || uniqueKeyPropertyName == null ) {
return factory.getIdentifierPropertyName( getAssociatedEntityName() ); return factory.getIdentifierPropertyName( getAssociatedEntityName() );
} }
else { else {

View File

@ -67,9 +67,15 @@ public class ManyToOneType extends EntityType {
* @param lazy Should the association be handled lazily * @param lazy Should the association be handled lazily
*/ */
public ManyToOneType(TypeFactory.TypeScope scope, String referencedEntityName, boolean lazy) { public ManyToOneType(TypeFactory.TypeScope scope, String referencedEntityName, boolean lazy) {
this( scope, referencedEntityName, null, lazy, true, false, false ); this( scope, referencedEntityName, true, null, lazy, true, false, false );
} }
/**
* @deprecated Use {@link #ManyToOneType(TypeFactory.TypeScope, String, boolean, String, boolean, boolean, boolean, boolean ) } instead.
* See Jira issue: <a href="https://hibernate.onjira.com/browse/HHH-7771">HHH-7771</a>
*/
@Deprecated
public ManyToOneType( public ManyToOneType(
TypeFactory.TypeScope scope, TypeFactory.TypeScope scope,
String referencedEntityName, String referencedEntityName,
@ -78,20 +84,18 @@ public class ManyToOneType extends EntityType {
boolean unwrapProxy, boolean unwrapProxy,
boolean ignoreNotFound, boolean ignoreNotFound,
boolean isLogicalOneToOne) { boolean isLogicalOneToOne) {
super( scope, referencedEntityName, uniqueKeyPropertyName, !lazy, unwrapProxy ); this( scope, referencedEntityName, uniqueKeyPropertyName == null, uniqueKeyPropertyName, lazy, unwrapProxy, ignoreNotFound, isLogicalOneToOne );
this.ignoreNotFound = ignoreNotFound;
this.isLogicalOneToOne = isLogicalOneToOne;
} }
public ManyToOneType( public ManyToOneType(
TypeFactory.TypeScope scope, TypeFactory.TypeScope scope,
String referencedEntityName, String referencedEntityName,
boolean referenceToPrimaryKey,
String uniqueKeyPropertyName, String uniqueKeyPropertyName,
boolean lazy, boolean lazy,
boolean unwrapProxy, boolean unwrapProxy,
boolean ignoreNotFound, boolean ignoreNotFound,
boolean isLogicalOneToOne, boolean isLogicalOneToOne) {
Class returnedClass) { super( scope, referencedEntityName, referenceToPrimaryKey, uniqueKeyPropertyName, !lazy, unwrapProxy );
super( scope, referencedEntityName, uniqueKeyPropertyName, !lazy, unwrapProxy, returnedClass );
this.ignoreNotFound = ignoreNotFound; this.ignoreNotFound = ignoreNotFound;
this.isLogicalOneToOne = isLogicalOneToOne; this.isLogicalOneToOne = isLogicalOneToOne;
} }

View File

@ -47,6 +47,12 @@ public class OneToOneType extends EntityType {
private final String propertyName; private final String propertyName;
private final String entityName; private final String entityName;
/**
* @deprecated Use {@link #OneToOneType(TypeFactory.TypeScope, String, ForeignKeyDirection, boolean, String, boolean, boolean, String, String)}
* instead.
* See Jira issue: <a href="https://hibernate.onjira.com/browse/HHH-7771">HHH-7771</a>
*/
@Deprecated
public OneToOneType( public OneToOneType(
TypeFactory.TypeScope scope, TypeFactory.TypeScope scope,
String referencedEntityName, String referencedEntityName,
@ -56,23 +62,20 @@ public class OneToOneType extends EntityType {
boolean unwrapProxy, boolean unwrapProxy,
String entityName, String entityName,
String propertyName) { String propertyName) {
super( scope, referencedEntityName, uniqueKeyPropertyName, !lazy, unwrapProxy ); this( scope, referencedEntityName, foreignKeyType, uniqueKeyPropertyName == null, uniqueKeyPropertyName, lazy, unwrapProxy, entityName, propertyName );
this.foreignKeyType = foreignKeyType;
this.propertyName = propertyName;
this.entityName = entityName;
} }
public OneToOneType( public OneToOneType(
TypeFactory.TypeScope scope, TypeFactory.TypeScope scope,
String referencedEntityName, String referencedEntityName,
ForeignKeyDirection foreignKeyType, ForeignKeyDirection foreignKeyType,
boolean referenceToPrimaryKey,
String uniqueKeyPropertyName, String uniqueKeyPropertyName,
boolean lazy, boolean lazy,
boolean unwrapProxy, boolean unwrapProxy,
String entityName, String entityName,
String propertyName, String propertyName) {
Class returnedClass) { super( scope, referencedEntityName, referenceToPrimaryKey, uniqueKeyPropertyName, !lazy, unwrapProxy );
super( scope, referencedEntityName, uniqueKeyPropertyName, !lazy, unwrapProxy, returnedClass );
this.foreignKeyType = foreignKeyType; this.foreignKeyType = foreignKeyType;
this.propertyName = propertyName; this.propertyName = propertyName;
this.entityName = entityName; this.entityName = entityName;

View File

@ -43,6 +43,10 @@ import org.hibernate.metamodel.spi.relational.Size;
*/ */
public class SpecialOneToOneType extends OneToOneType { public class SpecialOneToOneType extends OneToOneType {
/**
* @deprecated Use {@link #SpecialOneToOneType(org.hibernate.type.TypeFactory.TypeScope, String, ForeignKeyDirection, boolean, String, boolean, boolean, String, String)} instead.
*/
@Deprecated
public SpecialOneToOneType( public SpecialOneToOneType(
TypeFactory.TypeScope scope, TypeFactory.TypeScope scope,
String referencedEntityName, String referencedEntityName,
@ -52,10 +56,24 @@ public class SpecialOneToOneType extends OneToOneType {
boolean unwrapProxy, boolean unwrapProxy,
String entityName, String entityName,
String propertyName) { String propertyName) {
this( scope, referencedEntityName, foreignKeyType, uniqueKeyPropertyName == null, uniqueKeyPropertyName, lazy, unwrapProxy, entityName, propertyName );
}
public SpecialOneToOneType(
TypeFactory.TypeScope scope,
String referencedEntityName,
ForeignKeyDirection foreignKeyType,
boolean referenceToPrimaryKey,
String uniqueKeyPropertyName,
boolean lazy,
boolean unwrapProxy,
String entityName,
String propertyName) {
super( super(
scope, scope,
referencedEntityName, referencedEntityName,
foreignKeyType, foreignKeyType,
referenceToPrimaryKey,
uniqueKeyPropertyName, uniqueKeyPropertyName,
lazy, lazy,
unwrapProxy, unwrapProxy,

View File

@ -27,8 +27,6 @@ import java.io.Serializable;
import java.util.Comparator; import java.util.Comparator;
import java.util.Properties; import java.util.Properties;
import org.jboss.logging.Logger;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.classic.Lifecycle; import org.hibernate.classic.Lifecycle;
@ -39,6 +37,7 @@ import org.hibernate.tuple.component.ComponentMetamodel;
import org.hibernate.usertype.CompositeUserType; import org.hibernate.usertype.CompositeUserType;
import org.hibernate.usertype.ParameterizedType; import org.hibernate.usertype.ParameterizedType;
import org.hibernate.usertype.UserType; import org.hibernate.usertype.UserType;
import org.jboss.logging.Logger;
/** /**
* Used internally to build instances of {@link Type}, specifically it builds instances of * Used internally to build instances of {@link Type}, specifically it builds instances of
@ -208,6 +207,11 @@ public final class TypeFactory implements Serializable {
// one-to-one type builders ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // one-to-one type builders ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* @deprecated Use {@link #oneToOne(String, ForeignKeyDirection, String, boolean, boolean, String, String, boolean)} instead.
* See Jira issue: <a href="https://hibernate.onjira.com/browse/HHH-7771">HHH-7771</a>
*/
@Deprecated
public EntityType oneToOne( public EntityType oneToOne(
String persistentClass, String persistentClass,
ForeignKeyDirection foreignKeyType, ForeignKeyDirection foreignKeyType,
@ -216,10 +220,28 @@ public final class TypeFactory implements Serializable {
boolean unwrapProxy, boolean unwrapProxy,
String entityName, String entityName,
String propertyName) { String propertyName) {
return new OneToOneType( typeScope, persistentClass, foreignKeyType, uniqueKeyPropertyName, return oneToOne( persistentClass, foreignKeyType, uniqueKeyPropertyName == null, uniqueKeyPropertyName, lazy, unwrapProxy, entityName,
lazy, unwrapProxy, entityName, propertyName ); propertyName );
} }
public EntityType oneToOne(
String persistentClass,
ForeignKeyDirection foreignKeyType,
boolean referenceToPrimaryKey,
String uniqueKeyPropertyName,
boolean lazy,
boolean unwrapProxy,
String entityName,
String propertyName) {
return new OneToOneType( typeScope, persistentClass, foreignKeyType, referenceToPrimaryKey,
uniqueKeyPropertyName, lazy, unwrapProxy, entityName, propertyName );
}
/**
* @deprecated Use {@link #specialOneToOne(String, ForeignKeyDirection, String, boolean, boolean, String, String, boolean)} instead.
*/
@Deprecated
public EntityType specialOneToOne( public EntityType specialOneToOne(
String persistentClass, String persistentClass,
ForeignKeyDirection foreignKeyType, ForeignKeyDirection foreignKeyType,
@ -228,34 +250,21 @@ public final class TypeFactory implements Serializable {
boolean unwrapProxy, boolean unwrapProxy,
String entityName, String entityName,
String propertyName) { String propertyName) {
return new SpecialOneToOneType( typeScope, persistentClass, foreignKeyType, uniqueKeyPropertyName, return specialOneToOne( persistentClass, foreignKeyType, uniqueKeyPropertyName == null, uniqueKeyPropertyName, lazy, unwrapProxy,
lazy, unwrapProxy, entityName, propertyName ); entityName, propertyName );
}
public EntityType oneToOne(
String persistentClass,
ForeignKeyDirection foreignKeyType,
String uniqueKeyPropertyName,
boolean lazy,
boolean unwrapProxy,
String entityName,
String propertyName,
Class returnedClass) {
return new OneToOneType( typeScope, persistentClass, foreignKeyType, uniqueKeyPropertyName,
lazy, unwrapProxy, entityName, propertyName, returnedClass );
} }
public EntityType specialOneToOne( public EntityType specialOneToOne(
String persistentClass, String persistentClass,
ForeignKeyDirection foreignKeyType, ForeignKeyDirection foreignKeyType,
boolean referenceToPrimaryKey,
String uniqueKeyPropertyName, String uniqueKeyPropertyName,
boolean lazy, boolean lazy,
boolean unwrapProxy, boolean unwrapProxy,
String entityName, String entityName,
String propertyName, String propertyName) {
Class returnedClass) { return new SpecialOneToOneType( typeScope, persistentClass, foreignKeyType, referenceToPrimaryKey,
return new SpecialOneToOneType( typeScope, persistentClass, foreignKeyType, uniqueKeyPropertyName, uniqueKeyPropertyName, lazy, unwrapProxy, entityName, propertyName );
lazy, unwrapProxy, entityName, propertyName, returnedClass );
} }
@ -269,6 +278,11 @@ public final class TypeFactory implements Serializable {
return new ManyToOneType( typeScope, persistentClass, lazy ); return new ManyToOneType( typeScope, persistentClass, lazy );
} }
/**
* @deprecated Use {@link #manyToOne(String, boolean, String, boolean, boolean, boolean, boolean)} instead.
* See Jira issue: <a href="https://hibernate.onjira.com/browse/HHH-7771">HHH-7771</a>
*/
@Deprecated
public EntityType manyToOne( public EntityType manyToOne(
String persistentClass, String persistentClass,
String uniqueKeyPropertyName, String uniqueKeyPropertyName,
@ -276,9 +290,23 @@ public final class TypeFactory implements Serializable {
boolean unwrapProxy, boolean unwrapProxy,
boolean ignoreNotFound, boolean ignoreNotFound,
boolean isLogicalOneToOne) { boolean isLogicalOneToOne) {
return manyToOne( persistentClass, uniqueKeyPropertyName == null, uniqueKeyPropertyName, lazy, unwrapProxy, ignoreNotFound,
isLogicalOneToOne );
}
public EntityType manyToOne(
String persistentClass,
boolean referenceToPrimaryKey,
String uniqueKeyPropertyName,
boolean lazy,
boolean unwrapProxy,
boolean ignoreNotFound,
boolean isLogicalOneToOne) {
return new ManyToOneType( return new ManyToOneType(
typeScope, typeScope,
persistentClass, persistentClass,
referenceToPrimaryKey,
uniqueKeyPropertyName, uniqueKeyPropertyName,
lazy, lazy,
unwrapProxy, unwrapProxy,
@ -287,26 +315,6 @@ public final class TypeFactory implements Serializable {
); );
} }
public EntityType manyToOne(
String persistentClass,
String uniqueKeyPropertyName,
boolean lazy,
boolean unwrapProxy,
boolean ignoreNotFound,
boolean isLogicalOneToOne,
Class returnedClass) {
return new ManyToOneType(
typeScope,
persistentClass,
uniqueKeyPropertyName,
lazy,
unwrapProxy,
ignoreNotFound,
isLogicalOneToOne ,
returnedClass
);
}
// collection type builders ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // collection type builders ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public CollectionType array(String role, String propertyRef, Class elementClass) { public CollectionType array(String role, String propertyRef, Class elementClass) {

View File

@ -0,0 +1,352 @@
/*
* 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;
import java.io.Serializable;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Embeddable;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import org.junit.Test;
import org.hibernate.Session;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.jdbc.Work;
import org.hibernate.loader.internal.EntityLoadQueryBuilderImpl;
import org.hibernate.loader.internal.LoadQueryAliasResolutionContextImpl;
import org.hibernate.loader.internal.ResultSetProcessorImpl;
import org.hibernate.loader.plan.internal.SingleRootReturnLoadPlanBuilderStrategy;
import org.hibernate.loader.plan.spi.LoadPlan;
import org.hibernate.loader.plan.spi.build.LoadPlanBuilder;
import org.hibernate.loader.spi.LoadQueryAliasResolutionContext;
import org.hibernate.loader.spi.NamedParameterContext;
import org.hibernate.loader.spi.NoOpLoadPlanAdvisor;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.test.component.cascading.toone.PersonalInfo;
import org.hibernate.testing.FailureExpected;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.hibernate.testing.junit4.ExtraAssertions;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
/**
* @author Gail Badner
*/
public class EncapsulatedCompositeAttributeResultSetProcessorTest extends BaseCoreFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] { Person.class, Customer.class };
}
@Test
public void testSimpleNestedCompositeAttributeProcessing() throws Exception {
// create some test data
Session session = openSession();
session.beginTransaction();
Person person = new Person();
person.id = 1;
person.name = "Joe Blow";
person.address = new Address();
person.address.address1 = "1313 Mockingbird Lane";
person.address.city = "Pleasantville";
person.address.country = "USA";
AddressType addressType = new AddressType();
addressType.typeName = "snail mail";
person.address.type = addressType;
session.save( person );
session.getTransaction().commit();
session.close();
session = openSession();
session.beginTransaction();
Person personGotten = (Person) session.get( Person.class, person.id );
assertEquals( person.id, personGotten.id );
assertEquals( person.address.address1, personGotten.address.address1 );
assertEquals( person.address.city, personGotten.address.city );
assertEquals( person.address.country, personGotten.address.country );
assertEquals( person.address.type.typeName, personGotten.address.type.typeName );
session.getTransaction().commit();
session.close();
List results = getResults( sessionFactory().getEntityPersister( Person.class.getName() ) );
assertEquals( 1, results.size() );
Object result = results.get( 0 );
assertNotNull( result );
Person personWork = ExtraAssertions.assertTyping( Person.class, result );
assertEquals( person.id, personWork.id );
assertEquals( person.address.address1, personWork.address.address1 );
assertEquals( person.address.city, personWork.address.city );
assertEquals( person.address.country, personWork.address.country );
assertEquals( person.address.type.typeName, personGotten.address.type.typeName );
// clean up test data
session = openSession();
session.beginTransaction();
session.createQuery( "delete Person" ).executeUpdate();
session.getTransaction().commit();
session.close();
}
@Test
public void testNestedCompositeElementCollectionProcessing() throws Exception {
// create some test data
Session session = openSession();
session.beginTransaction();
Person person = new Person();
person.id = 1;
person.name = "Joe Blow";
session.save( person );
Customer customer = new Customer();
customer.id = 1L;
Investment investment1 = new Investment();
investment1.description = "stock";
investment1.date = new Date();
investment1.monetaryAmount = new MonetaryAmount();
investment1.monetaryAmount.currency = MonetaryAmount.CurrencyCode.USD;
investment1.monetaryAmount.amount = BigDecimal.valueOf( 1234, 2 );
investment1.performedBy = person;
Investment investment2 = new Investment();
investment2.description = "bond";
investment2.date = new Date();
investment2.monetaryAmount = new MonetaryAmount();
investment2.monetaryAmount.currency = MonetaryAmount.CurrencyCode.EUR;
investment2.monetaryAmount.amount = BigDecimal.valueOf( 98176, 1 );
customer.investments.add( investment1 );
customer.investments.add( investment2 );
session.save( customer );
session.getTransaction().commit();
session.close();
session = openSession();
session.beginTransaction();
Customer customerGotten = (Customer) session.get( Customer.class, customer.id );
assertEquals( customer.id, customerGotten.id );
session.getTransaction().commit();
session.close();
List results = getResults( sessionFactory().getEntityPersister( Customer.class.getName() ) );
assertEquals( 2, results.size() );
assertSame( results.get( 0 ), results.get( 1 ) );
Object result = results.get( 0 );
assertNotNull( result );
Customer customerWork = ExtraAssertions.assertTyping( Customer.class, result );
// clean up test data
session = openSession();
session.beginTransaction();
session.delete( customerWork.investments.get( 0 ).performedBy );
session.delete( customerWork );
session.getTransaction().commit();
session.close();
}
private List<?> getResults(EntityPersister entityPersister ) {
final SingleRootReturnLoadPlanBuilderStrategy strategy = new SingleRootReturnLoadPlanBuilderStrategy(
sessionFactory(),
LoadQueryInfluencers.NONE
);
final LoadPlan plan = LoadPlanBuilder.buildRootEntityLoadPlan( strategy, entityPersister );
final LoadQueryAliasResolutionContext aliasResolutionContext =
new LoadQueryAliasResolutionContextImpl(
sessionFactory(),
0,
Collections.singletonMap( plan.getReturns().get( 0 ), new String[] { "abc" } )
);
final EntityLoadQueryBuilderImpl queryBuilder = new EntityLoadQueryBuilderImpl(
LoadQueryInfluencers.NONE,
plan
);
final String sql = queryBuilder.generateSql( 1, sessionFactory(), aliasResolutionContext );
final ResultSetProcessorImpl resultSetProcessor = new ResultSetProcessorImpl( plan );
final List results = new ArrayList();
final Session workSession = openSession();
workSession.beginTransaction();
workSession.doWork(
new Work() {
@Override
public void execute(Connection connection) throws SQLException {
PreparedStatement ps = connection.prepareStatement( sql );
ps.setInt( 1, 1 );
ResultSet resultSet = ps.executeQuery();
results.addAll(
resultSetProcessor.extractResults(
NoOpLoadPlanAdvisor.INSTANCE,
resultSet,
(SessionImplementor) workSession,
new QueryParameters(),
new NamedParameterContext() {
@Override
public int[] getNamedParameterLocations(String name) {
return new int[0];
}
},
aliasResolutionContext,
true,
false,
null,
null
)
);
resultSet.close();
ps.close();
}
}
);
workSession.getTransaction().commit();
workSession.close();
return results;
}
@Entity( name = "Person" )
public static class Person implements Serializable {
@Id
Integer id;
String name;
@Embedded
Address address;
}
@Embeddable
public static class Address implements Serializable {
String address1;
String city;
String country;
AddressType type;
}
@Embeddable
public static class AddressType {
String typeName;
}
@Entity( name = "Customer" )
public static class Customer {
private Long id;
private List<Investment> investments = new ArrayList<Investment>();
@Id
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@ElementCollection(fetch = FetchType.EAGER)
public List<Investment> getInvestments() {
return investments;
}
public void setInvestments(List<Investment> investments) {
this.investments = investments;
}
}
@Embeddable
public static class Investment {
private MonetaryAmount monetaryAmount;
private String description;
private Date date;
private Person performedBy;
@Embedded
public MonetaryAmount getMonetaryAmount() {
return monetaryAmount;
}
public void setMonetaryAmount(MonetaryAmount monetaryAmount) {
this.monetaryAmount = monetaryAmount;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
@ManyToOne
public Person getPerformedBy() {
return performedBy;
}
public void setPerformedBy(Person performedBy) {
this.performedBy = performedBy;
}
}
@Embeddable
public static class MonetaryAmount {
public static enum CurrencyCode {
USD,
EUR
}
private BigDecimal amount;
@Column(length = 3)
@Enumerated(EnumType.STRING)
private CurrencyCode currency;
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
public CurrencyCode getCurrency() {
return currency;
}
public void setCurrency(CurrencyCode currency) {
this.currency = currency;
}
}
}

View File

@ -0,0 +1,434 @@
/*
* 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;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.persistence.Embeddable;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import org.junit.Test;
import org.hibernate.LockOptions;
import org.hibernate.Session;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.jdbc.Work;
import org.hibernate.loader.internal.EntityLoadQueryBuilderImpl;
import org.hibernate.loader.internal.LoadQueryAliasResolutionContextImpl;
import org.hibernate.loader.internal.ResultSetProcessorImpl;
import org.hibernate.loader.plan.internal.SingleRootReturnLoadPlanBuilderStrategy;
import org.hibernate.loader.plan.spi.LoadPlan;
import org.hibernate.loader.plan.spi.build.LoadPlanBuilder;
import org.hibernate.loader.spi.LoadQueryAliasResolutionContext;
import org.hibernate.loader.spi.NamedParameterContext;
import org.hibernate.loader.spi.NoOpLoadPlanAdvisor;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.hibernate.testing.junit4.ExtraAssertions;
import org.hibernate.type.Type;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
/**
* @author Gail Badner
*/
public class EncapsulatedCompositeIdResultSetProcessorTest extends BaseCoreFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] { Parent.class, CardField.class, Card.class };
}
@Test
public void testSimpleCompositeId() throws Exception {
// create some test data
Session session = openSession();
session.beginTransaction();
Parent parent = new Parent();
parent.id = new ParentPK();
parent.id.firstName = "Joe";
parent.id.lastName = "Blow";
session.save( parent );
session.getTransaction().commit();
session.close();
session = openSession();
session.beginTransaction();
Parent parentGotten = (Parent) session.get( Parent.class, parent.id );
assertEquals( parent, parentGotten );
session.getTransaction().commit();
session.close();
final List results = getResults(
sessionFactory().getEntityPersister( Parent.class.getName() ),
new Callback() {
@Override
public void bind(PreparedStatement ps) throws SQLException {
ps.setString( 1, "Joe" );
ps.setString( 2, "Blow" );
}
@Override
public QueryParameters getQueryParameters() {
return new QueryParameters();
}
}
);
assertEquals( 1, results.size() );
Object result = results.get( 0 );
assertNotNull( result );
Parent parentWork = ExtraAssertions.assertTyping( Parent.class, result );
assertEquals( parent, parentWork );
// clean up test data
session = openSession();
session.beginTransaction();
session.createQuery( "delete Parent" ).executeUpdate();
session.getTransaction().commit();
session.close();
}
@Test
public void testCompositeIdWithKeyManyToOne() throws Exception {
final String cardId = "ace-of-spades";
// create some test data
Session session = openSession();
session.beginTransaction();
Card card = new Card( cardId );
final CardField cardField = new CardField( card, 1 );
session.persist( card );
session.persist( cardField );
session.getTransaction().commit();
session.close();
session = openSession();
session.beginTransaction();
Card cardProxy = (Card) session.load( Card.class, cardId );
final CardFieldPK cardFieldPK = new CardFieldPK( cardProxy, 1 );
CardField cardFieldGotten = (CardField) session.get( CardField.class, cardFieldPK );
//assertEquals( card, cardGotten );
session.getTransaction().commit();
session.close();
final EntityPersister entityPersister = sessionFactory().getEntityPersister( CardField.class.getName() );
final List results = getResults(
entityPersister,
new Callback() {
@Override
public void bind(PreparedStatement ps) throws SQLException {
ps.setString( 1, cardField.primaryKey.card.id );
ps.setInt( 2, cardField.primaryKey.fieldNumber );
}
@Override
public QueryParameters getQueryParameters() {
QueryParameters qp = new QueryParameters();
qp.setPositionalParameterTypes( new Type[] { entityPersister.getIdentifierType() } );
qp.setPositionalParameterValues( new Object[] { cardFieldPK } );
qp.setOptionalObject( null );
qp.setOptionalEntityName( entityPersister.getEntityName() );
qp.setOptionalId( cardFieldPK );
qp.setLockOptions( LockOptions.NONE );
return qp;
}
}
);
assertEquals( 1, results.size() );
Object result = results.get( 0 );
assertNotNull( result );
CardField cardFieldWork = ExtraAssertions.assertTyping( CardField.class, result );
assertEquals( cardFieldGotten, cardFieldWork );
// clean up test data
session = openSession();
session.beginTransaction();
session.createQuery( "delete CardField" ).executeUpdate();
session.createQuery( "delete Card" ).executeUpdate();
session.getTransaction().commit();
session.close();
}
private List getResults(final EntityPersister entityPersister, final Callback callback) {
final SingleRootReturnLoadPlanBuilderStrategy strategy = new SingleRootReturnLoadPlanBuilderStrategy(
sessionFactory(),
LoadQueryInfluencers.NONE
);
final LoadPlan plan = LoadPlanBuilder.buildRootEntityLoadPlan( strategy, entityPersister );
final LoadQueryAliasResolutionContext aliasResolutionContext =
new LoadQueryAliasResolutionContextImpl(
sessionFactory(),
0,
Collections.singletonMap( plan.getReturns().get( 0 ), new String[] { "abc" } )
);
final EntityLoadQueryBuilderImpl queryBuilder = new EntityLoadQueryBuilderImpl(
LoadQueryInfluencers.NONE,
plan
);
final String sql = queryBuilder.generateSql( 1, sessionFactory(), aliasResolutionContext );
final ResultSetProcessorImpl resultSetProcessor = new ResultSetProcessorImpl( plan );
final List results = new ArrayList();
final Session workSession = openSession();
workSession.beginTransaction();
workSession.doWork(
new Work() {
@Override
public void execute(Connection connection) throws SQLException {
PreparedStatement ps = connection.prepareStatement( sql );
callback.bind( ps );
ResultSet resultSet = ps.executeQuery();
//callback.beforeExtractResults( workSession );
results.addAll(
resultSetProcessor.extractResults(
NoOpLoadPlanAdvisor.INSTANCE,
resultSet,
(SessionImplementor) workSession,
callback.getQueryParameters(),
new NamedParameterContext() {
@Override
public int[] getNamedParameterLocations(String name) {
return new int[0];
}
},
aliasResolutionContext,
true,
false,
null,
null
)
);
resultSet.close();
ps.close();
}
}
);
workSession.getTransaction().commit();
workSession.close();
return results;
}
private interface Callback {
void bind(PreparedStatement ps) throws SQLException;
QueryParameters getQueryParameters ();
}
@Entity ( name = "Parent" )
public static class Parent {
@EmbeddedId
public ParentPK id;
public boolean equals(Object o) {
if ( this == o ) return true;
if ( !( o instanceof Parent ) ) return false;
final Parent parent = (Parent) o;
if ( !id.equals( parent.id ) ) return false;
return true;
}
public int hashCode() {
return id.hashCode();
}
}
@Embeddable
public static class ParentPK implements Serializable {
private String firstName;
private String lastName;
public boolean equals(Object o) {
if ( this == o ) return true;
if ( !( o instanceof ParentPK ) ) return false;
final ParentPK parentPk = (ParentPK) o;
if ( !firstName.equals( parentPk.firstName ) ) return false;
if ( !lastName.equals( parentPk.lastName ) ) return false;
return true;
}
public int hashCode() {
int result;
result = firstName.hashCode();
result = 29 * result + lastName.hashCode();
return result;
}
}
@Entity ( name = "CardField" )
public static class CardField implements Serializable {
@EmbeddedId
private CardFieldPK primaryKey;
CardField(Card card, int fieldNumber) {
this.primaryKey = new CardFieldPK(card, fieldNumber);
}
CardField() {
}
public CardFieldPK getPrimaryKey() {
return primaryKey;
}
public void setPrimaryKey(CardFieldPK primaryKey) {
this.primaryKey = primaryKey;
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
CardField cardField = (CardField) o;
if ( primaryKey != null ? !primaryKey.equals( cardField.primaryKey ) : cardField.primaryKey != null ) {
return false;
}
return true;
}
@Override
public int hashCode() {
return primaryKey != null ? primaryKey.hashCode() : 0;
}
}
@Embeddable
public static class CardFieldPK implements Serializable {
@ManyToOne(optional = false)
private Card card;
private int fieldNumber;
public CardFieldPK(Card card, int fieldNumber) {
this.card = card;
this.fieldNumber = fieldNumber;
}
CardFieldPK() {
}
public Card getCard() {
return card;
}
public void setCard(Card card) {
this.card = card;
}
public int getFieldNumber() {
return fieldNumber;
}
public void setFieldNumber(int fieldNumber) {
this.fieldNumber = fieldNumber;
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
CardFieldPK that = (CardFieldPK) o;
if ( fieldNumber != that.fieldNumber ) {
return false;
}
if ( card != null ? !card.equals( that.card ) : that.card != null ) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = card != null ? card.hashCode() : 0;
result = 31 * result + fieldNumber;
return result;
}
}
@Entity ( name = "Card" )
public static class Card implements Serializable {
@Id
private String id;
public Card(String id) {
this();
this.id = id;
}
Card() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
}

View File

@ -69,7 +69,7 @@ import static org.junit.Assert.assertTrue;
* @author Gail Badner * @author Gail Badner
*/ */
@FailureExpectedWithNewMetamodel @FailureExpectedWithNewMetamodel
public class EntityWithCollectionResultSetProcessorTest extends BaseCoreFunctionalTestCase { public class EntityWithNonLazyCollectionResultSetProcessorTest extends BaseCoreFunctionalTestCase {
@Override @Override
protected Class<?>[] getAnnotatedClasses() { protected Class<?>[] getAnnotatedClasses() {

View File

@ -0,0 +1,215 @@
/*
* 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;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import org.junit.Test;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.jdbc.Work;
import org.hibernate.loader.internal.EntityLoadQueryBuilderImpl;
import org.hibernate.loader.internal.LoadQueryAliasResolutionContextImpl;
import org.hibernate.loader.internal.ResultSetProcessorImpl;
import org.hibernate.loader.plan.internal.SingleRootReturnLoadPlanBuilderStrategy;
import org.hibernate.loader.plan.spi.LoadPlan;
import org.hibernate.loader.plan.spi.build.LoadPlanBuilder;
import org.hibernate.loader.spi.LoadQueryAliasResolutionContext;
import org.hibernate.loader.spi.NamedParameterContext;
import org.hibernate.loader.spi.NoOpLoadPlanAdvisor;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.hibernate.testing.junit4.ExtraAssertions;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
/**
* @author Gail Badner
*/
public class EntityWithNonLazyOneToManyListResultSetProcessorTest extends BaseCoreFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] { Poster.class, Message.class };
}
@Test
public void testEntityWithList() throws Exception {
final EntityPersister entityPersister = sessionFactory().getEntityPersister( Poster.class.getName() );
// create some test data
Session session = openSession();
session.beginTransaction();
Poster poster = new Poster();
poster.pid = 0;
poster.name = "John Doe";
Message message1 = new Message();
message1.mid = 1;
message1.msgTxt = "Howdy!";
message1.poster = poster;
poster.messages.add( message1 );
Message message2 = new Message();
message2.mid = 2;
message2.msgTxt = "Bye!";
message2.poster = poster;
poster.messages.add( message2 );
session.save( poster );
session.getTransaction().commit();
session.close();
session = openSession();
session.beginTransaction();
Poster posterGotten = (Poster) session.get( Poster.class, poster.pid );
assertEquals( 0, posterGotten.pid.intValue() );
assertEquals( poster.name, posterGotten.name );
assertTrue( Hibernate.isInitialized( posterGotten.messages ) );
assertEquals( 2, posterGotten.messages.size() );
assertEquals( message1.msgTxt, posterGotten.messages.get( 0 ).msgTxt );
assertEquals( message2.msgTxt, posterGotten.messages.get( 1 ).msgTxt );
assertSame( posterGotten, posterGotten.messages.get( 0 ).poster );
assertSame( posterGotten, posterGotten.messages.get( 1 ).poster );
session.getTransaction().commit();
session.close();
{
final SingleRootReturnLoadPlanBuilderStrategy strategy = new SingleRootReturnLoadPlanBuilderStrategy(
sessionFactory(),
LoadQueryInfluencers.NONE
);
final LoadPlan plan = LoadPlanBuilder.buildRootEntityLoadPlan( strategy, entityPersister );
final LoadQueryAliasResolutionContext aliasResolutionContext =
new LoadQueryAliasResolutionContextImpl(
sessionFactory(),
0,
Collections.singletonMap( plan.getReturns().get( 0 ), new String[] { "abc" } )
);
final EntityLoadQueryBuilderImpl queryBuilder = new EntityLoadQueryBuilderImpl(
LoadQueryInfluencers.NONE,
plan
);
final String sql = queryBuilder.generateSql( 1, sessionFactory(), aliasResolutionContext );
final ResultSetProcessorImpl resultSetProcessor = new ResultSetProcessorImpl( plan );
final List results = new ArrayList();
final Session workSession = openSession();
workSession.beginTransaction();
workSession.doWork(
new Work() {
@Override
public void execute(Connection connection) throws SQLException {
PreparedStatement ps = connection.prepareStatement( sql );
ps.setInt( 1, 0 );
ResultSet resultSet = ps.executeQuery();
results.addAll(
resultSetProcessor.extractResults(
NoOpLoadPlanAdvisor.INSTANCE,
resultSet,
(SessionImplementor) workSession,
new QueryParameters(),
new NamedParameterContext() {
@Override
public int[] getNamedParameterLocations(String name) {
return new int[0];
}
},
aliasResolutionContext,
true,
false,
null,
null
)
);
resultSet.close();
ps.close();
}
}
);
assertEquals( 2, results.size() );
Object result1 = results.get( 0 );
assertNotNull( result1 );
assertSame( result1, results.get( 1 ) );
Poster workPoster = ExtraAssertions.assertTyping( Poster.class, result1 );
assertEquals( 0, workPoster.pid.intValue() );
assertEquals( poster.name, workPoster.name );
assertTrue( Hibernate.isInitialized( workPoster.messages ) );
assertEquals( 2, workPoster.messages.size() );
assertTrue( Hibernate.isInitialized( posterGotten.messages ) );
assertEquals( 2, workPoster.messages.size() );
assertEquals( message1.msgTxt, workPoster.messages.get( 0 ).msgTxt );
assertEquals( message2.msgTxt, workPoster.messages.get( 1 ).msgTxt );
assertSame( workPoster, workPoster.messages.get( 0 ).poster );
assertSame( workPoster, workPoster.messages.get( 1 ).poster );
workSession.getTransaction().commit();
workSession.close();
}
// clean up test data
session = openSession();
session.beginTransaction();
session.delete( poster );
session.getTransaction().commit();
session.close();
}
@Entity( name = "Message" )
public static class Message {
@Id
private Integer mid;
private String msgTxt;
@ManyToOne
@JoinColumn
private Poster poster;
}
@Entity( name = "Poster" )
public static class Poster {
@Id
private Integer pid;
private String name;
@OneToMany(mappedBy = "poster", fetch = FetchType.EAGER, cascade = CascadeType.ALL )
private List<Message> messages = new ArrayList<Message>();
}
}

View File

@ -72,7 +72,7 @@ import static org.junit.Assert.fail;
* @author Gail Badner * @author Gail Badner
*/ */
@FailureExpectedWithNewMetamodel @FailureExpectedWithNewMetamodel
public class EntityWithOneToManyResultSetProcessorTest extends BaseCoreFunctionalTestCase { public class EntityWithNonLazyOneToManySetResultSetProcessorTest extends BaseCoreFunctionalTestCase {
@Override @Override
protected Class<?>[] getAnnotatedClasses() { protected Class<?>[] getAnnotatedClasses() {

View File

@ -38,6 +38,7 @@ import org.hibernate.persister.walking.spi.CollectionDefinition;
import org.hibernate.persister.walking.spi.CollectionElementDefinition; import org.hibernate.persister.walking.spi.CollectionElementDefinition;
import org.hibernate.persister.walking.spi.CollectionIndexDefinition; import org.hibernate.persister.walking.spi.CollectionIndexDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition; import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.persister.walking.spi.CompositionElementDefinition;
import org.hibernate.persister.walking.spi.EntityDefinition; import org.hibernate.persister.walking.spi.EntityDefinition;
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition; import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
import org.hibernate.persister.walking.spi.MetadataDrivenModelGraphVisitor; import org.hibernate.persister.walking.spi.MetadataDrivenModelGraphVisitor;
@ -168,6 +169,28 @@ public class BasicWalkingTest extends BaseCoreFunctionalTestCase {
); );
} }
@Override
public void startingCompositeElement(CompositionElementDefinition compositionElementDefinition) {
System.out.println(
String.format(
"%s Starting composite (%s)",
StringHelper.repeat( ">>", ++depth ),
compositionElementDefinition.toString()
)
);
}
@Override
public void finishingCompositeElement(CompositionElementDefinition compositionElementDefinition) {
System.out.println(
String.format(
"%s Finishing composite (%s)",
StringHelper.repeat( ">>", depth-- ),
compositionElementDefinition.toString()
)
);
}
@Override @Override
public boolean startingAttribute(AttributeDefinition attributeDefinition) { public boolean startingAttribute(AttributeDefinition attributeDefinition) {
System.out.println( System.out.println(

View File

@ -26,6 +26,9 @@ package org.hibernate.test.annotations.derivedidentities.bidirectional;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.testing.FailureExpected; import org.hibernate.testing.FailureExpected;
import org.hibernate.testing.TestForIssue; import org.hibernate.testing.TestForIssue;
@ -35,6 +38,7 @@ import org.junit.Test;
@FailureExpected(jiraKey = "HHH-5695") @FailureExpected(jiraKey = "HHH-5695")
public class OneToOneWithDerivedIdentityTest extends BaseCoreFunctionalTestCase { public class OneToOneWithDerivedIdentityTest extends BaseCoreFunctionalTestCase {
@Test @Test
@TestForIssue(jiraKey = "HHH-5695")
public void testInsertFooAndBarWithDerivedId() { public void testInsertFooAndBarWithDerivedId() {
Session s = openSession(); Session s = openSession();
s.beginTransaction(); s.beginTransaction();
@ -81,11 +85,50 @@ public class OneToOneWithDerivedIdentityTest extends BaseCoreFunctionalTestCase
s.close(); s.close();
} }
@Test
@TestForIssue(jiraKey = "HHH-6813")
// Regression test utilizing multiple types of queries.
public void testCase() {
Session s = openSession();
s.getTransaction().begin();
Person p = new Person();
p.setName( "Alfio" );
PersonInfo pi = new PersonInfo();
pi.setId( p );
pi.setInfo( "Some information" );
s.persist( p );
s.persist( pi );
s.getTransaction().commit();
s.clear();
s.getTransaction().begin();
Query q = s.getNamedQuery( "PersonQuery" );
List<Person> persons = q.list();
assertEquals( persons.size(), 1 );
assertEquals( persons.get( 0 ).getName(), "Alfio" );
s.getTransaction().commit();
s.clear();
s.getTransaction().begin();
p = (Person) s.get( Person.class, persons.get( 0 ).getId() );
assertEquals( p.getName(), "Alfio" );
s.getTransaction().commit();
s.close();
}
@Override @Override
protected Class<?>[] getAnnotatedClasses() { protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] { return new Class<?>[] {
Foo.class, Foo.class,
Bar.class Bar.class,
Person.class,
PersonInfo.class
}; };
} }

View File

@ -0,0 +1,77 @@
package org.hibernate.test.annotations.derivedidentities.bidirectional;
import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.OneToOne;
@Entity
@NamedQuery(name="PersonQuery", query="SELECT p FROM Person p")
public class Person
implements Serializable
{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
@Basic
private String name;
@OneToOne(mappedBy="id")
private PersonInfo personInfo;
public Integer getId()
{
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public int hashCode()
{
int hash = 0;
hash += (this.id != null ? this.id.hashCode() : 0);
return hash;
}
public boolean equals(Object object)
{
if (!(object instanceof Person)) {
return false;
}
Person other = (Person)object;
return ((this.id != null) || (other.id == null)) && ((this.id == null) || (this.id.equals(other.id)));
}
public String toString()
{
return "nogroup.hibertest.Person[ id=" + this.id + " ]";
}
public PersonInfo getPersonInfo()
{
return this.personInfo;
}
public void setPersonInfo(PersonInfo personInfo)
{
this.personInfo = personInfo;
}
}

View File

@ -0,0 +1,60 @@
package org.hibernate.test.annotations.derivedidentities.bidirectional;
import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToOne;
@Entity
public class PersonInfo
implements Serializable
{
private static final long serialVersionUID = 1L;
@Id
@OneToOne
private Person id;
@Basic
private String info;
public Person getId()
{
return this.id;
}
public void setId(Person id) {
this.id = id;
}
public String getInfo() {
return this.info;
}
public void setInfo(String info) {
this.info = info;
}
public int hashCode()
{
int hash = 0;
hash += (this.id != null ? this.id.hashCode() : 0);
return hash;
}
public boolean equals(Object object)
{
if (!(object instanceof PersonInfo)) {
return false;
}
PersonInfo other = (PersonInfo)object;
return ((this.id != null) || (other.id == null)) && ((this.id == null) || (this.id.equals(other.id)));
}
public String toString()
{
return "nogroup.hibertest.PersonInfo[ id=" + this.id + " ]";
}
}

View File

@ -38,7 +38,7 @@ import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.jdbc.env.spi.LobCreatorBuilder; import org.hibernate.engine.jdbc.env.spi.LobCreatorBuilder;
import org.hibernate.engine.jdbc.env.spi.QualifiedObjectNameSupport; import org.hibernate.engine.jdbc.env.spi.QualifiedObjectNameSupport;
import org.hibernate.engine.jdbc.internal.ResultSetWrapperImpl; import org.hibernate.engine.jdbc.internal.ResultSetWrapperImpl;
import org.hibernate.engine.jdbc.internal.TypeInfo; import org.hibernate.engine.jdbc.spi.TypeInfo;
import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.jdbc.spi.ResultSetWrapper; import org.hibernate.engine.jdbc.spi.ResultSetWrapper;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper; import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;

View File

@ -1007,7 +1007,8 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
sessionFactory, sessionFactory,
settings, settings,
configurationValues, configurationValues,
serviceRegistry.getService( ConfigurationService.class ).getSettings() serviceRegistry.getService( ConfigurationService.class ).getSettings(),
metadata
); );
} }
else { else {

View File

@ -68,7 +68,7 @@ public abstract class AbstractScannerImpl implements Scanner {
if ( persistenceUnit.getPersistenceUnitRootUrl() != null ) { if ( persistenceUnit.getPersistenceUnitRootUrl() != null ) {
final ArchiveDescriptor descriptor = buildArchiveDescriptor( persistenceUnit.getPersistenceUnitRootUrl(), true, scanOptions ); final ArchiveDescriptor descriptor = buildArchiveDescriptor( persistenceUnit.getPersistenceUnitRootUrl(), true, scanOptions );
final ArchiveContext context = buildArchiveContext( persistenceUnit, false, resultCollector ); final ArchiveContext context = buildArchiveContext( persistenceUnit, true, resultCollector );
descriptor.visitArchive( context ); descriptor.visitArchive( context );
} }

View File

@ -162,42 +162,42 @@ public abstract class AbstractGraphNode<T> implements GraphNodeImplementor {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <X> Subgraph<X> addSubgraph(Attribute<T, X> attribute) { public <X> SubgraphImpl<X> addSubgraph(Attribute<T, X> attribute) {
return addAttribute( attribute ).makeSubgraph(); return addAttribute( attribute ).makeSubgraph();
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <X> Subgraph<? extends X> addSubgraph(Attribute<T, X> attribute, Class<? extends X> type) { public <X> SubgraphImpl<? extends X> addSubgraph(Attribute<T, X> attribute, Class<? extends X> type) {
return addAttribute( attribute ).makeSubgraph( type ); return addAttribute( attribute ).makeSubgraph( type );
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <X> Subgraph<X> addSubgraph(String attributeName) { public <X> SubgraphImpl<X> addSubgraph(String attributeName) {
return addAttribute( attributeName ).makeSubgraph(); return addAttribute( attributeName ).makeSubgraph();
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <X> Subgraph<X> addSubgraph(String attributeName, Class<X> type) { public <X> SubgraphImpl<X> addSubgraph(String attributeName, Class<X> type) {
return addAttribute( attributeName ).makeSubgraph( type ); return addAttribute( attributeName ).makeSubgraph( type );
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <X> Subgraph<X> addKeySubgraph(Attribute<T, X> attribute) { public <X> SubgraphImpl<X> addKeySubgraph(Attribute<T, X> attribute) {
return addAttribute( attribute ).makeKeySubgraph(); return addAttribute( attribute ).makeKeySubgraph();
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <X> Subgraph<? extends X> addKeySubgraph(Attribute<T, X> attribute, Class<? extends X> type) { public <X> SubgraphImpl<? extends X> addKeySubgraph(Attribute<T, X> attribute, Class<? extends X> type) {
return addAttribute( attribute ).makeKeySubgraph( type ); return addAttribute( attribute ).makeKeySubgraph( type );
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <X> Subgraph<X> addKeySubgraph(String attributeName) { public <X> SubgraphImpl<X> addKeySubgraph(String attributeName) {
return addAttribute( attributeName ).makeKeySubgraph(); return addAttribute( attributeName ).makeKeySubgraph();
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <X> Subgraph<X> addKeySubgraph(String attributeName, Class<X> type) { public <X> SubgraphImpl<X> addKeySubgraph(String attributeName, Class<X> type) {
return addAttribute( attributeName ).makeKeySubgraph( type ); return addAttribute( attributeName ).makeKeySubgraph( type );
} }
} }

View File

@ -108,16 +108,16 @@ public class AttributeNodeImpl<T> implements AttributeNode<T>, AttributeNodeImpl
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> Subgraph<T> makeSubgraph() { public <T> SubgraphImpl<T> makeSubgraph() {
return (Subgraph<T>) internalMakeSubgraph( null ); return (SubgraphImpl<T>) internalMakeSubgraph( null );
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <X extends T> Subgraph<X> makeSubgraph(Class<X> type) { public <X extends T> SubgraphImpl<X> makeSubgraph(Class<X> type) {
return (Subgraph<X>) internalMakeSubgraph( type ); return (SubgraphImpl<X>) internalMakeSubgraph( type );
} }
private Subgraph internalMakeSubgraph(Class type) { private SubgraphImpl internalMakeSubgraph(Class type) {
if ( attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.BASIC if ( attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.BASIC
|| attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.EMBEDDED ) { || attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.EMBEDDED ) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
@ -193,12 +193,17 @@ public class AttributeNodeImpl<T> implements AttributeNode<T>, AttributeNodeImpl
return type.isAssignableFrom( entityPersister.getMappedClass() ); return type.isAssignableFrom( entityPersister.getMappedClass() );
} }
public <T> Subgraph<T> makeKeySubgraph() { @SuppressWarnings("unchecked")
return (SubgraphImpl<T>) makeKeySubgraph( null ); public <T> SubgraphImpl<T> makeKeySubgraph() {
return (SubgraphImpl<T>) internalMakeKeySubgraph( null );
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <X extends T> Subgraph<X> makeKeySubgraph(Class<X> type) { public <X extends T> SubgraphImpl<X> makeKeySubgraph(Class<X> type) {
return (SubgraphImpl<X>) internalMakeKeySubgraph( type );
}
public SubgraphImpl internalMakeKeySubgraph(Class type) {
if ( ! attribute.isCollection() ) { if ( ! attribute.isCollection() ) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
String.format( "Non-collection attribute [%s] cannot be target of key subgraph", getAttributeName() ) String.format( "Non-collection attribute [%s] cannot be target of key subgraph", getAttributeName() )

Some files were not shown because too many files have changed in this diff Show More