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 org.hibernate.procedure.ProcedureCall;
import org.hibernate.procedure.ProcedureCallMemento;
/**
* Contract methods shared between {@link Session} and {@link StatelessSession}.

View File

@ -61,14 +61,20 @@ public class RegionFactoryInitiator implements StandardServiceInitiator<RegionFa
@Override
@SuppressWarnings({ "unchecked" })
public RegionFactory initiateService(Map configurationValues, ServiceRegistryImplementor registry) {
Properties p = new Properties();
final Properties p = new Properties();
if (configurationValues != null) {
p.putAll( configurationValues );
}
boolean useSecondLevelCache = ConfigurationHelper.getBoolean( AvailableSettings.USE_SECOND_LEVEL_CACHE,
configurationValues, true );
boolean useQueryCache = ConfigurationHelper.getBoolean( AvailableSettings.USE_QUERY_CACHE, configurationValues );
final boolean useSecondLevelCache = ConfigurationHelper.getBoolean(
AvailableSettings.USE_SECOND_LEVEL_CACHE,
configurationValues,
true
);
final boolean useQueryCache = ConfigurationHelper.getBoolean(
AvailableSettings.USE_QUERY_CACHE,
configurationValues
);
RegionFactory regionFactory = NoCachingRegionFactory.INSTANCE;
@ -81,16 +87,6 @@ public class RegionFactoryInitiator implements StandardServiceInitiator<RegionFa
try {
regionFactory = registry.getService( StrategySelector.class )
.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 ) {
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) {
Map defaults = mappings.getReflectionManager().getDefaults();
// id generators ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{
List<SequenceGenerator> anns = ( List<SequenceGenerator> ) defaults.get( SequenceGenerator.class );
if ( anns != null ) {
@ -231,6 +234,9 @@ public final class AnnotationBinder {
}
}
}
// queries ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{
List<NamedQuery> anns = ( List<NamedQuery> ) defaults.get( NamedQuery.class );
if ( anns != null ) {
@ -247,6 +253,9 @@ public final class AnnotationBinder {
}
}
}
// result-set-mappings ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{
List<SqlResultSetMapping> anns = ( List<SqlResultSetMapping> ) defaults.get( SqlResultSetMapping.class );
if ( anns != null ) {
@ -256,6 +265,8 @@ public final class AnnotationBinder {
}
}
// stored procs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{
final List<NamedStoredProcedureQuery> annotations =
(List<NamedStoredProcedureQuery>) defaults.get( NamedStoredProcedureQuery.class );
@ -265,7 +276,6 @@ public final class AnnotationBinder {
}
}
}
{
final List<NamedStoredProcedureQueries> annotations =
(List<NamedStoredProcedureQueries>) defaults.get( NamedStoredProcedureQueries.class );

View File

@ -341,6 +341,7 @@ public class BinderHelper {
*/
if ( value instanceof ToOne ) {
( (ToOne) value ).setReferencedPropertyName( syntheticPropertyName );
( (ToOne) value ).setReferenceToPrimaryKey( syntheticPropertyName == null );
mappings.addUniquePropertyReference( ownerEntity.getEntityName(), syntheticPropertyName );
}
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.classloading.spi.ClassLoaderService;
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.reflection.JPAMetadataProvider;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
@ -217,6 +219,7 @@ public class Configuration implements Serializable {
protected Map<String, NamedSQLQueryDefinition> namedSqlQueries;
protected Map<String, NamedProcedureCallDefinition> namedProcedureCallMap;
protected Map<String, ResultSetMappingDefinition> sqlResultSetMappings;
protected Map<String, NamedEntityGraphDefinition> namedEntityGraphMap;
protected Map<String, TypeDef> typeDefs;
protected Map<String, FilterDefinition> filterDefinitions;
@ -299,6 +302,7 @@ public class Configuration implements Serializable {
namedQueries = new HashMap<String,NamedQueryDefinition>();
namedSqlQueries = new HashMap<String,NamedSQLQueryDefinition>();
sqlResultSetMappings = new HashMap<String, ResultSetMappingDefinition>();
namedEntityGraphMap = new HashMap<String, NamedEntityGraphDefinition>();
typeDefs = new HashMap<String,TypeDef>();
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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -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) {
applySQLQuery( name, query );
defaultNamedNativeQueryNames.add( name );

View File

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

View File

@ -36,6 +36,7 @@ import org.hibernate.MappingException;
import org.hibernate.annotations.AnyMetaDef;
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.cfg.annotations.NamedEntityGraphDefinition;
import org.hibernate.cfg.annotations.NamedProcedureCallDefinition;
import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.spi.FilterDefinition;
@ -347,6 +348,15 @@ public interface Mappings {
*/
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.
*

View File

@ -39,6 +39,7 @@ import org.hibernate.mapping.ManyToOne;
import org.hibernate.mapping.OneToOne;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Selectable;
import org.hibernate.mapping.SimpleValue;
import org.hibernate.type.ForeignKeyDirection;
@ -212,11 +213,9 @@ public class OneToOneSecondPass implements SecondPass {
propertyHolder.addProperty( prop, inferredData.getDeclaringClass() );
}
value.setReferencedPropertyName( mappedBy );
// 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
// Bar: @Id @OneToOne Foo foo
boolean referencesDerivedId = false;
@ -227,8 +226,14 @@ public class OneToOneSecondPass implements SecondPass {
catch ( MappingException e ) {
// ignore
}
String referencedPropertyName = referencesDerivedId ? null : mappedBy;
value.setReferencedPropertyName( referencedPropertyName );
boolean referenceToPrimaryKey = referencesDerivedId || mappedBy == null;
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();
if ( propertyRef != null ) {

View File

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

View File

@ -31,6 +31,8 @@ import javax.persistence.Access;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.NamedEntityGraph;
import javax.persistence.NamedEntityGraphs;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.SecondaryTable;
import javax.persistence.SecondaryTables;
@ -83,7 +85,6 @@ import org.hibernate.cfg.ObjectNameSource;
import org.hibernate.cfg.PropertyHolder;
import org.hibernate.cfg.UniqueConstraintHolder;
import org.hibernate.engine.OptimisticLockStyle;
import org.hibernate.engine.internal.Versioning;
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.internal.CoreMessageLogger;
@ -159,8 +160,27 @@ public class EntityBinder {
this.annotatedClass = annotatedClass;
bindEjb3Annotation( ejb3Ann );
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")
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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* 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) {
// by default, nothing to do
}
@ -1362,7 +1368,7 @@ public abstract class Dialect implements ConversionContext {
* @param lockOptions the lock options to apply
* @return The appropriate <tt>FOR UPDATE OF column_list</tt> clause string.
*/
@SuppressWarnings( {"unchecked"})
@SuppressWarnings({"unchecked", "UnusedParameters"})
public String getForUpdateString(String aliases, LockOptions lockOptions) {
LockMode lockMode = lockOptions.getLockMode();
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.
*/
@SuppressWarnings("UnusedParameters")
public int registerResultSetOutParameter(CallableStatement statement, String name) throws SQLException {
throw new UnsupportedOperationException(
getClass().getName() +
@ -1644,6 +1651,7 @@ public abstract class Dialect implements ConversionContext {
*
* @throws SQLException Indicates problems extracting the result set.
*/
@SuppressWarnings("UnusedParameters")
public ResultSet getResultSet(CallableStatement statement, int position) throws SQLException {
throw new UnsupportedOperationException(
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.
*/
@SuppressWarnings("UnusedParameters")
public ResultSet getResultSet(CallableStatement statement, String name) throws SQLException {
throw new UnsupportedOperationException(
getClass().getName() + " does not support resultsets via stored procedures"

View File

@ -40,7 +40,11 @@ import org.hibernate.service.spi.ServiceRegistryImplementor;
*
* @author Steve Ebersole
*/
@SuppressWarnings("deprecation")
public class DialectResolverInitiator implements StandardServiceInitiator<DialectResolver> {
/**
* Singleton access
*/
public static final DialectResolverInitiator INSTANCE = new DialectResolverInitiator();
@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.SchemaNameResolver;
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.spi.SqlExceptionHelper;
import org.hibernate.engine.jdbc.spi.TypeInfo;
import org.hibernate.exception.internal.SQLExceptionTypeDelegate;
import org.hibernate.exception.internal.SQLStateConversionDelegate;
import org.hibernate.exception.internal.StandardSQLExceptionConverter;

View File

@ -26,8 +26,8 @@ package org.hibernate.engine.jdbc.env.spi;
import java.util.Set;
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.TypeInfo;
import org.hibernate.metamodel.spi.relational.Identifier;
import org.hibernate.service.Service;

View File

@ -70,7 +70,6 @@ public class JdbcServicesImpl implements JdbcServices, ServiceRegistryAwareServi
@Override
public void configure(Map configValues) {
this.jdbcEnvironment = serviceRegistry.getService( JdbcEnvironment.class );
this.connectionProvider = serviceRegistry.getService( ConnectionProvider.class );
final boolean showSQL = ConfigurationHelper.getBoolean( Environment.SHOW_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.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.util.collections.ArrayHelper;

View File

@ -26,6 +26,8 @@ package org.hibernate.engine.jdbc.spi;
import java.sql.Connection;
/**
* A no-op adapter for ConnectionObserver.
*
* @author Steve Ebersole
*/
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.
*/
public int determineRemainingTransactionTimeOutPeriod();
/**
* Register a JDBC statement.
*
@ -200,8 +201,14 @@ public interface JdbcCoordinator extends Serializable {
*/
public void releaseResources();
/**
* Enable connection releases
*/
public void enableReleases();
/**
* Disable connection releases
*/
public void disableReleases();
/**
@ -211,5 +218,10 @@ public interface JdbcCoordinator extends Serializable {
*/
public void registerLastQuery(Statement statement);
/**
* Can this coordinator be serialized?
*
* @return {@code true} indicates the coordinator can be serialized.
*/
public boolean isReadyForSerialization();
}

View File

@ -23,8 +23,6 @@
*/
package org.hibernate.engine.jdbc.spi;
import java.sql.ResultSet;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.LobCreationContext;
import org.hibernate.engine.jdbc.LobCreator;
@ -90,7 +88,7 @@ public interface JdbcServices extends Service {
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.
*/
public ResultSetWrapper getResultSetWrapper();

View File

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

View File

@ -35,74 +35,83 @@ import java.sql.Statement;
* TODO: This could eventually utilize the new Return interface. It would be
* 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 Steve Ebersole
*/
public interface ResultSetReturn {
/**
* Extract the ResultSet from the statement. If user passes {@link CallableStatement}
* reference, method calls {@link #extract(CallableStatement)} internally.
* Extract the ResultSet from the PreparedStatement.
* <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);
/**
* 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 sql
* @param statement The JDBC Statement object to use
* @param sql The SQL to execute
*
* @return the ResultSet
* @return The resulting ResultSet
*/
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);
/**
* 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 sql
* @param statement The JDBC Statement object to use
* @param sql The SQL to execute
*
* @return the ResultSet
* @return The extracted ResultSet, or {@code null}
*/
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);
/**
* 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 sql
* @param statement The JDBC Statement object to use
* @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);
}

View File

@ -97,6 +97,12 @@ public class SqlStatementLogger {
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) {
if ( format ) {
if ( logToStdout || LOG.isDebugEnabled() ) {

View File

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

View File

@ -21,15 +21,30 @@
* 51 Franklin Street, Fifth Floor
* 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()}
*
* @author Steve Ebersole
*/
@SuppressWarnings("UnusedDeclaration")
public class TypeInfo {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
TypeInfo.class.getName()
);
private final String typeName;
private final int jdbcTypeCode;
private final String[] createParams;
@ -73,6 +88,64 @@ public class TypeInfo {
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() {
return typeName;
}

View File

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

View File

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

View File

@ -30,7 +30,13 @@ import org.hibernate.HibernateException;
* @author Steve Ebersole
*/
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
*/
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.Map;
import java.util.Properties;
import java.util.Set;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.InvalidNameException;
@ -36,11 +38,11 @@ import javax.naming.event.NamespaceChangeListener;
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.JndiNameException;
import org.hibernate.engine.jndi.spi.JndiService;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.jndi.JndiHelper;
/**
* Standard implementation of JNDI services.
@ -48,19 +50,66 @@ import org.hibernate.internal.util.jndi.JndiHelper;
* @author Steve Ebersole
*/
public class JndiServiceImpl implements JndiService {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, JndiServiceImpl.class.getName());
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
JndiServiceImpl.class.getName()
);
private final Hashtable initialContextSettings;
/**
* Constructs a JndiServiceImpl
*
* @param configurationValues Map of configuration settings, some of which apply to JNDI support.
*/
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
public Object locate(String jndiName) {
InitialContext initialContext = buildInitialContext();
Name name = parseName( jndiName, initialContext );
final InitialContext initialContext = buildInitialContext();
final Name name = parseName( jndiName, initialContext );
try {
return initialContext.lookup( name );
}
@ -104,8 +153,8 @@ public class JndiServiceImpl implements JndiService {
@Override
public void bind(String jndiName, Object value) {
InitialContext initialContext = buildInitialContext();
Name name = parseName( jndiName, initialContext );
final InitialContext initialContext = buildInitialContext();
final Name name = parseName( jndiName, initialContext );
try {
bind( name, value, initialContext );
}
@ -172,8 +221,8 @@ public class JndiServiceImpl implements JndiService {
@Override
public void unbind(String jndiName) {
InitialContext initialContext = buildInitialContext();
Name name = parseName( jndiName, initialContext );
final InitialContext initialContext = buildInitialContext();
final Name name = parseName( jndiName, initialContext );
try {
initialContext.unbind( name );
}
@ -187,8 +236,8 @@ public class JndiServiceImpl implements JndiService {
@Override
public void addListener(String jndiName, NamespaceChangeListener listener) {
InitialContext initialContext = buildInitialContext();
Name name = parseName( jndiName, initialContext );
final InitialContext initialContext = buildInitialContext();
final Name name = parseName( jndiName, initialContext );
try {
( (EventContext) initialContext ).addNamingListener( name, EventContext.OBJECT_SCOPE, listener );
}

View File

@ -35,6 +35,9 @@ import org.hibernate.service.spi.ServiceRegistryImplementor;
* @author Steve Ebersole
*/
public class JndiServiceInitiator implements StandardServiceInitiator<JndiService> {
/**
* Singleton access
*/
public static final JndiServiceInitiator INSTANCE = new JndiServiceInitiator();
@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.hibernate.HibernateException;
import org.hibernate.TransactionException;
import org.hibernate.cfg.Settings;
import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper;
@ -56,9 +57,9 @@ public class SynchronizationCallbackCoordinatorImpl implements SynchronizationCa
private AfterCompletionAction afterCompletionAction;
private ExceptionMapper exceptionMapper;
private long registrationThreadId;
private volatile long registrationThreadId;
private final int NO_STATUS = -1;
private int delayedCompletionHandlingStatus;
private volatile int delayedCompletionHandlingStatus;
public SynchronizationCallbackCoordinatorImpl(TransactionCoordinator transactionCoordinator) {
this.transactionCoordinator = transactionCoordinator;
@ -154,11 +155,12 @@ public class SynchronizationCallbackCoordinatorImpl implements SynchronizationCa
if ( delayedCompletionHandlingStatus != NO_STATUS ) {
doAfterCompletion( delayedCompletionHandlingStatus );
delayedCompletionHandlingStatus = NO_STATUS;
throw new HibernateException("Transaction was rolled back in a different thread!");
}
}
private void doAfterCompletion(int status) {
LOG.tracev( "Transaction after completion callback [status={0}]", status );
LOG.tracev( "Transaction afterCompletion callback [status={0}]", status );
try {
afterCompletionAction.doAction( transactionCoordinator, status );

View File

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

View File

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

View File

@ -23,17 +23,16 @@
*/
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.InitialContext;
import javax.naming.Name;
import javax.naming.NameNotFoundException;
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.
@ -54,42 +53,12 @@ public final class JndiHelper {
*/
@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;
return JndiServiceImpl.extractJndiProperties( configurationValues );
}
public static InitialContext getInitialContext(Properties props) throws NamingException {
Hashtable hash = extractJndiProperties(props);
return hash.size()==0 ?
new InitialContext() :
new InitialContext(hash);
final Hashtable hash = extractJndiProperties( props );
return hash.size() == 0 ? new InitialContext() : new InitialContext( hash );
}
/**
@ -108,7 +77,7 @@ public final class JndiHelper {
catch (Exception e) {
Name n = ctx.getNameParser( "" ).parse( name );
while ( n.size() > 1 ) {
String ctxName = n.get(0);
final String ctxName = n.get( 0 );
Context subctx = null;
try {

View File

@ -59,11 +59,8 @@ public abstract class AbstractJoinableAssociationImpl implements JoinableAssocia
boolean hasRestriction,
Map<String, Filter> enabledFilters) throws MappingException {
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 ) {
joinType = isNullable ? JoinType.LEFT_OUTER_JOIN : JoinType.INNER_JOIN;
joinType = currentFetch.isNullable() ? JoinType.LEFT_OUTER_JOIN : JoinType.INNER_JOIN;
}
else {
joinType = JoinType.NONE;

View File

@ -27,7 +27,6 @@ import java.util.HashMap;
import java.util.Map;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.engine.internal.JoinHelper;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.loader.CollectionAliases;
@ -36,6 +35,8 @@ import org.hibernate.loader.EntityAliases;
import org.hibernate.loader.GeneratedCollectionAliases;
import org.hibernate.loader.plan.spi.CollectionReference;
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.EntityReturn;
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.entity.EntityPersister;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.type.EntityType;
/**
@ -214,9 +214,18 @@ public class LoadQueryAliasResolutionContextImpl implements LoadQueryAliasResolu
if ( EntityReference.class.isInstance( currentFetch.getOwner() ) ) {
lhsAlias = resolveEntityTableAlias( (EntityReference) currentFetch.getOwner() );
}
else {
throw new NotYetImplementedException( "Cannot determine LHS alias for a FetchOwner that is not an EntityReference yet." );
else if ( CompositeElementGraph.class.isInstance( currentFetch.getOwner() ) ) {
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;
if ( EntityReference.class.isInstance( 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
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 );
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.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.type.EntityType;
/**
* @author Steve Ebersole
@ -63,6 +64,7 @@ public class LoadPlanBuildingHelper {
LockMode.NONE, // todo : for now
fetchOwner,
attributeDefinition.getName(),
(EntityType) attributeDefinition.getType(),
fetchStrategy
);
}
@ -73,7 +75,7 @@ public class LoadPlanBuildingHelper {
LoadPlanBuildingContext loadPlanBuildingContext) {
return new CompositeFetch(
loadPlanBuildingContext.getSessionFactory(),
(AbstractFetchOwner) fetchOwner,
fetchOwner,
attributeDefinition.getName()
);
}

View File

@ -27,20 +27,24 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchStrategy;
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 Gail Badner
*/
public abstract class AbstractFetchOwner extends AbstractPlanNode implements FetchOwner {
private final LockMode lockMode;
private List<Fetch> fetches;
public AbstractFetchOwner(SessionFactoryImplementor factory, LockMode lockMode) {
public AbstractFetchOwner(SessionFactoryImplementor factory) {
super( factory );
this.lockMode = lockMode;
validate();
}
@ -50,11 +54,10 @@ public abstract class AbstractFetchOwner extends AbstractPlanNode implements Fet
/**
* 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) {
super( original );
this.lockMode = original.lockMode;
validate();
copyContext.getReturnGraphVisitationStrategy().startingFetches( original );
@ -62,6 +65,7 @@ public abstract class AbstractFetchOwner extends AbstractPlanNode implements Fet
this.fetches = Collections.emptyList();
}
else {
// TODO: don't think this is correct...
List<Fetch> fetchesCopy = new ArrayList<Fetch>();
for ( Fetch fetch : fetches ) {
fetchesCopy.add( fetch.makeCopy( copyContext, this ) );
@ -71,11 +75,6 @@ public abstract class AbstractFetchOwner extends AbstractPlanNode implements Fet
copyContext.getReturnGraphVisitationStrategy().finishingFetches( original );
}
public LockMode getLockMode() {
return lockMode;
}
@Override
public void addFetch(Fetch fetch) {
if ( fetch.getOwner() != this ) {
throw new IllegalArgumentException( "Fetch and owner did not match" );
@ -92,4 +91,55 @@ public abstract class AbstractFetchOwner extends AbstractPlanNode implements Fet
public Fetch[] getFetches() {
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;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.spi.SessionFactoryImplementor;
@ -42,11 +41,10 @@ public abstract class AbstractSingularAttributeFetch extends AbstractFetchOwner
public AbstractSingularAttributeFetch(
SessionFactoryImplementor factory,
LockMode lockMode,
FetchOwner owner,
String ownerProperty,
FetchStrategy fetchStrategy) {
super( factory, lockMode );
super( factory );
this.owner = owner;
this.ownerProperty = ownerProperty;
this.fetchStrategy = fetchStrategy;
@ -77,6 +75,16 @@ public abstract class AbstractSingularAttributeFetch extends AbstractFetchOwner
return ownerProperty;
}
@Override
public boolean isNullable() {
return owner.isNullable( this );
}
@Override
public String[] getColumnNames() {
return owner.getColumnNames( this );
}
@Override
public FetchStrategy getFetchStrategy() {
return fetchStrategy;

View File

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

View File

@ -1,29 +1,24 @@
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.engine.FetchStrategy;
import org.hibernate.engine.spi.SessionFactoryImplementor;
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.QueryableCollection;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.type.CompositeType;
/**
* @author Steve Ebersole
*/
public class CompositeElementGraph extends AbstractPlanNode implements FetchableCollectionElement {
public class CompositeElementGraph extends AbstractFetchOwner implements FetchableCollectionElement {
private final CollectionReference collectionReference;
private final PropertyPath propertyPath;
private final CollectionPersister collectionPersister;
private List<Fetch> fetches;
private final FetchOwnerDelegate fetchOwnerDelegate;
public CompositeElementGraph(
SessionFactoryImplementor sessionFactory,
@ -34,39 +29,24 @@ public class CompositeElementGraph extends AbstractPlanNode implements Fetchable
this.collectionReference = collectionReference;
this.collectionPersister = collectionReference.getCollectionPersister();
this.propertyPath = collectionPath.append( "<elements>" );
this.fetchOwnerDelegate = new CompositeFetchOwnerDelegate(
sessionFactory,
(CompositeType) collectionPersister.getElementType(),
( (QueryableCollection) collectionPersister ).getElementColumnNames()
);
}
public CompositeElementGraph(CompositeElementGraph original, CopyContext copyContext) {
super( original );
super( original, copyContext );
this.collectionReference = original.collectionReference;
this.collectionPersister = original.collectionPersister;
this.propertyPath = original.propertyPath;
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 );
this.fetchOwnerDelegate = original.fetchOwnerDelegate;
}
@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() ] );
public CollectionReference getCollectionReference() {
return collectionReference;
}
@Override
@ -83,6 +63,16 @@ public class CompositeElementGraph extends AbstractPlanNode implements Fetchable
return propertyPath;
}
@Override
public CompositeElementGraph makeCopy(CopyContext copyContext) {
return new CompositeElementGraph( this, copyContext );
}
@Override
protected FetchOwnerDelegate getFetchOwnerDelegate() {
return fetchOwnerDelegate;
}
@Override
public CollectionFetch buildCollectionFetch(
AssociationAttributeDefinition attributeDefinition,
@ -90,29 +80,4 @@ public class CompositeElementGraph extends AbstractPlanNode implements Fetchable
LoadPlanBuildingContext loadPlanBuildingContext) {
throw new HibernateException( "Collection composite element cannot define collections" );
}
@Override
public EntityFetch buildEntityFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardEntityFetch(
this,
attributeDefinition,
fetchStrategy,
loadPlanBuildingContext
);
}
@Override
public CompositeFetch buildCompositeFetch(
CompositionDefinition attributeDefinition,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardCompositeFetch( this, attributeDefinition, loadPlanBuildingContext );
}
@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.SQLException;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
import org.hibernate.loader.plan.spi.build.LoadPlanBuildingContext;
import org.hibernate.loader.spi.ResultSetProcessingContext;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.type.CompositeType;
/**
* @author Steve Ebersole
@ -43,15 +43,28 @@ import org.hibernate.persister.walking.spi.CompositionDefinition;
public class CompositeFetch extends AbstractSingularAttributeFetch {
public static final FetchStrategy FETCH_PLAN = new FetchStrategy( FetchTiming.IMMEDIATE, FetchStyle.JOIN );
private final FetchOwnerDelegate delegate;
public CompositeFetch(
SessionFactoryImplementor sessionFactory,
FetchOwner owner,
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) {
super( original, copyContext, fetchOwnerCopy );
this.delegate = original.getFetchOwnerDelegate();
}
@Override
protected FetchOwnerDelegate getFetchOwnerDelegate() {
return delegate;
}
@Override
@ -72,13 +85,18 @@ public class CompositeFetch extends AbstractSingularAttributeFetch {
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
return null; //To change body of implemented methods use File | Settings | File Templates.
return LoadPlanBuildingHelper.buildStandardEntityFetch(
this,
attributeDefinition,
fetchStrategy,
loadPlanBuildingContext
);
}
@Override
public CompositeFetch buildCompositeFetch(
CompositionDefinition attributeDefinition, LoadPlanBuildingContext loadPlanBuildingContext) {
return null; //To change body of implemented methods use File | Settings | File Templates.
return LoadPlanBuildingHelper.buildStandardCompositeFetch( this, attributeDefinition, loadPlanBuildingContext );
}
@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;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.PropertyPath;
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
import org.hibernate.loader.plan.spi.build.LoadPlanBuildingContext;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.type.CompositeType;
/**
* @author Steve Ebersole
*/
public class CompositeIndexGraph extends AbstractPlanNode implements FetchableCollectionIndex {
public class CompositeIndexGraph extends AbstractFetchOwner implements FetchableCollectionIndex {
private final CollectionReference collectionReference;
private final PropertyPath propertyPath;
private final CollectionPersister collectionPersister;
private List<Fetch> fetches;
private final FetchOwnerDelegate fetchOwnerDelegate;
public CompositeIndexGraph(
SessionFactoryImplementor sessionFactory,
@ -33,39 +28,19 @@ public class CompositeIndexGraph extends AbstractPlanNode implements FetchableCo
this.collectionReference = collectionReference;
this.collectionPersister = collectionReference.getCollectionPersister();
this.propertyPath = propertyPath.append( "<index>" );
this.fetchOwnerDelegate = new CompositeFetchOwnerDelegate(
sessionFactory,
(CompositeType) collectionPersister.getIndexType(),
( (QueryableCollection) collectionPersister ).getIndexColumnNames()
);
}
protected CompositeIndexGraph(CompositeIndexGraph original, CopyContext copyContext) {
super( original );
super( original, copyContext );
this.collectionReference = original.collectionReference;
this.collectionPersister = original.collectionPersister;
this.propertyPath = original.propertyPath;
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() ] );
this.fetchOwnerDelegate = original.fetchOwnerDelegate;
}
@Override
@ -77,12 +52,25 @@ public class CompositeIndexGraph extends AbstractPlanNode implements FetchableCo
return collectionPersister.getOwnerEntityPersister();
}
public CollectionReference getCollectionReference() {
return collectionReference;
}
@Override
public PropertyPath getPropertyPath() {
return propertyPath;
}
@Override
public CompositeIndexGraph makeCopy(CopyContext copyContext) {
return new CompositeIndexGraph( this, copyContext );
}
@Override
protected FetchOwnerDelegate getFetchOwnerDelegate() {
return fetchOwnerDelegate;
}
public CollectionFetch buildCollectionFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
@ -90,28 +78,4 @@ public class CompositeIndexGraph extends AbstractPlanNode implements FetchableCo
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;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.PropertyPath;
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
import org.hibernate.loader.plan.spi.build.LoadPlanBuildingContext;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.type.AssociationType;
/**
* @author Steve Ebersole
*/
public class EntityElementGraph extends AbstractPlanNode implements FetchableCollectionElement, EntityReference {
public class EntityElementGraph extends AbstractFetchOwner implements FetchableCollectionElement, EntityReference {
private final CollectionReference collectionReference;
private final CollectionPersister collectionPersister;
private final AssociationType elementType;
private final EntityPersister elementPersister;
private final PropertyPath propertyPath;
private List<Fetch> fetches;
private final FetchOwnerDelegate fetchOwnerDelegate;
private IdentifierDescription identifierDescription;
@ -40,30 +31,19 @@ public class EntityElementGraph extends AbstractPlanNode implements FetchableCol
this.collectionPersister = collectionReference.getCollectionPersister();
this.elementType = (AssociationType) collectionPersister.getElementType();
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) {
super( original );
super( original, copyContext );
this.collectionReference = original.collectionReference;
this.collectionPersister = original.collectionReference.getCollectionPersister();
this.elementType = original.elementType;
this.elementPersister = original.elementPersister;
this.propertyPath = original.propertyPath;
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 );
this.fetchOwnerDelegate = original.fetchOwnerDelegate;
}
@Override
@ -86,19 +66,6 @@ public class EntityElementGraph extends AbstractPlanNode implements FetchableCol
return identifierDescription;
}
@Override
public void addFetch(Fetch fetch) {
if ( fetches == null ) {
fetches = new ArrayList<Fetch>();
}
fetches.add( fetch );
}
@Override
public Fetch[] getFetches() {
return fetches == null ? NO_FETCHES : fetches.toArray( new Fetch[ fetches.size() ] );
}
@Override
public void validateFetchPlan(FetchStrategy fetchStrategy) {
}
@ -113,39 +80,6 @@ public class EntityElementGraph extends AbstractPlanNode implements FetchableCol
return propertyPath;
}
@Override
public CollectionFetch buildCollectionFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardCollectionFetch(
this,
attributeDefinition,
fetchStrategy,
loadPlanBuildingContext
);
}
@Override
public EntityFetch buildEntityFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardEntityFetch(
this,
attributeDefinition,
fetchStrategy,
loadPlanBuildingContext
);
}
@Override
public CompositeFetch buildCompositeFetch(
CompositionDefinition attributeDefinition,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardCompositeFetch( this, attributeDefinition, loadPlanBuildingContext );
}
@Override
public void injectIdentifierDescription(IdentifierDescription identifierDescription) {
this.identifierDescription = identifierDescription;
@ -156,8 +90,18 @@ public class EntityElementGraph extends AbstractPlanNode implements FetchableCol
return new EntityElementGraph( this, copyContext );
}
@Override
public CollectionReference getCollectionReference() {
return collectionReference;
}
@Override
public String toString() {
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.spi.EntityKey;
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.persister.entity.EntityPersister;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.type.EntityType;
/**
* @author Steve Ebersole
*/
public class EntityFetch extends AbstractSingularAttributeFetch implements EntityReference {
public class EntityFetch extends AbstractSingularAttributeFetch implements EntityReference, Fetch {
private final EntityType associationType;
private final EntityPersister persister;
private final LockMode lockMode;
private final FetchOwnerDelegate fetchOwnerDelegate;
private IdentifierDescription identifierDescription;
@ -55,11 +53,14 @@ public class EntityFetch extends AbstractSingularAttributeFetch implements Entit
LockMode lockMode,
FetchOwner owner,
String ownerProperty,
EntityType entityType,
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.lockMode = lockMode;
this.fetchOwnerDelegate = new EntityFetchOwnerDelegate( persister );
}
/**
@ -72,6 +73,8 @@ public class EntityFetch extends AbstractSingularAttributeFetch implements Entit
super( original, copyContext, fetchOwnerCopy );
this.associationType = original.associationType;
this.persister = original.persister;
this.lockMode = original.lockMode;
this.fetchOwnerDelegate = original.fetchOwnerDelegate;
}
public EntityType getAssociationType() {
@ -93,45 +96,16 @@ public class EntityFetch extends AbstractSingularAttributeFetch implements Entit
return identifierDescription;
}
@Override
public LockMode getLockMode() {
return lockMode;
}
@Override
public EntityPersister retrieveFetchSourcePersister() {
return persister;
}
@Override
public CollectionFetch buildCollectionFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardCollectionFetch(
this,
attributeDefinition,
fetchStrategy,
loadPlanBuildingContext
);
}
@Override
public EntityFetch buildEntityFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardEntityFetch(
this,
attributeDefinition,
fetchStrategy,
loadPlanBuildingContext
);
}
@Override
public CompositeFetch buildCompositeFetch(
CompositionDefinition attributeDefinition,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardCompositeFetch( this, attributeDefinition, loadPlanBuildingContext );
}
@Override
public void injectIdentifierDescription(IdentifierDescription identifierDescription) {
this.identifierDescription = identifierDescription;
@ -267,4 +241,9 @@ public class EntityFetch extends AbstractSingularAttributeFetch implements Entit
copyContext.getReturnGraphVisitationStrategy().finishingEntityFetch( this );
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;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.PropertyPath;
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
import org.hibernate.loader.plan.spi.build.LoadPlanBuildingContext;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.type.AssociationType;
/**
* @author Steve Ebersole
*/
public class EntityIndexGraph extends AbstractPlanNode implements FetchableCollectionIndex, EntityReference {
public class EntityIndexGraph extends AbstractFetchOwner implements FetchableCollectionIndex, EntityReference {
private final CollectionReference collectionReference;
private final CollectionPersister collectionPersister;
private final AssociationType indexType;
private final EntityPersister indexPersister;
private final PropertyPath propertyPath;
private List<Fetch> fetches;
private final FetchOwnerDelegate fetchOwnerDelegate;
private IdentifierDescription identifierDescription;
@ -63,28 +54,17 @@ public class EntityIndexGraph extends AbstractPlanNode implements FetchableColle
this.indexType = (AssociationType) collectionPersister.getIndexType();
this.indexPersister = (EntityPersister) this.indexType.getAssociatedJoinable( sessionFactory() );
this.propertyPath = collectionPath.append( "<index>" ); // todo : do we want the <index> part?
this.fetchOwnerDelegate = new EntityFetchOwnerDelegate( indexPersister );
}
public EntityIndexGraph(EntityIndexGraph original, CopyContext copyContext) {
super( original );
super( original, copyContext );
this.collectionReference = original.collectionReference;
this.collectionPersister = original.collectionReference.getCollectionPersister();
this.indexType = original.indexType;
this.indexPersister = original.indexPersister;
this.propertyPath = original.propertyPath;
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 );
this.fetchOwnerDelegate = original.fetchOwnerDelegate;
}
@Override
@ -107,19 +87,6 @@ public class EntityIndexGraph extends AbstractPlanNode implements FetchableColle
return identifierDescription;
}
@Override
public void addFetch(Fetch fetch) {
if ( fetches == null ) {
fetches = new ArrayList<Fetch>();
}
fetches.add( fetch );
}
@Override
public Fetch[] getFetches() {
return fetches == null ? NO_FETCHES : fetches.toArray( new Fetch[ fetches.size() ] );
}
@Override
public void validateFetchPlan(FetchStrategy fetchStrategy) {
}
@ -134,39 +101,6 @@ public class EntityIndexGraph extends AbstractPlanNode implements FetchableColle
return propertyPath;
}
@Override
public CollectionFetch buildCollectionFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardCollectionFetch(
this,
attributeDefinition,
fetchStrategy,
loadPlanBuildingContext
);
}
@Override
public EntityFetch buildEntityFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardEntityFetch(
this,
attributeDefinition,
fetchStrategy,
loadPlanBuildingContext
);
}
@Override
public CompositeFetch buildCompositeFetch(
CompositionDefinition attributeDefinition,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardCompositeFetch( this, attributeDefinition, loadPlanBuildingContext );
}
@Override
public void injectIdentifierDescription(IdentifierDescription identifierDescription) {
this.identifierDescription = identifierDescription;
@ -176,4 +110,9 @@ public class EntityIndexGraph extends AbstractPlanNode implements FetchableColle
public EntityIndexGraph makeCopy(CopyContext 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.SessionFactoryImplementor;
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.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;
@ -50,24 +46,32 @@ public class EntityReturn extends AbstractFetchOwner implements Return, EntityRe
private final PropertyPath propertyPath = new PropertyPath(); // its a root
private final LockMode lockMode;
private final FetchOwnerDelegate fetchOwnerDelegate;
private IdentifierDescription identifierDescription;
public EntityReturn(
SessionFactoryImplementor sessionFactory,
LockMode lockMode,
String entityName) {
super( sessionFactory, lockMode );
super( sessionFactory );
this.persister = sessionFactory.getEntityPersister( entityName );
this.lockMode = lockMode;
this.fetchOwnerDelegate = new EntityFetchOwnerDelegate( persister );
}
protected EntityReturn(EntityReturn original, CopyContext copyContext) {
super( original, copyContext );
this.persister = original.persister;
this.lockMode = original.lockMode;
this.fetchOwnerDelegate = original.fetchOwnerDelegate;
}
@Override
public LockMode getLockMode() {
return super.getLockMode();
return lockMode;
}
@Override
@ -99,42 +103,9 @@ public class EntityReturn extends AbstractFetchOwner implements Return, EntityRe
return propertyPath;
}
@Override
public CollectionFetch buildCollectionFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardCollectionFetch(
this,
attributeDefinition,
fetchStrategy,
loadPlanBuildingContext
);
}
@Override
public EntityFetch buildEntityFetch(
AssociationAttributeDefinition attributeDefinition,
FetchStrategy fetchStrategy,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardEntityFetch(
this,
attributeDefinition,
fetchStrategy,
loadPlanBuildingContext
);
}
@Override
public CompositeFetch buildCompositeFetch(
CompositionDefinition attributeDefinition,
LoadPlanBuildingContext loadPlanBuildingContext) {
return LoadPlanBuildingHelper.buildStandardCompositeFetch( this, attributeDefinition, loadPlanBuildingContext );
}
@Override
public void hydrate(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
EntityKey entityKey = context.getDictatedRootEntityKey();
EntityKey entityKey = getEntityKeyFromContext( context );
if ( entityKey != null ) {
context.getIdentifierResolutionContext( this ).registerEntityKey( entityKey );
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
public void resolve(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
final IdentifierResolutionContext identifierResolutionContext = context.getIdentifierResolutionContext( this );
@ -194,4 +178,9 @@ public class EntityReturn extends AbstractFetchOwner implements Return, EntityRe
public EntityReturn makeCopy(CopyContext 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 boolean isNullable();
public String[] getColumnNames();
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.walking.spi.AssociationAttributeDefinition;
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.
@ -56,6 +57,12 @@ public interface FetchOwner {
*/
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?
*

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;
import org.hibernate.persister.collection.CollectionPersister;
/**
* @author Steve Ebersole
*/
public interface FetchableCollectionElement extends FetchOwner, CopyableReturn {
@Override
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.LockMode;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchTiming;
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.loader.PropertyPath;
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.CollectionReference;
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.CompositeFetchOwnerDelegate;
import org.hibernate.loader.plan.spi.EntityFetch;
import org.hibernate.loader.plan.spi.EntityReference;
import org.hibernate.loader.plan.spi.EntityReturn;
import org.hibernate.loader.plan.spi.Fetch;
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.Return;
import org.hibernate.loader.spi.ResultSetProcessingContext;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.spi.HydratedCompoundValueHandler;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.AttributeDefinition;
@ -64,9 +70,11 @@ import org.hibernate.persister.walking.spi.CollectionDefinition;
import org.hibernate.persister.walking.spi.CollectionElementDefinition;
import org.hibernate.persister.walking.spi.CollectionIndexDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.persister.walking.spi.CompositionElementDefinition;
import org.hibernate.persister.walking.spi.EntityDefinition;
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
import org.hibernate.persister.walking.spi.WalkingException;
import org.hibernate.type.CompositeType;
import org.hibernate.type.Type;
import static org.hibernate.loader.spi.ResultSetProcessingContext.IdentifierResolutionContext;
@ -190,8 +198,13 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
final FetchOwner identifierAttributeCollector;
if ( entityIdentifierDefinition.isEncapsulated() ) {
if ( entityIdentifierDefinition.getEntityDefinition().getEntityPersister().getIdentifierType().isComponentType() ) {
identifierAttributeCollector = new EncapsulatedCompositeIdentifierAttributeCollector( entityReference );
}
else {
identifierAttributeCollector = new EncapsulatedIdentifierAttributeCollector( entityReference );
}
}
else {
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
}
@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
public void finishingCollection(CollectionDefinition collectionDefinition) {
// 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 {
protected final EntityReference entityReference;
private final PropertyPath propertyPath;
protected final List<EntityFetch> identifierFetches = new ArrayList<EntityFetch>();
protected final Map<EntityFetch,HydratedCompoundValueHandler> fetchToHydratedStateExtractorMap
= new HashMap<EntityFetch, HydratedCompoundValueHandler>();
protected final List<AbstractSingularAttributeFetch> identifierFetches = new ArrayList<AbstractSingularAttributeFetch>();
protected final Map<AbstractSingularAttributeFetch,HydratedCompoundValueHandler> fetchToHydratedStateExtractorMap
= new HashMap<AbstractSingularAttributeFetch, HydratedCompoundValueHandler>();
public AbstractIdentifierAttributeCollector(EntityReference entityReference) {
this.entityReference = entityReference;
this.propertyPath = ( (FetchOwner) entityReference ).getPropertyPath().append( "<id>" );
}
@Override
@ -513,6 +553,11 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
return entityReference.getEntityPersister();
}
@Override
public boolean isNullable(Fetch fetch) {
return false;
}
@Override
public IdentifierDescription getIdentifierDescription() {
return entityReference.getIdentifierDescription();
@ -533,7 +578,7 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
LoadPlanBuildingContext loadPlanBuildingContext) {
// we have a key-many-to-one
//
// IMPL NOTE: we pass ourselves as the FetchOwner which will route the fetch back throw our #addFetch
// IMPL 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
final EntityFetch fetch = LoadPlanBuildingHelper.buildStandardEntityFetch(
this,
@ -551,7 +596,7 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
CompositionDefinition attributeDefinition, LoadPlanBuildingContext loadPlanBuildingContext) {
// nested composition. Unusual, but not disallowed.
//
// IMPL NOTE: we pass ourselves as the FetchOwner which will route the fetch back throw our #addFetch
// IMPL 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
return LoadPlanBuildingHelper.buildStandardCompositeFetch(
this,
@ -570,7 +615,7 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
@Override
public void addFetch(Fetch fetch) {
identifierFetches.add( (EntityFetch) fetch );
identifierFetches.add( (AbstractSingularAttributeFetch) fetch );
}
@Override
@ -588,11 +633,6 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
return ( (FetchOwner) entityReference ).retrieveFetchSourcePersister();
}
@Override
public PropertyPath getPropertyPath() {
return propertyPath;
}
@Override
public void injectIdentifierDescription(IdentifierDescription identifierDescription) {
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 {
private final PropertyPath propertyPath;
public EncapsulatedIdentifierAttributeCollector(EntityReference entityReference) {
super( entityReference );
this.propertyPath = ( (FetchOwner) entityReference ).getPropertyPath();
}
@Override
protected IdentifierDescription buildIdentifierDescription() {
return new IdentifierDescriptionImpl(
entityReference,
identifierFetches.toArray( new EntityFetch[ identifierFetches.size() ] ),
identifierFetches.toArray( new AbstractSingularAttributeFetch[ identifierFetches.size() ] ),
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 {
public NonEncapsulatedIdentifierAttributeCollector(EntityReference entityReference) {
@Override
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 );
this.propertyPath = ( (FetchOwner) entityReference ).getPropertyPath();
}
@Override
protected IdentifierDescription buildIdentifierDescription() {
return new IdentifierDescriptionImpl(
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
);
}
@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 final EntityReference entityReference;
private final EntityFetch[] identifierFetches;
private final Map<EntityFetch,HydratedCompoundValueHandler> fetchToHydratedStateExtractorMap;
private final AbstractSingularAttributeFetch[] identifierFetches;
private final Map<AbstractSingularAttributeFetch,HydratedCompoundValueHandler> fetchToHydratedStateExtractorMap;
private IdentifierDescriptionImpl(
EntityReference entityReference, EntityFetch[] identifierFetches,
Map<EntityFetch, HydratedCompoundValueHandler> fetchToHydratedStateExtractorMap) {
EntityReference entityReference,
AbstractSingularAttributeFetch[] identifierFetches,
Map<AbstractSingularAttributeFetch, HydratedCompoundValueHandler> fetchToHydratedStateExtractorMap) {
this.entityReference = entityReference;
this.identifierFetches = identifierFetches;
this.fetchToHydratedStateExtractorMap = fetchToHydratedStateExtractorMap;
@ -656,14 +796,14 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
final Object ownerIdentifierHydratedState = ownerIdentifierResolutionContext.getHydratedForm();
if ( ownerIdentifierHydratedState != null ) {
for ( EntityFetch fetch : identifierFetches ) {
for ( AbstractSingularAttributeFetch fetch : identifierFetches ) {
if ( fetch instanceof EntityFetch ) {
final IdentifierResolutionContext identifierResolutionContext =
context.getIdentifierResolutionContext( fetch );
context.getIdentifierResolutionContext( (EntityFetch) fetch );
// if the identifier was already hydrated, nothing to do
if ( identifierResolutionContext.getHydratedForm() != null ) {
continue;
}
// try to extract the sub-hydrated value from the owners tuple array
if ( fetchToHydratedStateExtractorMap != null && ownerIdentifierHydratedState != null ) {
Serializable extracted = (Serializable) fetchToHydratedStateExtractorMap.get( fetch )
@ -675,6 +815,10 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
// if we can't, then read from result set
fetch.hydrate( resultSet, context );
}
else {
throw new NotYetImplementedException( "Cannot hydrate identifier Fetch that is not an EntityFetch" );
}
}
return;
}
@ -689,15 +833,8 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
@Override
public EntityKey resolve(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
for ( EntityFetch fetch : identifierFetches ) {
final IdentifierResolutionContext identifierResolutionContext =
context.getIdentifierResolutionContext( fetch );
if ( identifierResolutionContext.getEntityKey() != null ) {
continue;
}
EntityKey fetchKey = fetch.resolveInIdentifier( resultSet, context );
identifierResolutionContext.registerEntityKey( fetchKey );
for ( AbstractSingularAttributeFetch fetch : identifierFetches ) {
resolveIdentifierFetch( resultSet, context, fetch );
}
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 {
private ArrayDeque<PropertyPath> pathStack = new ArrayDeque<PropertyPath>();

View File

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

View File

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

View File

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

View File

@ -40,6 +40,7 @@ public abstract class ToOne extends SimpleValue implements Fetchable {
private String referencedEntityName;
private boolean lazy = true;
protected boolean unwrapProxy;
protected boolean referenceToPrimaryKey = true;
protected ToOne(Mappings mappings, Table table) {
super( mappings, table );
@ -111,4 +112,12 @@ public abstract class ToOne extends SimpleValue implements Fetchable {
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.cache.spi.access.AccessType;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.cfg.annotations.NamedEntityGraphDefinition;
import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.engine.spi.NamedQueryDefinition;
@ -115,6 +116,8 @@ public interface Metadata {
public Iterable<NamedQueryDefinition> getNamedQueryDefinitions();
public Map<String, NamedEntityGraphDefinition> getNamedEntityGraphMap();
public Iterable<NamedSQLQueryDefinition> getNamedNativeQueryDefinitions();
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.cfg.NamingStrategy;
import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.cfg.annotations.NamedEntityGraphDefinition;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.jdbc.spi.JdbcServices;
@ -134,7 +135,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
private final MappingDefaults mappingDefaults;
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, 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, NamedSQLQueryDefinition> namedNativeQueryDefs = new HashMap<String, NamedSQLQueryDefinition>();
private Map<String, ResultSetMappingDefinition> resultSetMappings = new HashMap<String, ResultSetMappingDefinition>();
private final Map<String, NamedEntityGraphDefinition> namedEntityGraphMap = new HashMap<String, NamedEntityGraphDefinition>( );
private boolean globallyQuotedIdentifiers = false;
@ -375,6 +377,19 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -24,6 +24,7 @@
package org.hibernate.metamodel.spi;
import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.cfg.annotations.NamedEntityGraphDefinition;
import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.engine.spi.Mapping;
@ -69,6 +70,8 @@ public interface MetadataImplementor extends Metadata, BindingContext, Mapping {
public void addNamedNativeQuery(NamedSQLQueryDefinition def);
public void addNamedEntityGraph(NamedEntityGraphDefinition def);
public void addNamedQuery(NamedQueryDefinition def);
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.PropertyMapping;
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.CollectionElementDefinition;
import org.hibernate.persister.walking.spi.CollectionIndexDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.persister.walking.spi.CompositionElementDefinition;
import org.hibernate.persister.walking.spi.EntityDefinition;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.sql.Alias;
@ -2342,7 +2346,6 @@ public abstract class AbstractCollectionPersister
public abstract FilterAliasGenerator getFilterAliasGenerator(final String rootAlias);
// ColectionDefinition impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
@ -2408,12 +2411,42 @@ public abstract class AbstractCollectionPersister
}
@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() ) {
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.StructuredCacheEntry;
import org.hibernate.cache.spi.entry.UnstructuredCacheEntry;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.dialect.lock.LockingStrategy;
import org.hibernate.engine.OptimisticLockStyle;
import org.hibernate.engine.internal.StatefulPersistenceContext;
@ -120,12 +119,9 @@ import org.hibernate.metamodel.spi.relational.DerivedValue;
import org.hibernate.metamodel.spi.relational.Table;
import org.hibernate.metamodel.spi.relational.TableSpecification;
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.AttributeSource;
import org.hibernate.persister.walking.spi.EncapsulatedEntityIdentifierDefinition;
import org.hibernate.persister.walking.spi.EntityDefinition;
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
import org.hibernate.persister.walking.spi.NonEncapsulatedEntityIdentifierDefinition;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.property.BackrefPropertyAccessor;
import org.hibernate.sql.Alias;
@ -5290,80 +5286,20 @@ public abstract class AbstractEntityPersister
final Type idType = getIdentifierType();
if ( !idType.isComponentType() ) {
entityIdentifierDefinition = buildEncapsulatedIdentifierDefinition();
entityIdentifierDefinition =
EntityIdentifierDefinitionHelper.buildSimpleEncapsulatedIdentifierDefinition( this );
return;
}
final CompositeType cidType = (CompositeType) idType;
if ( !cidType.isEmbedded() ) {
entityIdentifierDefinition = buildEncapsulatedIdentifierDefinition();
entityIdentifierDefinition =
EntityIdentifierDefinitionHelper.buildEncapsulatedCompositeIdentifierDefinition( this );
return;
}
entityIdentifierDefinition = new NonEncapsulatedEntityIdentifierDefinition() {
@Override
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;
}
};
entityIdentifierDefinition =
EntityIdentifierDefinitionHelper.buildNonEncapsulatedCompositeIdentifierDefinition( this );
}
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
*/
public class Helper {
public class FetchStrategyHelper {
/**
* Determine the fetch-style (if one) explicitly set for this association via fetch profiles.
* <p/>

View File

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

View File

@ -35,5 +35,5 @@ public interface CollectionElementDefinition {
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() );
final boolean continueWalk;
if ( attributeDefinition.getType().isAssociationType() ) {
continueWalk =
! isDuplicateAssociation( ( (AssociationAttributeDefinition) attributeDefinition ).getAssociationKey() ) &&
strategy.startingAttribute( attributeDefinition );
if ( attributeDefinition.getType().isAssociationType() &&
isDuplicateAssociationKey( ( (AssociationAttributeDefinition) attributeDefinition ).getAssociationKey() ) ) {
log.debug( "Property path deemed to be circular : " + subPath.getFullPath() );
continueWalk = false;
}
else {
continueWalk = strategy.startingAttribute( attributeDefinition );
@ -143,6 +143,8 @@ public class MetadataDrivenModelGraphVisitor {
private void visitAssociation(AssociationAttributeDefinition attribute) {
// todo : do "too deep" checks; but see note about adding depth to PropertyPath
addAssociationKey( attribute.getAssociationKey() );
if ( attribute.isCollection() ) {
visitCollectionDefinition( attribute.toCollectionDefinition() );
}
@ -200,7 +202,7 @@ public class MetadataDrivenModelGraphVisitor {
strategy.startingCollectionElements( elementDefinition );
if ( elementDefinition.getType().isComponentType() ) {
visitCompositeDefinition( elementDefinition.toCompositeDefinition() );
visitCompositeElementDefinition( elementDefinition.toCompositeElementDefinition() );
}
else if ( elementDefinition.getType().isEntityType() ) {
visitEntityDefinition( elementDefinition.toEntityDefinition() );
@ -209,18 +211,37 @@ public class MetadataDrivenModelGraphVisitor {
strategy.finishingCollectionElements( elementDefinition );
}
private void visitCompositeElementDefinition(CompositionElementDefinition compositionElementDefinition) {
strategy.startingCompositeElement( compositionElementDefinition );
visitAttributes( compositionElementDefinition );
strategy.finishingCompositeElement( compositionElementDefinition );
}
private final Set<AssociationKey> visitedAssociationKeys = new HashSet<AssociationKey>();
protected boolean isDuplicateAssociation(AssociationKey associationKey) {
boolean isDuplicate = !visitedAssociationKeys.add( associationKey );
if ( isDuplicate ) {
log.debug( "Property path deemed to be circular : " + currentPropertyPath.getFullPath() );
return true;
}
else {
return false;
/**
* Add association key to indicate the association is being visited.
* @param associationKey - the association key.
* @throws WalkingException if the association with the specified association key
* has already been visited.
*/
protected void addAssociationKey(AssociationKey associationKey) {
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;
public AbstractCompositeBasedAttribute(
AbstractCompositionDefinition source,
AbstractCompositionAttribute source,
SessionFactoryImplementor sessionFactory,
int attributeNumber,
String attributeName,
@ -55,7 +55,7 @@ public abstract class AbstractCompositeBasedAttribute
}
@Override
public AbstractCompositionDefinition getSource() {
return (AbstractCompositionDefinition) super.getSource();
public AbstractCompositionAttribute getSource() {
return (AbstractCompositionAttribute) super.getSource();
}
}

View File

@ -48,9 +48,9 @@ import static org.hibernate.engine.internal.JoinHelper.getRHSColumnNames;
/**
* @author Steve Ebersole
*/
public abstract class AbstractCompositionDefinition extends AbstractNonIdentifierAttribute implements
public abstract class AbstractCompositionAttribute extends AbstractNonIdentifierAttribute implements
CompositionDefinition {
protected AbstractCompositionDefinition(
protected AbstractCompositionAttribute(
AttributeSource source,
SessionFactoryImplementor sessionFactory,
int attributeNumber,
@ -72,21 +72,21 @@ public abstract class AbstractCompositionDefinition extends AbstractNonIdentifie
public Iterator<AttributeDefinition> iterator() {
return new Iterator<AttributeDefinition>() {
private final int numberOfAttributes = getType().getSubtypes().length;
private int currentAttributeNumber = 0;
private int currentSubAttributeNumber = 0;
private int currentColumnPosition = 0;
@Override
public boolean hasNext() {
return currentAttributeNumber < numberOfAttributes;
return currentSubAttributeNumber < numberOfAttributes;
}
@Override
public AttributeDefinition next() {
final int attributeNumber = currentAttributeNumber;
currentAttributeNumber++;
final int subAttributeNumber = currentSubAttributeNumber;
currentSubAttributeNumber++;
final String name = getType().getPropertyNames()[attributeNumber];
final Type type = getType().getSubtypes()[attributeNumber];
final String name = getType().getPropertyNames()[subAttributeNumber];
final Type type = getType().getSubtypes()[subAttributeNumber];
int columnPosition = currentColumnPosition;
currentColumnPosition += type.getColumnSpan( sessionFactory() );
@ -101,13 +101,13 @@ public abstract class AbstractCompositionDefinition extends AbstractNonIdentifie
getLHSTableName(
aType,
attributeNumber(),
(OuterJoinLoadable) joinable
(OuterJoinLoadable) locateOwningPersister()
),
getLHSColumnNames(
aType,
attributeNumber(),
columnPosition,
(OuterJoinLoadable) joinable,
(OuterJoinLoadable) locateOwningPersister(),
sessionFactory()
)
);
@ -120,63 +120,63 @@ public abstract class AbstractCompositionDefinition extends AbstractNonIdentifie
}
return new CompositeBasedAssociationAttribute(
AbstractCompositionDefinition.this,
AbstractCompositionAttribute.this,
sessionFactory(),
currentAttributeNumber,
subAttributeNumber,
name,
(AssociationType) type,
new BaselineAttributeInformation.Builder()
.setInsertable( AbstractCompositionDefinition.this.isInsertable() )
.setUpdateable( AbstractCompositionDefinition.this.isUpdateable() )
.setInsertGenerated( AbstractCompositionDefinition.this.isInsertGenerated() )
.setUpdateGenerated( AbstractCompositionDefinition.this.isUpdateGenerated() )
.setNullable( getType().getPropertyNullability()[currentAttributeNumber] )
.setInsertable( AbstractCompositionAttribute.this.isInsertable() )
.setUpdateable( AbstractCompositionAttribute.this.isUpdateable() )
.setInsertGenerated( AbstractCompositionAttribute.this.isInsertGenerated() )
.setUpdateGenerated( AbstractCompositionAttribute.this.isUpdateGenerated() )
.setNullable( getType().getPropertyNullability()[subAttributeNumber] )
.setDirtyCheckable( true )
.setVersionable( AbstractCompositionDefinition.this.isVersionable() )
.setCascadeStyle( getType().getCascadeStyle( currentAttributeNumber ) )
.setFetchMode( getType().getFetchMode( currentAttributeNumber ) )
.setVersionable( AbstractCompositionAttribute.this.isVersionable() )
.setCascadeStyle( getType().getCascadeStyle( subAttributeNumber ) )
.setFetchMode( getType().getFetchMode( subAttributeNumber ) )
.createInformation(),
AbstractCompositionDefinition.this.attributeNumber(),
AbstractCompositionAttribute.this.attributeNumber(),
associationKey
);
}
else if ( type.isComponentType() ) {
return new CompositionBasedCompositionAttribute(
AbstractCompositionDefinition.this,
AbstractCompositionAttribute.this,
sessionFactory(),
currentAttributeNumber,
subAttributeNumber,
name,
(CompositeType) type,
new BaselineAttributeInformation.Builder()
.setInsertable( AbstractCompositionDefinition.this.isInsertable() )
.setUpdateable( AbstractCompositionDefinition.this.isUpdateable() )
.setInsertGenerated( AbstractCompositionDefinition.this.isInsertGenerated() )
.setUpdateGenerated( AbstractCompositionDefinition.this.isUpdateGenerated() )
.setNullable( getType().getPropertyNullability()[currentAttributeNumber] )
.setInsertable( AbstractCompositionAttribute.this.isInsertable() )
.setUpdateable( AbstractCompositionAttribute.this.isUpdateable() )
.setInsertGenerated( AbstractCompositionAttribute.this.isInsertGenerated() )
.setUpdateGenerated( AbstractCompositionAttribute.this.isUpdateGenerated() )
.setNullable( getType().getPropertyNullability()[subAttributeNumber] )
.setDirtyCheckable( true )
.setVersionable( AbstractCompositionDefinition.this.isVersionable() )
.setCascadeStyle( getType().getCascadeStyle( currentAttributeNumber ) )
.setFetchMode( getType().getFetchMode( currentAttributeNumber ) )
.setVersionable( AbstractCompositionAttribute.this.isVersionable() )
.setCascadeStyle( getType().getCascadeStyle( subAttributeNumber ) )
.setFetchMode( getType().getFetchMode( subAttributeNumber ) )
.createInformation()
);
}
else {
return new CompositeBasedBasicAttribute(
AbstractCompositionDefinition.this,
AbstractCompositionAttribute.this,
sessionFactory(),
currentAttributeNumber,
subAttributeNumber,
name,
type,
new BaselineAttributeInformation.Builder()
.setInsertable( AbstractCompositionDefinition.this.isInsertable() )
.setUpdateable( AbstractCompositionDefinition.this.isUpdateable() )
.setInsertGenerated( AbstractCompositionDefinition.this.isInsertGenerated() )
.setUpdateGenerated( AbstractCompositionDefinition.this.isUpdateGenerated() )
.setNullable( getType().getPropertyNullability()[currentAttributeNumber] )
.setInsertable( AbstractCompositionAttribute.this.isInsertable() )
.setUpdateable( AbstractCompositionAttribute.this.isUpdateable() )
.setInsertGenerated( AbstractCompositionAttribute.this.isInsertGenerated() )
.setUpdateGenerated( AbstractCompositionAttribute.this.isUpdateGenerated() )
.setNullable( getType().getPropertyNullability()[subAttributeNumber] )
.setDirtyCheckable( true )
.setVersionable( AbstractCompositionDefinition.this.isVersionable() )
.setCascadeStyle( getType().getCascadeStyle( currentAttributeNumber ) )
.setFetchMode( getType().getFetchMode( currentAttributeNumber ) )
.setVersionable( AbstractCompositionAttribute.this.isVersionable() )
.setCascadeStyle( getType().getCascadeStyle( subAttributeNumber ) )
.setFetchMode( getType().getFetchMode( subAttributeNumber ) )
.createInformation()
);
}
@ -196,7 +196,7 @@ public abstract class AbstractCompositionDefinition extends AbstractNonIdentifie
return ( (EntityDefinition) getSource() ).getEntityPersister();
}
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.Joinable;
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.AssociationKey;
import org.hibernate.persister.walking.spi.CollectionDefinition;
@ -55,7 +55,7 @@ public class CompositeBasedAssociationAttribute
private Joinable joinable;
public CompositeBasedAssociationAttribute(
AbstractCompositionDefinition source,
AbstractCompositionAttribute source,
SessionFactoryImplementor factory,
int attributeNumber,
String attributeName,
@ -130,7 +130,7 @@ public class CompositeBasedAssociationAttribute
EntityPersister owningPersister,
PropertyPath propertyPath,
int ownerAttributeNumber) {
return Helper.determineFetchStyleByProfile(
return FetchStrategyHelper.determineFetchStyleByProfile(
loadQueryInfluencers,
owningPersister,
propertyPath,
@ -139,11 +139,11 @@ public class CompositeBasedAssociationAttribute
}
protected FetchStyle determineFetchStyleByMetadata(FetchMode fetchMode, AssociationType type) {
return Helper.determineFetchStyleByMetadata( fetchMode, type, sessionFactory() );
return FetchStrategyHelper.determineFetchStyleByMetadata( fetchMode, type, sessionFactory() );
}
private FetchTiming determineFetchTiming(FetchStyle style) {
return Helper.determineFetchTiming( style, getType(), sessionFactory() );
return FetchStrategyHelper.determineFetchTiming( style, getType(), sessionFactory() );
}
private EntityPersister locateOwningPersister() {

View File

@ -32,7 +32,7 @@ import org.hibernate.type.CompositeType;
* @author Steve Ebersole
*/
public class CompositionBasedCompositionAttribute
extends AbstractCompositionDefinition
extends AbstractCompositionAttribute
implements CompositionDefinition {
public CompositionBasedCompositionAttribute(
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.OuterJoinLoadable;
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.AssociationKey;
import org.hibernate.persister.walking.spi.CollectionDefinition;
@ -129,14 +129,14 @@ public class EntityBasedAssociationAttribute
public FetchStrategy determineFetchPlan(LoadQueryInfluencers loadQueryInfluencers, PropertyPath propertyPath) {
final EntityPersister owningPersister = getSource().getEntityPersister();
FetchStyle style = Helper.determineFetchStyleByProfile(
FetchStyle style = FetchStrategyHelper.determineFetchStyleByProfile(
loadQueryInfluencers,
owningPersister,
propertyPath,
attributeNumber()
);
if ( style == null ) {
style = Helper.determineFetchStyleByMetadata(
style = FetchStrategyHelper.determineFetchStyleByMetadata(
( (OuterJoinLoadable) getSource().getEntityPersister() ).getFetchMode( attributeNumber() ),
getType(),
sessionFactory()
@ -144,7 +144,7 @@ public class EntityBasedAssociationAttribute
}
return new FetchStrategy(
Helper.determineFetchTiming( style, getType(), sessionFactory() ),
FetchStrategyHelper.determineFetchTiming( style, getType(), sessionFactory() ),
style
);
}

View File

@ -25,7 +25,7 @@ package org.hibernate.tuple.entity;
import org.hibernate.engine.spi.SessionFactoryImplementor;
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.tuple.BaselineAttributeInformation;
import org.hibernate.type.CompositeType;
@ -34,7 +34,7 @@ import org.hibernate.type.CompositeType;
* @author Steve Ebersole
*/
public class EntityBasedCompositionAttribute
extends AbstractCompositionDefinition
extends AbstractCompositionAttribute
implements CompositionDefinition {
public EntityBasedCompositionAttribute(

View File

@ -23,6 +23,7 @@
*/
package org.hibernate.type;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
@ -34,7 +35,11 @@ import org.hibernate.Filter;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
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.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Joinable;
@ -53,6 +58,7 @@ public abstract class EntityType extends AbstractType implements AssociationType
protected final String uniqueKeyPropertyName;
private final boolean eager;
private final boolean unwrapProxy;
private final boolean referenceToPrimaryKey;
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
* says to return the "implementation target" of lazy prooxies; typically only possible
* 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(
TypeFactory.TypeScope scope,
String entityName,
String uniqueKeyPropertyName,
boolean eager,
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(
TypeFactory.TypeScope scope,
String entityName,
boolean referenceToPrimaryKey,
String uniqueKeyPropertyName,
boolean eager,
boolean unwrapProxy,
Class returnedClass) {
boolean unwrapProxy) {
this.scope = scope;
this.associatedEntityName = entityName;
this.uniqueKeyPropertyName = uniqueKeyPropertyName;
this.eager = eager;
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.
*/
public boolean isReferenceToPrimaryKey() {
return uniqueKeyPropertyName==null;
return referenceToPrimaryKey;
}
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() {
@ -397,14 +422,15 @@ public abstract class EntityType extends AbstractType implements AssociationType
if ( isNull( owner, session ) ) {
return null; //EARLY EXIT!
}
if ( isReferenceToPrimaryKey() ) {
return resolveIdentifier( (Serializable) value, session );
}
else {
else if ( uniqueKeyPropertyName != null ) {
return loadByUniqueKey( getAssociatedEntityName(), uniqueKeyPropertyName, value, session );
}
}
return null;
}
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 {
if ( isReferenceToPrimaryKey() ) {
if ( isReferenceToPrimaryKey() || uniqueKeyPropertyName == null) {
return ForeignKeys.getEntityIdentifierIfNotUnsaved( getAssociatedEntityName(), value, session ); //tolerates nulls
}
else if ( value == null ) {
@ -516,7 +542,7 @@ public abstract class EntityType extends AbstractType implements AssociationType
* or unique key property name.
*/
public final Type getIdentifierOrUniqueKeyType(Mapping factory) throws MappingException {
if ( isReferenceToPrimaryKey() ) {
if ( isReferenceToPrimaryKey() || uniqueKeyPropertyName == null ) {
return getIdentifierType(factory);
}
else {
@ -538,7 +564,7 @@ public abstract class EntityType extends AbstractType implements AssociationType
*/
public final String getIdentifierOrUniqueKeyPropertyName(Mapping factory)
throws MappingException {
if ( isReferenceToPrimaryKey() ) {
if ( isReferenceToPrimaryKey() || uniqueKeyPropertyName == null ) {
return factory.getIdentifierPropertyName( getAssociatedEntityName() );
}
else {

View File

@ -67,9 +67,15 @@ public class ManyToOneType extends EntityType {
* @param lazy Should the association be handled lazily
*/
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(
TypeFactory.TypeScope scope,
String referencedEntityName,
@ -78,20 +84,18 @@ public class ManyToOneType extends EntityType {
boolean unwrapProxy,
boolean ignoreNotFound,
boolean isLogicalOneToOne) {
super( scope, referencedEntityName, uniqueKeyPropertyName, !lazy, unwrapProxy );
this.ignoreNotFound = ignoreNotFound;
this.isLogicalOneToOne = isLogicalOneToOne;
this( scope, referencedEntityName, uniqueKeyPropertyName == null, uniqueKeyPropertyName, lazy, unwrapProxy, ignoreNotFound, isLogicalOneToOne );
}
public ManyToOneType(
TypeFactory.TypeScope scope,
String referencedEntityName,
boolean referenceToPrimaryKey,
String uniqueKeyPropertyName,
boolean lazy,
boolean unwrapProxy,
boolean ignoreNotFound,
boolean isLogicalOneToOne,
Class returnedClass) {
super( scope, referencedEntityName, uniqueKeyPropertyName, !lazy, unwrapProxy, returnedClass );
boolean isLogicalOneToOne) {
super( scope, referencedEntityName, referenceToPrimaryKey, uniqueKeyPropertyName, !lazy, unwrapProxy );
this.ignoreNotFound = ignoreNotFound;
this.isLogicalOneToOne = isLogicalOneToOne;
}

View File

@ -47,6 +47,12 @@ public class OneToOneType extends EntityType {
private final String propertyName;
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(
TypeFactory.TypeScope scope,
String referencedEntityName,
@ -56,23 +62,20 @@ public class OneToOneType extends EntityType {
boolean unwrapProxy,
String entityName,
String propertyName) {
super( scope, referencedEntityName, uniqueKeyPropertyName, !lazy, unwrapProxy );
this.foreignKeyType = foreignKeyType;
this.propertyName = propertyName;
this.entityName = entityName;
this( scope, referencedEntityName, foreignKeyType, uniqueKeyPropertyName == null, uniqueKeyPropertyName, lazy, unwrapProxy, entityName, propertyName );
}
public OneToOneType(
TypeFactory.TypeScope scope,
String referencedEntityName,
ForeignKeyDirection foreignKeyType,
boolean referenceToPrimaryKey,
String uniqueKeyPropertyName,
boolean lazy,
boolean unwrapProxy,
String entityName,
String propertyName,
Class returnedClass) {
super( scope, referencedEntityName, uniqueKeyPropertyName, !lazy, unwrapProxy, returnedClass );
String propertyName) {
super( scope, referencedEntityName, referenceToPrimaryKey, uniqueKeyPropertyName, !lazy, unwrapProxy );
this.foreignKeyType = foreignKeyType;
this.propertyName = propertyName;
this.entityName = entityName;

View File

@ -43,6 +43,10 @@ import org.hibernate.metamodel.spi.relational.Size;
*/
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(
TypeFactory.TypeScope scope,
String referencedEntityName,
@ -52,10 +56,24 @@ public class SpecialOneToOneType extends OneToOneType {
boolean unwrapProxy,
String entityName,
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(
scope,
referencedEntityName,
foreignKeyType,
referenceToPrimaryKey,
uniqueKeyPropertyName,
lazy,
unwrapProxy,

View File

@ -27,8 +27,6 @@ import java.io.Serializable;
import java.util.Comparator;
import java.util.Properties;
import org.jboss.logging.Logger;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.classic.Lifecycle;
@ -39,6 +37,7 @@ import org.hibernate.tuple.component.ComponentMetamodel;
import org.hibernate.usertype.CompositeUserType;
import org.hibernate.usertype.ParameterizedType;
import org.hibernate.usertype.UserType;
import org.jboss.logging.Logger;
/**
* 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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* @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(
String persistentClass,
ForeignKeyDirection foreignKeyType,
@ -216,10 +220,28 @@ public final class TypeFactory implements Serializable {
boolean unwrapProxy,
String entityName,
String propertyName) {
return new OneToOneType( typeScope, persistentClass, foreignKeyType, uniqueKeyPropertyName,
lazy, unwrapProxy, entityName, propertyName );
return oneToOne( persistentClass, foreignKeyType, uniqueKeyPropertyName == null, uniqueKeyPropertyName, lazy, unwrapProxy, entityName,
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(
String persistentClass,
ForeignKeyDirection foreignKeyType,
@ -228,34 +250,21 @@ public final class TypeFactory implements Serializable {
boolean unwrapProxy,
String entityName,
String propertyName) {
return new SpecialOneToOneType( typeScope, persistentClass, foreignKeyType, uniqueKeyPropertyName,
lazy, unwrapProxy, 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 );
return specialOneToOne( persistentClass, foreignKeyType, uniqueKeyPropertyName == null, uniqueKeyPropertyName, lazy, unwrapProxy,
entityName, propertyName );
}
public EntityType specialOneToOne(
String persistentClass,
ForeignKeyDirection foreignKeyType,
boolean referenceToPrimaryKey,
String uniqueKeyPropertyName,
boolean lazy,
boolean unwrapProxy,
String entityName,
String propertyName,
Class returnedClass) {
return new SpecialOneToOneType( typeScope, persistentClass, foreignKeyType, uniqueKeyPropertyName,
lazy, unwrapProxy, entityName, propertyName, returnedClass );
String propertyName) {
return new SpecialOneToOneType( typeScope, persistentClass, foreignKeyType, referenceToPrimaryKey,
uniqueKeyPropertyName, lazy, unwrapProxy, entityName, propertyName );
}
@ -269,6 +278,11 @@ public final class TypeFactory implements Serializable {
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(
String persistentClass,
String uniqueKeyPropertyName,
@ -276,9 +290,23 @@ public final class TypeFactory implements Serializable {
boolean unwrapProxy,
boolean ignoreNotFound,
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(
typeScope,
persistentClass,
referenceToPrimaryKey,
uniqueKeyPropertyName,
lazy,
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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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
*/
@FailureExpectedWithNewMetamodel
public class EntityWithCollectionResultSetProcessorTest extends BaseCoreFunctionalTestCase {
public class EntityWithNonLazyCollectionResultSetProcessorTest extends BaseCoreFunctionalTestCase {
@Override
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
*/
@FailureExpectedWithNewMetamodel
public class EntityWithOneToManyResultSetProcessorTest extends BaseCoreFunctionalTestCase {
public class EntityWithNonLazyOneToManySetResultSetProcessorTest extends BaseCoreFunctionalTestCase {
@Override
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.CollectionIndexDefinition;
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.EntityIdentifierDefinition;
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
public boolean startingAttribute(AttributeDefinition attributeDefinition) {
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.assertNotNull;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.testing.FailureExpected;
import org.hibernate.testing.TestForIssue;
@ -35,6 +38,7 @@ import org.junit.Test;
@FailureExpected(jiraKey = "HHH-5695")
public class OneToOneWithDerivedIdentityTest extends BaseCoreFunctionalTestCase {
@Test
@TestForIssue(jiraKey = "HHH-5695")
public void testInsertFooAndBarWithDerivedId() {
Session s = openSession();
s.beginTransaction();
@ -81,11 +85,50 @@ public class OneToOneWithDerivedIdentityTest extends BaseCoreFunctionalTestCase
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
protected Class<?>[] getAnnotatedClasses() {
return new 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.QualifiedObjectNameSupport;
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.ResultSetWrapper;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;

View File

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

View File

@ -68,7 +68,7 @@ public abstract class AbstractScannerImpl implements Scanner {
if ( persistenceUnit.getPersistenceUnitRootUrl() != null ) {
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 );
}

View File

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

View File

@ -108,16 +108,16 @@ public class AttributeNodeImpl<T> implements AttributeNode<T>, AttributeNodeImpl
}
@SuppressWarnings("unchecked")
public <T> Subgraph<T> makeSubgraph() {
return (Subgraph<T>) internalMakeSubgraph( null );
public <T> SubgraphImpl<T> makeSubgraph() {
return (SubgraphImpl<T>) internalMakeSubgraph( null );
}
@SuppressWarnings("unchecked")
public <X extends T> Subgraph<X> makeSubgraph(Class<X> type) {
return (Subgraph<X>) internalMakeSubgraph( type );
public <X extends T> SubgraphImpl<X> makeSubgraph(Class<X> type) {
return (SubgraphImpl<X>) internalMakeSubgraph( type );
}
private Subgraph internalMakeSubgraph(Class type) {
private SubgraphImpl internalMakeSubgraph(Class type) {
if ( attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.BASIC
|| attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.EMBEDDED ) {
throw new IllegalArgumentException(
@ -193,12 +193,17 @@ public class AttributeNodeImpl<T> implements AttributeNode<T>, AttributeNodeImpl
return type.isAssignableFrom( entityPersister.getMappedClass() );
}
public <T> Subgraph<T> makeKeySubgraph() {
return (SubgraphImpl<T>) makeKeySubgraph( null );
@SuppressWarnings("unchecked")
public <T> SubgraphImpl<T> makeKeySubgraph() {
return (SubgraphImpl<T>) internalMakeKeySubgraph( null );
}
@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() ) {
throw new IllegalArgumentException(
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