From b3871f319b83667a399287173b283304b21be6fd Mon Sep 17 00:00:00 2001 From: Strong Liu Date: Thu, 31 Oct 2013 17:22:03 +0100 Subject: [PATCH] HHH-8285 Initial JPA 2.1 entity graph support (EntityManager.find()) --- .../org/hibernate/cfg/AvailableSettings.java | 236 ++++++------ .../engine/spi/LoadQueryInfluencers.java | 19 + .../graph/spi/AttributeNodeImplementor.java | 9 +- .../graph/spi/GraphNodeImplementor.java | 15 +- .../AbstractLoadPlanBasedEntityLoader.java | 24 +- ...AbstractEntityGraphVisitationStrategy.java | 359 ++++++++++++++++++ .../FetchGraphLoadPlanBuildingStrategy.java | 61 +++ .../LoadGraphLoadPlanBuildingStrategy.java | 71 ++++ .../entity/AbstractEntityPersister.java | 8 + .../org/hibernate/jpa/AvailableSettings.java | 123 +++--- .../jpa/graph/internal/AbstractGraphNode.java | 10 +- .../jpa/graph/internal/AttributeNodeImpl.java | 9 +- .../jpa/graph/internal/EntityGraphImpl.java | 5 +- .../jpa/graph/internal/SubgraphImpl.java | 3 +- .../graph/internal/advisor/AdviceHelper.java | 12 +- .../advisor/JpaGraphCollectionReference.java | 2 +- .../JpaGraphReferenceSubGraphSupport.java | 2 +- .../advisor/JpaGraphRootEntityReference.java | 2 +- .../JpaGraphSingularAttributeReference.java | 3 +- .../jpa/spi/AbstractEntityManagerImpl.java | 11 +- .../HibernateEntityManagerFactoryAware.java | 40 ++ .../HibernateEntityManagerImplementor.java | 9 +- .../EntityGraphLoadPlanBuilderTest.java | 214 +++++++++++ 23 files changed, 1010 insertions(+), 237 deletions(-) rename {hibernate-entitymanager/src/main/java/org/hibernate/jpa => hibernate-core/src/main/java/org/hibernate}/graph/spi/AttributeNodeImplementor.java (87%) rename {hibernate-entitymanager/src/main/java/org/hibernate/jpa => hibernate-core/src/main/java/org/hibernate}/graph/spi/GraphNodeImplementor.java (75%) create mode 100644 hibernate-core/src/main/java/org/hibernate/loader/plan2/build/internal/AbstractEntityGraphVisitationStrategy.java create mode 100644 hibernate-core/src/main/java/org/hibernate/loader/plan2/build/internal/FetchGraphLoadPlanBuildingStrategy.java create mode 100644 hibernate-core/src/main/java/org/hibernate/loader/plan2/build/internal/LoadGraphLoadPlanBuildingStrategy.java create mode 100644 hibernate-entitymanager/src/main/java/org/hibernate/jpa/spi/HibernateEntityManagerFactoryAware.java create mode 100644 hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/EntityGraphLoadPlanBuilderTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java index a4ebf53176..3582269a39 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java @@ -35,13 +35,13 @@ public interface AvailableSettings { * * @see #SESSION_FACTORY_NAME_IS_JNDI */ - public static final String SESSION_FACTORY_NAME = "hibernate.session_factory_name"; + String SESSION_FACTORY_NAME = "hibernate.session_factory_name"; /** * Does the value defined by {@link #SESSION_FACTORY_NAME} represent a {@literal JNDI} namespace into which * the {@link org.hibernate.SessionFactory} should be bound? */ - public static final String SESSION_FACTORY_NAME_IS_JNDI = "hibernate.session_factory_name_is_jndi"; + String SESSION_FACTORY_NAME_IS_JNDI = "hibernate.session_factory_name_is_jndi"; /** * Names the {@link org.hibernate.engine.jdbc.connections.spi.ConnectionProvider} to use for obtaining @@ -50,17 +50,17 @@ public interface AvailableSettings { * reference to the {@link org.hibernate.engine.jdbc.connections.spi.ConnectionProvider} implementation * class. */ - public static final String CONNECTION_PROVIDER ="hibernate.connection.provider_class"; + String CONNECTION_PROVIDER ="hibernate.connection.provider_class"; /** * Names the {@literal JDBC} driver class */ - public static final String DRIVER ="hibernate.connection.driver_class"; + String DRIVER ="hibernate.connection.driver_class"; /** * Names the {@literal JDBC} connection url. */ - public static final String URL ="hibernate.connection.url"; + String URL ="hibernate.connection.url"; /** * Names the connection user. This might mean one of 2 things in out-of-the-box Hibernate @@ -69,210 +69,210 @@ public interface AvailableSettings { *
  • The username used to obtain a JDBC connection from a data source
  • * */ - public static final String USER ="hibernate.connection.username"; + String USER ="hibernate.connection.username"; /** * Names the connection password. See usage discussion on {@link #USER} */ - public static final String PASS ="hibernate.connection.password"; + String PASS ="hibernate.connection.password"; /** * Names the {@literal JDBC} transaction isolation level */ - public static final String ISOLATION ="hibernate.connection.isolation"; + String ISOLATION ="hibernate.connection.isolation"; /** * Names the {@literal JDBC} autocommit mode */ - public static final String AUTOCOMMIT ="hibernate.connection.autocommit"; + String AUTOCOMMIT ="hibernate.connection.autocommit"; /** * Maximum number of inactive connections for the built-in Hibernate connection pool. */ - public static final String POOL_SIZE ="hibernate.connection.pool_size"; + String POOL_SIZE ="hibernate.connection.pool_size"; /** * Names a {@link javax.sql.DataSource}. Can either reference a {@link javax.sql.DataSource} instance or * a {@literal JNDI} name under which to locate the {@link javax.sql.DataSource}. */ - public static final String DATASOURCE ="hibernate.connection.datasource"; + String DATASOURCE ="hibernate.connection.datasource"; /** * Names a prefix used to define arbitrary JDBC connection properties. These properties are passed along to * the {@literal JDBC} provider when creating a connection. */ - public static final String CONNECTION_PREFIX = "hibernate.connection"; + String CONNECTION_PREFIX = "hibernate.connection"; /** * Names the {@literal JNDI} {@link javax.naming.InitialContext} class. * * @see javax.naming.Context#INITIAL_CONTEXT_FACTORY */ - public static final String JNDI_CLASS ="hibernate.jndi.class"; + String JNDI_CLASS ="hibernate.jndi.class"; /** * Names the {@literal JNDI} provider/connection url * * @see javax.naming.Context#PROVIDER_URL */ - public static final String JNDI_URL ="hibernate.jndi.url"; + String JNDI_URL ="hibernate.jndi.url"; /** * Names a prefix used to define arbitrary {@literal JNDI} {@link javax.naming.InitialContext} properties. These * properties are passed along to {@link javax.naming.InitialContext#InitialContext(java.util.Hashtable)} */ - public static final String JNDI_PREFIX = "hibernate.jndi"; + String JNDI_PREFIX = "hibernate.jndi"; /** * Names the Hibernate {@literal SQL} {@link org.hibernate.dialect.Dialect} class */ - public static final String DIALECT ="hibernate.dialect"; + String DIALECT ="hibernate.dialect"; /** * Names any additional {@link org.hibernate.engine.jdbc.dialect.spi.DialectResolver} implementations to * register with the standard {@link org.hibernate.engine.jdbc.dialect.spi.DialectFactory}. */ - public static final String DIALECT_RESOLVERS = "hibernate.dialect_resolvers"; + String DIALECT_RESOLVERS = "hibernate.dialect_resolvers"; /** * A default database schema (owner) name to use for unqualified tablenames */ - public static final String DEFAULT_SCHEMA = "hibernate.default_schema"; + String DEFAULT_SCHEMA = "hibernate.default_schema"; /** * A default database catalog name to use for unqualified tablenames */ - public static final String DEFAULT_CATALOG = "hibernate.default_catalog"; + String DEFAULT_CATALOG = "hibernate.default_catalog"; /** * Enable logging of generated SQL to the console */ - public static final String SHOW_SQL ="hibernate.show_sql"; + String SHOW_SQL ="hibernate.show_sql"; /** * Enable formatting of SQL logged to the console */ - public static final String FORMAT_SQL ="hibernate.format_sql"; + String FORMAT_SQL ="hibernate.format_sql"; /** * Add comments to the generated SQL */ - public static final String USE_SQL_COMMENTS ="hibernate.use_sql_comments"; + String USE_SQL_COMMENTS ="hibernate.use_sql_comments"; /** * Maximum depth of outer join fetching */ - public static final String MAX_FETCH_DEPTH = "hibernate.max_fetch_depth"; + String MAX_FETCH_DEPTH = "hibernate.max_fetch_depth"; /** * The default batch size for batch fetching */ - public static final String DEFAULT_BATCH_FETCH_SIZE = "hibernate.default_batch_fetch_size"; + String DEFAULT_BATCH_FETCH_SIZE = "hibernate.default_batch_fetch_size"; /** * Use java.io streams to read / write binary data from / to JDBC */ - public static final String USE_STREAMS_FOR_BINARY = "hibernate.jdbc.use_streams_for_binary"; + String USE_STREAMS_FOR_BINARY = "hibernate.jdbc.use_streams_for_binary"; /** * Use JDBC scrollable ResultSets. This property is only necessary when there is * no ConnectionProvider, ie. the user is supplying JDBC connections. */ - public static final String USE_SCROLLABLE_RESULTSET = "hibernate.jdbc.use_scrollable_resultset"; + String USE_SCROLLABLE_RESULTSET = "hibernate.jdbc.use_scrollable_resultset"; /** * Tells the JDBC driver to attempt to retrieve row Id with the JDBC 3.0 PreparedStatement.getGeneratedKeys() * method. In general, performance will be better if this property is set to true and the underlying * JDBC driver supports getGeneratedKeys(). */ - public static final String USE_GET_GENERATED_KEYS = "hibernate.jdbc.use_get_generated_keys"; + String USE_GET_GENERATED_KEYS = "hibernate.jdbc.use_get_generated_keys"; /** * Gives the JDBC driver a hint as to the number of rows that should be fetched from the database * when more rows are needed. If 0, JDBC driver default settings will be used. */ - public static final String STATEMENT_FETCH_SIZE = "hibernate.jdbc.fetch_size"; + String STATEMENT_FETCH_SIZE = "hibernate.jdbc.fetch_size"; /** * Maximum JDBC batch size. A nonzero value enables batch updates. */ - public static final String STATEMENT_BATCH_SIZE = "hibernate.jdbc.batch_size"; + String STATEMENT_BATCH_SIZE = "hibernate.jdbc.batch_size"; /** * Select a custom batcher. */ - public static final String BATCH_STRATEGY = "hibernate.jdbc.factory_class"; + String BATCH_STRATEGY = "hibernate.jdbc.factory_class"; /** * Should versioned data be included in batching? */ - public static final String BATCH_VERSIONED_DATA = "hibernate.jdbc.batch_versioned_data"; + String BATCH_VERSIONED_DATA = "hibernate.jdbc.batch_versioned_data"; /** * An XSLT resource used to generate "custom" XML */ - public static final String OUTPUT_STYLESHEET ="hibernate.xml.output_stylesheet"; + String OUTPUT_STYLESHEET ="hibernate.xml.output_stylesheet"; /** * Maximum size of C3P0 connection pool */ - public static final String C3P0_MAX_SIZE = "hibernate.c3p0.max_size"; + String C3P0_MAX_SIZE = "hibernate.c3p0.max_size"; /** * Minimum size of C3P0 connection pool */ - public static final String C3P0_MIN_SIZE = "hibernate.c3p0.min_size"; + String C3P0_MIN_SIZE = "hibernate.c3p0.min_size"; /** * Maximum idle time for C3P0 connection pool */ - public static final String C3P0_TIMEOUT = "hibernate.c3p0.timeout"; + String C3P0_TIMEOUT = "hibernate.c3p0.timeout"; /** * Maximum size of C3P0 statement cache */ - public static final String C3P0_MAX_STATEMENTS = "hibernate.c3p0.max_statements"; + String C3P0_MAX_STATEMENTS = "hibernate.c3p0.max_statements"; /** * Number of connections acquired when pool is exhausted */ - public static final String C3P0_ACQUIRE_INCREMENT = "hibernate.c3p0.acquire_increment"; + String C3P0_ACQUIRE_INCREMENT = "hibernate.c3p0.acquire_increment"; /** * Idle time before a C3P0 pooled connection is validated */ - public static final String C3P0_IDLE_TEST_PERIOD = "hibernate.c3p0.idle_test_period"; + String C3P0_IDLE_TEST_PERIOD = "hibernate.c3p0.idle_test_period"; /** * Proxool/Hibernate property prefix * @deprecated Use {@link #PROXOOL_CONFIG_PREFIX} instead */ - public static final String PROXOOL_PREFIX = "hibernate.proxool"; + String PROXOOL_PREFIX = "hibernate.proxool"; /** * Proxool property to configure the Proxool Provider using an XML (/path/to/file.xml) */ - public static final String PROXOOL_XML = "hibernate.proxool.xml"; + String PROXOOL_XML = "hibernate.proxool.xml"; /** * Proxool property to configure the Proxool Provider using a properties file (/path/to/proxool.properties) */ - public static final String PROXOOL_PROPERTIES = "hibernate.proxool.properties"; + String PROXOOL_PROPERTIES = "hibernate.proxool.properties"; /** * Proxool property to configure the Proxool Provider from an already existing pool (true / false) */ - public static final String PROXOOL_EXISTING_POOL = "hibernate.proxool.existing_pool"; + String PROXOOL_EXISTING_POOL = "hibernate.proxool.existing_pool"; /** * Proxool property with the Proxool pool alias to use * (Required for PROXOOL_EXISTING_POOL, PROXOOL_PROPERTIES, or * PROXOOL_XML) */ - public static final String PROXOOL_POOL_ALIAS = "hibernate.proxool.pool_alias"; + String PROXOOL_POOL_ALIAS = "hibernate.proxool.pool_alias"; /** * Enable automatic session close at end of transaction */ - public static final String AUTO_CLOSE_SESSION = "hibernate.transaction.auto_close_session"; + String AUTO_CLOSE_SESSION = "hibernate.transaction.auto_close_session"; /** * Enable automatic flush during the JTA beforeCompletion() callback */ - public static final String FLUSH_BEFORE_COMPLETION = "hibernate.transaction.flush_before_completion"; + String FLUSH_BEFORE_COMPLETION = "hibernate.transaction.flush_before_completion"; /** * Specifies how Hibernate should release JDBC connections. */ - public static final String RELEASE_CONNECTIONS = "hibernate.connection.release_mode"; + String RELEASE_CONNECTIONS = "hibernate.connection.release_mode"; /** * Context scoping impl for {@link org.hibernate.SessionFactory#getCurrentSession()} processing. */ - public static final String CURRENT_SESSION_CONTEXT_CLASS = "hibernate.current_session_context_class"; + String CURRENT_SESSION_CONTEXT_CLASS = "hibernate.current_session_context_class"; /** * Names the implementation of {@link org.hibernate.engine.transaction.spi.TransactionFactory} to use for * creating {@link org.hibernate.Transaction} instances */ - public static final String TRANSACTION_STRATEGY = "hibernate.transaction.factory_class"; + String TRANSACTION_STRATEGY = "hibernate.transaction.factory_class"; /** * Names the {@link org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform} implementation to use for integrating @@ -280,91 +280,91 @@ public interface AvailableSettings { * instance or the name of the {@link org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform} implementation class * @since 4.0 */ - public static final String JTA_PLATFORM = "hibernate.transaction.jta.platform"; + String JTA_PLATFORM = "hibernate.transaction.jta.platform"; /** * Names the {@link org.hibernate.engine.transaction.jta.platform.spi.JtaPlatformResolver} implementation to use. * @since 4.3 */ - public static final String JTA_PLATFORM_RESOLVER = "hibernate.transaction.jta.platform_resolver"; + String JTA_PLATFORM_RESOLVER = "hibernate.transaction.jta.platform_resolver"; /** * The {@link org.hibernate.cache.spi.RegionFactory} implementation class */ - public static final String CACHE_REGION_FACTORY = "hibernate.cache.region.factory_class"; + String CACHE_REGION_FACTORY = "hibernate.cache.region.factory_class"; /** * The CacheProvider implementation class */ - public static final String CACHE_PROVIDER_CONFIG = "hibernate.cache.provider_configuration_file_resource_path"; + String CACHE_PROVIDER_CONFIG = "hibernate.cache.provider_configuration_file_resource_path"; /** * The CacheProvider JNDI namespace, if pre-bound to JNDI. */ - public static final String CACHE_NAMESPACE = "hibernate.cache.jndi"; + String CACHE_NAMESPACE = "hibernate.cache.jndi"; /** * Enable the query cache (disabled by default) */ - public static final String USE_QUERY_CACHE = "hibernate.cache.use_query_cache"; + String USE_QUERY_CACHE = "hibernate.cache.use_query_cache"; /** * The QueryCacheFactory implementation class. */ - public static final String QUERY_CACHE_FACTORY = "hibernate.cache.query_cache_factory"; + String QUERY_CACHE_FACTORY = "hibernate.cache.query_cache_factory"; /** * Enable the second-level cache (enabled by default) */ - public static final String USE_SECOND_LEVEL_CACHE = "hibernate.cache.use_second_level_cache"; + String USE_SECOND_LEVEL_CACHE = "hibernate.cache.use_second_level_cache"; /** * Optimize the cache for minimal puts instead of minimal gets */ - public static final String USE_MINIMAL_PUTS = "hibernate.cache.use_minimal_puts"; + String USE_MINIMAL_PUTS = "hibernate.cache.use_minimal_puts"; /** * The CacheProvider region name prefix */ - public static final String CACHE_REGION_PREFIX = "hibernate.cache.region_prefix"; + String CACHE_REGION_PREFIX = "hibernate.cache.region_prefix"; /** * Enable use of structured second-level cache entries */ - public static final String USE_STRUCTURED_CACHE = "hibernate.cache.use_structured_entries"; + String USE_STRUCTURED_CACHE = "hibernate.cache.use_structured_entries"; /** * Enables the automatic eviction of a bi-directional association's collection cache when an element in the * ManyToOne collection is added/updated/removed without properly managing the change on the OneToMany side. */ - public static final String AUTO_EVICT_COLLECTION_CACHE = "hibernate.cache.auto_evict_collection_cache"; + String AUTO_EVICT_COLLECTION_CACHE = "hibernate.cache.auto_evict_collection_cache"; /** * Enable statistics collection */ - public static final String GENERATE_STATISTICS = "hibernate.generate_statistics"; + String GENERATE_STATISTICS = "hibernate.generate_statistics"; - public static final String USE_IDENTIFIER_ROLLBACK = "hibernate.use_identifier_rollback"; + String USE_IDENTIFIER_ROLLBACK = "hibernate.use_identifier_rollback"; /** * Use bytecode libraries optimized property access */ - public static final String USE_REFLECTION_OPTIMIZER = "hibernate.bytecode.use_reflection_optimizer"; + String USE_REFLECTION_OPTIMIZER = "hibernate.bytecode.use_reflection_optimizer"; /** * The classname of the HQL query parser factory */ - public static final String QUERY_TRANSLATOR = "hibernate.query.factory_class"; + String QUERY_TRANSLATOR = "hibernate.query.factory_class"; /** * A comma-separated list of token substitutions to use when translating a Hibernate * query to SQL */ - public static final String QUERY_SUBSTITUTIONS = "hibernate.query.substitutions"; + String QUERY_SUBSTITUTIONS = "hibernate.query.substitutions"; /** * Should named queries be checked during startup (the default is enabled). *

    * Mainly intended for test environments. */ - public static final String QUERY_STARTUP_CHECKING = "hibernate.query.startup_check"; + String QUERY_STARTUP_CHECKING = "hibernate.query.startup_check"; /** * Auto export/update schema using hbm2ddl tool. Valid values are update, * create, create-drop and validate. */ - public static final String HBM2DDL_AUTO = "hibernate.hbm2ddl.auto"; + String HBM2DDL_AUTO = "hibernate.hbm2ddl.auto"; /** * Comma-separated names of the optional files containing SQL DML statements executed @@ -377,7 +377,7 @@ public interface AvailableSettings { * * The default value is /import.sql */ - public static final String HBM2DDL_IMPORT_FILES = "hibernate.hbm2ddl.import_files"; + String HBM2DDL_IMPORT_FILES = "hibernate.hbm2ddl.import_files"; /** * {@link String} reference to {@link org.hibernate.tool.hbm2ddl.ImportSqlCommandExtractor} implementation class. @@ -385,46 +385,46 @@ public interface AvailableSettings { * * The default value is org.hibernate.tool.hbm2ddl.SingleLineSqlCommandExtractor. */ - public static final String HBM2DDL_IMPORT_FILES_SQL_EXTRACTOR = "hibernate.hbm2ddl.import_files_sql_extractor"; + String HBM2DDL_IMPORT_FILES_SQL_EXTRACTOR = "hibernate.hbm2ddl.import_files_sql_extractor"; /** * The {@link org.hibernate.exception.spi.SQLExceptionConverter} to use for converting SQLExceptions * to Hibernate's JDBCException hierarchy. The default is to use the configured * {@link org.hibernate.dialect.Dialect}'s preferred SQLExceptionConverter. */ - public static final String SQL_EXCEPTION_CONVERTER = "hibernate.jdbc.sql_exception_converter"; + String SQL_EXCEPTION_CONVERTER = "hibernate.jdbc.sql_exception_converter"; /** * Enable wrapping of JDBC result sets in order to speed up column name lookups for * broken JDBC drivers */ - public static final String WRAP_RESULT_SETS = "hibernate.jdbc.wrap_result_sets"; + String WRAP_RESULT_SETS = "hibernate.jdbc.wrap_result_sets"; /** * Enable ordering of update statements by primary key value */ - public static final String ORDER_UPDATES = "hibernate.order_updates"; + String ORDER_UPDATES = "hibernate.order_updates"; /** * Enable ordering of insert statements for the purpose of more efficient JDBC batching. */ - public static final String ORDER_INSERTS = "hibernate.order_inserts"; + String ORDER_INSERTS = "hibernate.order_inserts"; /** * Default precedence of null values in {@code ORDER BY} clause. Supported options: {@code none} (default), * {@code first}, {@code last}. */ - public static final String DEFAULT_NULL_ORDERING = "hibernate.order_by.default_null_ordering"; + String DEFAULT_NULL_ORDERING = "hibernate.order_by.default_null_ordering"; /** * The EntityMode in which set the Session opened from the SessionFactory. */ - public static final String DEFAULT_ENTITY_MODE = "hibernate.default_entity_mode"; + String DEFAULT_ENTITY_MODE = "hibernate.default_entity_mode"; /** * Should all database identifiers be quoted. */ - public static final String GLOBALLY_QUOTED_IDENTIFIERS = "hibernate.globally_quoted_identifiers"; + String GLOBALLY_QUOTED_IDENTIFIERS = "hibernate.globally_quoted_identifiers"; /** * Enable nullability checking. @@ -432,32 +432,32 @@ public interface AvailableSettings { * Default to false if Bean Validation is present in the classpath and Hibernate Annotations is used, * true otherwise. */ - public static final String CHECK_NULLABILITY = "hibernate.check_nullability"; + String CHECK_NULLABILITY = "hibernate.check_nullability"; - public static final String BYTECODE_PROVIDER = "hibernate.bytecode.provider"; + String BYTECODE_PROVIDER = "hibernate.bytecode.provider"; - public static final String JPAQL_STRICT_COMPLIANCE= "hibernate.query.jpaql_strict_compliance"; + String JPAQL_STRICT_COMPLIANCE= "hibernate.query.jpaql_strict_compliance"; /** * When using pooled {@link org.hibernate.id.enhanced.Optimizer optimizers}, prefer interpreting the * database value as the lower (lo) boundary. The default is to interpret it as the high boundary. */ - public static final String PREFER_POOLED_VALUES_LO = "hibernate.id.optimizer.pooled.prefer_lo"; + String PREFER_POOLED_VALUES_LO = "hibernate.id.optimizer.pooled.prefer_lo"; /** * The maximum number of strong references maintained by {@link org.hibernate.engine.query.spi.QueryPlanCache}. Default is 128. * @deprecated in favor of {@link #QUERY_PLAN_CACHE_PARAMETER_METADATA_MAX_SIZE} */ @Deprecated - public static final String QUERY_PLAN_CACHE_MAX_STRONG_REFERENCES = "hibernate.query.plan_cache_max_strong_references"; + String QUERY_PLAN_CACHE_MAX_STRONG_REFERENCES = "hibernate.query.plan_cache_max_strong_references"; /** * The maximum number of soft references maintained by {@link org.hibernate.engine.query.spi.QueryPlanCache}. Default is 2048. * @deprecated in favor of {@link #QUERY_PLAN_CACHE_MAX_SIZE} */ @Deprecated - public static final String QUERY_PLAN_CACHE_MAX_SOFT_REFERENCES = "hibernate.query.plan_cache_max_soft_references"; + String QUERY_PLAN_CACHE_MAX_SOFT_REFERENCES = "hibernate.query.plan_cache_max_soft_references"; /** * The maximum number of entries including: @@ -469,18 +469,18 @@ public interface AvailableSettings { * * maintained by {@link org.hibernate.engine.query.spi.QueryPlanCache}. Default is 2048. */ - public static final String QUERY_PLAN_CACHE_MAX_SIZE = "hibernate.query.plan_cache_max_size"; + String QUERY_PLAN_CACHE_MAX_SIZE = "hibernate.query.plan_cache_max_size"; /** * The maximum number of {@link org.hibernate.engine.query.spi.ParameterMetadata} maintained * by {@link org.hibernate.engine.query.spi.QueryPlanCache}. Default is 128. */ - public static final String QUERY_PLAN_CACHE_PARAMETER_METADATA_MAX_SIZE = "hibernate.query.plan_parameter_metadata_max_size"; + String QUERY_PLAN_CACHE_PARAMETER_METADATA_MAX_SIZE = "hibernate.query.plan_parameter_metadata_max_size"; /** * Should we not use contextual LOB creation (aka based on {@link java.sql.Connection#createBlob()} et al). */ - public static final String NON_CONTEXTUAL_LOB_CREATION = "hibernate.jdbc.lob.non_contextual_creation"; + String NON_CONTEXTUAL_LOB_CREATION = "hibernate.jdbc.lob.non_contextual_creation"; /** * Used to define a {@link java.util.Collection} of the {@link ClassLoader} instances Hibernate should use for @@ -488,7 +488,7 @@ public interface AvailableSettings { * * @since 5.0 */ - public static final String CLASSLOADERS = "hibernate.classLoaders"; + String CLASSLOADERS = "hibernate.classLoaders"; /** * Names the {@link ClassLoader} used to load user application classes. @@ -497,7 +497,7 @@ public interface AvailableSettings { * @deprecated Use {@link #CLASSLOADERS} instead */ @Deprecated - public static final String APP_CLASSLOADER = "hibernate.classLoader.application"; + String APP_CLASSLOADER = "hibernate.classLoader.application"; /** * Names the {@link ClassLoader} Hibernate should use to perform resource loading. @@ -505,7 +505,7 @@ public interface AvailableSettings { * @deprecated Use {@link #CLASSLOADERS} instead */ @Deprecated - public static final String RESOURCES_CLASSLOADER = "hibernate.classLoader.resources"; + String RESOURCES_CLASSLOADER = "hibernate.classLoader.resources"; /** * Names the {@link ClassLoader} responsible for loading Hibernate classes. By default this is @@ -514,7 +514,7 @@ public interface AvailableSettings { * @deprecated Use {@link #CLASSLOADERS} instead */ @Deprecated - public static final String HIBERNATE_CLASSLOADER = "hibernate.classLoader.hibernate"; + String HIBERNATE_CLASSLOADER = "hibernate.classLoader.hibernate"; /** * Names the {@link ClassLoader} used when Hibernate is unable to locates classes on the @@ -523,54 +523,54 @@ public interface AvailableSettings { * @deprecated Use {@link #CLASSLOADERS} instead */ @Deprecated - public static final String ENVIRONMENT_CLASSLOADER = "hibernate.classLoader.environment"; + String ENVIRONMENT_CLASSLOADER = "hibernate.classLoader.environment"; - public static final String C3P0_CONFIG_PREFIX = "hibernate.c3p0"; + String C3P0_CONFIG_PREFIX = "hibernate.c3p0"; - public static final String PROXOOL_CONFIG_PREFIX = "hibernate.proxool"; + String PROXOOL_CONFIG_PREFIX = "hibernate.proxool"; - public static final String JMX_ENABLED = "hibernate.jmx.enabled"; - public static final String JMX_PLATFORM_SERVER = "hibernate.jmx.usePlatformServer"; - public static final String JMX_AGENT_ID = "hibernate.jmx.agentId"; - public static final String JMX_DOMAIN_NAME = "hibernate.jmx.defaultDomain"; - public static final String JMX_SF_NAME = "hibernate.jmx.sessionFactoryName"; - public static final String JMX_DEFAULT_OBJ_NAME_DOMAIN = "org.hibernate.core"; + String JMX_ENABLED = "hibernate.jmx.enabled"; + String JMX_PLATFORM_SERVER = "hibernate.jmx.usePlatformServer"; + String JMX_AGENT_ID = "hibernate.jmx.agentId"; + String JMX_DOMAIN_NAME = "hibernate.jmx.defaultDomain"; + String JMX_SF_NAME = "hibernate.jmx.sessionFactoryName"; + String JMX_DEFAULT_OBJ_NAME_DOMAIN = "org.hibernate.core"; /** * A configuration value key used to indicate that it is safe to cache * {@link javax.transaction.TransactionManager} references. * @since 4.0 */ - public static final String JTA_CACHE_TM = "hibernate.jta.cacheTransactionManager"; + String JTA_CACHE_TM = "hibernate.jta.cacheTransactionManager"; /** * A configuration value key used to indicate that it is safe to cache * {@link javax.transaction.UserTransaction} references. * @since 4.0 */ - public static final String JTA_CACHE_UT = "hibernate.jta.cacheUserTransaction"; + String JTA_CACHE_UT = "hibernate.jta.cacheUserTransaction"; /** * Setting used to give the name of the default {@link org.hibernate.annotations.CacheConcurrencyStrategy} * to use when either {@link javax.persistence.Cacheable @Cacheable} or * {@link org.hibernate.annotations.Cache @Cache} is used. {@link org.hibernate.annotations.Cache @Cache(strategy="..")} is used to override. */ - public static final String DEFAULT_CACHE_CONCURRENCY_STRATEGY = "hibernate.cache.default_cache_concurrency_strategy"; + String DEFAULT_CACHE_CONCURRENCY_STRATEGY = "hibernate.cache.default_cache_concurrency_strategy"; /** * Setting which indicates whether or not the new {@link org.hibernate.id.IdentifierGenerator} are used * for AUTO, TABLE and SEQUENCE. * Default to false to keep backward compatibility. */ - public static final String USE_NEW_ID_GENERATOR_MAPPINGS = "hibernate.id.new_generator_mappings"; + String USE_NEW_ID_GENERATOR_MAPPINGS = "hibernate.id.new_generator_mappings"; /** * Setting to identify a {@link org.hibernate.CustomEntityDirtinessStrategy} to use. May point to * either a class name or instance. */ - public static final String CUSTOM_ENTITY_DIRTINESS_STRATEGY = "hibernate.entity_dirtiness_strategy"; + String CUSTOM_ENTITY_DIRTINESS_STRATEGY = "hibernate.entity_dirtiness_strategy"; /** * Strategy for multi-tenancy. @@ -578,7 +578,7 @@ public interface AvailableSettings { * @see org.hibernate.MultiTenancyStrategy * @since 4.0 */ - public static final String MULTI_TENANT = "hibernate.multiTenancy"; + String MULTI_TENANT = "hibernate.multiTenancy"; /** * Names a {@link org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider} implementation to @@ -587,7 +587,7 @@ public interface AvailableSettings { * * @since 4.1 */ - public static final String MULTI_TENANT_CONNECTION_PROVIDER = "hibernate.multi_tenant_connection_provider"; + String MULTI_TENANT_CONNECTION_PROVIDER = "hibernate.multi_tenant_connection_provider"; /** * Names a {@link org.hibernate.context.spi.CurrentTenantIdentifierResolver} implementation to use. @@ -600,33 +600,33 @@ public interface AvailableSettings { * * @since 4.1 */ - public static final String MULTI_TENANT_IDENTIFIER_RESOLVER = "hibernate.tenant_identifier_resolver"; + String MULTI_TENANT_IDENTIFIER_RESOLVER = "hibernate.tenant_identifier_resolver"; - public static final String FORCE_DISCRIMINATOR_IN_SELECTS_BY_DEFAULT = "hibernate.discriminator.force_in_select"; + String FORCE_DISCRIMINATOR_IN_SELECTS_BY_DEFAULT = "hibernate.discriminator.force_in_select"; - public static final String ENABLE_LAZY_LOAD_NO_TRANS = "hibernate.enable_lazy_load_no_trans"; + String ENABLE_LAZY_LOAD_NO_TRANS = "hibernate.enable_lazy_load_no_trans"; - public static final String HQL_BULK_ID_STRATEGY = "hibernate.hql.bulk_id_strategy"; + String HQL_BULK_ID_STRATEGY = "hibernate.hql.bulk_id_strategy"; /** * Names the {@link org.hibernate.loader.BatchFetchStyle} to use. Can specify either the * {@link org.hibernate.loader.BatchFetchStyle} name (insensitively), or a * {@link org.hibernate.loader.BatchFetchStyle} instance. */ - public static final String BATCH_FETCH_STYLE = "hibernate.batch_fetch_style"; + String BATCH_FETCH_STYLE = "hibernate.batch_fetch_style"; /** * Enable direct storage of entity references into the second level cache when applicable (immutable data, etc). * Default is to not store direct references. */ - public static final String USE_DIRECT_REFERENCE_CACHE_ENTRIES = "hibernate.cache.use_reference_entries"; + String USE_DIRECT_REFERENCE_CACHE_ENTRIES = "hibernate.cache.use_reference_entries"; /** * Enable nationalized character support on all string / clob based attribute ( string, char, clob, text etc ). * * Default is false. */ - public static final String USE_NATIONALIZED_CHARACTER_DATA = "hibernate.use_nationalized_character_data"; + String USE_NATIONALIZED_CHARACTER_DATA = "hibernate.use_nationalized_character_data"; /** * A transaction can be rolled back by another thread ("tracking by thread") @@ -637,11 +637,11 @@ public interface AvailableSettings { * * Default is true (enabled). */ - public static final String JTA_TRACK_BY_THREAD = "hibernate.jta.track_by_thread"; + String JTA_TRACK_BY_THREAD = "hibernate.jta.track_by_thread"; - public static final String JACC_CONTEXT_ID = "hibernate.jacc_context_id"; - public static final String JACC_PREFIX = "hibernate.jacc"; - public static final String JACC_ENABLED = "hibernate.jacc.enabled"; + String JACC_CONTEXT_ID = "hibernate.jacc_context_id"; + String JACC_PREFIX = "hibernate.jacc"; + String JACC_ENABLED = "hibernate.jacc.enabled"; /** * If enabled, allows {@link org.hibernate.tool.hbm2ddl.DatabaseMetadata} to @@ -649,7 +649,7 @@ public interface AvailableSettings { * possibility that this would return duplicate tables (especially in * Oracle), this is disabled by default. */ - public static final String ENABLE_SYNONYMS = "hibernate.synonyms"; + String ENABLE_SYNONYMS = "hibernate.synonyms"; /** * Unique columns and unique keys both use unique constraints in most dialects. @@ -667,5 +667,5 @@ public interface AvailableSettings { * {@link org.hibernate.tool.hbm2ddl.UniqueConstraintSchemaUpdateStrategy#SKIP}: * do not attempt to create unique constraints on a schema update */ - public static final String UNIQUE_CONSTRAINT_SCHEMA_UPDATE_STRATEGY = "hibernate.schema_update.unique_constraint_strategy"; + String UNIQUE_CONSTRAINT_SCHEMA_UPDATE_STRATEGY = "hibernate.schema_update.unique_constraint_strategy"; } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/LoadQueryInfluencers.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/LoadQueryInfluencers.java index 41e6ad8f79..86cb49c34c 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/LoadQueryInfluencers.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/LoadQueryInfluencers.java @@ -30,6 +30,8 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import javax.persistence.EntityGraph; + import org.hibernate.Filter; import org.hibernate.UnknownProfileException; import org.hibernate.internal.FilterImpl; @@ -57,6 +59,8 @@ public class LoadQueryInfluencers implements Serializable { private String internalFetchProfile; private final Map enabledFilters; private final Set enabledFetchProfileNames; + private EntityGraph fetchGraph; + private EntityGraph loadGraph; public LoadQueryInfluencers() { this( null ); @@ -195,4 +199,19 @@ public class LoadQueryInfluencers implements Serializable { enabledFetchProfileNames.remove( name ); } + public EntityGraph getFetchGraph() { + return fetchGraph; + } + + public void setFetchGraph(final EntityGraph fetchGraph) { + this.fetchGraph = fetchGraph; + } + + public EntityGraph getLoadGraph() { + return loadGraph; + } + + public void setLoadGraph(final EntityGraph loadGraph) { + this.loadGraph = loadGraph; + } } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/spi/AttributeNodeImplementor.java b/hibernate-core/src/main/java/org/hibernate/graph/spi/AttributeNodeImplementor.java similarity index 87% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/spi/AttributeNodeImplementor.java rename to hibernate-core/src/main/java/org/hibernate/graph/spi/AttributeNodeImplementor.java index 7d767b9fee..d689d144e5 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/spi/AttributeNodeImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/spi/AttributeNodeImplementor.java @@ -21,20 +21,15 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.jpa.graph.spi; +package org.hibernate.graph.spi; import javax.persistence.AttributeNode; import javax.persistence.metamodel.Attribute; -import org.hibernate.jpa.HibernateEntityManagerFactory; - /** - * @author Steve Ebersole + * @author Strong Liu */ public interface AttributeNodeImplementor extends AttributeNode { - public HibernateEntityManagerFactory entityManagerFactory(); - public Attribute getAttribute(); - public AttributeNodeImplementor makeImmutableCopy(); } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/spi/GraphNodeImplementor.java b/hibernate-core/src/main/java/org/hibernate/graph/spi/GraphNodeImplementor.java similarity index 75% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/spi/GraphNodeImplementor.java rename to hibernate-core/src/main/java/org/hibernate/graph/spi/GraphNodeImplementor.java index b5b5c647f8..708757e43c 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/spi/GraphNodeImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/spi/GraphNodeImplementor.java @@ -21,20 +21,15 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.jpa.graph.spi; +package org.hibernate.graph.spi; -import javax.persistence.AttributeNode; import java.util.List; - -import org.hibernate.jpa.HibernateEntityManagerFactory; +import javax.persistence.AttributeNode; /** - * Extended contract for a "graph node" (entity-graph or sub-graph). - * - * @author Steve Ebersole + * @author Strong Liu */ public interface GraphNodeImplementor { - public HibernateEntityManagerFactory entityManagerFactory(); - public List> attributeImplementorNodes(); - public List> attributeNodes(); + List> attributeImplementorNodes(); + List> attributeNodes(); } diff --git a/hibernate-core/src/main/java/org/hibernate/loader/entity/plan/AbstractLoadPlanBasedEntityLoader.java b/hibernate-core/src/main/java/org/hibernate/loader/entity/plan/AbstractLoadPlanBasedEntityLoader.java index 828b03bef4..ceccedba77 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/entity/plan/AbstractLoadPlanBasedEntityLoader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/entity/plan/AbstractLoadPlanBasedEntityLoader.java @@ -40,7 +40,10 @@ import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.loader.entity.UniqueEntityLoader; +import org.hibernate.loader.plan2.build.internal.FetchGraphLoadPlanBuildingStrategy; import org.hibernate.loader.plan2.build.internal.FetchStyleLoadPlanBuildingAssociationVisitationStrategy; +import org.hibernate.loader.plan2.build.internal.LoadGraphLoadPlanBuildingStrategy; +import org.hibernate.loader.plan2.build.spi.LoadPlanBuildingAssociationVisitationStrategy; import org.hibernate.loader.plan2.build.spi.MetamodelDrivenLoadPlanBuilder; import org.hibernate.loader.plan2.exec.internal.AbstractLoadPlanBasedLoader; import org.hibernate.loader.plan2.exec.query.spi.NamedParameterContext; @@ -80,11 +83,22 @@ public abstract class AbstractLoadPlanBasedEntityLoader extends AbstractLoadPlan this.uniqueKeyType = uniqueKeyType; this.entityName = entityPersister.getEntityName(); - final FetchStyleLoadPlanBuildingAssociationVisitationStrategy strategy = new FetchStyleLoadPlanBuildingAssociationVisitationStrategy( - factory, - buildingParameters.getQueryInfluencers(), - buildingParameters.getLockMode() - ); + final LoadPlanBuildingAssociationVisitationStrategy strategy; + if ( buildingParameters.getQueryInfluencers().getFetchGraph() != null ) { + strategy = new FetchGraphLoadPlanBuildingStrategy( + factory, buildingParameters.getQueryInfluencers(),buildingParameters.getLockMode() + ); + } + else if ( buildingParameters.getQueryInfluencers().getLoadGraph() != null ) { + strategy = new LoadGraphLoadPlanBuildingStrategy( + factory, buildingParameters.getQueryInfluencers(),buildingParameters.getLockMode() + ); + } + else { + strategy = new FetchStyleLoadPlanBuildingAssociationVisitationStrategy( + factory, buildingParameters.getQueryInfluencers(),buildingParameters.getLockMode() + ); + } this.plan = MetamodelDrivenLoadPlanBuilder.buildRootEntityLoadPlan( strategy, entityPersister ); this.staticLoadQuery = EntityLoadQueryDetails.makeForBatching( diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan2/build/internal/AbstractEntityGraphVisitationStrategy.java b/hibernate-core/src/main/java/org/hibernate/loader/plan2/build/internal/AbstractEntityGraphVisitationStrategy.java new file mode 100644 index 0000000000..3490f2204f --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan2/build/internal/AbstractEntityGraphVisitationStrategy.java @@ -0,0 +1,359 @@ +/* + * 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.plan2.build.internal; + +import java.util.ArrayDeque; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.persistence.AttributeNode; +import javax.persistence.Subgraph; +import javax.persistence.metamodel.Attribute; + +import org.jboss.logging.Logger; + +import org.hibernate.HibernateException; +import org.hibernate.LockMode; +import org.hibernate.engine.FetchStrategy; +import org.hibernate.engine.FetchStyle; +import org.hibernate.engine.FetchTiming; +import org.hibernate.engine.spi.LoadQueryInfluencers; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.graph.spi.AttributeNodeImplementor; +import org.hibernate.graph.spi.GraphNodeImplementor; +import org.hibernate.internal.CoreLogging; +import org.hibernate.loader.plan2.build.spi.AbstractLoadPlanBuildingAssociationVisitationStrategy; +import org.hibernate.loader.plan2.spi.EntityReturn; +import org.hibernate.loader.plan2.spi.LoadPlan; +import org.hibernate.loader.plan2.spi.Return; +import org.hibernate.persister.walking.spi.AssociationAttributeDefinition; +import org.hibernate.persister.walking.spi.AttributeDefinition; +import org.hibernate.persister.walking.spi.CollectionDefinition; +import org.hibernate.persister.walking.spi.CollectionElementDefinition; +import org.hibernate.persister.walking.spi.CollectionIndexDefinition; +import org.hibernate.persister.walking.spi.CompositionDefinition; +import org.hibernate.persister.walking.spi.EntityDefinition; +import org.hibernate.persister.walking.spi.WalkingException; + +/** + * Abstract strategy of building loadplan based on entity graph. + * + * The problem we're resolving here is, we have TWO trees to walk (only entity loading here): + *

    + * + * And most time, the entity graph tree is partial of entity metadata tree. + * + * So, the idea here is, we walk the entity metadata tree, just as how we build the static loadplan from mappings, + * and we try to match the node to entity graph ( and subgraph ), if there is a match, then the attribute is fetched, + * it is not, then depends on which property is used to apply this entity graph. + * + * @author Strong Liu + */ +public abstract class AbstractEntityGraphVisitationStrategy + extends AbstractLoadPlanBuildingAssociationVisitationStrategy { + private static final Logger LOG = CoreLogging.logger( AbstractEntityGraphVisitationStrategy.class ); + /** + * The JPA 2.1 SPEC's Entity Graph only defines _WHEN_ to load an attribute, it doesn't define _HOW_ to load it + * So I'm here just making an assumption that when it is EAGER, then we use JOIN, and when it is LAZY, then we use SELECT. + * + * NOTE: this may be changed in the near further, though ATM I have no idea how this will be changed to :) + * -- stliu + */ + protected static final FetchStrategy DEFAULT_EAGER = new FetchStrategy( FetchTiming.IMMEDIATE, FetchStyle.JOIN ); + protected static final FetchStrategy DEFAULT_LAZY = new FetchStrategy( FetchTiming.DELAYED, FetchStyle.SELECT ); + protected final LoadQueryInfluencers loadQueryInfluencers; + protected final ArrayDeque graphStack = new ArrayDeque(); + protected final ArrayDeque attributeStack = new ArrayDeque(); + //the attribute nodes defined in the current graph node (entity graph or subgraph) we're working on + protected Map attributeNodeImplementorMap = Collections.emptyMap(); + private EntityReturn rootEntityReturn; + private final LockMode lockMode; + + protected AbstractEntityGraphVisitationStrategy( + final SessionFactoryImplementor sessionFactory, final LoadQueryInfluencers loadQueryInfluencers, + final LockMode lockMode) { + super( sessionFactory ); + this.loadQueryInfluencers = loadQueryInfluencers; + this.lockMode = lockMode; + } + + @Override + public void start() { + super.start(); + graphStack.addLast( getRootEntityGraph() ); + } + + @Override + public void finish() { + super.finish(); + graphStack.removeLast(); + //applying a little internal stack checking + if ( !graphStack.isEmpty() || !attributeStack.isEmpty() || !attributeNodeImplementorMap.isEmpty() ) { + throw new WalkingException( "Internal stack error" ); + } + } + + @Override + public void startingEntity(final EntityDefinition entityDefinition) { + //TODO check if the passed in entity definition is the same as the root entity graph (a.k.a they are came from same entity class)? + //this maybe the root entity graph or a sub graph. + attributeNodeImplementorMap = buildAttributeNodeMap(); + super.startingEntity( entityDefinition ); + } + + /** + * Build "name" -- "attribute node" map from the current entity graph we're visiting. + */ + protected Map buildAttributeNodeMap() { + GraphNodeImplementor graphNode = graphStack.peekLast(); + List> attributeNodeImplementors = graphNode.attributeImplementorNodes(); + Map attributeNodeImplementorMap = attributeNodeImplementors.isEmpty() ? Collections + .emptyMap() : new HashMap( + attributeNodeImplementors.size() + ); + for ( AttributeNodeImplementor attribute : attributeNodeImplementors ) { + attributeNodeImplementorMap.put( attribute.getAttributeName(), attribute ); + } + return attributeNodeImplementorMap; + } + + @Override + public void finishingEntity(final EntityDefinition entityDefinition) { + attributeNodeImplementorMap = Collections.emptyMap(); + super.finishingEntity( entityDefinition ); + } + + /** + * I'm using NULL-OBJECT pattern here, for attributes that not existing in the EntityGraph, + * a predefined NULL-ATTRIBUTE-NODE is pushed to the stack. + * + * and for an not existing sub graph, a predefined NULL-SUBGRAPH is pushed to the stack. + * + * So, whenever we're start visiting an attribute, there will be a attribute node pushed to the attribute stack, + * and a subgraph node pushed to the graph stack. + * + * when we're finish visiting an attribute, these two will be poped from each stack. + */ + @Override + public boolean startingAttribute(AttributeDefinition attributeDefinition) { + final String attrName = attributeDefinition.getName(); + AttributeNodeImplementor attributeNode = NON_EXIST_ATTRIBUTE_NODE; + GraphNodeImplementor subGraphNode = NON_EXIST_SUBGRAPH_NODE; + //the attribute is in the EntityGraph, so, let's continue + if ( attributeNodeImplementorMap.containsKey( attrName ) ) { + attributeNode = attributeNodeImplementorMap.get( attrName ); + //here we need to check if there is a subgraph (or sub key graph if it is an indexed attribute ) + Map subGraphs = attributeNode.getSubgraphs(); + Class javaType = attributeDefinition.getType().getReturnedClass(); + if ( !subGraphs.isEmpty() && subGraphs.containsKey( javaType ) ) { + subGraphNode = (GraphNodeImplementor) subGraphs.get( javaType ); + } + + } + attributeStack.addLast( attributeNode ); + graphStack.addLast( subGraphNode ); + return super.startingAttribute( attributeDefinition ); + } + + + @Override + public void finishingAttribute(final AttributeDefinition attributeDefinition) { + attributeStack.removeLast(); + graphStack.removeLast(); + super.finishingAttribute( attributeDefinition ); + } + + @Override + protected boolean handleAssociationAttribute( + final AssociationAttributeDefinition attributeDefinition) { + return super.handleAssociationAttribute( attributeDefinition ); + } + + @Override + protected boolean handleCompositeAttribute( + final CompositionDefinition attributeDefinition) { + return super.handleCompositeAttribute( attributeDefinition ); + } + + + @Override + public void startingComposite(final CompositionDefinition compositionDefinition) { + super.startingComposite( compositionDefinition ); + } + + + @Override + public void finishingComposite(final CompositionDefinition compositionDefinition) { + super.finishingComposite( compositionDefinition ); + } + + + @Override + public void startingCollection(final CollectionDefinition collectionDefinition) { + super.startingCollection( collectionDefinition ); + } + + @Override + public void finishingCollection(final CollectionDefinition collectionDefinition) { + super.finishingCollection( collectionDefinition ); + } + + + @Override + public void startingCollectionElements( + final CollectionElementDefinition elementDefinition) { + super.startingCollectionElements( elementDefinition ); + } + + @Override + public void finishingCollectionElements( + final CollectionElementDefinition elementDefinition) { + super.finishingCollectionElements( elementDefinition ); + } + + + @Override + public void startingCollectionIndex(final CollectionIndexDefinition indexDefinition) { + AttributeNodeImplementor attributeNode = attributeStack.peekLast(); + GraphNodeImplementor subGraphNode = NON_EXIST_SUBGRAPH_NODE; + Map subGraphs = attributeNode.getKeySubgraphs(); + Class javaType = indexDefinition.getType().getReturnedClass(); + if ( !subGraphs.isEmpty() && subGraphs.containsKey( javaType ) ) { + subGraphNode = (GraphNodeImplementor) subGraphs.get( javaType ); + } + graphStack.addLast( subGraphNode ); + super.startingCollectionIndex( indexDefinition ); + } + + @Override + public void finishingCollectionIndex(final CollectionIndexDefinition indexDefinition) { + super.finishingCollectionIndex( indexDefinition ); + graphStack.removeLast(); + } + + + @Override + protected boolean supportsRootCollectionReturns() { + return false; //entity graph doesn't support root collection. + } + + + @Override + protected void addRootReturn(final Return rootReturn) { + if ( this.rootEntityReturn != null ) { + throw new HibernateException( "Root return already identified" ); + } + if ( !( rootReturn instanceof EntityReturn ) ) { + throw new HibernateException( "Load entity graph only supports EntityReturn" ); + } + this.rootEntityReturn = (EntityReturn) rootReturn; + } + + @Override + protected FetchStrategy determineFetchStrategy( + final AssociationAttributeDefinition attributeDefinition) { + return attributeStack.peekLast() != NON_EXIST_ATTRIBUTE_NODE ? DEFAULT_EAGER : resolveImplicitFetchStrategyFromEntityGraph( + attributeDefinition + ); + } + + protected abstract FetchStrategy resolveImplicitFetchStrategyFromEntityGraph( + final AssociationAttributeDefinition attributeDefinition); + + protected FetchStrategy adjustJoinFetchIfNeeded( + AssociationAttributeDefinition attributeDefinition, FetchStrategy fetchStrategy) { + if ( lockMode.greaterThan( LockMode.READ ) ) { + return new FetchStrategy( fetchStrategy.getTiming(), FetchStyle.SELECT ); + } + + final Integer maxFetchDepth = sessionFactory().getSettings().getMaximumFetchDepth(); + if ( maxFetchDepth != null && currentDepth() > maxFetchDepth ) { + return new FetchStrategy( fetchStrategy.getTiming(), FetchStyle.SELECT ); + } + + if ( attributeDefinition.getType().isCollectionType() && isTooManyCollections() ) { + // todo : have this revert to batch or subselect fetching once "sql gen redesign" is in place + return new FetchStrategy( fetchStrategy.getTiming(), FetchStyle.SELECT ); + } + + return fetchStrategy; + } + + + @Override + public LoadPlan buildLoadPlan() { + LOG.debug( "Building LoadPlan..." ); + return new LoadPlanImpl( rootEntityReturn, getQuerySpaces() ); + } + + abstract protected GraphNodeImplementor getRootEntityGraph(); + + private static final AttributeNodeImplementor NON_EXIST_ATTRIBUTE_NODE = new AttributeNodeImplementor() { + @Override + public Attribute getAttribute() { + return null; + } + + @Override + public AttributeNodeImplementor makeImmutableCopy() { + return this; + } + + @Override + public String getAttributeName() { + return null; + } + + @Override + public Map getSubgraphs() { + return Collections.emptyMap(); + } + + @Override + public Map getKeySubgraphs() { + return Collections.emptyMap(); + } + + @Override + public String toString() { + return "Mocked NON-EXIST attribute node"; + } + }; + private static final GraphNodeImplementor NON_EXIST_SUBGRAPH_NODE = new GraphNodeImplementor() { + @Override + public List> attributeImplementorNodes() { + return Collections.EMPTY_LIST; + } + + @Override + public List> attributeNodes() { + return Collections.EMPTY_LIST; + } + }; +} diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan2/build/internal/FetchGraphLoadPlanBuildingStrategy.java b/hibernate-core/src/main/java/org/hibernate/loader/plan2/build/internal/FetchGraphLoadPlanBuildingStrategy.java new file mode 100644 index 0000000000..0b70f00be3 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan2/build/internal/FetchGraphLoadPlanBuildingStrategy.java @@ -0,0 +1,61 @@ +/* + * 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.plan2.build.internal; + +import org.hibernate.LockMode; +import org.hibernate.engine.FetchStrategy; +import org.hibernate.engine.spi.LoadQueryInfluencers; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.graph.spi.GraphNodeImplementor; +import org.hibernate.persister.walking.spi.AssociationAttributeDefinition; + +/** + * Loadplan building strategy for {@link javax.persistence.EntityGraph} is applied in {@code javax.persistence.fetchgraph} mode. + * + * @author Strong Liu + */ +public class FetchGraphLoadPlanBuildingStrategy extends AbstractEntityGraphVisitationStrategy { + private final GraphNodeImplementor rootEntityGraph; + + public FetchGraphLoadPlanBuildingStrategy( + final SessionFactoryImplementor sessionFactory, final LoadQueryInfluencers loadQueryInfluencers, + final LockMode lockMode) { + super( sessionFactory, loadQueryInfluencers, lockMode ); + this.rootEntityGraph = (GraphNodeImplementor) loadQueryInfluencers.getFetchGraph(); + } + + @Override + protected GraphNodeImplementor getRootEntityGraph() { + return rootEntityGraph; + } + + @Override + protected FetchStrategy resolveImplicitFetchStrategyFromEntityGraph( + final AssociationAttributeDefinition attributeDefinition) { + //under fetchgraph mode, according to the SPEC, all other attributes that no in entity graph are supposed to be lazily loaded + return DEFAULT_LAZY; + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan2/build/internal/LoadGraphLoadPlanBuildingStrategy.java b/hibernate-core/src/main/java/org/hibernate/loader/plan2/build/internal/LoadGraphLoadPlanBuildingStrategy.java new file mode 100644 index 0000000000..e4ab504b41 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan2/build/internal/LoadGraphLoadPlanBuildingStrategy.java @@ -0,0 +1,71 @@ +/* + * 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.plan2.build.internal; + + +import org.hibernate.LockMode; +import org.hibernate.engine.FetchStrategy; +import org.hibernate.engine.FetchStyle; +import org.hibernate.engine.FetchTiming; +import org.hibernate.engine.spi.LoadQueryInfluencers; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.graph.spi.GraphNodeImplementor; +import org.hibernate.persister.walking.spi.AssociationAttributeDefinition; + +/** + * Loadplan building strategy for {@link javax.persistence.EntityGraph} is applied in {@code javax.persistence.loadgraph} mode. + * + * @author Strong Liu + */ +public class LoadGraphLoadPlanBuildingStrategy extends AbstractEntityGraphVisitationStrategy { + private final GraphNodeImplementor rootEntityGraph; + + public LoadGraphLoadPlanBuildingStrategy( + final SessionFactoryImplementor sessionFactory, final LoadQueryInfluencers loadQueryInfluencers,final LockMode lockMode) { + super( sessionFactory, loadQueryInfluencers , lockMode); + this.rootEntityGraph = (GraphNodeImplementor) loadQueryInfluencers.getLoadGraph(); + } + + @Override + protected GraphNodeImplementor getRootEntityGraph() { + return rootEntityGraph; + } + + @Override + protected FetchStrategy resolveImplicitFetchStrategyFromEntityGraph( + final AssociationAttributeDefinition attributeDefinition) { + FetchStrategy fetchStrategy = attributeDefinition.determineFetchPlan( + loadQueryInfluencers, + currentPropertyPath + ); + if ( fetchStrategy.getTiming() == FetchTiming.IMMEDIATE && fetchStrategy.getStyle() == FetchStyle.JOIN ) { + // see if we need to alter the join fetch to another form for any reason + fetchStrategy = adjustJoinFetchIfNeeded( attributeDefinition, fetchStrategy ); + } + + return fetchStrategy; + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 638dc3e869..4d37951475 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -4031,6 +4031,11 @@ public abstract class AbstractEntityPersister affectingFetchProfileNames.add( fetchProfileName ); } + private boolean isAffectedByEntityGraph(SessionImplementor session) { + return session.getLoadQueryInfluencers().getFetchGraph() != null || session.getLoadQueryInfluencers() + .getLoadGraph() != null; + } + private boolean isAffectedByEnabledFetchProfiles(SessionImplementor session) { for ( String s : session.getLoadQueryInfluencers().getEnabledFetchProfileNames() ) { if ( affectingFetchProfileNames.contains( s ) ) { @@ -4067,6 +4072,9 @@ public abstract class AbstractEntityPersister // SQL query used for loading based on those influencers return createEntityLoader(lockOptions, session.getLoadQueryInfluencers() ); } + else if ( isAffectedByEntityGraph( session ) ) { + return createEntityLoader( lockOptions, session.getLoadQueryInfluencers() ); + } else if ( lockOptions.getTimeOut() != LockOptions.WAIT_FOREVER ) { return createEntityLoader( lockOptions, session.getLoadQueryInfluencers() ); } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/AvailableSettings.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/AvailableSettings.java index 86fe0150be..aa7946e346 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/AvailableSettings.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/AvailableSettings.java @@ -41,28 +41,28 @@ public interface AvailableSettings { *

    * See JPA 2 sections 9.4.3 and 8.2.1.4 */ - public static final String PROVIDER = "javax.persistence.provider"; + String PROVIDER = "javax.persistence.provider"; /** * The type of transactions supported by the entity managers. *

    * See JPA 2 sections 9.4.3 and 8.2.1.2 */ - public static final String TRANSACTION_TYPE = "javax.persistence.transactionType"; + String TRANSACTION_TYPE = "javax.persistence.transactionType"; /** * The JNDI name of a JTA {@link javax.sql.DataSource}. *

    * See JPA 2 sections 9.4.3 and 8.2.1.5 */ - public static final String JTA_DATASOURCE = "javax.persistence.jtaDataSource"; + String JTA_DATASOURCE = "javax.persistence.jtaDataSource"; /** * The JNDI name of a non-JTA {@link javax.sql.DataSource}. *

    * See JPA 2 sections 9.4.3 and 8.2.1.5 */ - public static final String NON_JTA_DATASOURCE = "javax.persistence.nonJtaDataSource"; + String NON_JTA_DATASOURCE = "javax.persistence.nonJtaDataSource"; /** * The name of a JDBC driver to use to connect to the database. @@ -73,7 +73,7 @@ public interface AvailableSettings { *

    * See section 8.2.1.9 */ - public static final String JDBC_DRIVER = "javax.persistence.jdbc.driver"; + String JDBC_DRIVER = "javax.persistence.jdbc.driver"; /** * The JDBC connection url to use to connect to the database. @@ -84,7 +84,7 @@ public interface AvailableSettings { *

    * See section 8.2.1.9 */ - public static final String JDBC_URL = "javax.persistence.jdbc.url"; + String JDBC_URL = "javax.persistence.jdbc.url"; /** * The JDBC connection user name. @@ -95,7 +95,7 @@ public interface AvailableSettings { *

    * See section 8.2.1.9 */ - public static final String JDBC_USER = "javax.persistence.jdbc.user"; + String JDBC_USER = "javax.persistence.jdbc.user"; /** * The JDBC connection password. @@ -106,7 +106,7 @@ public interface AvailableSettings { *

    * See JPA 2 section 8.2.1.9 */ - public static final String JDBC_PASSWORD = "javax.persistence.jdbc.password"; + String JDBC_PASSWORD = "javax.persistence.jdbc.password"; /** * Used to indicate whether second-level (what JPA terms shared cache) caching is @@ -115,7 +115,7 @@ public interface AvailableSettings { * See JPA 2 sections 9.4.3 and 8.2.1.7 * @see javax.persistence.SharedCacheMode */ - public static final String SHARED_CACHE_MODE = "javax.persistence.sharedCache.mode"; + String SHARED_CACHE_MODE = "javax.persistence.sharedCache.mode"; /** * NOTE : Not a valid EMF property... @@ -125,7 +125,7 @@ public interface AvailableSettings { * * @see javax.persistence.CacheRetrieveMode */ - public static final String SHARED_CACHE_RETRIEVE_MODE ="javax.persistence.cache.retrieveMode"; + String SHARED_CACHE_RETRIEVE_MODE ="javax.persistence.cache.retrieveMode"; /** * NOTE : Not a valid EMF property... @@ -135,7 +135,7 @@ public interface AvailableSettings { * * @see javax.persistence.CacheStoreMode */ - public static final String SHARED_CACHE_STORE_MODE ="javax.persistence.cache.storeMode"; + String SHARED_CACHE_STORE_MODE ="javax.persistence.cache.storeMode"; /** * Used to indicate what form of automatic validation is in effect as per rules defined @@ -144,52 +144,52 @@ public interface AvailableSettings { * See JPA 2 sections 9.4.3 and 8.2.1.8 * @see javax.persistence.ValidationMode */ - public static final String VALIDATION_MODE = "javax.persistence.validation.mode"; + String VALIDATION_MODE = "javax.persistence.validation.mode"; /** * Used to pass along any discovered validator factory. */ - public static final String VALIDATION_FACTORY = "javax.persistence.validation.factory"; + String VALIDATION_FACTORY = "javax.persistence.validation.factory"; /** * Used to request (hint) a pessimistic lock scope. *

    * See JPA 2 sections 8.2.1.9 and 3.4.4.3 */ - public static final String LOCK_SCOPE = "javax.persistence.lock.scope"; + String LOCK_SCOPE = "javax.persistence.lock.scope"; /** * Used to request (hint) a pessimistic lock timeout (in milliseconds). *

    * See JPA 2 sections 8.2.1.9 and 3.4.4.3 */ - public static final String LOCK_TIMEOUT = "javax.persistence.lock.timeout"; + String LOCK_TIMEOUT = "javax.persistence.lock.timeout"; /** * Used to coordinate with bean validators *

    * See JPA 2 section 8.2.1.9 */ - public static final String PERSIST_VALIDATION_GROUP = "javax.persistence.validation.group.pre-persist"; + String PERSIST_VALIDATION_GROUP = "javax.persistence.validation.group.pre-persist"; /** * Used to coordinate with bean validators *

    * See JPA 2 section 8.2.1.9 */ - public static final String UPDATE_VALIDATION_GROUP = "javax.persistence.validation.group.pre-update"; + String UPDATE_VALIDATION_GROUP = "javax.persistence.validation.group.pre-update"; /** * Used to coordinate with bean validators *

    * See JPA 2 section 8.2.1.9 */ - public static final String REMOVE_VALIDATION_GROUP = "javax.persistence.validation.group.pre-remove"; + String REMOVE_VALIDATION_GROUP = "javax.persistence.validation.group.pre-remove"; /** * Used to pass along the CDI BeanManager, if any, to be used. */ - public static final String CDI_BEAN_MANAGER = "javax.persistence.bean.manager"; + String CDI_BEAN_MANAGER = "javax.persistence.bean.manager"; /** * Specifies whether schema generation commands for schema creation are to be determine based on object/relational @@ -205,7 +205,7 @@ public interface AvailableSettings { * * @see SchemaGenSource */ - public static final String SCHEMA_GEN_CREATE_SOURCE = "javax.persistence.schema-generation.create-source"; + String SCHEMA_GEN_CREATE_SOURCE = "javax.persistence.schema-generation.create-source"; /** * Specifies whether schema generation commands for schema dropping are to be determine based on object/relational @@ -221,7 +221,7 @@ public interface AvailableSettings { * * @see SchemaGenSource */ - public static final String SCHEMA_GEN_DROP_SOURCE = "javax.persistence.schema-generation.drop-source"; + String SCHEMA_GEN_DROP_SOURCE = "javax.persistence.schema-generation.drop-source"; /** * Specifies the CREATE script file as either a {@link java.io.Reader} configured for reading of the DDL script @@ -230,7 +230,7 @@ public interface AvailableSettings { * @see #SCHEMA_GEN_CREATE_SOURCE * @see #SCHEMA_GEN_DROP_SCRIPT_SOURCE */ - public static final String SCHEMA_GEN_CREATE_SCRIPT_SOURCE = "javax.persistence.schema-generation.create-script-source"; + String SCHEMA_GEN_CREATE_SCRIPT_SOURCE = "javax.persistence.schema-generation.create-script-source"; /** * Specifies the DROP script file as either a {@link java.io.Reader} configured for reading of the DDL script @@ -239,7 +239,7 @@ public interface AvailableSettings { * @see #SCHEMA_GEN_DROP_SOURCE * @see #SCHEMA_GEN_CREATE_SCRIPT_SOURCE */ - public static final String SCHEMA_GEN_DROP_SCRIPT_SOURCE = "javax.persistence.schema-generation.drop-script-source"; + String SCHEMA_GEN_DROP_SCRIPT_SOURCE = "javax.persistence.schema-generation.drop-script-source"; /** * Specifies the type of schema generation action to be taken by the persistence provider in regards to sending @@ -249,7 +249,7 @@ public interface AvailableSettings { * * @see SchemaGenAction */ - public static final String SCHEMA_GEN_DATABASE_ACTION = "javax.persistence.schema-generation.database.action"; + String SCHEMA_GEN_DATABASE_ACTION = "javax.persistence.schema-generation.database.action"; /** * Specifies the type of schema generation action to be taken by the persistence provider in regards to writing @@ -259,7 +259,7 @@ public interface AvailableSettings { * * @see SchemaGenAction */ - public static final String SCHEMA_GEN_SCRIPTS_ACTION = "javax.persistence.schema-generation.scripts.action"; + String SCHEMA_GEN_SCRIPTS_ACTION = "javax.persistence.schema-generation.scripts.action"; /** * For cases where the {@value #SCHEMA_GEN_SCRIPTS_ACTION} value indicates that schema creation commands should @@ -270,7 +270,7 @@ public interface AvailableSettings { * @see #SCHEMA_GEN_SCRIPTS_ACTION */ @SuppressWarnings("JavaDoc") - public static final String SCHEMA_GEN_SCRIPTS_CREATE_TARGET = "javax.persistence.schema-generation.scripts.create-target"; + String SCHEMA_GEN_SCRIPTS_CREATE_TARGET = "javax.persistence.schema-generation.scripts.create-target"; /** * For cases where the {@value #SCHEMA_GEN_SCRIPTS_ACTION} value indicates that schema drop commands should @@ -281,7 +281,7 @@ public interface AvailableSettings { * @see #SCHEMA_GEN_SCRIPTS_ACTION */ @SuppressWarnings("JavaDoc") - public static final String SCHEMA_GEN_SCRIPTS_DROP_TARGET = "javax.persistence.schema-generation.scripts.drop-target"; + String SCHEMA_GEN_SCRIPTS_DROP_TARGET = "javax.persistence.schema-generation.scripts.drop-target"; /** * Specifies whether the persistence provider is to create the database schema(s) in addition to creating @@ -290,7 +290,7 @@ public interface AvailableSettings { * contains “CREATE SCHEMA” commands. If this property is not supplied (or is explicitly {@code false}), the * provider should not attempt to create database schemas. */ - public static final String SCHEMA_GEN_CREATE_SCHEMAS = "javax.persistence.create-database-schemas"; + String SCHEMA_GEN_CREATE_SCHEMAS = "javax.persistence.create-database-schemas"; /** * Allows passing the specific {@link java.sql.Connection} instance to be used for performing schema generation @@ -299,7 +299,7 @@ public interface AvailableSettings { * May also be used to determine the values for {@value #SCHEMA_GEN_DB_NAME}, * {@value #SCHEMA_GEN_DB_MAJOR_VERSION} and {@value #SCHEMA_GEN_DB_MINOR_VERSION}. */ - public static final String SCHEMA_GEN_CONNECTION = "javax.persistence.schema-generation-connection"; + String SCHEMA_GEN_CONNECTION = "javax.persistence.schema-generation-connection"; /** * Specifies the name of the database provider in cases where a Connection to the underlying database is @@ -316,7 +316,7 @@ public interface AvailableSettings { * @see #SCHEMA_GEN_DB_MINOR_VERSION */ @SuppressWarnings("JavaDoc") - public static final String SCHEMA_GEN_DB_NAME = "javax.persistence.database-product-name"; + String SCHEMA_GEN_DB_NAME = "javax.persistence.database-product-name"; /** * Specifies the major version of the underlying database, as would be returned by @@ -327,7 +327,7 @@ public interface AvailableSettings { * @see #SCHEMA_GEN_DB_NAME * @see #SCHEMA_GEN_DB_MINOR_VERSION */ - public static final String SCHEMA_GEN_DB_MAJOR_VERSION = "javax.persistence.database-major-version"; + String SCHEMA_GEN_DB_MAJOR_VERSION = "javax.persistence.database-major-version"; /** * Specifies the minor version of the underlying database, as would be returned by @@ -339,7 +339,7 @@ public interface AvailableSettings { * @see #SCHEMA_GEN_DB_NAME * @see #SCHEMA_GEN_DB_MAJOR_VERSION */ - public static final String SCHEMA_GEN_DB_MINOR_VERSION = "javax.persistence.database-minor-version"; + String SCHEMA_GEN_DB_MINOR_VERSION = "javax.persistence.database-minor-version"; /** * Specifies a {@link java.io.Reader} configured for reading of the SQL load script or a string designating the @@ -347,7 +347,7 @@ public interface AvailableSettings { *

    * A "SQL load script" is a script that performs some database initialization (INSERT, etc). */ - public static final String SCHEMA_GEN_LOAD_SCRIPT_SOURCE = "javax.persistence.sql-load-script-source"; + String SCHEMA_GEN_LOAD_SCRIPT_SOURCE = "javax.persistence.sql-load-script-source"; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -367,75 +367,75 @@ public interface AvailableSettings { * would apply someLockMode to the alias "a". */ //Use the org.hibernate prefix. instead of hibernate. as it is a query hint se QueryHints - public static final String ALIAS_SPECIFIC_LOCK_MODE = "org.hibernate.lockMode"; + String ALIAS_SPECIFIC_LOCK_MODE = "org.hibernate.lockMode"; /** * JAR autodetection artifacts class, hbm */ - public static final String AUTODETECTION = "hibernate.archive.autodetection"; + String AUTODETECTION = "hibernate.archive.autodetection"; /** * cfg.xml configuration file used */ - public static final String CFG_FILE = "hibernate.ejb.cfgfile"; + String CFG_FILE = "hibernate.ejb.cfgfile"; /** * Caching configuration should follow the following pattern * hibernate.ejb.classcache. usage[, region] * where usage is the cache strategy used and region the cache region name */ - public static final String CLASS_CACHE_PREFIX = "hibernate.ejb.classcache"; + String CLASS_CACHE_PREFIX = "hibernate.ejb.classcache"; /** * Caching configuration should follow the following pattern * hibernate.ejb.collectioncache.. usage[, region] * where usage is the cache strategy used and region the cache region name */ - public static final String COLLECTION_CACHE_PREFIX = "hibernate.ejb.collectioncache"; + String COLLECTION_CACHE_PREFIX = "hibernate.ejb.collectioncache"; /** * Interceptor class name, the class has to have a no-arg constructor * the interceptor instance is shared amongst all EntityManager of a given EntityManagerFactory */ - public static final String INTERCEPTOR = "hibernate.ejb.interceptor"; + String INTERCEPTOR = "hibernate.ejb.interceptor"; /** * Interceptor class name, the class has to have a no-arg constructor */ - public static final String SESSION_INTERCEPTOR = "hibernate.ejb.interceptor.session_scoped"; + String SESSION_INTERCEPTOR = "hibernate.ejb.interceptor.session_scoped"; /** * SessionFactoryObserver class name, the class must have a no-arg constructor */ - public static final String SESSION_FACTORY_OBSERVER = "hibernate.ejb.session_factory_observer"; + String SESSION_FACTORY_OBSERVER = "hibernate.ejb.session_factory_observer"; /** * Naming strategy class name, the class has to have a no-arg constructor */ - public static final String NAMING_STRATEGY = "hibernate.ejb.naming_strategy"; + String NAMING_STRATEGY = "hibernate.ejb.naming_strategy"; /** * IdentifierGeneratorStrategyProvider class name, the class must have a no-arg constructor * @deprecated if possible wait of Hibernate 4.1 and theService registry (MutableIdentifierGeneratorStrategy service) */ - public static final String IDENTIFIER_GENERATOR_STRATEGY_PROVIDER = "hibernate.ejb.identifier_generator_strategy_provider"; + String IDENTIFIER_GENERATOR_STRATEGY_PROVIDER = "hibernate.ejb.identifier_generator_strategy_provider"; /** * Event configuration should follow the following pattern * hibernate.ejb.event.[eventType] f.q.c.n.EventListener1, f.q.c.n.EventListener12 ... */ - public static final String EVENT_LISTENER_PREFIX = "hibernate.ejb.event"; + String EVENT_LISTENER_PREFIX = "hibernate.ejb.event"; /** * Enable the class file enhancement */ - public static final String USE_CLASS_ENHANCER = "hibernate.ejb.use_class_enhancer"; + String USE_CLASS_ENHANCER = "hibernate.ejb.use_class_enhancer"; /** * Whether or not discard persistent context on entityManager.close() * The EJB3 compliant and default choice is false */ - public static final String DISCARD_PC_ON_CLOSE = "hibernate.ejb.discard_pc_on_close"; + String DISCARD_PC_ON_CLOSE = "hibernate.ejb.discard_pc_on_close"; /** * Consider this as experimental @@ -445,20 +445,20 @@ public interface AvailableSettings { * @deprecated Configuration going away. */ @Deprecated - public static final String CONFIGURATION_JNDI_NAME = "hibernate.ejb.configuration_jndi_name"; + String CONFIGURATION_JNDI_NAME = "hibernate.ejb.configuration_jndi_name"; /** * Used to determine flush mode. */ //Use the org.hibernate prefix. instead of hibernate. as it is a query hint se QueryHints - public static final String FLUSH_MODE = "org.hibernate.flushMode"; + String FLUSH_MODE = "org.hibernate.flushMode"; /** * Pass an implementation of {@link org.hibernate.ejb.packaging.Scanner}: * - preferably an actual instance * - or a class name with a no-arg constructor */ - public static final String SCANNER = "hibernate.ejb.resource_scanner"; + String SCANNER = "hibernate.ejb.resource_scanner"; /** * List of classes names @@ -468,7 +468,7 @@ public interface AvailableSettings { */ @Deprecated @SuppressWarnings("UnusedDeclaration") - public static final String CLASS_NAMES = "hibernate.ejb.classes"; + String CLASS_NAMES = "hibernate.ejb.classes"; /** * List of annotated packages @@ -478,18 +478,18 @@ public interface AvailableSettings { */ @Deprecated @SuppressWarnings("UnusedDeclaration") - public static final String PACKAGE_NAMES = "hibernate.ejb.packages"; + String PACKAGE_NAMES = "hibernate.ejb.packages"; /** * EntityManagerFactory name */ - public static final String ENTITY_MANAGER_FACTORY_NAME = "hibernate.ejb.entitymanager_factory_name"; + String ENTITY_MANAGER_FACTORY_NAME = "hibernate.ejb.entitymanager_factory_name"; /** * @deprecated use {@link #JPA_METAMODEL_POPULATION} instead. */ @Deprecated - public static final String JPA_METAMODEL_GENERATION = "hibernate.ejb.metamodel.generation"; + String JPA_METAMODEL_GENERATION = "hibernate.ejb.metamodel.generation"; /** * Setting that controls whether we seek out JPA "static metamodel" classes and populate them. Accepts @@ -507,16 +507,16 @@ public interface AvailableSettings { * * */ - public static final String JPA_METAMODEL_POPULATION = "hibernate.ejb.metamodel.population"; + String JPA_METAMODEL_POPULATION = "hibernate.ejb.metamodel.population"; /** * List of classes names * Internal use only */ - public static final String XML_FILE_NAMES = "hibernate.ejb.xml_files"; - public static final String HBXML_FILES = "hibernate.hbmxml.files"; - public static final String LOADED_CLASSES = "hibernate.ejb.loaded.classes"; + String XML_FILE_NAMES = "hibernate.ejb.xml_files"; + String HBXML_FILES = "hibernate.hbmxml.files"; + String LOADED_CLASSES = "hibernate.ejb.loaded.classes"; /** * Deprecated @@ -524,7 +524,7 @@ public interface AvailableSettings { * @deprecated Use {@link org.hibernate.cfg.AvailableSettings#JACC_CONTEXT_ID} instead */ @Deprecated - public static final String JACC_CONTEXT_ID = org.hibernate.cfg.AvailableSettings.JACC_CONTEXT_ID; + String JACC_CONTEXT_ID = org.hibernate.cfg.AvailableSettings.JACC_CONTEXT_ID; /** * Deprecated @@ -532,7 +532,7 @@ public interface AvailableSettings { * @deprecated Use {@link org.hibernate.cfg.AvailableSettings#JACC_PREFIX} instead */ @Deprecated - public static final String JACC_PREFIX = org.hibernate.cfg.AvailableSettings.JACC_PREFIX; + String JACC_PREFIX = org.hibernate.cfg.AvailableSettings.JACC_PREFIX; /** * Deprecated @@ -540,11 +540,10 @@ public interface AvailableSettings { * @deprecated Use {@link org.hibernate.cfg.AvailableSettings#JACC_ENABLED} instead */ @Deprecated - public static final String JACC_ENABLED = org.hibernate.cfg.AvailableSettings.JACC_ENABLED; + String JACC_ENABLED = org.hibernate.cfg.AvailableSettings.JACC_ENABLED; /** * Used to pass along the name of the persistence unit. */ - public static final String PERSISTENCE_UNIT_NAME = "hibernate.ejb.persistenceUnitName"; - + String PERSISTENCE_UNIT_NAME = "hibernate.ejb.persistenceUnitName"; } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/AbstractGraphNode.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/AbstractGraphNode.java index e30c4f88fb..74c1a3e08c 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/AbstractGraphNode.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/AbstractGraphNode.java @@ -24,7 +24,6 @@ package org.hibernate.jpa.graph.internal; import javax.persistence.AttributeNode; -import javax.persistence.Subgraph; import javax.persistence.metamodel.Attribute; import java.util.ArrayList; import java.util.Collections; @@ -34,17 +33,18 @@ import java.util.Map; import org.jboss.logging.Logger; +import org.hibernate.graph.spi.AttributeNodeImplementor; +import org.hibernate.graph.spi.GraphNodeImplementor; import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.jpa.HibernateEntityManagerFactory; -import org.hibernate.jpa.graph.spi.AttributeNodeImplementor; -import org.hibernate.jpa.graph.spi.GraphNodeImplementor; +import org.hibernate.jpa.spi.HibernateEntityManagerFactoryAware; /** * Base class for EntityGraph and Subgraph implementations. * * @author Steve Ebersole */ -public abstract class AbstractGraphNode implements GraphNodeImplementor { +public abstract class AbstractGraphNode implements GraphNodeImplementor, HibernateEntityManagerFactoryAware{ private static final Logger log = Logger.getLogger( AbstractGraphNode.class ); private final HibernateEntityManagerFactory entityManagerFactory; @@ -80,7 +80,7 @@ public abstract class AbstractGraphNode implements GraphNodeImplementor { } @Override - public HibernateEntityManagerFactory entityManagerFactory() { + public HibernateEntityManagerFactory getFactory() { return entityManagerFactory; } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/AttributeNodeImpl.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/AttributeNodeImpl.java index 159c5bb278..dabcdde6b0 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/AttributeNodeImpl.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/AttributeNodeImpl.java @@ -34,11 +34,12 @@ import javax.persistence.metamodel.ManagedType; import javax.persistence.metamodel.PluralAttribute; import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.graph.spi.AttributeNodeImplementor; import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.jpa.HibernateEntityManagerFactory; -import org.hibernate.jpa.graph.spi.AttributeNodeImplementor; import org.hibernate.jpa.internal.metamodel.Helper; import org.hibernate.jpa.internal.metamodel.PluralAttributeImpl; +import org.hibernate.jpa.spi.HibernateEntityManagerFactoryAware; import org.hibernate.persister.collection.QueryableCollection; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.Joinable; @@ -50,7 +51,7 @@ import org.hibernate.type.Type; * * @author Steve Ebersole */ -public class AttributeNodeImpl implements AttributeNode, AttributeNodeImplementor { +public class AttributeNodeImpl implements AttributeNode, AttributeNodeImplementor, HibernateEntityManagerFactoryAware { private final HibernateEntityManagerFactory entityManagerFactory; private final Attribute attribute; @@ -77,12 +78,12 @@ public class AttributeNodeImpl implements AttributeNode, AttributeNodeImpl } @Override - public HibernateEntityManagerFactory entityManagerFactory() { + public HibernateEntityManagerFactory getFactory() { return entityManagerFactory; } private SessionFactoryImplementor sessionFactory() { - return (SessionFactoryImplementor) entityManagerFactory().getSessionFactory(); + return (SessionFactoryImplementor) getFactory().getSessionFactory(); } @Override diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/EntityGraphImpl.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/EntityGraphImpl.java index c41ed06b65..07d9798d97 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/EntityGraphImpl.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/EntityGraphImpl.java @@ -32,6 +32,7 @@ import javax.persistence.metamodel.IdentifiableType; import java.util.List; import org.hibernate.cfg.NotYetImplementedException; +import org.hibernate.graph.spi.GraphNodeImplementor; import org.hibernate.jpa.HibernateEntityManagerFactory; /** @@ -39,7 +40,7 @@ import org.hibernate.jpa.HibernateEntityManagerFactory; * * @author Steve Ebersole */ -public class EntityGraphImpl extends AbstractGraphNode implements EntityGraph { +public class EntityGraphImpl extends AbstractGraphNode implements EntityGraph, GraphNodeImplementor { private final String name; private final EntityType entityType; @@ -150,7 +151,7 @@ public class EntityGraphImpl extends AbstractGraphNode implements EntityGr @SuppressWarnings("unchecked") public boolean appliesTo(String entityName) { - return appliesTo( entityManagerFactory().getEntityTypeByName( entityName ) ); + return appliesTo( getFactory().getEntityTypeByName( entityName ) ); } public boolean appliesTo(EntityType entityType) { diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/SubgraphImpl.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/SubgraphImpl.java index f52c01dba1..9413fb661e 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/SubgraphImpl.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/SubgraphImpl.java @@ -29,12 +29,13 @@ import javax.persistence.metamodel.Attribute; import javax.persistence.metamodel.ManagedType; import java.util.List; +import org.hibernate.graph.spi.GraphNodeImplementor; import org.hibernate.jpa.HibernateEntityManagerFactory; /** * @author Steve Ebersole */ -public class SubgraphImpl extends AbstractGraphNode implements Subgraph { +public class SubgraphImpl extends AbstractGraphNode implements Subgraph, GraphNodeImplementor { private final ManagedType managedType; private final Class subclass; diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/advisor/AdviceHelper.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/advisor/AdviceHelper.java index e11942e66e..f4328042d0 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/advisor/AdviceHelper.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/advisor/AdviceHelper.java @@ -23,20 +23,10 @@ */ package org.hibernate.jpa.graph.internal.advisor; -import org.hibernate.LockMode; import org.hibernate.cfg.NotYetImplementedException; -import org.hibernate.engine.FetchStrategy; -import org.hibernate.engine.FetchStyle; -import org.hibernate.engine.FetchTiming; -import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.jpa.graph.spi.AttributeNodeImplementor; -import org.hibernate.jpa.internal.metamodel.Helper; -import org.hibernate.loader.plan.spi.CollectionFetch; -import org.hibernate.loader.plan.spi.CompositeFetch; -import org.hibernate.loader.plan.spi.EntityFetch; +import org.hibernate.graph.spi.AttributeNodeImplementor; import org.hibernate.loader.plan.spi.Fetch; import org.hibernate.loader.plan.spi.FetchOwner; -import org.hibernate.type.EntityType; /** * @author Steve Ebersole diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/advisor/JpaGraphCollectionReference.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/advisor/JpaGraphCollectionReference.java index f97ee4f2ea..83690d7674 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/advisor/JpaGraphCollectionReference.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/advisor/JpaGraphCollectionReference.java @@ -23,7 +23,7 @@ */ package org.hibernate.jpa.graph.internal.advisor; -import org.hibernate.jpa.graph.spi.AttributeNodeImplementor; +import org.hibernate.graph.spi.AttributeNodeImplementor; import org.hibernate.loader.plan.spi.FetchOwner; /** diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/advisor/JpaGraphReferenceSubGraphSupport.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/advisor/JpaGraphReferenceSubGraphSupport.java index 8341fb06db..d827edb986 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/advisor/JpaGraphReferenceSubGraphSupport.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/advisor/JpaGraphReferenceSubGraphSupport.java @@ -30,7 +30,7 @@ import java.util.Map; import org.jboss.logging.Logger; -import org.hibernate.jpa.graph.spi.AttributeNodeImplementor; +import org.hibernate.graph.spi.AttributeNodeImplementor; import org.hibernate.loader.plan.spi.FetchOwner; /** diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/advisor/JpaGraphRootEntityReference.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/advisor/JpaGraphRootEntityReference.java index 46cd884053..4331dc2651 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/advisor/JpaGraphRootEntityReference.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/advisor/JpaGraphRootEntityReference.java @@ -29,8 +29,8 @@ import java.util.Map; import org.jboss.logging.Logger; +import org.hibernate.graph.spi.AttributeNodeImplementor; import org.hibernate.jpa.graph.internal.EntityGraphImpl; -import org.hibernate.jpa.graph.spi.AttributeNodeImplementor; import org.hibernate.loader.plan.spi.FetchOwner; /** diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/advisor/JpaGraphSingularAttributeReference.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/advisor/JpaGraphSingularAttributeReference.java index d9cd03099f..9b7542d016 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/advisor/JpaGraphSingularAttributeReference.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/advisor/JpaGraphSingularAttributeReference.java @@ -23,7 +23,8 @@ */ package org.hibernate.jpa.graph.internal.advisor; -import org.hibernate.jpa.graph.spi.AttributeNodeImplementor; + +import org.hibernate.graph.spi.AttributeNodeImplementor; /** * @author Steve Ebersole diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/spi/AbstractEntityManagerImpl.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/spi/AbstractEntityManagerImpl.java index d50a12d93c..09cbc5e8c8 100755 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/spi/AbstractEntityManagerImpl.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/spi/AbstractEntityManagerImpl.java @@ -26,6 +26,7 @@ package org.hibernate.jpa.spi; import javax.persistence.CacheRetrieveMode; import javax.persistence.CacheStoreMode; import javax.persistence.EntityExistsException; +import javax.persistence.EntityGraph; import javax.persistence.EntityManager; import javax.persistence.EntityNotFoundException; import javax.persistence.EntityTransaction; @@ -109,7 +110,6 @@ import org.hibernate.engine.transaction.synchronization.spi.AfterCompletionActio import org.hibernate.engine.transaction.synchronization.spi.ExceptionMapper; import org.hibernate.engine.transaction.synchronization.spi.ManagedFlushChecker; import org.hibernate.engine.transaction.synchronization.spi.SynchronizationCallbackCoordinator; -import org.hibernate.internal.util.ReflectHelper; import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.HibernateEntityManagerFactory; @@ -1098,6 +1098,12 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage CacheMode cacheMode = determineAppropriateLocalCacheMode( properties ); LockOptions lockOptions = null; try { + if ( properties != null && !properties.isEmpty() ) { + ( (SessionImplementor) session ).getLoadQueryInfluencers() + .setFetchGraph( (EntityGraph) properties.get( QueryHints.HINT_FETCHGRAPH ) ); + ( (SessionImplementor) session ).getLoadQueryInfluencers() + .setLoadGraph( (EntityGraph) properties.get( QueryHints.HINT_LOADGRAPH ) ); + } session.setCacheMode( cacheMode ); if ( lockModeType != null ) { lockOptions = getLockRequest( lockModeType, properties ); @@ -1145,6 +1151,9 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage } finally { session.setCacheMode( previousCacheMode ); + ((SessionImplementor)session).getLoadQueryInfluencers().setFetchGraph( null ); + ((SessionImplementor)session).getLoadQueryInfluencers().setLoadGraph( null ); + } } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/spi/HibernateEntityManagerFactoryAware.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/spi/HibernateEntityManagerFactoryAware.java new file mode 100644 index 0000000000..54fea41a0b --- /dev/null +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/spi/HibernateEntityManagerFactoryAware.java @@ -0,0 +1,40 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.jpa.spi; + +import org.hibernate.jpa.HibernateEntityManagerFactory; + +/** + * Internal contact for things that have {@link HibernateEntityManagerFactory} access. + * + * @author Strong Liu + */ +public interface HibernateEntityManagerFactoryAware { + /** + * Get access to the Hibernate extended EMF contract. + * + * @return The Hibernate EMF contract for this EM. + */ + HibernateEntityManagerFactory getFactory(); +} diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/spi/HibernateEntityManagerImplementor.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/spi/HibernateEntityManagerImplementor.java index 64cd3ef0e1..988d772581 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/spi/HibernateEntityManagerImplementor.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/spi/HibernateEntityManagerImplementor.java @@ -44,13 +44,8 @@ import org.hibernate.type.Type; * @author Emmanuel Bernard * @author Steve Ebersole */ -public interface HibernateEntityManagerImplementor extends HibernateEntityManager { - /** - * Get access to the Hibernate extended EMF contract. - * - * @return The Hibernate EMF contract for this EM. - */ - public HibernateEntityManagerFactory getFactory(); +public interface HibernateEntityManagerImplementor extends HibernateEntityManager, HibernateEntityManagerFactoryAware { + /** * Used to ensure the EntityManager is open, throwing IllegalStateException if it is closed. diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/EntityGraphLoadPlanBuilderTest.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/EntityGraphLoadPlanBuilderTest.java new file mode 100644 index 0000000000..0ea055b24c --- /dev/null +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/EntityGraphLoadPlanBuilderTest.java @@ -0,0 +1,214 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2013, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc.. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + * + */ +package org.hibernate.jpa.test.graphs; + +import java.util.Iterator; +import java.util.Set; +import javax.persistence.Embeddable; +import javax.persistence.Embedded; +import javax.persistence.Entity; +import javax.persistence.EntityGraph; +import javax.persistence.EntityManager; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; + + +import org.junit.Test; + +import static org.junit.Assert.*; + +import org.hibernate.LockMode; +import org.hibernate.SessionFactory; +import org.hibernate.engine.spi.LoadQueryInfluencers; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.jpa.graph.internal.EntityGraphImpl; +import org.hibernate.jpa.graph.internal.SubgraphImpl; +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; +import org.hibernate.loader.plan2.build.internal.FetchGraphLoadPlanBuildingStrategy; +import org.hibernate.loader.plan2.build.internal.FetchStyleLoadPlanBuildingAssociationVisitationStrategy; +import org.hibernate.loader.plan2.build.internal.LoadGraphLoadPlanBuildingStrategy; +import org.hibernate.loader.plan2.build.spi.AbstractLoadPlanBuildingAssociationVisitationStrategy; +import org.hibernate.loader.plan2.build.spi.LoadPlanTreePrinter; +import org.hibernate.loader.plan2.build.spi.MetamodelDrivenLoadPlanBuilder; +import org.hibernate.loader.plan2.exec.internal.AliasResolutionContextImpl; +import org.hibernate.loader.plan2.spi.Join; +import org.hibernate.loader.plan2.spi.LoadPlan; +import org.hibernate.loader.plan2.spi.QuerySpace; +import org.hibernate.persister.entity.EntityPersister; + +/** + * @author Strong Liu + */ +public class EntityGraphLoadPlanBuilderTest extends BaseEntityManagerFunctionalTestCase { + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { Cat.class, Person.class, Country.class }; + } + + @Entity + public static class Cat { + @Id + String name; + @ManyToOne(fetch = FetchType.LAZY) + Person owner; + + } + + @Entity + public static class Person { + @Id + String name; + @OneToMany(mappedBy = "owner") + Set pets; + @Embedded + Address homeAddress; + } + + @Embeddable + public static class Address { + @ManyToOne + Country country; + + } + + @Entity + public static class Country { + @Id + String name; + } + + @Test + public void testBasicFetchLoadPlanBuilding() { + EntityManager em = getOrCreateEntityManager(); + EntityGraph eg = em.createEntityGraph( Cat.class ); + LoadPlan plan = buildLoadPlan( eg, Mode.FETCH ); + LoadPlanTreePrinter.INSTANCE.logTree( plan, new AliasResolutionContextImpl( sfi() ) ); + QuerySpace rootQuerySpace = plan.getQuerySpaces().getRootQuerySpaces().get( 0 ); + assertFalse( + "With fetchgraph property and an empty EntityGraph, there should be no join at all", + rootQuerySpace.getJoins().iterator().hasNext() + ); + // -------------------------------------------------- another a little more complicated case + eg = em.createEntityGraph( Cat.class ); + eg.addSubgraph( "owner", Person.class ); + plan = buildLoadPlan( eg, Mode.FETCH ); + LoadPlanTreePrinter.INSTANCE.logTree( plan, new AliasResolutionContextImpl( sfi() ) ); + rootQuerySpace = plan.getQuerySpaces().getRootQuerySpaces().get( 0 ); + Iterator iterator = rootQuerySpace.getJoins().iterator(); + assertTrue( + "With fetchgraph property and an empty EntityGraph, there should be no join at all", iterator.hasNext() + ); + Join personJoin = iterator.next(); + assertNotNull( personJoin ); + QuerySpace.Disposition disposition = personJoin.getRightHandSide().getDisposition(); + assertEquals( + "This should be an entity join which fetches Person", QuerySpace.Disposition.ENTITY, disposition + ); + + iterator = personJoin.getRightHandSide().getJoins().iterator(); + assertTrue( "The composite address should be fetched", iterator.hasNext() ); + Join addressJoin = iterator.next(); + assertNotNull( addressJoin ); + disposition = addressJoin.getRightHandSide().getDisposition(); + assertEquals( QuerySpace.Disposition.COMPOSITE, disposition ); + assertFalse( iterator.hasNext() ); + assertFalse( + "The ManyToOne attribute in composite should not be fetched", + addressJoin.getRightHandSide().getJoins().iterator().hasNext() + ); + em.close(); + } + + @Test + public void testBasicLoadLoadPlanBuilding() { + EntityManager em = getOrCreateEntityManager(); + EntityGraph eg = em.createEntityGraph( Cat.class ); + LoadPlan plan = buildLoadPlan( eg, Mode.LOAD ); + LoadPlanTreePrinter.INSTANCE.logTree( plan, new AliasResolutionContextImpl( sfi() ) ); + QuerySpace rootQuerySpace = plan.getQuerySpaces().getRootQuerySpaces().get( 0 ); + assertFalse( + "With fetchgraph property and an empty EntityGraph, there should be no join at all", + rootQuerySpace.getJoins().iterator().hasNext() + ); + // -------------------------------------------------- another a little more complicated case + eg = em.createEntityGraph( Cat.class ); + eg.addSubgraph( "owner", Person.class ); + plan = buildLoadPlan( eg, Mode.LOAD ); + LoadPlanTreePrinter.INSTANCE.logTree( plan, new AliasResolutionContextImpl( sfi() ) ); + rootQuerySpace = plan.getQuerySpaces().getRootQuerySpaces().get( 0 ); + Iterator iterator = rootQuerySpace.getJoins().iterator(); + assertTrue( + "With fetchgraph property and an empty EntityGraph, there should be no join at all", iterator.hasNext() + ); + Join personJoin = iterator.next(); + assertNotNull( personJoin ); + QuerySpace.Disposition disposition = personJoin.getRightHandSide().getDisposition(); + assertEquals( + "This should be an entity join which fetches Person", QuerySpace.Disposition.ENTITY, disposition + ); + + iterator = personJoin.getRightHandSide().getJoins().iterator(); + assertTrue( "The composite address should be fetched", iterator.hasNext() ); + Join addressJoin = iterator.next(); + assertNotNull( addressJoin ); + disposition = addressJoin.getRightHandSide().getDisposition(); + assertEquals( QuerySpace.Disposition.COMPOSITE, disposition ); + iterator = addressJoin.getRightHandSide().getJoins().iterator(); + assertTrue( iterator.hasNext() ); + Join countryJoin = iterator.next(); + assertNotNull( countryJoin ); + disposition = countryJoin.getRightHandSide().getDisposition(); + assertEquals( QuerySpace.Disposition.ENTITY, disposition ); + assertFalse( + "The ManyToOne attribute in composite should not be fetched", + countryJoin.getRightHandSide().getJoins().iterator().hasNext() + ); + em.close(); + } + + private SessionFactoryImplementor sfi() { + return entityManagerFactory().unwrap( SessionFactoryImplementor.class ); + } + + private LoadPlan buildLoadPlan(EntityGraph entityGraph, Mode mode) { + + LoadQueryInfluencers loadQueryInfluencers = new LoadQueryInfluencers( sfi() ); + if ( Mode.FETCH == mode ) { + loadQueryInfluencers.setFetchGraph( entityGraph ); + } + else { + loadQueryInfluencers.setLoadGraph( entityGraph ); + } + EntityPersister ep = (EntityPersister) sfi().getClassMetadata( Cat.class ); + AbstractLoadPlanBuildingAssociationVisitationStrategy strategy = Mode.FETCH == mode ? new FetchGraphLoadPlanBuildingStrategy( + sfi(), loadQueryInfluencers, LockMode.NONE + ) : new LoadGraphLoadPlanBuildingStrategy( sfi(), loadQueryInfluencers, LockMode.NONE ); + return MetamodelDrivenLoadPlanBuilder.buildRootEntityLoadPlan( strategy, ep ); + } + + public static enum Mode {FETCH, LOAD} +}