diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/PersistenceContext.adoc b/documentation/src/main/asciidoc/userguide/chapters/pc/PersistenceContext.adoc index 7d509012e04f..ecfd7c54d072 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/PersistenceContext.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/pc/PersistenceContext.adoc @@ -135,50 +135,50 @@ Unless the entity class is declared `final`, the proxy extends the entity class. === Obtain an entity with its data initialized It is also quite common to want to obtain an entity along with its data (e.g. like when we need to display it in the UI). +Hibernate offers two flavors of this operation: -[[pc-find-jpa-example]] -.Obtaining an entity reference with its data initialized with Jakarta Persistence +find():: Performs the requested lookup, returning `null` if no matching row was found. +get():: Performs the requested lookup, throwing an exception if no matching row was found. + +[[pc-find-example]] +.Finding an initialized entity reference ==== [source, java, indent=0] ---- -include::{example-dir-pc}/PersistenceContextTest.java[tags=pc-find-jpa-example] +include::{example-dir-pc}/PersistenceContextTest.java[tags=pc-find-example] ---- ==== -[[pc-find-native-example]] -.Obtaining an entity reference with its data initialized with Hibernate API +[[pc-get-example]] +.Getting an initialized entity reference ==== - [source, java, indent=0] ---- -include::{example-dir-pc}/PersistenceContextTest.java[tags=pc-find-native-example] +include::{example-dir-pc}/PersistenceContextTest.java[tags=pc-get-example] ---- ==== -[[pc-find-by-id-native-example]] -.Obtaining an entity reference with its data initialized using the `byId()` Hibernate API -==== +Hibernate also offers a consistent way to `find()` and `get()` an entity by its <>. +[[pc-find-by-natual-id-example]] +.Finding an entity by natural-id +==== [source, java, indent=0] ---- -include::{example-dir-pc}/PersistenceContextTest.java[tags=pc-find-by-id-native-example] +include::{example-dir-pc}/PersistenceContextTest.java[tags=pc-find-by-natural-id-example] ---- ==== -In both cases null is returned if no matching database row was found. - -It's possible to return a Java 8 `Optional` as well: - -[[tag::pc-find-optional-by-id-native-example]] -.Obtaining an Optional entity reference with its data initialized using the `byId()` Hibernate API +[[pc-get-by-natual-id-example]] +.Getting an entity by natural-id ==== - [source, java, indent=0] ---- -include::{example-dir-pc}/PersistenceContextTest.java[tags=pc-find-optional-by-id-native-example] +include::{example-dir-pc}/PersistenceContextTest.java[tags=pc-get-by-natural-id-example] ---- ==== + [[pc-by-multiple-ids]] === Obtain multiple entities by their identifiers @@ -202,8 +202,8 @@ Hibernate offers this functionality via the `Session#findMultiple` methods which Now, assuming we have 3 `Person` entities in the database, we can load all of them with a single call as illustrated by the following example: -[[tag::pc-by-multiple-ids-example]] -.Loading multiple entities using the `findMultiple()` Hibernate API +[[tag::pc-find-multiple-example]] +.Loading multiple entities using `findMultiple()` ==== [source, java, indent=0] @@ -212,63 +212,30 @@ include::{example-dir-pc}/FindMultipleDocTests.java[tags=pc-find-multiple-exampl ---- ==== -[[pc-find-natural-id]] -=== Obtain an entity by natural-id +There is also `getMultiple()` which behaves in a similar manner to `get()` in that an exception is thrown if any of the identifiers could not be located. -In addition to allowing to load the entity by its identifier, Hibernate allows applications to load entities by the declared natural identifier. - -[[pc-find-by-natural-id-entity-example]] -.Natural-id mapping -==== -[source, java, indent=0] ----- -include::{example-dir-pc}/PersistenceContextTest.java[tags=pc-find-by-natural-id-entity-example] ----- +[[tag::pc-get-multiple-example]] +.Loading multiple entities using `getMultiple()` ==== -We can also opt to fetch the entity or just retrieve a reference to it when using the natural identifier loading methods. - -[[pc-find-by-simple-natural-id-example]] -.Get entity reference by simple natural-id -==== [source, java, indent=0] ---- -include::{example-dir-pc}/PersistenceContextTest.java[tags=pc-find-by-simple-natural-id-example] ----- -==== - -[[pc-find-by-natural-id-example]] -.Load entity by natural-id -==== -[source, java, indent=0] ----- -include::{example-dir-pc}/PersistenceContextTest.java[tags=pc-find-by-natural-id-example] +include::{example-dir-pc}/FindMultipleDocTests.java[tags=pc-find-multiple-example] ---- ==== -We can also use a Java 8 `Optional` to load an entity by its natural id: +Note that `findMultiple()` and `getMultiple()` both support loading by natural-id as well with the same semantics. -[[pc-find-optional-by-simple-natural-id-example]] -.Load an Optional entity by natural-id +[[tag::pc-get-multiple-example]] +.Loading multiple entities using `getMultiple()` ==== + [source, java, indent=0] ---- -include::{example-dir-pc}/PersistenceContextTest.java[tags=pc-find-optional-by-simple-natural-id-example] +include::{example-dir-pc}/FindMultipleDocTests.java[tags=pc-find-multiple-natural-id-example] ---- ==== -Hibernate offers a consistent API for accessing persistent data by identifier or by the natural-id. Each of these defines the same two data access methods: - -getReference:: - Should be used in cases where the identifier is assumed to exist, where non-existence would be an actual error. - Should never be used to test existence. - That is because this method will prefer to create and return a proxy if the data is not already associated with the Session rather than hit the database. - The quintessential use-case for using this method is to create foreign key based associations. -load:: - Will return the persistent data associated with the given identifier value or null if that identifier does not exist. - -Each of these two methods defines an overloading variant accepting a `org.hibernate.LockOptions` argument. -Locking is discussed in a separate <>. [[pc-filtering]] === Filtering entities and associations diff --git a/hibernate-core/hibernate-core.gradle b/hibernate-core/hibernate-core.gradle index 89a0da7869b1..06131cb2df00 100644 --- a/hibernate-core/hibernate-core.gradle +++ b/hibernate-core/hibernate-core.gradle @@ -128,12 +128,12 @@ xjc { xjcPlugins('inheritance', 'simplify') } configuration { - xsdFile = file( 'src/main/resources/org/hibernate/xsd/cfg/configuration-3.2.0.xsd' ) + xsdFile = file( 'src/main/resources/org/hibernate/xsd/cfg/configuration-8.0.xsd' ) xjcBindingFile = file( 'src/main/xjb/configuration-bindings.xjb' ) xjcPlugins('inheritance', 'simplify') } mapping { - xsdFile = file( 'src/main/resources/org/hibernate/xsd/mapping/mapping-7.0.xsd' ) + xsdFile = file( 'src/main/resources/org/hibernate/xsd/mapping/mapping-8.0.xsd' ) xjcBindingFile = file( 'src/main/xjb/mapping-bindings.xjb' ) xjcPlugins('inheritance', 'simplify') } diff --git a/hibernate-core/src/main/java/org/hibernate/Locking.java b/hibernate-core/src/main/java/org/hibernate/Locking.java index 5bf3cb2886b1..a1e759112308 100644 --- a/hibernate-core/src/main/java/org/hibernate/Locking.java +++ b/hibernate-core/src/main/java/org/hibernate/Locking.java @@ -72,8 +72,7 @@ enum Scope implements FindOption, LockOption, RefreshOption { /** * All tables with fetched rows will be locked. * - * @apiNote This is Hibernate's legacy behavior, and has no - * corresponding JPA scope. + * @see PessimisticLockScope#FETCHED */ INCLUDE_FETCHES; @@ -86,11 +85,14 @@ public PessimisticLockScope getCorrespondingJpaScope() { return switch (this) { case ROOT_ONLY -> PessimisticLockScope.NORMAL; case INCLUDE_COLLECTIONS -> PessimisticLockScope.EXTENDED; - case INCLUDE_FETCHES -> null; + case INCLUDE_FETCHES -> PessimisticLockScope.FETCHED; }; } public static Scope fromJpaScope(PessimisticLockScope scope) { + if ( scope == PessimisticLockScope.FETCHED ) { + return INCLUDE_FETCHES; + } if ( scope == PessimisticLockScope.EXTENDED ) { return INCLUDE_COLLECTIONS; } @@ -104,6 +106,20 @@ public static Scope interpret(String name) { } return valueOf( name.toUpperCase( Locale.ROOT ) ); } + + public static Scope fromHint(Object hintValue) { + assert hintValue != null; + + if ( hintValue instanceof Scope scope ) { + return scope; + } + + if ( hintValue instanceof PessimisticLockScope jpaScope ) { + return fromJpaScope( jpaScope ); + } + + return valueOf( hintValue.toString().toUpperCase( Locale.ROOT ) ); + } } /** diff --git a/hibernate-core/src/main/java/org/hibernate/Session.java b/hibernate-core/src/main/java/org/hibernate/Session.java index 79996816cb1c..8597ee331eea 100644 --- a/hibernate-core/src/main/java/org/hibernate/Session.java +++ b/hibernate-core/src/main/java/org/hibernate/Session.java @@ -486,24 +486,6 @@ public interface Session extends SharedSessionContract, EntityManager { @Override T find(Class entityType, Object id, FindOption... options); - /// Return the persistent instance of the named entity type with the given identifier, - /// or null if there is no such persistent instance. - /// - /// Differs from {@linkplain #find(Class, Object)} in that this form accepts - /// the entity name of a [dynamic entity][org.hibernate.metamodel.RepresentationMode#MAP]. - /// - /// @see #find(Class, Object) - Object find(String entityName, Object primaryKey); - - /// Return the persistent instance of the named entity type with the given identifier - /// using the specified options, or null if there is no such persistent instance. - /// - /// Differs from [#find(Class, Object, FindOption...)] in that this form accepts - /// the entity name of a [dynamic entity][org.hibernate.metamodel.RepresentationMode#MAP]. - /// - /// @see #find(Class, Object, FindOption...) - Object find(String entityName, Object primaryKey, FindOption... options); - /// Return the persistent instances of the given entity class with the given identifiers /// as a list. The position of an instance in the returned list matches the position of its /// identifier in the given list of identifiers, and the returned list contains a null value @@ -801,39 +783,6 @@ public interface Session extends SharedSessionContract, EntityManager { @Override void clear(); - /// Return the persistent instance of the given entity class with the given identifier, - /// or null if there is no such persistent instance. If the instance is already associated - /// with the session, return that instance. This method never returns an uninitialized - /// instance. - /// - /// The object returned by `get()` or `find()` is either an unproxied instance - /// of the given entity class, or a fully-fetched proxy object. - /// - /// This operation requests [LockMode#NONE], that is, no lock, allowing the object - /// to be retrieved from the cache without the cost of database access. However, if it is - /// necessary to read the state from the database, the object will be returned with the - /// lock mode [LockMode#READ]. - /// - /// To bypass the second-level cache, and ensure that the state is read from the database, - /// either: - /// - /// - call [#get(Class,Object,LockMode)] with the explicit lock mode - /// [LockMode#READ], or - /// - {@linkplain #setCacheMode set the cache mode} to [CacheMode#IGNORE] - /// before calling this method. - /// - /// @apiNote This operation is very similar to [#find(Class,Object)]. - /// - /// @param entityType the entity type - /// @param id an identifier - /// - /// @return a persistent instance or null - /// - /// @deprecated Because the semantics of this method may change in a future release. - /// Use [#find(Class,Object)] instead. - @Deprecated(since = "7.0", forRemoval = true) - T get(Class entityType, Object id); - /// Return the persistent instance of the given entity class with the given identifier, /// or null if there is no such persistent instance. If the instance is already associated /// with the session, return that instance. This method never returns an uninitialized @@ -851,26 +800,6 @@ public interface Session extends SharedSessionContract, EntityManager { @Deprecated(since = "7.0", forRemoval = true) T get(Class entityType, Object id, LockMode lockMode); - /// Return the persistent instance of the given named entity with the given identifier, - /// or null if there is no such persistent instance. If the instance is already associated - /// with the session, return that instance. This method never returns an uninitialized - /// instance. - /// - /// @param entityName the entity name - /// @param id an identifier - /// - /// @return a persistent instance or null - /// - /// @deprecated The semantics of this method may change in a future release. - /// Use [SessionFactory#createGraphForDynamicEntity(String)] - /// together with [#find(EntityGraph,Object,FindOption...)] - /// to load [dynamic entities][org.hibernate.metamodel.RepresentationMode#MAP]. - /// - /// @see SessionFactory#createGraphForDynamicEntity(String) - /// @see #find(EntityGraph, Object, FindOption...) - @Deprecated(since = "7", forRemoval = true) - Object get(String entityName, Object id); - /// Return the persistent instance of the given entity class with the given identifier, /// or null if there is no such persistent instance. If the instance is already associated /// with the session, return that instance. This method never returns an uninitialized @@ -1402,4 +1331,10 @@ public interface Session extends SharedSessionContract, EntityManager { default T unwrap(Class type) { return SharedSessionContract.super.unwrap(type); } + + /// @deprecated (since 8.0) Use #createNamedQuery instead. Still here to allow for + /// forms using Hibernate's legacy result-set building, though such usages should + /// move to using [jakarta.persistence.sql.ResultSetMapping]. + @Deprecated @SuppressWarnings("rawtypes") + NativeQuery getNamedNativeQuery(String name); } diff --git a/hibernate-core/src/main/java/org/hibernate/SharedSessionContract.java b/hibernate-core/src/main/java/org/hibernate/SharedSessionContract.java index 40be308448b8..8f4d85561e4e 100644 --- a/hibernate-core/src/main/java/org/hibernate/SharedSessionContract.java +++ b/hibernate-core/src/main/java/org/hibernate/SharedSessionContract.java @@ -10,13 +10,30 @@ import java.util.function.Function; import jakarta.persistence.EntityGraph; +import jakarta.persistence.EntityHandler; +import jakarta.persistence.FindOption; import jakarta.persistence.PersistenceException; +import jakarta.persistence.TypedQuery; +import jakarta.persistence.TypedQueryReference; +import jakarta.persistence.criteria.CriteriaDelete; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.CriteriaSelect; +import jakarta.persistence.criteria.CriteriaUpdate; +import jakarta.persistence.sql.ResultSetMapping; import org.hibernate.graph.RootGraph; import org.hibernate.jdbc.ReturningWork; import org.hibernate.jdbc.Work; import org.hibernate.procedure.ProcedureCall; -import org.hibernate.query.QueryProducer; +import org.hibernate.query.IllegalMutationQueryException; +import org.hibernate.query.IllegalSelectQueryException; +import org.hibernate.query.MutationQuery; +import org.hibernate.query.NativeQuery; +import org.hibernate.query.Query; +import org.hibernate.query.SelectionQuery; +import org.hibernate.query.SemanticException; +import org.hibernate.query.UnknownNamedQueryException; import org.hibernate.query.criteria.HibernateCriteriaBuilder; +import org.hibernate.query.criteria.JpaCriteriaInsert; import static org.hibernate.internal.TransactionManagement.manageTransaction; @@ -25,26 +42,7 @@ * * @author Steve Ebersole */ -public interface SharedSessionContract extends QueryProducer, AutoCloseable, Serializable { - - /** - * Obtain a {@link StatelessSession} builder with the ability to copy certain - * information from this session. - * - * @return the session builder - * - * @since 7.2 - */ - @Incubating - SharedStatelessSessionBuilder statelessWithOptions(); - - /** - * Obtain a {@link Session} builder with the ability to copy certain - * information from this session. - * - * @return the session builder - */ - SharedSessionBuilder sessionWithOptions(); +public interface SharedSessionContract extends EntityHandler, AutoCloseable, Serializable { /** * Obtain the tenant identifier associated with this session, as a string. @@ -184,6 +182,432 @@ public interface SharedSessionContract extends QueryProducer, AutoCloseable, Ser */ boolean isJoinedToTransaction(); + /// Corollary to [#find(Class,Object)] for dynamic models. + /// + /// @param entityName The entity name + /// @param id The identifier + /// @return The persistent instance, or null + /// @throws IllegalArgumentException If the given name does not match + /// a mapped dynamic entity + /// @see SessionFactory#createGraphForDynamicEntity(String) + /// @see #find(EntityGraph, Object, FindOption...) + default Object find(String entityName, Object id) { + return find( entityName, id, LockMode.NONE ); + } + + /// Corollary to [#find(Class,Object,FindOption...)] for dynamic models. + /// + /// @param entityName The entity name + /// @param key The key (primary or natural, based on [KeyType]) + /// @param findOptions Options for the load operation. + /// + /// @return The persistent instance, or null + /// + /// @throws IllegalArgumentException If the given name does not match + /// a mapped dynamic entity + /// + /// @see SessionFactory#createGraphForDynamicEntity(String) + /// @see #find(EntityGraph,Object,FindOption...) + Object find(String entityName, Object key, FindOption... findOptions); + + /// Form of [#find(String,Object)] throwing [jakarta.persistence.EntityNotFoundException] + /// if no entity exists for that id rather than returning null. + /// + /// @param entityName The entity name + /// @param id The identifier + /// @return The persistent instance + /// @throws IllegalArgumentException If the given name does not match + /// a mapped dynamic entity + /// @throws jakarta.persistence.EntityNotFoundException if no entity + /// was found for the given `id` + /// @see SessionFactory#createGraphForDynamicEntity(String) + /// @see #get(EntityGraph, Object, FindOption...) + default Object get(String entityName, Object id) { + return get( entityName, id, LockMode.NONE ); + } + + /// Form of [#find(String,Object,FindOption...)] throwing [jakarta.persistence.EntityNotFoundException] + /// if no entity exists for that id rather than returning null. + /// + /// @param entityName The entity name + /// @param key The key (primary or natural, based on [KeyType]) + /// @param findOptions Options for the load operation. + /// + /// @return a persistent instance + /// + /// @throws IllegalArgumentException If the given name does not match + /// a mapped dynamic entity + /// @throws jakarta.persistence.EntityNotFoundException if no entity + /// was found for the given `key` + /// + /// @see SessionFactory#createGraphForDynamicEntity(String) + /// @see #get(EntityGraph,Object,FindOption...) + Object get(String entityName, Object key, FindOption... findOptions); + + /** + * Create a typed {@link Query} instance for the given HQL query + * string and given query result type. + *
    + *
  • If the query has a single item in the {@code select} list, + * then the select item must be assignable to the given result + * type. + *
  • Otherwise, if there are multiple select items, then the + * select items will be packaged into an instance of the + * result type. The result type must have an appropriate + * constructor with parameter types matching the select items, + * or it must be one of the types {@code Object[]}, + * {@link java.util.List}, {@link java.util.Map}, or + * {@link jakarta.persistence.Tuple}. + *
+ *

+ * If a query has no explicit {@code select} list, the select list + * is inferred from the given query result type: + *

    + *
  • if the result type is an entity type, the query must have + * exactly one root entity in the {@code from} clause, it must + * be assignable to the result type, and the inferred select + * list will contain just that entity, or + *
  • otherwise, the select list contains every root entity and + * every non-{@code fetch} joined entity, and each query result + * will be packaged into an instance of the result type, just + * as specified above. + *
+ *

+ * If a query has no explicit {@code from} clause, and the given + * result type is an entity type, the root entity is inferred to + * be the result type. + *

+ * Passing {@code Object.class} as the query result type is not + * recommended. + *

+ * The returned {@code Query} may be executed by calling + * {@link Query#getResultList()} or {@link Query#getSingleResult()}. + * + * @param queryString The HQL query + * @param resultClass The {@link Class} object representing the + * query result type, which should not be + * {@code Object.class} + * @return The {@link Query} instance for manipulation and execution + * + * @see jakarta.persistence.EntityManager#createQuery(String,Class) + */ + @Override + Query createQuery(String queryString, Class resultClass); + + /** + * @see jakarta.persistence.EntityHandler#createQuery(String,EntityGraph) + */ + @Override + Query createQuery(String s, EntityGraph entityGraph); + + /** + * Create a {@link SelectionQuery} instance for the given HQL query + * string and given query result type. + *

    + *
  • If the query has a single item in the {@code select} list, + * then the select item must be assignable to the given result + * type. + *
  • Otherwise, if there are multiple select items, then the + * select items will be packaged into an instance of the + * result type. The result type must have an appropriate + * constructor with parameter types matching the select items, + * or it must be one of the types {@code Object[]}, + * {@link java.util.List}, {@link java.util.Map}, or + * {@link jakarta.persistence.Tuple}. + *
+ *

+ * If a query has no explicit {@code select} list, the select list + * is inferred from the given query result type: + *

    + *
  • if the result type is an entity type, the query must have + * exactly one root entity in the {@code from} clause, it must + * be assignable to the result type, and the inferred select + * list will contain just that entity, or + *
  • otherwise, the select list contains every root entity and + * every non-{@code fetch} joined entity, and each query result + * will be packaged into an instance of the result type, just + * as specified above. + *
+ *

+ * If a query has no explicit {@code from} clause, and the given + * result type is an entity type, the root entity is inferred to + * be the result type. + *

+ * Passing {@code Object.class} as the query result type is not + * recommended. + *

+ * The returned {@code Query} may be executed by calling + * {@link Query#getResultList()} or {@link Query#getSingleResult()}. + + * @param hqlString The HQL {@code select} query as a string + * @param resultType The {@link Class} object representing the + * query result type, which should not be + * {@code Object.class} + * + * @see jakarta.persistence.EntityManager#createQuery(String) + * + * @throws IllegalSelectQueryException if the given HQL query + * is an {@code insert}, {@code update} or {@code delete} + * statement + */ + SelectionQuery createSelectionQuery(String hqlString, Class resultType); + + /** + * Create a {@link SelectionQuery} instance for the given HQL query + * string and given {@link EntityGraph}, which is interpreted as a + * {@linkplain org.hibernate.graph.GraphSemantic#LOAD load graph}. + * The query result type is the root entity of the given graph. + *

    + *
  • If the query has an explicit {@code select} clause, there must + * be a single item in the {@code select} list, and the select + * item must be assignable to the root type of the given graph. + *
  • Otherwise, if a query has no explicit {@code select} list, the + * select list is inferred from the given entity graph. The query + * must have exactly one root entity in the {@code from} clause, + * it must be assignable to the root type of the given graph, and + * the inferred select list will contain just that entity. + *
+ *

+ * If a query has no explicit {@code from} clause, and the given + * result type is an entity type, the root entity is inferred to + * be the result type. + *

+ * The returned {@code Query} may be executed by calling + * {@link Query#getResultList()} or {@link Query#getSingleResult()}. + + * @param hqlString The HQL {@code select} query as a string + * @param resultGraph An {@link EntityGraph} whose root type is the + * query result type, which is interpreted as a + * {@linkplain org.hibernate.graph.GraphSemantic#LOAD + * load graph} + * + * @see jakarta.persistence.EntityManager#createQuery(String) + * + * @throws IllegalSelectQueryException if the given HQL query + * is an {@code insert}, {@code update} or {@code delete} + * statement + * + * @since 7.0 + */ + SelectionQuery createSelectionQuery(String hqlString, EntityGraph resultGraph); + + /** + * Create a {@link MutationQuery} reference for the given HQL insert, + * update, or delete statement. + * + * @param hqlString The HQL {@code insert}, {@code update}, or + * {@code delete} statement + * + * @throws IllegalMutationQueryException if the given HQL query + * is a {@code select} query + */ + MutationQuery createMutationQuery(String hqlString); + + /** + * Create a typed {@link Query} instance for the given typed query reference. + * + * @param typedQueryReference the type query reference + * + * @return The {@link Query} instance for execution + * + * @throws IllegalArgumentException if a query has not been + * defined with the name of the typed query reference or if + * the query result is found to not be assignable to + * result class of the typed query reference + * + * @see jakarta.persistence.EntityManager#createQuery(TypedQueryReference) + */ + @Override + Query createQuery(TypedQueryReference typedQueryReference); + + /** + * Create a {@link Query} for the given JPA {@link CriteriaQuery}. + */ + @Override + Query createQuery(CriteriaQuery criteriaQuery); + + /** + * @see jakarta.persistence.EntityHandler#createQuery(CriteriaSelect) + */ + @Override + Query createQuery(CriteriaSelect criteriaSelect); + + /** + * @see jakarta.persistence.EntityHandler#createQuery(CriteriaUpdate) + */ + @Override + Query createQuery(CriteriaUpdate criteriaUpdate); + + /** + * @see jakarta.persistence.EntityHandler#createQuery(CriteriaDelete) + */ + @Override + Query createQuery(CriteriaDelete criteriaDelete); + + /** + * Create a {@link SelectionQuery} reference for the given + * {@link CriteriaQuery}. + * + * @see jakarta.persistence.EntityManager#createQuery(CriteriaSelect) + */ + SelectionQuery createSelectionQuery(CriteriaSelect criteria); + + /** + * Create a {@link SelectionQuery} reference for the given + * {@link CriteriaQuery}. + * + * @see jakarta.persistence.EntityManager#createQuery(CriteriaQuery) + */ + SelectionQuery createSelectionQuery(CriteriaQuery criteria); + + /** + * Create a {@link MutationQuery} from the given update criteria tree + */ + MutationQuery createMutationQuery(@SuppressWarnings("rawtypes") CriteriaUpdate updateQuery); + + /** + * Create a {@link MutationQuery} from the given delete criteria tree + */ + MutationQuery createMutationQuery(@SuppressWarnings("rawtypes") CriteriaDelete deleteQuery); + + /** + * Create a {@link MutationQuery} from the given insert criteria tree + */ + MutationQuery createMutationQuery(@SuppressWarnings("rawtypes") JpaCriteriaInsert insert); + + /** + * Create a {@link NativeQuery} instance for the given native SQL query. + * + * @param sqlString The native (SQL) query string + * + * @return The {@link NativeQuery} instance for manipulation and execution + * + * @see jakarta.persistence.EntityHandler#createNativeQuery(String) + */ + @Override + NativeQuery createNativeQuery(String sqlString); + + /** + * Create a {@link NativeQuery} instance for the given native SQL query + * using an implicit mapping to the specified Java type. + *

    + *
  • If the given class is an entity class, this method is equivalent + * to {@code createNativeQuery(sqlString).addEntity(resultClass)}. + *
  • If the given class has a registered + * {@link org.hibernate.type.descriptor.java.JavaType}, then the + * query must return a result set with a single column whose + * {@code JdbcType} is compatible with that {@code JavaType}. + *
  • Otherwise, the select items will be packaged into an instance of + * the result type. The result type must have an appropriate + * constructor with parameter types matching the select items, or it + * must be one of the types {@code Object[]}, {@link java.util.List}, + * {@link java.util.Map}, or {@link jakarta.persistence.Tuple}. + *
+ * + * @param sqlString The native (SQL) query string + * @param resultClass The Java type to map results to + * + * @return The {@link NativeQuery} instance for manipulation and execution + * + * @see jakarta.persistence.EntityHandler#createNativeQuery(String,Class) + */ + @Override + NativeQuery createNativeQuery(String sqlString, Class resultClass); + + /** + * Create a {@link NativeQuery} instance for the given native SQL query + * using an implicit mapping to the specified Java entity type. + *

+ * The given class must be an entity class. This method is equivalent to + * {@code createNativeQuery(sqlString).addEntity(tableAlias, resultClass)}. + * + * @param sqlString Native (SQL) query string + * @param resultClass The Java entity class to map results to + * @param tableAlias The table alias for columns in the result set + * + * @return The {@link NativeQuery} instance for manipulation and execution + * + * @see jakarta.persistence.EntityManager#createNativeQuery(String,Class) + */ + NativeQuery createNativeQuery(String sqlString, Class resultClass, String tableAlias); + + /** + * Create a {@link NativeQuery} instance for the given native SQL query + * using an explicit mapping to the specified Java type. + *

+ * The given result set mapping name must identify a mapping defined by + * a {@link jakarta.persistence.SqlResultSetMapping} annotation. + * + * @param sqlString The native (SQL) query string + * @param resultSetMappingName The explicit result mapping name + * + * @return The {@link NativeQuery} instance for manipulation and execution + * + * @see jakarta.persistence.EntityManager#createNativeQuery(String,Class) + * @see jakarta.persistence.SqlResultSetMapping + */ + NativeQuery createNativeQuery(String sqlString, String resultSetMappingName, Class resultClass); + + /** + * Create a {@link NativeQuery} instance for the given native SQL statement. + * + * @param sqlString a native SQL statement string + * + * @return The NativeQuery instance for manipulation and execution + */ + MutationQuery createNativeMutationQuery(String sqlString); + + /** + * Create a typed {@link Query} instance for the given named query. + * The named query might be defined in HQL or in native SQL. + * + * @param name the name of a query defined in metadata + * @param resultClass the type of the query result + * + * @return The {@link Query} instance for manipulation and execution + * + * @throws IllegalArgumentException if a query has not been + * defined with the given name or if the query string is + * found to be invalid or if the query result is found to + * not be assignable to the specified type + * + * @see jakarta.persistence.EntityManager#createNamedQuery(String,Class) + */ + @Override + Query createNamedQuery(String name, Class resultClass); + + @Override + Query createNamedQuery(String s); + + NativeQuery createNamedQuery(String name, String resultSetMappingName); + NativeQuery createNamedQuery(String name, String resultSetMappingName, Class resultClass); + + @Override + NativeQuery createNativeQuery(String sql, String resultSetMapping); + + @Override + TypedQuery createNativeQuery(String sql, ResultSetMapping resultSetMapping); + + /** + * Create a {@link SelectionQuery} instance for the named + * {@link jakarta.persistence.NamedQuery} with the given result type. + * + * @throws IllegalSelectQueryException if the given HQL query is not a select query + * @throws UnknownNamedQueryException if no query has been defined with the given name + */ + SelectionQuery createNamedSelectionQuery(String name, Class resultType); + + /** + * Create a {@link MutationQuery} instance for the given named insert, + * update, or delete HQL query. The named query might be defined as + * {@linkplain jakarta.persistence.NamedQuery HQL}) or + * {@linkplain jakarta.persistence.NamedNativeQuery native-SQL}. + * + * @throws IllegalMutationQueryException if the given HQL query is a select query + * @throws UnknownNamedQueryException if no query has been defined with the given name + */ + MutationQuery createNamedMutationQuery(String name); + /** * Obtain a {@link ProcedureCall} based on a named template * @@ -497,6 +921,25 @@ default R fromTransaction(Function action) { return manageTransaction( transaction, transaction, action ); } + /** + * Obtain a {@link StatelessSession} builder with the ability to copy certain + * information from this session. + * + * @return the session builder + * + * @since 7.2 + */ + @Incubating + SharedStatelessSessionBuilder statelessWithOptions(); + + /** + * Obtain a {@link Session} builder with the ability to copy certain + * information from this session. + * + * @return the session builder + */ + SharedSessionBuilder sessionWithOptions(); + /** * Return an object of the specified type to allow access to * a provider-specific API. @@ -520,4 +963,53 @@ default T unwrap(Class type) { throw new PersistenceException( "Hibernate cannot unwrap '" + getClass().getName() + "' as '" + type.getName() + "'" ); } + + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Deprecations + + + /** + * Create a {@link Query} instance for the given HQL query, or + * HQL insert, update, or delete statement. + *

+ * If a query has no explicit {@code select} list, the select list + * is inferred: + *

    + *
  • if there is exactly one root entity in the {@code from} + * clause, and it has no non-{@code fetch} joins, then that + * root entity is the only element of the select list, or + *
  • if there is an entity with the alias {@code this}, then + * that entity is the only element of the select list, or + *
  • otherwise, the query is considered ambiguous, and this + * method throws a {@link SemanticException}. + *
+ *

+ * The query must have an explicit {@code from} clause, which + * can never be inferred. + * + * @deprecated The overloaded form + * {@link #createQuery(String, Class)} which takes a result type + * is strongly recommended in preference to this method, since it + * returns a typed {@code Query} object, and because it is able to + * use the given result type to infer the {@code select} list, and + * even sometimes the {@code from} clause. Alternatively, + * {@link #createSelectionQuery(String, Class)} is preferred for + * queries, and {@link #createMutationQuery(String)} for insert, + * update, and delete statements. + * + * @apiNote Returns a raw {@code Query} type instead of a wildcard + * type {@code Query}, to match the signature of the JPA method + * {@link jakarta.persistence.EntityManager#createQuery(String)}. + * + * @param queryString The HQL query + * + * @return The {@link Query} instance for manipulation and execution + * + * @see jakarta.persistence.EntityManager#createQuery(String) + */ + @Override + @Deprecated + @SuppressWarnings("rawtypes") + Query createQuery(String queryString); } diff --git a/hibernate-core/src/main/java/org/hibernate/StatelessSession.java b/hibernate-core/src/main/java/org/hibernate/StatelessSession.java index d3b320a814e5..a4a002ee3f45 100644 --- a/hibernate-core/src/main/java/org/hibernate/StatelessSession.java +++ b/hibernate-core/src/main/java/org/hibernate/StatelessSession.java @@ -4,6 +4,7 @@ */ package org.hibernate; +import jakarta.persistence.EntityAgent; import jakarta.persistence.EntityGraph; import org.hibernate.graph.GraphSemantic; @@ -78,7 +79,7 @@ * * @author Gavin King */ -public interface StatelessSession extends SharedSessionContract { +public interface StatelessSession extends SharedSessionContract, EntityAgent { /** * Insert a record. @@ -94,7 +95,7 @@ public interface StatelessSession extends SharedSessionContract { * * @return The identifier of the inserted entity */ - Object insert(Object entity); + void insert(Object entity); /** * Insert multiple records in the same order as the entity @@ -238,28 +239,6 @@ public interface StatelessSession extends SharedSessionContract { @Incubating void upsert(String entityName, Object entity); - /** - * Retrieve a record. - * - * @param entityName The name of the entity to retrieve - * @param id The id of the entity to retrieve - * - * @return a detached entity instance, or null if there - * is no instance with the given id - */ - Object get(String entityName, Object id); - - /** - * Retrieve a record. - * - * @param entityClass The class of the entity to retrieve - * @param id The id of the entity to retrieve - * - * @return a detached entity instance, or null if there - * is no instance with the given id - */ - T get(Class entityClass, Object id); - /** * Retrieve a record, obtaining the specified lock mode. * @@ -471,7 +450,7 @@ public interface StatelessSession extends SharedSessionContract { * * @since 6.0 */ - void fetch(Object association); + T fetch(T association); /** * Return the identifier value of the given entity, which may be detached. @@ -483,4 +462,7 @@ public interface StatelessSession extends SharedSessionContract { * @since 6.6 */ Object getIdentifier(Object entity); + + @Override + T unwrap(Class type); } diff --git a/hibernate-core/src/main/java/org/hibernate/Timeouts.java b/hibernate-core/src/main/java/org/hibernate/Timeouts.java index c96315975244..7897c979199f 100644 --- a/hibernate-core/src/main/java/org/hibernate/Timeouts.java +++ b/hibernate-core/src/main/java/org/hibernate/Timeouts.java @@ -5,6 +5,15 @@ package org.hibernate; import jakarta.persistence.Timeout; +import org.hibernate.internal.log.DeprecationLogger; + +import java.util.Map; + +import static org.hibernate.cfg.AvailableSettings.JAKARTA_LOCK_TIMEOUT; +import static org.hibernate.jpa.HibernateHints.HINT_TIMEOUT; +import static org.hibernate.jpa.LegacySpecHints.HINT_JAVAEE_QUERY_TIMEOUT; +import static org.hibernate.jpa.SpecHints.HINT_SPEC_LOCK_TIMEOUT; +import static org.hibernate.jpa.SpecHints.HINT_SPEC_QUERY_TIMEOUT; /** * Helpers for dealing with {@linkplain jakarta.persistence.Timeout timeout} @@ -110,7 +119,7 @@ static boolean isMagicValue(int millis) { * Functionally, returns whether the {@linkplain Timeout#milliseconds() value} is greater than zero. */ static boolean isRealTimeout(Timeout timeout) { - return isRealTimeout( timeout.milliseconds() ); + return timeout != null && isRealTimeout( timeout.milliseconds() ); } /** @@ -128,6 +137,10 @@ static int getTimeoutInSeconds(Timeout timeout) { return getTimeoutInSeconds( timeout.milliseconds() ); } + static Integer getEffectiveTimeoutInSeconds(Timeout timeout) { + return timeout == null ? null : getTimeoutInSeconds( timeout ); + } + /** * Get the number of (whole) seconds represented by the given {@code timeout}. */ @@ -137,14 +150,37 @@ static int getTimeoutInSeconds(int timeoutInMilliseconds) { return timeoutInMilliseconds == 0 ? 0 : Math.max( 1, Math.round( timeoutInMilliseconds / 1e3f ) ); } - static int fromHint(Object factoryHint) { - if ( factoryHint instanceof Timeout timeout ) { - return timeout.milliseconds(); + static Timeout fromHints(Map properties) { + var result = lockTimeoutFromHints( properties ); + if ( result == null ) { + result = statementTimeoutFromHints( properties ); } - if ( factoryHint instanceof Integer number ) { - return number; + return result; + } + + static Timeout lockTimeoutFromHints(Map properties) { + var lockTimeoutRef = properties.get( HINT_SPEC_LOCK_TIMEOUT ); + if ( lockTimeoutRef == null ) { + lockTimeoutRef = properties.get( JAKARTA_LOCK_TIMEOUT ); + if ( lockTimeoutRef != null ) { + DeprecationLogger.DEPRECATION_LOGGER.deprecatedHint( JAKARTA_LOCK_TIMEOUT, HINT_SPEC_LOCK_TIMEOUT ); + } + } + return Timeouts.fromHintTimeout( lockTimeoutRef ); + } + + static Timeout statementTimeoutFromHints(Map properties) { + var timeoutRef = properties.get( HINT_TIMEOUT ); + if ( timeoutRef == null ) { + timeoutRef = properties.get( HINT_SPEC_QUERY_TIMEOUT ); + } + if ( timeoutRef == null ) { + timeoutRef = properties.get( HINT_JAVAEE_QUERY_TIMEOUT ); + if ( timeoutRef != null ) { + DeprecationLogger.DEPRECATION_LOGGER.deprecatedHint( HINT_SPEC_QUERY_TIMEOUT, HINT_JAVAEE_QUERY_TIMEOUT ); + } } - return Integer.parseInt( factoryHint.toString() ); + return Timeouts.fromHintTimeout( timeoutRef ); } static Timeout fromHintTimeout(Object factoryHint) { diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/NamedHqlQueryDefinitionImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/NamedHqlQueryDefinitionImpl.java index b6663f62393a..56bc31ce1d38 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/NamedHqlQueryDefinitionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/NamedHqlQueryDefinitionImpl.java @@ -4,18 +4,18 @@ */ package org.hibernate.boot.internal; -import java.util.Map; - +import jakarta.persistence.Timeout; +import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.CacheMode; import org.hibernate.FlushMode; import org.hibernate.LockOptions; -import org.hibernate.boot.spi.AbstractNamedQueryDefinition; import org.hibernate.boot.query.NamedHqlQueryDefinition; +import org.hibernate.boot.spi.AbstractNamedQueryDefinition; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.query.hql.internal.NamedHqlQueryMementoImpl; import org.hibernate.query.sqm.spi.NamedSqmQueryMemento; -import org.checkerframework.checker.nullness.qual.Nullable; +import java.util.Map; /** * @author Steve Ebersole @@ -38,7 +38,7 @@ public NamedHqlQueryDefinitionImpl( FlushMode flushMode, Boolean readOnly, LockOptions lockOptions, - Integer timeout, + Timeout timeout, Integer fetchSize, String comment, Map parameterTypes, diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/NamedNativeQueryDefinitionImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/NamedNativeQueryDefinitionImpl.java index 63719d8e0174..58862a147fce 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/NamedNativeQueryDefinitionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/NamedNativeQueryDefinitionImpl.java @@ -7,6 +7,7 @@ import java.util.Map; import java.util.Set; +import jakarta.persistence.Timeout; import org.hibernate.CacheMode; import org.hibernate.FlushMode; import org.hibernate.boot.spi.AbstractNamedQueryDefinition; @@ -39,7 +40,7 @@ public NamedNativeQueryDefinitionImpl( CacheMode cacheMode, FlushMode flushMode, Boolean readOnly, - Integer timeout, + Timeout timeout, Integer fetchSize, String comment, Integer firstResult, diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/NamedProcedureCallDefinitionImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/NamedProcedureCallDefinitionImpl.java index a0eb40699f28..7bb05fbdb297 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/NamedProcedureCallDefinitionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/NamedProcedureCallDefinitionImpl.java @@ -10,6 +10,11 @@ import java.util.Map; import java.util.Set; +import jakarta.persistence.CacheRetrieveMode; +import jakarta.persistence.CacheStoreMode; +import jakarta.persistence.LockModeType; +import jakarta.persistence.PessimisticLockScope; +import jakarta.persistence.Timeout; import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.CacheMode; import org.hibernate.FlushMode; @@ -22,7 +27,7 @@ import org.hibernate.procedure.internal.NamedCallableQueryMementoImpl; import org.hibernate.procedure.spi.NamedCallableQueryMemento; import org.hibernate.procedure.spi.ParameterStrategy; -import org.hibernate.query.results.ResultSetMapping; +import org.hibernate.query.results.spi.ResultSetMapping; import jakarta.persistence.NamedStoredProcedureQuery; import jakarta.persistence.ParameterMode; @@ -214,4 +219,34 @@ private static String normalize(String name) { public Map getHints() { return hints; } + + @Override + public CacheRetrieveMode getCacheRetrieveMode() { + return null; + } + + @Override + public CacheStoreMode getCacheStoreMode() { + return null; + } + + @Override + public LockModeType getLockMode() { + return null; + } + + @Override + public PessimisticLockScope getPessimisticLockScope() { + return null; + } + + @Override + public Timeout getTimeout() { + return null; + } + + @Override + public String getEntityGraphName() { + return ""; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/cfg/internal/TransactionTypeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/cfg/internal/TransactionTypeMarshalling.java index 2a93eaed3afa..5873613a2935 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/cfg/internal/TransactionTypeMarshalling.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/cfg/internal/TransactionTypeMarshalling.java @@ -6,12 +6,13 @@ import org.hibernate.internal.util.StringHelper; -import jakarta.persistence.spi.PersistenceUnitTransactionType; +import jakarta.persistence.PersistenceUnitTransactionType; /** + * JAXB marshal/unmarshal support for {@linkplain PersistenceUnitTransactionType}. + * * @author Steve Ebersole */ -@SuppressWarnings("removal") public class TransactionTypeMarshalling { public static PersistenceUnitTransactionType fromXml(String name) { if ( StringHelper.isEmpty( name ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/ConfigurationBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/ConfigurationBinder.java index ea5f3962e99f..38e2c7741128 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/ConfigurationBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/ConfigurationBinder.java @@ -44,7 +44,7 @@ protected Binding doBind( final XMLEventReader reader = new ConfigurationEventReader( staxEventReader, xmlEventFactory ); final JaxbPersistenceImpl bindingRoot = jaxb( reader, - ConfigXsdSupport.configurationXsd().getSchema(), + ConfigXsdSupport.latestDescriptor().getSchema(), jaxbContext(), origin ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/FetchTypeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/FetchTypeMarshalling.java index 9e8c2e174470..26368468d5d8 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/FetchTypeMarshalling.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/FetchTypeMarshalling.java @@ -13,7 +13,9 @@ */ public class FetchTypeMarshalling { public static FetchType fromXml(String name) { - return name == null ? null : FetchType.valueOf( name ); + final FetchType result = name == null ? null : FetchType.valueOf( name ); + assert result != FetchType.DEFAULT; + return result; } public static String toXml(FetchType fetchType) { diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/PessimisticLockScopeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/PessimisticLockScopeMarshalling.java new file mode 100644 index 000000000000..bb370e1771f2 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/PessimisticLockScopeMarshalling.java @@ -0,0 +1,20 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.boot.jaxb.mapping.internal; + +import jakarta.persistence.PessimisticLockScope; + +/// JAXB marshaling for [PessimisticLockScope] +/// +/// @author Steve Ebersole +public class PessimisticLockScopeMarshalling { + public static PessimisticLockScope fromXml(String name) { + return name == null ? null : PessimisticLockScope.valueOf( name ); + } + + public static String toXml(PessimisticLockScope lockScope) { + return lockScope == null ? null : lockScope.name(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/TimeoutMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/TimeoutMarshalling.java new file mode 100644 index 000000000000..d04ebbe038fd --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/TimeoutMarshalling.java @@ -0,0 +1,20 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.boot.jaxb.mapping.internal; + +import jakarta.persistence.Timeout; + +/// JAXB marshaling for [Timeout] +/// +/// @author Steve Ebersole +public class TimeoutMarshalling { + public static Timeout fromXml(String value) { + return value == null ? null : Timeout.seconds( Integer.parseInt( value ) ); + } + + public static String toXml(Timeout timeout) { + return timeout == null ? null : Integer.toString( timeout.milliseconds() * 1000 ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbNamedQuery.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbNamedQuery.java index f1983b13b65a..0cd849e86215 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbNamedQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbNamedQuery.java @@ -6,6 +6,7 @@ import java.util.List; +import jakarta.persistence.Timeout; import org.hibernate.CacheMode; import org.hibernate.FlushMode; @@ -15,7 +16,7 @@ public interface JaxbNamedQuery extends JaxbQueryHintContainer { String getQuery(); String getComment(); - Integer getTimeout(); + Timeout getTimeout(); Boolean isCacheable(); String getCacheRegion(); Integer getFetchSize(); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BinderHelper.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BinderHelper.java index 0b980091f048..4b69d1715ede 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BinderHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BinderHelper.java @@ -874,6 +874,7 @@ public static FetchMode getFetchMode(FetchType fetch) { return switch ( fetch ) { case EAGER -> FetchMode.JOIN; case LAZY -> FetchMode.SELECT; + case DEFAULT -> throw new UnsupportedOperationException( "Not implemented yet - decide how to handle" ); }; } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java index 646426742685..148120dc56c3 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java @@ -83,6 +83,7 @@ import static jakarta.persistence.AccessType.PROPERTY; import static jakarta.persistence.ConstraintMode.NO_CONSTRAINT; import static jakarta.persistence.ConstraintMode.PROVIDER_DEFAULT; +import static jakarta.persistence.FetchType.DEFAULT; import static jakarta.persistence.FetchType.LAZY; import static org.hibernate.annotations.CascadeType.DELETE_ORPHAN; import static org.hibernate.boot.BootLogging.BOOT_LOGGER; @@ -114,6 +115,7 @@ import static org.hibernate.boot.models.annotations.internal.JoinColumnJpaAnnotation.toJoinColumn; import static org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle.fromResultCheckStyle; import static org.hibernate.internal.util.ReflectHelper.getDefaultSupplier; +import static org.hibernate.internal.util.StringHelper.coalesce; import static org.hibernate.internal.util.StringHelper.getNonEmptyOrConjunctionIfBothNonEmpty; import static org.hibernate.internal.util.StringHelper.isBlank; import static org.hibernate.internal.util.StringHelper.isNotBlank; @@ -1434,23 +1436,23 @@ private void handleLazy() { private FetchType getJpaFetchType() { final var oneToMany = property.getDirectAnnotationUsage( OneToMany.class ); - final var manyToMany = property.getDirectAnnotationUsage( ManyToMany.class ); - final var elementCollection = property.getDirectAnnotationUsage( ElementCollection.class ); - final var manyToAny = property.getDirectAnnotationUsage( ManyToAny.class ); if ( oneToMany != null ) { - return oneToMany.fetch(); + return handlingDefault( oneToMany.fetch() ); } + final var manyToMany = property.getDirectAnnotationUsage( ManyToMany.class ); if ( manyToMany != null ) { - return manyToMany.fetch(); + return handlingDefault( manyToMany.fetch() ); } + final var elementCollection = property.getDirectAnnotationUsage( ElementCollection.class ); if ( elementCollection != null ) { - return elementCollection.fetch(); + return handlingDefault( elementCollection.fetch() ); } + final var manyToAny = property.getDirectAnnotationUsage( ManyToAny.class ); if ( manyToAny != null ) { - return manyToAny.fetch(); + return handlingDefault( manyToAny.fetch() ); } throw new AssertionFailure( @@ -1458,6 +1460,10 @@ private FetchType getJpaFetchType() { ); } + private FetchType handlingDefault(FetchType specifiedType) { + return specifiedType == DEFAULT ? LAZY : specifiedType; + } + TypeDetails getElementType() { if ( isDefault( targetEntity ) ) { if ( collectionElementType != null ) { @@ -1836,7 +1842,7 @@ private void setMapKey(MapKey key) { hasMapKeyProperty = key != null; if ( hasMapKeyProperty ) { // JPA says: if missing, use primary key of associated entity - mapKeyPropertyName = nullIfEmpty( key.name() ); + mapKeyPropertyName = coalesce( key.value(), key.name() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java index 5b47e47ff3c1..26433813f05c 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java @@ -157,7 +157,7 @@ import static org.hibernate.internal.util.StringHelper.unqualify; import static org.hibernate.internal.util.collections.CollectionHelper.isEmpty; import static org.hibernate.internal.util.collections.CollectionHelper.isNotEmpty; -import static org.hibernate.jpa.event.internal.CallbackDefinitionResolver.resolveLifecycleCallbacks; +import static org.hibernate.jpa.boot.internal.CallbackDefinitionResolver.resolveLifecycleCallbacks; import static org.hibernate.models.spi.TypeDetailsHelper.resolveRelativeType; import static org.hibernate.property.access.spi.BuiltInPropertyAccessStrategies.EMBEDDED; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/QueryBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/QueryBinder.java index 6c114cead078..229590a20066 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/QueryBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/QueryBinder.java @@ -13,6 +13,7 @@ import jakarta.persistence.QueryHint; import jakarta.persistence.SqlResultSetMapping; import jakarta.persistence.StoredProcedureParameter; +import jakarta.persistence.Timeout; import org.hibernate.AnnotationException; import org.hibernate.CacheMode; import org.hibernate.FlushMode; @@ -104,7 +105,7 @@ private static NamedHqlQueryDefinitionImpl createNamedQueryDefinition( .setCacheable(hints.getCacheability()) .setCacheMode(hints.getCacheMode()) .setCacheRegion(hints.getString(HibernateHints.HINT_CACHE_REGION)) - .setTimeout(hints.getTimeout()) + .setTimeout(hints.getTimeoutRef()) .setFetchSize(hints.getInteger(HibernateHints.HINT_FETCH_SIZE)) .setFlushMode(hints.getFlushMode()) .setReadOnly(hints.getBooleanWrapper(HibernateHints.HINT_READ_ONLY)) @@ -164,7 +165,7 @@ private static NamedNativeQueryDefinition createNamedQueryDefinition( .setCacheable(hints.getCacheability()) .setCacheMode(hints.getCacheMode()) .setCacheRegion(hints.getString(HibernateHints.HINT_CACHE_REGION)) - .setTimeout(hints.getTimeout()) + .setTimeout(hints.getTimeoutRef()) .setFetchSize(hints.getInteger(HibernateHints.HINT_FETCH_SIZE)) .setFlushMode(hints.getFlushMode()) .setReadOnly(hints.getBooleanWrapper(HibernateHints.HINT_READ_ONLY)) @@ -239,7 +240,8 @@ private static NamedNativeQueryDefinition.Builder createQueryDefinition( org.hibernate.annotations.NamedNativeQuery namedNativeQuery, String registrationName, String resultSetMappingName, Class resultClass, - int timeout, int fetchSize, + int timeout, + int fetchSize, HashSet querySpaces, AnnotationTarget location) { return new NamedNativeQueryDefinition.Builder(registrationName, location) @@ -249,7 +251,7 @@ private static NamedNativeQueryDefinition.Builder createQueryDefinition( .setCacheable(namedNativeQuery.cacheable()) .setCacheRegion(nullIfEmpty(namedNativeQuery.cacheRegion())) .setCacheMode(getCacheMode(namedNativeQuery.cacheRetrieveMode(), namedNativeQuery.cacheStoreMode())) - .setTimeout(timeout < 0 ? null : timeout) + .setTimeout(timeout < 0 ? null : Timeout.seconds( timeout ) ) .setFetchSize(fetchSize < 0 ? null : fetchSize) .setFlushMode(getFlushMode(namedNativeQuery.flush(), namedNativeQuery.flushMode())) .setReadOnly(namedNativeQuery.readOnly()) @@ -395,7 +397,7 @@ private static NamedHqlQueryDefinition.Builder createQueryDefinition( .setCacheable(namedQuery.cacheable()) .setCacheRegion(nullIfEmpty(namedQuery.cacheRegion())) .setCacheMode(getCacheMode(namedQuery.cacheRetrieveMode(), namedQuery.cacheStoreMode())) - .setTimeout(timeout < 0 ? null : timeout) + .setTimeout(timeout < 0 ? null : Timeout.seconds( timeout )) .setFetchSize(fetchSize < 0 ? null : fetchSize) .setFlushMode(getFlushMode(namedQuery.flush(), namedQuery.flushMode())) .setReadOnly(namedQuery.readOnly()) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/QueryHintDefinition.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/QueryHintDefinition.java index e8d21ae2effd..ab16180dd757 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/QueryHintDefinition.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/QueryHintDefinition.java @@ -6,6 +6,7 @@ import java.util.Map; +import jakarta.persistence.Timeout; import org.hibernate.AnnotationException; import org.hibernate.CacheMode; import org.hibernate.FlushMode; @@ -109,6 +110,11 @@ public Integer getTimeout() { return getInteger( HibernateHints.HINT_TIMEOUT ); } + public Timeout getTimeoutRef() { + final Integer timeoutSeconds = getTimeout(); + return timeoutSeconds == null ? null : Timeout.seconds( timeoutSeconds ); + } + public boolean getCacheability() { return getBoolean( HibernateHints.HINT_CACHEABLE ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ToOneBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ToOneBinder.java index 86352cdafc7b..4b19cf41d650 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ToOneBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ToOneBinder.java @@ -43,6 +43,7 @@ import jakarta.persistence.PrimaryKeyJoinColumn; import jakarta.persistence.PrimaryKeyJoinColumns; +import static jakarta.persistence.FetchType.DEFAULT; import static jakarta.persistence.FetchType.EAGER; import static jakarta.persistence.FetchType.LAZY; import static org.hibernate.boot.model.internal.BinderHelper.aggregateCascadeTypes; @@ -347,7 +348,7 @@ private static void handleLazy(ToOne toOne, MemberDetails property) { toOne.setUnwrapProxy( true ); } else { - final boolean eager = isEager( property ); + final boolean eager = isEager( property, toOne.getBuildingContext() ); toOne.setLazy( !eager ); toOne.setUnwrapProxy( eager ); toOne.setUnwrapProxyImplicit( true ); @@ -373,7 +374,7 @@ private static void handleFetch(ToOne toOne, MemberDetails property) { setHibernateFetchMode( toOne, property, fetchAnnotationUsage.value() ); } else { - toOne.setFetchMode( getFetchMode( getJpaFetchType( property ) ) ); + toOne.setFetchMode( getFetchMode( getJpaFetchType( property, toOne.getBuildingContext() ) ) ); } } @@ -395,22 +396,31 @@ private static void setHibernateFetchMode(ToOne toOne, MemberDetails property, o } } - private static boolean isEager(MemberDetails property) { - return getJpaFetchType( property ) == EAGER; + private static boolean isEager(MemberDetails property, MetadataBuildingContext context) { + return getJpaFetchType( property, context ) == EAGER; } - private static FetchType getJpaFetchType(MemberDetails property) { + private static FetchType getJpaFetchType(MemberDetails property, MetadataBuildingContext context) { final var manyToOne = property.getDirectAnnotationUsage( ManyToOne.class ); - final var oneToOne = property.getDirectAnnotationUsage( OneToOne.class ); if ( manyToOne != null ) { - return manyToOne.fetch(); - } - else if ( oneToOne != null ) { - return oneToOne.fetch(); + return handlingDefault( manyToOne.fetch(), context ); } - else { - throw new AssertionFailure("Define fetch strategy on a property not annotated with @OneToMany nor @OneToOne"); + + final var oneToOne = property.getDirectAnnotationUsage( OneToOne.class ); + if ( oneToOne != null ) { + return handlingDefault( oneToOne.fetch(), context ); } + + throw new AssertionFailure("Define fetch strategy on a property not annotated with @OneToMany nor @OneToOne"); + } + + private static FetchType handlingDefault(FetchType specifiedType, MetadataBuildingContext context) { + return specifiedType == DEFAULT + // todo (jpa4) : Account for the JPA 4.0 notion of default-to-one-fetch-type + // ideally, somehow account for it as part of MappingDefaults. + // easiest would be to consider that when calculating effective defaults + ? context.getEffectiveDefaults().isDefaultEntityLaziness() ? LAZY : EAGER + : specifiedType; } static void bindOneToOne( diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/CollectionTableJpaAnnotation.java b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/CollectionTableJpaAnnotation.java index 10eacab63795..48997d4aa5c1 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/CollectionTableJpaAnnotation.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/CollectionTableJpaAnnotation.java @@ -7,6 +7,7 @@ import java.lang.annotation.Annotation; import java.util.Map; +import jakarta.persistence.CheckConstraint; import org.hibernate.boot.jaxb.mapping.spi.JaxbCollectionTableImpl; import org.hibernate.boot.models.JpaAnnotations; import org.hibernate.boot.models.annotations.spi.CommonTableDetails; @@ -22,6 +23,7 @@ import static org.hibernate.boot.models.xml.internal.XmlAnnotationHelper.applyCatalog; import static org.hibernate.boot.models.xml.internal.XmlAnnotationHelper.applyOptionalString; import static org.hibernate.boot.models.xml.internal.XmlAnnotationHelper.applySchema; +import static org.hibernate.boot.models.xml.internal.XmlAnnotationHelper.collectCheckConstraints; import static org.hibernate.boot.models.xml.internal.XmlAnnotationHelper.collectIndexes; import static org.hibernate.boot.models.xml.internal.XmlAnnotationHelper.collectUniqueConstraints; @@ -32,10 +34,12 @@ public class CollectionTableJpaAnnotation implements CollectionTable, CommonTabl private String name; private String catalog; private String schema; + private String comment; private jakarta.persistence.JoinColumn[] joinColumns; private jakarta.persistence.ForeignKey foreignKey; private jakarta.persistence.UniqueConstraint[] uniqueConstraints; private jakarta.persistence.Index[] indexes; + private jakarta.persistence.CheckConstraint[] check; private String options; /** @@ -45,10 +49,12 @@ public CollectionTableJpaAnnotation(ModelsContext modelContext) { this.name = ""; this.catalog = ""; this.schema = ""; + this.comment = ""; this.joinColumns = new jakarta.persistence.JoinColumn[0]; this.foreignKey = JpaAnnotations.FOREIGN_KEY.createUsage( modelContext ); this.uniqueConstraints = new jakarta.persistence.UniqueConstraint[0]; this.indexes = new jakarta.persistence.Index[0]; + this.check = new jakarta.persistence.CheckConstraint[0]; this.options = ""; } @@ -59,10 +65,12 @@ public CollectionTableJpaAnnotation(CollectionTable annotation, ModelsContext mo this.name = annotation.name(); this.catalog = annotation.catalog(); this.schema = annotation.schema(); + this.comment = annotation.comment(); this.joinColumns = extractJdkValue( annotation, COLLECTION_TABLE, "joinColumns", modelContext ); this.foreignKey = extractJdkValue( annotation, COLLECTION_TABLE, "foreignKey", modelContext ); this.uniqueConstraints = extractJdkValue( annotation, COLLECTION_TABLE, "uniqueConstraints", modelContext ); this.indexes = extractJdkValue( annotation, COLLECTION_TABLE, "indexes", modelContext ); + this.check = extractJdkValue( annotation, COLLECTION_TABLE, "check", modelContext ); this.options = extractJdkValue( annotation, COLLECTION_TABLE, "options", modelContext ); } @@ -73,10 +81,12 @@ public CollectionTableJpaAnnotation(Map attributeValues, ModelsC this.name = (String) attributeValues.get( "name" ); this.catalog = (String) attributeValues.get( "catalog" ); this.schema = (String) attributeValues.get( "schema" ); + this.comment = (String) attributeValues.get( "comment" ); this.joinColumns = (jakarta.persistence.JoinColumn[]) attributeValues.get( "joinColumns" ); this.foreignKey = (jakarta.persistence.ForeignKey) attributeValues.get( "foreignKey" ); this.uniqueConstraints = (jakarta.persistence.UniqueConstraint[]) attributeValues.get( "uniqueConstraints" ); this.indexes = (jakarta.persistence.Index[]) attributeValues.get( "indexes" ); + this.check = (jakarta.persistence.CheckConstraint[]) attributeValues.get( "check" ); this.options = (String) attributeValues.get( "options" ); } @@ -115,6 +125,15 @@ public void schema(String value) { } + @Override + public String comment() { + return comment; + } + + public void comment(String comment) { + this.comment = comment; + } + @Override public jakarta.persistence.JoinColumn[] joinColumns() { return joinColumns; @@ -155,6 +174,16 @@ public void indexes(jakarta.persistence.Index[] value) { } + @Override + public CheckConstraint[] check() { + return check; + } + + public void check(CheckConstraint[] check) { + this.check = check; + } + + @Override public String options() { return options; @@ -168,6 +197,7 @@ public void apply(JaxbCollectionTableImpl jaxbTable, XmlDocumentContext xmlDocum applyOptionalString( jaxbTable.getName(), this::name ); applyCatalog( jaxbTable, this, xmlDocumentContext ); applySchema( jaxbTable, this, xmlDocumentContext ); + applyOptionalString( jaxbTable.getComment(), this::comment); applyOptionalString( jaxbTable.getOptions(), this::options ); joinColumns( JoinColumnProcessing.transformJoinColumnList( jaxbTable.getJoinColumns(), xmlDocumentContext ) ); @@ -181,6 +211,7 @@ public void apply(JaxbCollectionTableImpl jaxbTable, XmlDocumentContext xmlDocum indexes( collectIndexes( jaxbTable.getIndexes(), xmlDocumentContext ) ); uniqueConstraints( collectUniqueConstraints( jaxbTable.getUniqueConstraints(), xmlDocumentContext ) ); + check( collectCheckConstraints( jaxbTable.getCheckConstraints(), xmlDocumentContext ) ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/ColumnJpaAnnotation.java b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/ColumnJpaAnnotation.java index 9fb4e0dcbf4f..27b48aeff048 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/ColumnJpaAnnotation.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/ColumnJpaAnnotation.java @@ -4,20 +4,18 @@ */ package org.hibernate.boot.models.annotations.internal; -import java.lang.annotation.Annotation; -import java.util.Map; - +import jakarta.persistence.Column; import org.hibernate.boot.jaxb.mapping.spi.JaxbColumnImpl; import org.hibernate.boot.models.JpaAnnotations; import org.hibernate.boot.models.annotations.spi.CheckConstraintCollector; import org.hibernate.boot.models.annotations.spi.ColumnDetails; -import org.hibernate.boot.models.annotations.spi.Commentable; import org.hibernate.boot.models.xml.internal.XmlAnnotationHelper; import org.hibernate.boot.models.xml.spi.XmlDocumentContext; import org.hibernate.internal.util.StringHelper; import org.hibernate.models.spi.ModelsContext; -import jakarta.persistence.Column; +import java.lang.annotation.Annotation; +import java.util.Map; import static org.hibernate.boot.models.internal.OrmAnnotationHelper.extractJdkValue; @@ -28,9 +26,7 @@ public class ColumnJpaAnnotation implements Column, ColumnDetails.Mutable, ColumnDetails.Sizable, ColumnDetails.Uniqueable, - ColumnDetails.Definable, ColumnDetails.AlternateTableCapable, - Commentable, CheckConstraintCollector { private String name; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/ConstructorResultJpaAnnotation.java b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/ConstructorResultJpaAnnotation.java index 256f4287e6c8..839e4ea8ce81 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/ConstructorResultJpaAnnotation.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/ConstructorResultJpaAnnotation.java @@ -7,6 +7,7 @@ import java.lang.annotation.Annotation; import java.util.Map; +import jakarta.persistence.EntityResult; import org.hibernate.models.spi.ModelsContext; import jakarta.persistence.ConstructorResult; @@ -20,6 +21,7 @@ public class ConstructorResultJpaAnnotation implements ConstructorResult { private java.lang.Class targetClass; private jakarta.persistence.ColumnResult[] columns; + private jakarta.persistence.EntityResult[] entities; /** * Used in creating dynamic annotation instances (e.g. from XML) @@ -33,6 +35,7 @@ public ConstructorResultJpaAnnotation(ModelsContext modelContext) { public ConstructorResultJpaAnnotation(ConstructorResult annotation, ModelsContext modelContext) { this.targetClass = annotation.targetClass(); this.columns = extractJdkValue( annotation, CONSTRUCTOR_RESULT, "columns", modelContext ); + this.entities = extractJdkValue( annotation, CONSTRUCTOR_RESULT, "entities", modelContext ); } /** @@ -43,6 +46,7 @@ public ConstructorResultJpaAnnotation( ModelsContext modelContext) { this.targetClass = (Class) attributeValues.get( "targetClass" ); this.columns = (jakarta.persistence.ColumnResult[]) attributeValues.get( "columns" ); + this.entities = (jakarta.persistence.EntityResult[]) attributeValues.get( "entities" ); } @Override @@ -70,4 +74,12 @@ public void columns(jakarta.persistence.ColumnResult[] value) { } + @Override + public EntityResult[] entities() { + return entities; + } + + public void entities(EntityResult[] entities) { + this.entities = entities; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/DiscriminatorColumnJpaAnnotation.java b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/DiscriminatorColumnJpaAnnotation.java index b573ce7f6ac6..0fddafc7f4f5 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/DiscriminatorColumnJpaAnnotation.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/DiscriminatorColumnJpaAnnotation.java @@ -9,6 +9,8 @@ import org.hibernate.boot.jaxb.mapping.spi.JaxbDiscriminatorColumnImpl; import org.hibernate.boot.models.annotations.spi.ColumnDetails; +import org.hibernate.boot.models.annotations.spi.Commentable; +import org.hibernate.boot.models.annotations.spi.Optionable; import org.hibernate.boot.models.xml.spi.XmlDocumentContext; import org.hibernate.internal.util.StringHelper; import org.hibernate.models.spi.ModelsContext; @@ -17,10 +19,11 @@ @SuppressWarnings({ "ClassExplicitlyAnnotation", "unused" }) @jakarta.annotation.Generated("org.hibernate.orm.build.annotations.ClassGeneratorProcessor") -public class DiscriminatorColumnJpaAnnotation implements DiscriminatorColumn, ColumnDetails { +public class DiscriminatorColumnJpaAnnotation implements DiscriminatorColumn, ColumnDetails, Commentable, Optionable { private String name; private jakarta.persistence.DiscriminatorType discriminatorType; + private String comment; private String columnDefinition; private String options; private int length; @@ -31,6 +34,7 @@ public class DiscriminatorColumnJpaAnnotation implements DiscriminatorColumn, Co public DiscriminatorColumnJpaAnnotation(ModelsContext modelContext) { this.name = "DTYPE"; this.discriminatorType = jakarta.persistence.DiscriminatorType.STRING; + this.comment = ""; this.columnDefinition = ""; this.options = ""; this.length = 31; @@ -42,6 +46,7 @@ public DiscriminatorColumnJpaAnnotation(ModelsContext modelContext) { public DiscriminatorColumnJpaAnnotation(DiscriminatorColumn annotation, ModelsContext modelContext) { this.name = annotation.name(); this.discriminatorType = annotation.discriminatorType(); + this.comment = annotation.comment(); this.columnDefinition = annotation.columnDefinition(); this.options = annotation.options(); this.length = annotation.length(); @@ -55,6 +60,7 @@ public DiscriminatorColumnJpaAnnotation( ModelsContext modelContext) { this.name = (String) attributeValues.get( "name" ); this.discriminatorType = (jakarta.persistence.DiscriminatorType) attributeValues.get( "discriminatorType" ); + this.comment = (String) attributeValues.get( "comment" ); this.columnDefinition = (String) attributeValues.get( "columnDefinition" ); this.options = (String) attributeValues.get( "options" ); this.length = (int) attributeValues.get( "length" ); @@ -85,6 +91,16 @@ public void discriminatorType(jakarta.persistence.DiscriminatorType value) { } + @Override + public String comment() { + return comment; + } + + public void comment(String comment) { + this.comment = comment; + } + + @Override public String columnDefinition() { return columnDefinition; @@ -124,6 +140,10 @@ public void apply(JaxbDiscriminatorColumnImpl jaxbColumn, XmlDocumentContext xml discriminatorType( jaxbColumn.getDiscriminatorType() ); } + if ( StringHelper.isNotEmpty( jaxbColumn.getComment() ) ) { + comment( jaxbColumn.getComment() ); + } + if ( jaxbColumn.getLength() != null ) { length( jaxbColumn.getLength() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/MapKeyColumnJpaAnnotation.java b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/MapKeyColumnJpaAnnotation.java index 59a28c78a36e..0b2e71812126 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/MapKeyColumnJpaAnnotation.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/MapKeyColumnJpaAnnotation.java @@ -7,6 +7,7 @@ import java.lang.annotation.Annotation; import java.util.Map; +import jakarta.persistence.CheckConstraint; import org.hibernate.boot.jaxb.mapping.spi.JaxbMapKeyColumnImpl; import org.hibernate.boot.models.annotations.spi.ColumnDetails; import org.hibernate.boot.models.xml.spi.XmlDocumentContext; @@ -23,13 +24,13 @@ public class MapKeyColumnJpaAnnotation implements MapKeyColumn, ColumnDetails.Mutable, ColumnDetails.Sizable, ColumnDetails.Uniqueable, - ColumnDetails.Definable, ColumnDetails.AlternateTableCapable { private String name; private boolean unique; private boolean nullable; private boolean insertable; private boolean updatable; + private String comment; private String columnDefinition; private String options; private String table; @@ -46,6 +47,7 @@ public MapKeyColumnJpaAnnotation(ModelsContext modelContext) { this.nullable = false; this.insertable = true; this.updatable = true; + this.comment = ""; this.columnDefinition = ""; this.options = ""; this.table = ""; @@ -63,6 +65,7 @@ public MapKeyColumnJpaAnnotation(MapKeyColumn annotation, ModelsContext modelCon this.nullable = annotation.nullable(); this.insertable = annotation.insertable(); this.updatable = annotation.updatable(); + this.comment = annotation.comment(); this.columnDefinition = annotation.columnDefinition(); this.options = annotation.options(); this.table = annotation.table(); @@ -80,6 +83,7 @@ public MapKeyColumnJpaAnnotation(Map attributeValues, ModelsCont this.nullable = (boolean) attributeValues.get( "nullable" ); this.insertable = (boolean) attributeValues.get( "insertable" ); this.updatable = (boolean) attributeValues.get( "updatable" ); + this.comment = (String) attributeValues.get( "comment" ); this.columnDefinition = (String) attributeValues.get( "columnDefinition" ); this.options = (String) attributeValues.get( "options" ); this.table = (String) attributeValues.get( "table" ); @@ -143,6 +147,16 @@ public void updatable(boolean value) { } + @Override + public String comment() { + return comment; + } + + public void comment(String comment) { + this.comment = comment; + } + + @Override public String columnDefinition() { return columnDefinition; @@ -202,6 +216,10 @@ public void scale(int value) { this.scale = value; } + @Override + public CheckConstraint[] check() { + return new CheckConstraint[0]; + } public void apply(JaxbMapKeyColumnImpl jaxbColumn, XmlDocumentContext xmlDocumentContext) { if ( StringHelper.isNotEmpty( jaxbColumn.getName() ) ) { @@ -228,6 +246,10 @@ public void apply(JaxbMapKeyColumnImpl jaxbColumn, XmlDocumentContext xmlDocumen updatable( jaxbColumn.isUpdatable() ); } + if ( StringHelper.isNotEmpty( jaxbColumn.getComment() ) ) { + comment( jaxbColumn.getComment() ); + } + if ( StringHelper.isNotEmpty( jaxbColumn.getColumnDefinition() ) ) { columnDefinition( jaxbColumn.getColumnDefinition() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/MapKeyJoinColumnJpaAnnotation.java b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/MapKeyJoinColumnJpaAnnotation.java index 097a0f52a482..51a82fb1152d 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/MapKeyJoinColumnJpaAnnotation.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/MapKeyJoinColumnJpaAnnotation.java @@ -7,6 +7,7 @@ import java.lang.annotation.Annotation; import java.util.Map; +import jakarta.persistence.CheckConstraint; import org.hibernate.boot.jaxb.mapping.spi.JaxbMapKeyJoinColumnImpl; import org.hibernate.boot.models.JpaAnnotations; import org.hibernate.boot.models.xml.internal.db.ForeignKeyProcessing; @@ -17,6 +18,7 @@ import jakarta.persistence.MapKeyJoinColumn; import static org.hibernate.boot.models.internal.OrmAnnotationHelper.extractJdkValue; +import static org.hibernate.boot.models.xml.internal.XmlAnnotationHelper.collectCheckConstraints; @SuppressWarnings({ "ClassExplicitlyAnnotation", "unused" }) @jakarta.annotation.Generated("org.hibernate.orm.build.annotations.ClassGeneratorProcessor") @@ -27,10 +29,12 @@ public class MapKeyJoinColumnJpaAnnotation implements MapKeyJoinColumn { private boolean nullable; private boolean insertable; private boolean updatable; + private String comment; private String columnDefinition; private String options; private String table; private jakarta.persistence.ForeignKey foreignKey; + private CheckConstraint[] check; /** * Used in creating dynamic annotation instances (e.g. from XML) @@ -145,6 +149,16 @@ public void updatable(boolean value) { } + @Override + public String comment() { + return comment; + } + + public void comment(String comment) { + this.comment = comment; + } + + @Override public String columnDefinition() { return columnDefinition; @@ -185,6 +199,15 @@ public void foreignKey(jakarta.persistence.ForeignKey value) { } + @Override + public CheckConstraint[] check() { + return check; + } + + public void check(CheckConstraint[] check) { + this.check = check; + } + public void apply(JaxbMapKeyJoinColumnImpl jaxbColumn, XmlDocumentContext xmlDocumentContext) { if ( StringHelper.isNotEmpty( jaxbColumn.getName() ) ) { name( jaxbColumn.getName() ); @@ -226,5 +249,7 @@ public void apply(JaxbMapKeyJoinColumnImpl jaxbColumn, XmlDocumentContext xmlDoc xmlDocumentContext ) ); } + + check( collectCheckConstraints( jaxbColumn.getCheckConstraints(), xmlDocumentContext ) ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/MapKeyJpaAnnotation.java b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/MapKeyJpaAnnotation.java index c65186a11f53..c74138dfb5b0 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/MapKeyJpaAnnotation.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/MapKeyJpaAnnotation.java @@ -14,12 +14,14 @@ @SuppressWarnings({ "ClassExplicitlyAnnotation", "unused" }) @jakarta.annotation.Generated("org.hibernate.orm.build.annotations.ClassGeneratorProcessor") public class MapKeyJpaAnnotation implements MapKey { + private String value; private String name; /** * Used in creating dynamic annotation instances (e.g. from XML) */ public MapKeyJpaAnnotation(ModelsContext modelContext) { + value = ""; this.name = ""; } @@ -27,6 +29,7 @@ public MapKeyJpaAnnotation(ModelsContext modelContext) { * Used in creating annotation instances from JDK variant */ public MapKeyJpaAnnotation(MapKey annotation, ModelsContext modelContext) { + this.value = annotation.value(); this.name = annotation.name(); } @@ -34,6 +37,7 @@ public MapKeyJpaAnnotation(MapKey annotation, ModelsContext modelContext) { * Used in creating annotation instances from Jandex variant */ public MapKeyJpaAnnotation(Map attributeValues, ModelsContext modelContext) { + this.value = (String) attributeValues.get( "value" ); this.name = (String) attributeValues.get( "name" ); } @@ -42,6 +46,15 @@ public Class annotationType() { return MapKey.class; } + @Override + public String value() { + return value; + } + + public void value(String value) { + this.value = value; + } + @Override public String name() { return name; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/NamedQueryAnnotation.java b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/NamedQueryAnnotation.java index af75f99e527c..5d4417cd39bb 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/NamedQueryAnnotation.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/NamedQueryAnnotation.java @@ -8,6 +8,7 @@ import java.util.Map; import org.hibernate.CacheMode; +import org.hibernate.Timeouts; import org.hibernate.annotations.FlushModeType; import org.hibernate.annotations.NamedQuery; import org.hibernate.boot.jaxb.mapping.spi.JaxbNamedHqlQueryImpl; @@ -255,7 +256,7 @@ public void apply(JaxbNamedHqlQueryImpl jaxbNamedQuery, XmlDocumentContext xmlDo } if ( jaxbNamedQuery.getTimeout() != null ) { - timeout( jaxbNamedQuery.getTimeout() ); + timeout( Timeouts.getTimeoutInSeconds( jaxbNamedQuery.getTimeout() ) ); } if ( StringHelper.isNotEmpty( jaxbNamedQuery.getComment() ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/NamedQueryJpaAnnotation.java b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/NamedQueryJpaAnnotation.java index 916a9038cd7a..31e71366ae47 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/NamedQueryJpaAnnotation.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/NamedQueryJpaAnnotation.java @@ -7,9 +7,11 @@ import java.lang.annotation.Annotation; import java.util.Map; +import jakarta.persistence.PessimisticLockScope; import org.hibernate.boot.jaxb.mapping.spi.JaxbNamedHqlQueryImpl; import org.hibernate.boot.models.JpaAnnotations; import org.hibernate.boot.models.xml.internal.QueryProcessing; +import org.hibernate.boot.models.xml.internal.TypeHelper; import org.hibernate.boot.models.xml.spi.XmlDocumentContext; import org.hibernate.models.spi.ModelsContext; @@ -24,7 +26,9 @@ public class NamedQueryJpaAnnotation implements NamedQuery { private String name; private String query; private java.lang.Class resultClass; + private String entityGraph; private jakarta.persistence.LockModeType lockMode; + private jakarta.persistence.PessimisticLockScope lockScope; private jakarta.persistence.QueryHint[] hints; /** @@ -32,7 +36,9 @@ public class NamedQueryJpaAnnotation implements NamedQuery { */ public NamedQueryJpaAnnotation(ModelsContext modelContext) { this.resultClass = void.class; + this.entityGraph = ""; this.lockMode = jakarta.persistence.LockModeType.NONE; + this.lockScope = PessimisticLockScope.NORMAL; this.hints = new jakarta.persistence.QueryHint[0]; } @@ -43,7 +49,9 @@ public NamedQueryJpaAnnotation(NamedQuery annotation, ModelsContext modelContext this.name = annotation.name(); this.query = annotation.query(); this.resultClass = annotation.resultClass(); + this.entityGraph = annotation.entityGraph(); this.lockMode = annotation.lockMode(); + this.lockScope = annotation.lockScope(); this.hints = extractJdkValue( annotation, JpaAnnotations.NAMED_QUERY, "hints", modelContext ); } @@ -54,7 +62,9 @@ public NamedQueryJpaAnnotation(Map attributeValues, ModelsContex this.name = (String) attributeValues.get( "name" ); this.query = (String) attributeValues.get( "query" ); this.resultClass = (Class) attributeValues.get( "resultClass" ); + this.entityGraph = (String) attributeValues.get( "entityGraph" ); this.lockMode = (jakarta.persistence.LockModeType) attributeValues.get( "lockMode" ); + this.lockScope = (PessimisticLockScope) attributeValues.get( "lockScope" ); this.hints = (jakarta.persistence.QueryHint[]) attributeValues.get( "hints" ); } @@ -98,11 +108,31 @@ public jakarta.persistence.LockModeType lockMode() { return lockMode; } + + @Override + public PessimisticLockScope lockScope() { + return lockScope; + } + + public void lockScope(PessimisticLockScope lockScope) { + this.lockScope = lockScope; + } + public void lockMode(jakarta.persistence.LockModeType value) { this.lockMode = value; } + @Override + public String entityGraph() { + return entityGraph; + } + + public void entityGraph(String entityGraph) { + this.entityGraph = entityGraph; + } + + @Override public jakarta.persistence.QueryHint[] hints() { return hints; @@ -116,7 +146,12 @@ public void hints(jakarta.persistence.QueryHint[] value) { public void apply(JaxbNamedHqlQueryImpl jaxbNamedQuery, XmlDocumentContext xmlDocumentContext) { name( jaxbNamedQuery.getName() ); query( jaxbNamedQuery.getQuery() ); + + resultClass( TypeHelper.resolveClassReference( jaxbNamedQuery.getResultClass(), xmlDocumentContext, void.class ) ); + entityGraph( jaxbNamedQuery.getEntityGraph() ); + lockMode( coalesce( jaxbNamedQuery.getLockMode(), jakarta.persistence.LockModeType.NONE ) ); + lockScope( coalesce( jaxbNamedQuery.getLockScope(), PessimisticLockScope.NORMAL ) ); hints( QueryProcessing.collectQueryHints( jaxbNamedQuery.getHints(), xmlDocumentContext ) ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/OrderColumnJpaAnnotation.java b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/OrderColumnJpaAnnotation.java index 9de1cb39c3b5..121085a9dc16 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/OrderColumnJpaAnnotation.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/OrderColumnJpaAnnotation.java @@ -19,7 +19,6 @@ @jakarta.annotation.Generated("org.hibernate.orm.build.annotations.ClassGeneratorProcessor") public class OrderColumnJpaAnnotation implements OrderColumn, ColumnDetails, - ColumnDetails.Definable, ColumnDetails.Nullable, ColumnDetails.Mutable { private String name; @@ -27,6 +26,7 @@ public class OrderColumnJpaAnnotation implements OrderColumn, private boolean insertable; private boolean updatable; private String columnDefinition; + private String comment; private String options; /** @@ -38,6 +38,7 @@ public OrderColumnJpaAnnotation(ModelsContext modelContext) { this.insertable = true; this.updatable = true; this.columnDefinition = ""; + this.comment = ""; this.options = ""; } @@ -50,6 +51,7 @@ public OrderColumnJpaAnnotation(OrderColumn annotation, ModelsContext modelConte this.insertable = annotation.insertable(); this.updatable = annotation.updatable(); this.columnDefinition = annotation.columnDefinition(); + this.comment = annotation.comment(); this.options = annotation.options(); } @@ -62,6 +64,7 @@ public OrderColumnJpaAnnotation(Map attributeValues, ModelsConte this.insertable = (boolean) attributeValues.get( "insertable" ); this.updatable = (boolean) attributeValues.get( "updatable" ); this.columnDefinition = (String) attributeValues.get( "columnDefinition" ); + this.comment = (String) attributeValues.get( "comment" ); this.options = (String) attributeValues.get( "options" ); } @@ -120,6 +123,16 @@ public void columnDefinition(String value) { } + @Override + public String comment() { + return comment; + } + + public void comment(String comment) { + this.comment = comment; + } + + @Override public String options() { return options; @@ -147,6 +160,10 @@ public void apply(JaxbOrderColumnImpl jaxbColumn, XmlDocumentContext xmlDocument updatable( jaxbColumn.isUpdatable() ); } + if ( StringHelper.isNotEmpty( jaxbColumn.getComment() ) ) { + comment( jaxbColumn.getComment() ); + } + if ( StringHelper.isNotEmpty( jaxbColumn.getColumnDefinition() ) ) { columnDefinition( jaxbColumn.getColumnDefinition() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/PrimaryKeyJoinColumnJpaAnnotation.java b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/PrimaryKeyJoinColumnJpaAnnotation.java index 3b131dff2eac..22c6039c4c61 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/PrimaryKeyJoinColumnJpaAnnotation.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/PrimaryKeyJoinColumnJpaAnnotation.java @@ -4,9 +4,8 @@ */ package org.hibernate.boot.models.annotations.internal; -import java.lang.annotation.Annotation; -import java.util.Map; - +import jakarta.persistence.CheckConstraint; +import jakarta.persistence.PrimaryKeyJoinColumn; import org.hibernate.boot.jaxb.mapping.spi.JaxbPrimaryKeyJoinColumnImpl; import org.hibernate.boot.models.JpaAnnotations; import org.hibernate.boot.models.annotations.spi.ColumnDetails; @@ -15,19 +14,23 @@ import org.hibernate.internal.util.StringHelper; import org.hibernate.models.spi.ModelsContext; -import jakarta.persistence.PrimaryKeyJoinColumn; +import java.lang.annotation.Annotation; +import java.util.Map; import static org.hibernate.boot.models.JpaAnnotations.PRIMARY_KEY_JOIN_COLUMN; import static org.hibernate.boot.models.internal.OrmAnnotationHelper.extractJdkValue; +import static org.hibernate.boot.models.xml.internal.XmlAnnotationHelper.collectCheckConstraints; @SuppressWarnings({ "ClassExplicitlyAnnotation", "unused" }) @jakarta.annotation.Generated("org.hibernate.orm.build.annotations.ClassGeneratorProcessor") -public class PrimaryKeyJoinColumnJpaAnnotation implements PrimaryKeyJoinColumn, ColumnDetails, ColumnDetails.Definable { +public class PrimaryKeyJoinColumnJpaAnnotation implements PrimaryKeyJoinColumn, ColumnDetails { private String name; private String referencedColumnName; + private String comment; private String columnDefinition; private String options; private jakarta.persistence.ForeignKey foreignKey; + private CheckConstraint[] check; /** * Used in creating dynamic annotation instances (e.g. from XML) @@ -35,9 +38,11 @@ public class PrimaryKeyJoinColumnJpaAnnotation implements PrimaryKeyJoinColumn, public PrimaryKeyJoinColumnJpaAnnotation(ModelsContext modelContext) { this.name = ""; this.referencedColumnName = ""; + this.comment = ""; this.columnDefinition = ""; this.options = ""; this.foreignKey = JpaAnnotations.FOREIGN_KEY.createUsage( modelContext ); + this.check = new CheckConstraint[0]; } /** @@ -46,9 +51,11 @@ public PrimaryKeyJoinColumnJpaAnnotation(ModelsContext modelContext) { public PrimaryKeyJoinColumnJpaAnnotation(PrimaryKeyJoinColumn annotation, ModelsContext modelContext) { this.name = annotation.name(); this.referencedColumnName = annotation.referencedColumnName(); + this.comment = annotation.comment(); this.columnDefinition = annotation.columnDefinition(); this.options = annotation.options(); this.foreignKey = extractJdkValue( annotation, PRIMARY_KEY_JOIN_COLUMN, "foreignKey", modelContext ); + this.check = extractJdkValue( annotation, PRIMARY_KEY_JOIN_COLUMN, "check", modelContext ); } /** @@ -59,9 +66,11 @@ public PrimaryKeyJoinColumnJpaAnnotation( ModelsContext modelContext) { this.name = (String) attributeValues.get( "name" ); this.referencedColumnName = (String) attributeValues.get( "referencedColumnName" ); + this.comment = (String) attributeValues.get( "comment" ); this.columnDefinition = (String) attributeValues.get( "columnDefinition" ); this.options = (String) attributeValues.get( "options" ); this.foreignKey = (jakarta.persistence.ForeignKey) attributeValues.get( "foreignKey" ); + this.check = (CheckConstraint[]) attributeValues.get( "check" ); } @Override @@ -89,6 +98,16 @@ public void referencedColumnName(String value) { } + @Override + public String comment() { + return comment; + } + + public void comment(String comment) { + this.comment = comment; + } + + @Override public String columnDefinition() { return columnDefinition; @@ -119,14 +138,28 @@ public void foreignKey(jakarta.persistence.ForeignKey value) { } + @Override + public CheckConstraint[] check() { + return check; + } + + public void check(CheckConstraint[] check) { + this.check = check; + } + public void apply(JaxbPrimaryKeyJoinColumnImpl jaxbColumn, XmlDocumentContext xmlDocumentContext) { if ( StringHelper.isNotEmpty( jaxbColumn.getName() ) ) { name( jaxbColumn.getName() ); } + if ( StringHelper.isNotEmpty( jaxbColumn.getComment() ) ) { + comment( jaxbColumn.getComment() ); + } + if ( StringHelper.isNotEmpty( jaxbColumn.getColumnDefinition() ) ) { columnDefinition( jaxbColumn.getColumnDefinition() ); } + if ( StringHelper.isNotEmpty( jaxbColumn.getOptions() ) ) { options( jaxbColumn.getOptions() ); } @@ -142,5 +175,6 @@ public void apply(JaxbPrimaryKeyJoinColumnImpl jaxbColumn, XmlDocumentContext xm ) ); } + check( collectCheckConstraints( jaxbColumn.getCheckConstraints(), xmlDocumentContext ) ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/spi/ColumnDetails.java b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/spi/ColumnDetails.java index 81f83286e40f..ea8242ddf923 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/spi/ColumnDetails.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/spi/ColumnDetails.java @@ -7,11 +7,15 @@ /** * @author Steve Ebersole */ -public interface ColumnDetails { +public interface ColumnDetails extends Commentable, Optionable { String name(); void name(String value); + String columnDefinition(); + + void columnDefinition(String value); + interface AlternateTableCapable { String table(); @@ -60,14 +64,4 @@ interface Uniqueable extends ColumnDetails { void unique(boolean value); } - - interface Definable extends ColumnDetails { - String columnDefinition(); - - void columnDefinition(String value); - - String options(); - - void options(String value); - } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/spi/CommonTableDetails.java b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/spi/CommonTableDetails.java index 9aedd5989e69..2c177a486e75 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/spi/CommonTableDetails.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/spi/CommonTableDetails.java @@ -9,7 +9,8 @@ * * @author Steve Ebersole */ -public interface CommonTableDetails extends DatabaseObjectDetails, UniqueConstraintCollector, IndexCollector { +public interface CommonTableDetails + extends DatabaseObjectDetails, UniqueConstraintCollector, IndexCollector, Commentable, Optionable { /** * The table name */ diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/spi/Optionable.java b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/spi/Optionable.java new file mode 100644 index 000000000000..a22489fe7cf7 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/annotations/spi/Optionable.java @@ -0,0 +1,14 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.boot.models.annotations.spi; + +/** + * @author Steve Ebersole + */ +public interface Optionable { + String options(); + + void options(String value); +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/QueryProcessing.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/QueryProcessing.java index 47b406c8ca52..fc4ddbd2703a 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/QueryProcessing.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/QueryProcessing.java @@ -255,6 +255,15 @@ public static ConstructorResult[] extractConstructorResults( constructorResult.columns( columnResults ); } } + if ( CollectionHelper.isNotEmpty( jaxbConstructorResult.getEntities() ) ) { + final EntityResult[] entityResults = extractEntityResults( + jaxbConstructorResult.getEntities(), + xmlDocumentContext + ); + if ( entityResults != null ) { + constructorResult.entities( entityResults ); + } + } } return constructorResults; } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/TypeHelper.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/TypeHelper.java new file mode 100644 index 000000000000..2f597c3e63b6 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/TypeHelper.java @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.boot.models.xml.internal; + +import org.hibernate.boot.models.xml.spi.XmlDocumentContext; +import org.hibernate.internal.util.StringHelper; + +/** + * @author Steve Ebersole + */ +public class TypeHelper { + public static Class resolveClassReference( + String className, + XmlDocumentContext xmlDocumentContext, + Class defaultValue) { + if ( StringHelper.isEmpty( className ) ) { + return defaultValue; + } + + className = xmlDocumentContext.resolveClassName( className ); + return xmlDocumentContext.resolveJavaType( className ).toJavaClass(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/CommonPluralAttributeProcessing.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/CommonPluralAttributeProcessing.java index 2c677a749e00..735d183fffd1 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/CommonPluralAttributeProcessing.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/CommonPluralAttributeProcessing.java @@ -110,8 +110,10 @@ public static void applyPluralAttributeStructure( JpaAnnotations.MAP_KEY, buildingContext ); - if ( jaxbPluralAttribute.getMapKey() != null && StringHelper.isNotEmpty( jaxbPluralAttribute.getMapKey().getName() ) ) { - mapKeyAnn.name( jaxbPluralAttribute.getMapKey().getName() ); + if ( StringHelper.isNotEmpty( jaxbPluralAttribute.getMapKey().getName() ) ) { + // since name() is deprecated with value() as a replacement + mapKeyAnn.value( jaxbPluralAttribute.getMapKey().getName() ); + mapKeyAnn.name( "" ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/query/AbstractNamedQueryBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/query/AbstractNamedQueryBuilder.java index a74b9c689e5b..7bf3009f02c0 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/query/AbstractNamedQueryBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/query/AbstractNamedQueryBuilder.java @@ -7,6 +7,7 @@ import java.util.HashMap; import java.util.Map; +import jakarta.persistence.Timeout; import org.hibernate.CacheMode; import org.hibernate.FlushMode; import org.hibernate.LockOptions; @@ -30,7 +31,7 @@ public abstract class AbstractNamedQueryBuilder extends TypedQueryReference { +public interface NamedQueryDefinition extends JpaTypedQueryReference { @Override default String getName() { return getRegistrationName(); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/query/SqlResultSetMappingDescriptor.java b/hibernate-core/src/main/java/org/hibernate/boot/query/SqlResultSetMappingDescriptor.java index b9e130ed6766..c269f103a755 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/query/SqlResultSetMappingDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/query/SqlResultSetMappingDescriptor.java @@ -65,7 +65,7 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr // representations) be what is used and handed to the // NamedResultSetMappingMemento directly. They simply need // to be capable of resolving themselves into ResultBuilders - // (`org.hibernate.query.results.ResultBuilder`) as part of the + // (`org.hibernate.query.results.spi.ResultBuilder`) as part of the // memento for its resolution public static SqlResultSetMappingDescriptor from(SqlResultSetMapping mappingAnnotation, String name) { diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractNamedQueryDefinition.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractNamedQueryDefinition.java index d10a9de39956..bcb47da6385a 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractNamedQueryDefinition.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractNamedQueryDefinition.java @@ -4,15 +4,19 @@ */ package org.hibernate.boot.spi; -import java.util.HashMap; -import java.util.Map; - +import jakarta.persistence.CacheRetrieveMode; +import jakarta.persistence.CacheStoreMode; +import jakarta.persistence.LockModeType; +import jakarta.persistence.PessimisticLockScope; +import jakarta.persistence.Timeout; +import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.CacheMode; import org.hibernate.FlushMode; import org.hibernate.LockOptions; import org.hibernate.boot.query.NamedQueryDefinition; -import org.checkerframework.checker.nullness.qual.Nullable; +import java.util.HashMap; +import java.util.Map; /** * @author Steve Ebersole @@ -30,7 +34,7 @@ public abstract class AbstractNamedQueryDefinition implements NamedQueryDefin private final LockOptions lockOptions; - private final Integer timeout; + private final Timeout timeout; private final Integer fetchSize; private final String comment; @@ -47,7 +51,7 @@ public AbstractNamedQueryDefinition( FlushMode flushMode, Boolean readOnly, LockOptions lockOptions, - Integer timeout, + Timeout timeout, Integer fetchSize, String comment, Map hints, @@ -94,6 +98,31 @@ public CacheMode getCacheMode() { return cacheMode; } + @Override + public CacheRetrieveMode getCacheRetrieveMode() { + return cacheMode == null ? null : cacheMode.getJpaRetrieveMode(); + } + + @Override + public CacheStoreMode getCacheStoreMode() { + return cacheMode == null ? null : cacheMode.getJpaStoreMode(); + } + + @Override + public LockModeType getLockMode() { + return lockOptions == null ? null : lockOptions.getLockMode().toJpaLockMode(); + } + + @Override + public PessimisticLockScope getPessimisticLockScope() { + return lockOptions == null ? null : lockOptions.getScope().getCorrespondingJpaScope(); + } + + @Override + public String getEntityGraphName() { + return null; + } + public FlushMode getFlushMode() { return flushMode; } @@ -106,7 +135,7 @@ public LockOptions getLockOptions() { return lockOptions; } - public Integer getTimeout() { + public Timeout getTimeout() { return timeout; } @@ -122,5 +151,4 @@ public String getComment() { public Map getHints() { return hints; } - } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/EffectiveMappingDefaults.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/EffectiveMappingDefaults.java index e569bf360fb3..23f6030d06c0 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/EffectiveMappingDefaults.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/EffectiveMappingDefaults.java @@ -7,6 +7,7 @@ import java.util.EnumSet; import org.hibernate.annotations.CascadeType; +import org.hibernate.boot.jaxb.configuration.spi.JaxbPersistenceImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl; import org.hibernate.boot.models.xml.spi.PersistenceUnitMetadata; import org.hibernate.cache.spi.access.AccessType; @@ -121,6 +122,7 @@ public interface EffectiveMappingDefaults { * * @see MappingDefaults#areEntitiesImplicitlyLazy() * @see JaxbEntityMappingsImpl#isDefaultLazy() + * @see JaxbPersistenceImpl.JaxbPersistenceUnitImpl#getDefaultToOneFetchType() */ boolean isDefaultEntityLaziness(); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java index ce8f8b3fff5e..4f3bc2b72f67 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java @@ -593,11 +593,11 @@ default boolean inClauseParameterPaddingEnabled() { int getQueryStatisticsMaxSize(); /** - * Should JPA entity lifecycle callbacks be processed by - * the {@link org.hibernate.event.spi.EventEngine} and - * {@link org.hibernate.jpa.event.spi.CallbackRegistry}? + * Whether to process Jakarta Persistence entity lifecycle callbacks. * * @see org.hibernate.cfg.PersistenceSettings#JPA_CALLBACKS_ENABLED + * @see org.hibernate.event.jpa.spi.EntityCallbacks + * @see org.hibernate.metamodel.mapping.EntityMappingType#getEntityCallbacks */ boolean areJPACallbacksEnabled(); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/xsd/ConfigXsdSupport.java b/hibernate-core/src/main/java/org/hibernate/boot/xsd/ConfigXsdSupport.java index ce897f3fc9a1..4c780f106472 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/xsd/ConfigXsdSupport.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/xsd/ConfigXsdSupport.java @@ -20,6 +20,10 @@ @SuppressWarnings("unused") public class ConfigXsdSupport { + public static XsdDescriptor latestDescriptor() { + return _80(); + } + /** * Needs synchronization on any access. * Custom keys: @@ -31,8 +35,10 @@ public class ConfigXsdSupport { * 5: JPA 2.2 (default) * 6: Jakarta Persistence 3.0 * 7: Jakarta Persistence 3.1 + * 8: Jakarta Persistence 3.2 + * 9: configurationXML 8.0 (JPA 4.0) */ - private static final XsdDescriptor[] xsdCache = new XsdDescriptor[8]; + private static final XsdDescriptor[] xsdCache = new XsdDescriptor[10]; public XsdDescriptor latestJpaDescriptor() { return getJPA31(); @@ -220,4 +226,20 @@ public static XsdDescriptor getJPA32() { } } + public static XsdDescriptor _80() { + final int index = 9; + synchronized ( xsdCache ) { + XsdDescriptor xsd = xsdCache[index]; + if ( xsd == null ) { + xsd = LocalXsdResolver.buildXsdDescriptor( + "org/hibernate/xsd/cfg/configuration-8.0.xsd", + "8.0" , + "http://www.hibernate.org/xsd/orm/configuration" + ); + xsdCache[index] = xsd; + } + return xsd; + } + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/xsd/MappingXsdSupport.java b/hibernate-core/src/main/java/org/hibernate/boot/xsd/MappingXsdSupport.java index 2db5052f6cf1..b3a5e385e1f7 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/xsd/MappingXsdSupport.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/xsd/MappingXsdSupport.java @@ -33,6 +33,12 @@ public class MappingXsdSupport { "http://www.hibernate.org/xsd/orm/mapping" ); + public static final XsdDescriptor _80 = LocalXsdResolver.buildXsdDescriptor( + "org/hibernate/xsd/mapping/mapping-8.0.xsd", + "8.0", + "http://www.hibernate.org/xsd/orm/mapping" + ); + public static final XsdDescriptor jpa10 = LocalXsdResolver.buildXsdDescriptor( "org/hibernate/jpa/orm_1_0.xsd", "1.0", @@ -92,7 +98,7 @@ private MappingXsdSupport() { } public static XsdDescriptor latestDescriptor() { - return _70; + return _80; } public static XsdDescriptor latestJpaDescriptor() { diff --git a/hibernate-core/src/main/java/org/hibernate/boot/xsd/XsdHelper.java b/hibernate-core/src/main/java/org/hibernate/boot/xsd/XsdHelper.java index f266df920c14..8b1c60b579e4 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/xsd/XsdHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/xsd/XsdHelper.java @@ -10,7 +10,10 @@ public class XsdHelper { public static boolean isValidJpaVersion(String version) { return switch ( version ) { - case "1.0", "2.0", "2.1", "2.2", "3.0", "3.1", "3.2", "7.0" -> true; + // JPA versions + case "1.0", "2.0", "2.1", "2.2", "3.0", "3.1", "3.2", "4.0" -> true; + // Hibernate mapping.xsd versions + case "7.0", "8.0" -> true; default -> false; }; } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/FetchTiming.java b/hibernate-core/src/main/java/org/hibernate/engine/FetchTiming.java index af4edf1c6e91..46c33fbb9fc5 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/FetchTiming.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/FetchTiming.java @@ -26,6 +26,7 @@ public static FetchTiming forType(FetchType type) { return switch (type) { case EAGER -> IMMEDIATE; case LAZY -> DELAYED; + case DEFAULT -> throw new UnsupportedOperationException( "Not implemented yet - decide how to handle" ); }; } } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/mutation/internal/MutationQueryOptions.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/mutation/internal/MutationQueryOptions.java index 9c8f1d9de5be..9085ae4a8b90 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/mutation/internal/MutationQueryOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/mutation/internal/MutationQueryOptions.java @@ -8,6 +8,7 @@ import java.util.List; import java.util.Set; +import jakarta.persistence.Timeout; import org.hibernate.FlushMode; import org.hibernate.LockOptions; import org.hibernate.graph.spi.AppliedGraph; @@ -26,7 +27,7 @@ public class MutationQueryOptions implements QueryOptions { public static final MutationQueryOptions INSTANCE = new MutationQueryOptions(); @Override - public Integer getTimeout() { + public Timeout getTimeout() { return null; } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/EffectiveEntityGraph.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/EffectiveEntityGraph.java index e7dd5208a35b..9d5907135f73 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/EffectiveEntityGraph.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/EffectiveEntityGraph.java @@ -6,6 +6,7 @@ import java.io.Serializable; import java.util.Map; +import java.util.function.Supplier; import org.hibernate.Incubating; import org.hibernate.graph.GraphSemantic; @@ -134,4 +135,30 @@ public void clear() { semantic = null; graph = null; } + + public void withAppliedGraph(GraphSemantic semantic, RootGraphImplementor graph, Runnable action) { + var currentSemantic = this.semantic; + var currentGraph = this.graph; + + try { + action.run(); + } + finally { + this.semantic = currentSemantic; + this.graph = currentGraph; + } + } + + public T fromAppliedGraph(GraphSemantic semantic, RootGraphImplementor graph, Supplier action) { + var currentSemantic = this.semantic; + var currentGraph = this.graph; + + try { + return action.get(); + } + finally { + this.semantic = currentSemantic; + this.graph = currentGraph; + } + } } 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 d7d41fa8f5d9..d894264cbd40 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 @@ -355,4 +355,12 @@ private boolean hasSubselectLoadableCollectionsEnabledInProfile(EntityPersister } return false; } + + public void withAppliedGraph(GraphSemantic semantic, RootGraphImplementor graph, Runnable action) { + effectiveEntityGraph.withAppliedGraph( semantic, graph, action ); + } + + public T fromAppliedGraph(GraphSemantic semantic, RootGraphImplementor graph, Supplier action) { + return effectiveEntityGraph.fromAppliedGraph( semantic, graph, action ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java index 492ecd4462c8..e09fe360bf14 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java @@ -6,6 +6,8 @@ import jakarta.persistence.CacheRetrieveMode; import jakarta.persistence.CacheStoreMode; +import jakarta.persistence.ConnectionConsumer; +import jakarta.persistence.ConnectionFunction; import jakarta.persistence.EntityGraph; import jakarta.persistence.EntityManagerFactory; import jakarta.persistence.FindOption; @@ -20,6 +22,7 @@ import jakarta.persistence.criteria.CriteriaUpdate; import jakarta.persistence.metamodel.EntityType; import jakarta.persistence.metamodel.Metamodel; +import jakarta.persistence.sql.ResultSetMapping; import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.CacheMode; import org.hibernate.Filter; @@ -56,12 +59,12 @@ import org.hibernate.persister.entity.EntityPersister; import org.hibernate.procedure.ProcedureCall; import org.hibernate.query.MutationQuery; +import org.hibernate.query.NativeQuery; import org.hibernate.query.SelectionQuery; import org.hibernate.query.criteria.HibernateCriteriaBuilder; import org.hibernate.query.criteria.JpaCriteriaInsert; import org.hibernate.query.spi.QueryImplementor; import org.hibernate.query.spi.QueryParameterBindings; -import org.hibernate.query.spi.QueryProducerImplementor; import org.hibernate.query.sql.spi.NativeQueryImplementor; import org.hibernate.resource.jdbc.spi.JdbcSessionContext; import org.hibernate.resource.transaction.spi.TransactionCoordinator; @@ -498,6 +501,54 @@ public Metamodel getMetamodel() { return delegate.getMetamodel(); } + @Override + public T get(Class entityClass, Object key, FindOption... findOptions) { + //noinspection resource + return delegate().get( entityClass, key, findOptions ); + } + + @Override + public T get(EntityGraph entityGraph, Object key, FindOption... findOptions) { + //noinspection resource + return delegate().get( entityGraph, key, findOptions ); + } + + @Override + public List getMultiple(Class entityClass, List keys, FindOption... findOptions) { + //noinspection resource + return delegate().getMultiple( entityClass, keys, findOptions ); + } + + @Override + public List getMultiple(EntityGraph entityGraph, List keys, FindOption... findOptions) { + //noinspection resource + return delegate().getMultiple( entityGraph, keys, findOptions ); + } + + @Override + public EntityGraph getEntityGraph(Class entityClass, String name) { + //noinspection resource + return delegate().getEntityGraph( entityClass, name ); + } + + @Override + public void runWithConnection(ConnectionConsumer connectionConsumer) { + //noinspection resource + delegate().runWithConnection( connectionConsumer ); + } + + @Override + public T callWithConnection(ConnectionFunction connectionFunction) { + //noinspection resource + return delegate().callWithConnection( connectionFunction ); + } + + @Override + public List> getEntityGraphs(Class entityClass) { + //noinspection resource + return delegate().getEntityGraphs( entityClass ); + } + @Override public RootGraphImplementor createEntityGraph(Class rootType) { return delegate.createEntityGraph( rootType ); @@ -518,117 +569,120 @@ public RootGraphImplementor getEntityGraph(String graphName) { return delegate.getEntityGraph( graphName ); } - @Override - public QueryImplementor createQuery(CriteriaSelect selectQuery) { - return delegate.createQuery( selectQuery ); - } - - @Override - public List> getEntityGraphs(Class entityClass) { - return delegate.getEntityGraphs( entityClass ); - } - - private QueryProducerImplementor queryDelegate() { - return delegate; + private SessionImplementor queryDelegate() { + return delegate(); } @Override public MutationQuery createMutationQuery(@SuppressWarnings("rawtypes") CriteriaUpdate updateQuery) { //noinspection resource - return delegate().createMutationQuery( updateQuery ); + return queryDelegate().createMutationQuery( updateQuery ); } @Override public MutationQuery createMutationQuery(@SuppressWarnings("rawtypes") CriteriaDelete deleteQuery) { //noinspection resource - return delegate().createMutationQuery( deleteQuery ); + return queryDelegate().createMutationQuery( deleteQuery ); } @Override public MutationQuery createMutationQuery(@SuppressWarnings("rawtypes") JpaCriteriaInsert insert) { //noinspection resource - return delegate().createMutationQuery( insert ); + return queryDelegate().createMutationQuery( insert ); } @Override public QueryImplementor createQuery(CriteriaQuery criteriaQuery) { + //noinspection resource + return queryDelegate().createQuery( criteriaQuery ); + } + + @Override + public QueryImplementor createQuery(CriteriaSelect criteriaQuery) { + //noinspection resource return queryDelegate().createQuery( criteriaQuery ); } @Override public @SuppressWarnings("rawtypes") QueryImplementor createQuery(CriteriaUpdate updateQuery) { + //noinspection resource return queryDelegate().createQuery( updateQuery ); } @Override public @SuppressWarnings("rawtypes") QueryImplementor createQuery(CriteriaDelete deleteQuery) { + //noinspection resource return queryDelegate().createQuery( deleteQuery ); } @Override - public QueryImplementor createQuery(TypedQueryReference typedQueryReference) { - return queryDelegate().createQuery( typedQueryReference ); - } - - @Override - public @SuppressWarnings("rawtypes") QueryImplementor getNamedQuery(String name) { - return queryDelegate().getNamedQuery( name ); - } - - @Override - public @SuppressWarnings("rawtypes") NativeQueryImplementor getNamedNativeQuery(String name) { - return queryDelegate().getNamedNativeQuery( name ); - } - - @Override - public @SuppressWarnings("rawtypes") NativeQueryImplementor getNamedNativeQuery(String name, String resultSetMapping) { - return queryDelegate().getNamedNativeQuery( name, resultSetMapping ); - } - - @Override @SuppressWarnings("rawtypes") - public QueryImplementor createQuery(String queryString) { + public @SuppressWarnings("rawtypes") QueryImplementor createQuery(String queryString) { + //noinspection resource return queryDelegate().createQuery( queryString ); } @Override - public SelectionQuery createSelectionQuery(String hqlString) { - return queryDelegate().createSelectionQuery( hqlString ); + public QueryImplementor createQuery(String hqlString, EntityGraph resultGraph) { + //noinspection resource + return queryDelegate().createQuery( hqlString, resultGraph ); } @Override public SelectionQuery createSelectionQuery(String hqlString, Class resultType) { + //noinspection resource return queryDelegate().createSelectionQuery( hqlString, resultType ); } @Override public SelectionQuery createSelectionQuery(String hqlString, EntityGraph resultGraph) { + //noinspection resource return queryDelegate().createSelectionQuery( hqlString, resultGraph ); } @Override public SelectionQuery createSelectionQuery(CriteriaQuery criteria) { + //noinspection resource + return queryDelegate().createSelectionQuery( criteria ); + } + + @Override + public SelectionQuery createSelectionQuery(CriteriaSelect criteria) { + //noinspection resource return queryDelegate().createSelectionQuery( criteria ); } @Override public QueryImplementor createQuery(String queryString, Class resultType) { + //noinspection resource return queryDelegate().createQuery( queryString, resultType ); } + @Override + public QueryImplementor createQuery(TypedQueryReference typedQueryReference) { + //noinspection resource + return queryDelegate().createQuery( typedQueryReference ); + } + @Override public @SuppressWarnings("rawtypes") QueryImplementor createNamedQuery(String name) { + //noinspection resource return queryDelegate().createNamedQuery( name ); } @Override public QueryImplementor createNamedQuery(String name, Class resultClass) { + //noinspection resource return queryDelegate().createNamedQuery( name, resultClass ); } @Override - public SelectionQuery createNamedSelectionQuery(String name) { - //noinspection resource - return delegate().createNamedSelectionQuery( name ); + public NativeQueryImplementor createNamedQuery(String name, String resultSetMappingName) { + return queryDelegate().createNamedQuery( name, resultSetMappingName ); + } + + @Override + public NativeQueryImplementor createNamedQuery(String name, String resultSetMappingName, Class resultClass) { + return queryDelegate().createNamedQuery( name, resultSetMappingName, resultClass ); } @Override @@ -639,6 +693,7 @@ public SelectionQuery createNamedSelectionQuery(String name, Class res @Override public @SuppressWarnings("rawtypes") NativeQueryImplementor createNativeQuery(String sqlString) { + //noinspection resource return queryDelegate().createNativeQuery( sqlString ); } @@ -646,57 +701,74 @@ public SelectionQuery createNamedSelectionQuery(String name, Class res //note: we're doing something a bit funny here to work around // the clashing signatures declared by the supertypes public NativeQueryImplementor createNativeQuery(String sqlString, Class resultClass) { + //noinspection resource return queryDelegate().createNativeQuery( sqlString, resultClass ); } @Override public NativeQueryImplementor createNativeQuery(String sqlString, Class resultClass, String tableAlias) { + //noinspection resource return queryDelegate().createNativeQuery( sqlString, resultClass, tableAlias ); } @Override public @SuppressWarnings("rawtypes") NativeQueryImplementor createNativeQuery(String sqlString, String resultSetMappingName) { - return queryDelegate().createNativeQuery( sqlString, resultSetMappingName ); + //noinspection resource + return queryDelegate().createNativeQuery( sqlString, resultSetMappingName, Object.class ); + } + + @Override + public NativeQueryImplementor createNativeQuery(String sql, ResultSetMapping resultSetMapping) { + //noinspection resource + return queryDelegate().createNativeQuery( sql, resultSetMapping ); } @Override public NativeQueryImplementor createNativeQuery(String sqlString, String resultSetMappingName, Class resultClass) { + //noinspection resource return queryDelegate().createNativeQuery( sqlString, resultSetMappingName, resultClass ); } @Override public MutationQuery createMutationQuery(String statementString) { - return delegate.createMutationQuery( statementString ); + //noinspection resource + return queryDelegate().createMutationQuery( statementString ); } @Override public MutationQuery createNamedMutationQuery(String name) { - return delegate.createNamedMutationQuery( name ); + //noinspection resource + return queryDelegate().createNamedMutationQuery( name ); } @Override public MutationQuery createNativeMutationQuery(String sqlString) { - return delegate.createNativeMutationQuery( sqlString ); + //noinspection resource + return queryDelegate().createNativeMutationQuery( sqlString ); } @Override public ProcedureCall createNamedStoredProcedureQuery(String name) { - return delegate.createNamedStoredProcedureQuery( name ); + //noinspection resource + return queryDelegate().createNamedStoredProcedureQuery( name ); } @Override public ProcedureCall createStoredProcedureQuery(String procedureName) { - return delegate.createStoredProcedureQuery( procedureName ); + //noinspection resource + return queryDelegate().createStoredProcedureQuery( procedureName ); } @Override - public ProcedureCall createStoredProcedureQuery(String procedureName, Class... resultClasses) { - return delegate.createStoredProcedureQuery( procedureName, resultClasses ); + public ProcedureCall createStoredProcedureQuery(String procedureName, Class... resultClasses) { + //noinspection resource + return queryDelegate().createStoredProcedureQuery( procedureName, resultClasses ); } @Override public ProcedureCall createStoredProcedureQuery(String procedureName, String... resultSetMappings) { - return delegate.createStoredProcedureQuery( procedureName, resultSetMappings ); + //noinspection resource + return queryDelegate().createStoredProcedureQuery( procedureName, resultSetMappings ); } @Override @@ -719,6 +791,11 @@ public T unwrap(Class cls) { return delegate.unwrap( cls ); } + @Override + public NativeQuery getNamedNativeQuery(String name) { + return delegate().getNamedNativeQuery( name ); + } + /** * This is the implementation of {@link jakarta.persistence.EntityManager#getDelegate()}. * It returns this object and not what we call the "delegate" session here. @@ -876,11 +953,6 @@ public void remove(Object entity) { return delegate.find( entityClass, primaryKey, properties ); } - @Override - public @Nullable T find(Class entityClass, Object primaryKey, LockModeType lockMode) { - return delegate.find( entityClass, primaryKey, lockMode ); - } - @Override public @Nullable T find(Class entityClass, Object primaryKey, LockModeType lockMode, Map properties) { return delegate.find( entityClass, primaryKey, lockMode, properties ); @@ -896,11 +968,6 @@ public T find(EntityGraph entityGraph, Object primaryKey, FindOption... o return delegate.find( entityGraph, primaryKey, options ); } - @Override - public Object find(String entityName, Object primaryKey) { - return delegate.find( entityName, primaryKey ); - } - @Override public Object find(String entityName, Object primaryKey, FindOption... options) { return delegate.find( entityName, primaryKey, options ); @@ -951,11 +1018,6 @@ public void refresh(Object entity, Map properties) { delegate.refresh( entity, properties ); } - @Override - public void refresh(Object entity, LockModeType lockMode) { - delegate.refresh( entity, lockMode ); - } - @Override public void refresh(Object entity, LockModeType lockMode, Map properties) { delegate.refresh( entity, lockMode, properties ); @@ -1007,8 +1069,8 @@ public T get(Class theClass, Object id, LockMode lockMode) { } @Override - public Object get(String entityName, Object id) { - return delegate.get( entityName, id ); + public Object get(String entityName, Object key, FindOption... findOptions) { + return delegate.get( entityName, key, findOptions ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryDelegatingImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryDelegatingImpl.java index 1ce6152abe87..a938ab702da9 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryDelegatingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryDelegatingImpl.java @@ -4,7 +4,10 @@ */ package org.hibernate.engine.spi; +import jakarta.persistence.EntityAgent; import jakarta.persistence.EntityGraph; +import jakarta.persistence.EntityHandler; +import jakarta.persistence.EntityListenerRegistration; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceUnitTransactionType; import jakarta.persistence.PersistenceUnitUtil; @@ -12,6 +15,7 @@ import jakarta.persistence.SynchronizationType; import jakarta.persistence.TypedQuery; import jakarta.persistence.TypedQueryReference; +import jakarta.persistence.sql.ResultSetMapping; import org.hibernate.CustomEntityDirtinessStrategy; import org.hibernate.HibernateException; import org.hibernate.Session; @@ -52,6 +56,7 @@ import javax.naming.NamingException; import javax.naming.Reference; +import java.lang.annotation.Annotation; import java.sql.Connection; import java.util.Collection; import java.util.List; @@ -183,6 +188,16 @@ public R callInTransaction(Function work) { return delegate.callInTransaction( work ); } + @Override + public void runInTransaction(Class handlerType, Consumer consumer) { + delegate.runInTransaction( handlerType, consumer ); + } + + @Override + public R callInTransaction(Class handlerType, Function function) { + return delegate.callInTransaction( handlerType, function ); + } + @Override public Set getDefinedFilterNames() { return delegate.getDefinedFilterNames(); @@ -248,6 +263,19 @@ public Map> getNamedEntityGraphs(Class e return delegate.getNamedEntityGraphs( entityType ); } + @Override + public Map> getResultSetMappings(Class type) { + return delegate.getResultSetMappings( type ); + } + + @Override + public EntityListenerRegistration addListener( + Class entityType, + Class eventType, + Consumer listener) { + return delegate.addListener( entityType, eventType, listener ); + } + @Override public String bestGuessEntityName(Object object) { return delegate.bestGuessEntityName( object ); @@ -353,6 +381,16 @@ public Session createEntityManager(SynchronizationType synchronizationType) { return delegate.createEntityManager( synchronizationType ); } + @Override + public EntityAgent createEntityAgent() { + return delegate.createEntityAgent(); + } + + @Override + public EntityAgent createEntityAgent(Map map) { + return delegate.createEntityAgent( map ); + } + @Override public Session createEntityManager(SynchronizationType synchronizationType, Map map) { return delegate.createEntityManager( synchronizationType, map ); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionImplementor.java index 5dd68770d060..18681e238ba6 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionImplementor.java @@ -4,8 +4,6 @@ */ package org.hibernate.engine.spi; -import jakarta.persistence.ConnectionConsumer; -import jakarta.persistence.ConnectionFunction; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.engine.jdbc.LobCreationContext; @@ -19,6 +17,7 @@ import jakarta.persistence.criteria.CriteriaSelect; + /** * Defines the "internal contract" between {@link Session} and other parts of Hibernate * including implementors of {@link org.hibernate.type.Type}, {@link EntityPersister}, @@ -100,30 +99,4 @@ default TransactionCompletionCallbacksImplementor getTransactionCompletionCallba * Initiate a flush to force deletion of a re-persisted entity. */ void forceFlush(EntityKey e) throws HibernateException; - - @Override - default void runWithConnection(ConnectionConsumer action) { - doWork( connection -> { - try { - //noinspection unchecked - action.accept( (C) connection ); - } - catch (Exception e) { - throw new RuntimeException( e ); - } - } ); - } - - @Override - default T callWithConnection(ConnectionFunction function) { - return doReturningWork( connection -> { - try { - //noinspection unchecked - return function.apply( (C) connection ); - } - catch (Exception e) { - throw new RuntimeException( e ); - } - } ); - } } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java index ca102676a444..5a660fe52acb 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java @@ -23,6 +23,7 @@ import jakarta.persistence.criteria.CriteriaUpdate; import jakarta.persistence.metamodel.EntityType; import jakarta.persistence.metamodel.Metamodel; +import jakarta.persistence.sql.ResultSetMapping; import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.CacheMode; import org.hibernate.Filter; @@ -282,14 +283,34 @@ public T get(Class entityType, Object id) { return this.lazySession.get().get( entityType, id ); } + @Override + public T get(Class entityType, Object key, FindOption... findOptions) { + return this.lazySession.get().get( entityType, key, findOptions ); + } + + @Override + public T get(EntityGraph entityGraph, Object key, FindOption... findOptions) { + return this.lazySession.get().get( entityGraph, key, findOptions ); + } + + @Override + public List getMultiple(Class entityType, List keys, FindOption... findOptions) { + return this.lazySession.get().getMultiple( entityType, keys, findOptions ); + } + + @Override + public List getMultiple(EntityGraph entityGraph, List keys, FindOption... findOptions) { + return this.lazySession.get().getMultiple( entityGraph, keys, findOptions ); + } + @Override public T get(Class entityType, Object id, LockMode lockMode) { return this.lazySession.get().get( entityType, id, lockMode ); } @Override - public Object get(String entityName, Object id) { - return this.lazySession.get().get( entityName, id ); + public Object get(String entityName, Object key, FindOption... findOptions) { + return this.lazySession.get().get( entityName, key, findOptions ); } @Override @@ -477,6 +498,11 @@ public RootGraph getEntityGraph(String graphName) { return this.lazySession.get().getEntityGraph( graphName ); } + @Override + public EntityGraph getEntityGraph(Class entityClass, String name) { + return this.lazySession.get().getEntityGraph( entityClass, name ); + } + @Override public List> getEntityGraphs(Class entityClass) { return this.lazySession.get().getEntityGraphs( entityClass ); @@ -497,6 +523,11 @@ public Query createQuery(String queryString, Class resultClass) { return this.lazySession.get().createQuery( queryString, resultClass ); } + @Override + public Query createQuery(String query, EntityGraph entityGraph) { + return this.lazySession.get().createQuery( query, entityGraph ); + } + @Override public Query createQuery(TypedQueryReference typedQueryReference) { return this.lazySession.get().createQuery( typedQueryReference ); @@ -514,6 +545,16 @@ public Query createNamedQuery(String name, Class resultClass) { return this.lazySession.get().createNamedQuery( name, resultClass ); } + @Override + public NativeQuery createNamedQuery(String name, String resultSetMappingName) { + return this.lazySession.get().createNamedQuery( name, resultSetMappingName ); + } + + @Override + public NativeQuery createNamedQuery(String name, String resultSetMappingName, Class resultClass) { + return this.lazySession.get().createNamedQuery( name, resultSetMappingName, resultClass ); + } + @SuppressWarnings("rawtypes") @Override @Deprecated @@ -527,7 +568,12 @@ public Query createQuery(CriteriaQuery criteriaQuery) { } @Override - public TypedQuery createQuery(CriteriaSelect selectQuery) { + public SelectionQuery createSelectionQuery(CriteriaSelect criteria) { + return this.lazySession.get().createSelectionQuery( criteria ); + } + + @Override + public Query createQuery(CriteriaSelect selectQuery) { return this.lazySession.get().createQuery( selectQuery ); } @@ -691,17 +737,17 @@ public NativeQuery createNativeQuery(String sqlString, Class resultCla @Override @Deprecated public NativeQuery createNativeQuery(String sqlString, String resultSetMappingName) { - return this.lazySession.get().createNativeQuery( sqlString, resultSetMappingName ); + return this.lazySession.get().createNativeQuery( sqlString, resultSetMappingName, Object.class ); } @Override - public NativeQuery createNativeQuery(String sqlString, String resultSetMappingName, Class resultClass) { - return this.lazySession.get().createNativeQuery( sqlString, resultSetMappingName, resultClass ); + public TypedQuery createNativeQuery(String sql, ResultSetMapping resultSetMapping) { + return this.lazySession.get().createNativeQuery( sql, resultSetMapping ); } @Override - public SelectionQuery createSelectionQuery(String hqlString) { - return this.lazySession.get().createSelectionQuery( hqlString ); + public NativeQuery createNativeQuery(String sqlString, String resultSetMappingName, Class resultClass) { + return this.lazySession.get().createNativeQuery( sqlString, resultSetMappingName, resultClass ); } @Override @@ -744,11 +790,6 @@ public MutationQuery createNativeMutationQuery(String sqlString) { return this.lazySession.get().createNativeMutationQuery( sqlString ); } - @Override - public SelectionQuery createNamedSelectionQuery(String name) { - return this.lazySession.get().createNamedSelectionQuery( name ); - } - @Override public SelectionQuery createNamedSelectionQuery(String name, Class resultType) { return this.lazySession.get().createNamedSelectionQuery( name, resultType ); @@ -759,27 +800,6 @@ public MutationQuery createNamedMutationQuery(String name) { return this.lazySession.get().createNamedMutationQuery( name ); } - @SuppressWarnings("rawtypes") - @Override - @Deprecated - public Query getNamedQuery(String queryName) { - return this.lazySession.get().getNamedQuery( queryName ); - } - - @SuppressWarnings("rawtypes") - @Override - @Deprecated - public NativeQuery getNamedNativeQuery(String name) { - return this.lazySession.get().getNamedNativeQuery( name ); - } - - @SuppressWarnings("rawtypes") - @Override - @Deprecated - public NativeQuery getNamedNativeQuery(String name, String resultSetMapping) { - return this.lazySession.get().getNamedNativeQuery( name, resultSetMapping ); - } - @Override public @Nullable T find(Class entityClass, Object primaryKey) { return this.lazySession.get().find( entityClass, primaryKey ); @@ -790,11 +810,6 @@ public NativeQuery getNamedNativeQuery(String name, String resultSetMapping) { return this.lazySession.get().find( entityClass, primaryKey, properties ); } - @Override - public @Nullable T find(Class entityClass, Object primaryKey, LockModeType lockMode) { - return this.lazySession.get().find( entityClass, primaryKey, lockMode ); - } - @Override public @Nullable T find(Class entityClass, Object primaryKey, LockModeType lockMode, Map properties) { return this.lazySession.get().find( entityClass, primaryKey, lockMode, properties ); @@ -810,11 +825,6 @@ public T find(EntityGraph entityGraph, Object primaryKey, FindOption... o return this.lazySession.get().find( entityGraph, primaryKey, options ); } - @Override - public Object find(String entityName, Object primaryKey) { - return this.lazySession.get().find( entityName, primaryKey ); - } - @Override public Object find(String entityName, Object primaryKey, FindOption... options) { return this.lazySession.get().find( entityName, primaryKey, options ); @@ -840,11 +850,6 @@ public void refresh(Object entity, Map properties) { this.lazySession.get().refresh( entity, properties ); } - @Override - public void refresh(Object entity, LockModeType lockMode) { - this.lazySession.get().refresh( entity, lockMode ); - } - @Override public void refresh(Object entity, LockModeType lockMode, Map properties) { this.lazySession.get().refresh( entity, lockMode, properties ); @@ -892,6 +897,11 @@ public T unwrap(Class type) { : lazySession.get().unwrap( type ); } + @Override + public NativeQuery getNamedNativeQuery(String name) { + return lazySession.get().getNamedNativeQuery( name ); + } + @Override public Object getDelegate() { return lazySession.get().getDelegate(); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java index f655ecf2bb73..9db612505e52 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java @@ -4,33 +4,38 @@ */ package org.hibernate.engine.spi; -import java.util.Set; -import java.util.UUID; +import jakarta.persistence.EntityGraph; import jakarta.persistence.TransactionRequiredException; +import jakarta.persistence.TypedQueryReference; +import jakarta.persistence.criteria.CriteriaDelete; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.CriteriaSelect; +import jakarta.persistence.criteria.CriteriaUpdate; +import jakarta.persistence.sql.ResultSetMapping; import org.checkerframework.checker.nullness.qual.Nullable; - import org.hibernate.FlushMode; import org.hibernate.HibernateException; import org.hibernate.Incubating; import org.hibernate.Interceptor; import org.hibernate.LockMode; import org.hibernate.LockOptions; -import org.hibernate.StatelessSession; -import org.hibernate.bytecode.enhance.spi.interceptor.SessionAssociationMarkers; -import org.hibernate.dialect.Dialect; -import org.hibernate.event.spi.EventSource; -import org.hibernate.graph.spi.RootGraphImplementor; -import org.hibernate.query.Query; import org.hibernate.SharedSessionContract; +import org.hibernate.StatelessSession; import org.hibernate.Transaction; +import org.hibernate.bytecode.enhance.spi.interceptor.SessionAssociationMarkers; import org.hibernate.cache.spi.CacheTransactionSynchronization; import org.hibernate.collection.spi.PersistentCollection; +import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.LobCreationContext; import org.hibernate.engine.jdbc.spi.JdbcCoordinator; import org.hibernate.engine.jdbc.spi.JdbcServices; +import org.hibernate.event.spi.EventSource; +import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.query.Query; +import org.hibernate.query.spi.QueryImplementor; import org.hibernate.query.spi.QueryParameterBindings; -import org.hibernate.query.spi.QueryProducerImplementor; +import org.hibernate.query.sql.spi.NativeQueryImplementor; import org.hibernate.resource.jdbc.spi.JdbcSessionOwner; import org.hibernate.resource.transaction.spi.TransactionCoordinator; import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder.Options; @@ -38,6 +43,9 @@ import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.spi.TypeConfiguration; +import java.util.Set; +import java.util.UUID; + /** * Defines the internal contract shared between {@link org.hibernate.Session} and * {@link org.hibernate.StatelessSession} as used by other parts of Hibernate, @@ -71,7 +79,7 @@ */ public interface SharedSessionContractImplementor extends SharedSessionContract, JdbcSessionOwner, Options, LobCreationContext, WrapperOptions, - QueryProducerImplementor, JavaType.CoercionContext { + JavaType.CoercionContext { /** * Obtain the {@linkplain SessionFactoryImplementor factory} which created this session. @@ -406,7 +414,6 @@ default String bestGuessEntityName(Object object, EntityEntry entry) { * * @return The flush mode */ - @Override FlushMode getHibernateFlushMode(); /** @@ -631,4 +638,68 @@ default boolean isStatelessSession() { @Override RootGraphImplementor getEntityGraph(String graphName); + + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Query-related covariance + + @Override + @SuppressWarnings("rawtypes") + QueryImplementor createQuery(String queryString); + + @Override + QueryImplementor createQuery(String queryString, Class resultClass); + + @Override + QueryImplementor createQuery(TypedQueryReference typedQueryReference); + + @Override + QueryImplementor createQuery(CriteriaQuery criteriaQuery); + + @Override + NativeQueryImplementor createNativeQuery(String sqlString, Class resultClass); + + @Override + NativeQueryImplementor createNativeQuery(String sqlString, Class resultClass, String tableAlias); + + @Override + NativeQueryImplementor createNativeQuery(String sqlString, String resultSetMappingName, Class resultClass); + + @Override + QueryImplementor createNamedQuery(String name, Class resultClass); + + @Override + NativeQueryImplementor createNamedQuery(String name, String resultSetMappingName); + + @Override + NativeQueryImplementor createNamedQuery(String name, String resultSetMappingName, Class resultClass); + + @Override + QueryImplementor createQuery(CriteriaSelect criteriaSelect); + + @Override + @SuppressWarnings("rawtypes") + QueryImplementor createQuery(CriteriaUpdate criteriaUpdate); + + @Override + @SuppressWarnings("rawtypes") + QueryImplementor createQuery(CriteriaDelete criteriaDelete); + + @Override + QueryImplementor createQuery(String queryString, EntityGraph entityGraph); + + @Override + @SuppressWarnings("rawtypes") + QueryImplementor createNamedQuery(String name); + + @Override + @SuppressWarnings("rawtypes") + NativeQueryImplementor createNativeQuery(String sql); + + @Override + @SuppressWarnings("rawtypes") + NativeQueryImplementor createNativeQuery(String sql, String resultSetMappingName); + + @Override + NativeQueryImplementor createNativeQuery(String sql, ResultSetMapping resultSetMapping); } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionDelegatorBaseImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionDelegatorBaseImpl.java index dd504209d509..865d4c13d4b6 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionDelegatorBaseImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionDelegatorBaseImpl.java @@ -4,11 +4,20 @@ */ package org.hibernate.engine.spi; +import jakarta.persistence.CacheRetrieveMode; +import jakarta.persistence.CacheStoreMode; +import jakarta.persistence.ConnectionConsumer; +import jakarta.persistence.ConnectionFunction; import jakarta.persistence.EntityGraph; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.FindOption; import jakarta.persistence.TypedQueryReference; import jakarta.persistence.criteria.CriteriaDelete; import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.CriteriaSelect; import jakarta.persistence.criteria.CriteriaUpdate; +import jakarta.persistence.metamodel.Metamodel; +import jakarta.persistence.sql.ResultSetMapping; import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.CacheMode; import org.hibernate.Filter; @@ -41,7 +50,6 @@ import org.hibernate.query.criteria.JpaCriteriaInsert; import org.hibernate.query.spi.QueryImplementor; import org.hibernate.query.spi.QueryParameterBindings; -import org.hibernate.query.spi.QueryProducerImplementor; import org.hibernate.query.sql.spi.NativeQueryImplementor; import org.hibernate.resource.jdbc.spi.JdbcSessionContext; import org.hibernate.resource.transaction.spi.TransactionCoordinator; @@ -50,6 +58,7 @@ import java.sql.Connection; import java.sql.SQLException; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.TimeZone; import java.util.UUID; @@ -61,7 +70,7 @@ * * @author Gavin King */ -@SuppressWarnings("deprecation") +@SuppressWarnings("resource") public class SharedSessionDelegatorBaseImpl implements SharedSessionContractImplementor { protected final SharedSessionContractImplementor delegate; @@ -77,6 +86,16 @@ protected SharedSessionContract delegate() { return delegate; } + @Override + public EntityManagerFactory getEntityManagerFactory() { + return delegate().getEntityManagerFactory(); + } + + @Override + public Metamodel getMetamodel() { + return delegate().getMetamodel(); + } + @Override public SharedStatelessSessionBuilder statelessWithOptions() { return delegate.statelessWithOptions(); @@ -92,7 +111,102 @@ public Object getTenantIdentifierValue() { return delegate.getTenantIdentifierValue(); } - private QueryProducerImplementor queryDelegate() { + @Override + public CacheRetrieveMode getCacheRetrieveMode() { + return delegate().getCacheRetrieveMode(); + } + + @Override + public void setCacheRetrieveMode(CacheRetrieveMode cacheRetrieveMode) { + delegate().setCacheRetrieveMode( cacheRetrieveMode ); + } + + @Override + public CacheStoreMode getCacheStoreMode() { + return delegate().getCacheStoreMode(); + } + + @Override + public void setCacheStoreMode(CacheStoreMode cacheStoreMode) { + delegate().setCacheStoreMode( cacheStoreMode ); + } + + @Override + public void setProperty(String propertyName, Object value) { + delegate().setProperty( propertyName, value ); + } + + @Override + public Map getProperties() { + return delegate().getProperties(); + } + + @Override + public T get(Class entityClass, Object id) { + return delegate().get( entityClass, entityClass ); + } + + @Override + public T get(Class entityClass, Object key, FindOption... findOptions) { + return delegate().get( entityClass, key, findOptions ); + } + + @Override + public T get(EntityGraph entityGraph, Object key, FindOption... findOptions) { + return delegate().get( entityGraph, key, findOptions ); + } + + @Override + public List getMultiple(Class entityClass, List keys, FindOption... findOptions) { + return delegate().getMultiple( entityClass, keys, findOptions ); + } + + @Override + public List getMultiple(EntityGraph entityGraph, List keys, FindOption... findOptions) { + return delegate().getMultiple( entityGraph, keys, findOptions ); + } + + @Override + public T find(Class entityClass, Object id) { + return delegate().find( entityClass, id ); + } + + @Override + public T find(Class entityClass, Object key, FindOption... findOptions) { + return delegate().find( entityClass, key, findOptions ); + } + + @Override + public T find(EntityGraph entityGraph, Object key, FindOption... findOptions) { + return delegate().find( entityGraph, key, findOptions ); + } + + @Override + public List findMultiple(Class entityClass, List keys, FindOption... findOptions) { + return delegate().findMultiple( entityClass, keys, findOptions ); + } + + @Override + public List findMultiple(EntityGraph entityGraph, List keys, FindOption... findOptions) { + return delegate().findMultiple( entityGraph, keys, findOptions ); + } + + @Override + public void runWithConnection(ConnectionConsumer connectionConsumer) { + delegate().runWithConnection( connectionConsumer ); + } + + @Override + public T callWithConnection(ConnectionFunction connectionFunction) { + return delegate().callWithConnection( connectionFunction ); + } + + @Override + public EntityGraph getEntityGraph(Class entityClass, String name) { + return delegate().getEntityGraph( entityClass, name ); + } + + private SharedSessionContractImplementor queryDelegate() { return delegate; } @@ -119,6 +233,11 @@ public QueryImplementor createQuery(CriteriaQuery criteriaQuery) { return queryDelegate().createQuery( criteriaQuery ); } + @Override + public QueryImplementor createQuery(CriteriaSelect criteriaQuery) { + return queryDelegate().createQuery( criteriaQuery ); + } + @Override public @SuppressWarnings("rawtypes") QueryImplementor createQuery(CriteriaUpdate updateQuery) { return queryDelegate().createQuery( updateQuery ); @@ -129,29 +248,14 @@ public QueryImplementor createQuery(CriteriaQuery criteriaQuery) { return queryDelegate().createQuery( deleteQuery ); } - @Override - public @SuppressWarnings("rawtypes") QueryImplementor getNamedQuery(String name) { - return queryDelegate().getNamedQuery( name ); - } - - @Override - public @SuppressWarnings("rawtypes") NativeQueryImplementor getNamedNativeQuery(String name) { - return queryDelegate().getNamedNativeQuery( name ); - } - - @Override - public @SuppressWarnings("rawtypes") NativeQueryImplementor getNamedNativeQuery(String name, String resultSetMapping) { - return queryDelegate().getNamedNativeQuery( name, resultSetMapping ); - } - @Override public @SuppressWarnings("rawtypes") QueryImplementor createQuery(String queryString) { return queryDelegate().createQuery( queryString ); } @Override - public SelectionQuery createSelectionQuery(String hqlString) { - return queryDelegate().createSelectionQuery( hqlString ); + public QueryImplementor createQuery(String hqlString, EntityGraph resultGraph) { + return queryDelegate().createQuery( hqlString, resultGraph ); } @Override @@ -169,6 +273,11 @@ public SelectionQuery createSelectionQuery(CriteriaQuery criteria) { return queryDelegate().createSelectionQuery( criteria ); } + @Override + public SelectionQuery createSelectionQuery(CriteriaSelect criteria) { + return queryDelegate().createSelectionQuery( criteria ); + } + @Override public QueryImplementor createQuery(String queryString, Class resultType) { return queryDelegate().createQuery( queryString, resultType ); @@ -190,9 +299,13 @@ public QueryImplementor createNamedQuery(String name, Class resultClas } @Override - public SelectionQuery createNamedSelectionQuery(String name) { - //noinspection resource - return delegate().createNamedSelectionQuery( name ); + public NativeQueryImplementor createNamedQuery(String name, String resultSetMappingName) { + return queryDelegate().createNamedQuery( name, resultSetMappingName ); + } + + @Override + public NativeQueryImplementor createNamedQuery(String name, String resultSetMappingName, Class resultClass) { + return queryDelegate().createNamedQuery( name, resultSetMappingName, resultClass ); } @Override @@ -220,7 +333,12 @@ public NativeQueryImplementor createNativeQuery(String sqlString, Class NativeQueryImplementor createNativeQuery(String sql, ResultSetMapping resultSetMapping) { + return queryDelegate().createNativeQuery( sql, resultSetMapping ); } @Override @@ -230,57 +348,57 @@ public NativeQueryImplementor createNativeQuery(String sqlString, String @Override public MutationQuery createMutationQuery(String statementString) { - return delegate.createMutationQuery( statementString ); + return queryDelegate().createMutationQuery( statementString ); } @Override public MutationQuery createNamedMutationQuery(String name) { - return delegate.createNamedMutationQuery( name ); + return queryDelegate().createNamedMutationQuery( name ); } @Override public MutationQuery createNativeMutationQuery(String sqlString) { - return delegate.createNativeMutationQuery( sqlString ); + return queryDelegate().createNativeMutationQuery( sqlString ); } @Override public ProcedureCall createNamedStoredProcedureQuery(String name) { - return delegate.createNamedStoredProcedureQuery( name ); + return queryDelegate().createNamedStoredProcedureQuery( name ); } @Override public ProcedureCall createStoredProcedureQuery(String procedureName) { - return delegate.createStoredProcedureQuery( procedureName ); + return queryDelegate().createStoredProcedureQuery( procedureName ); } @Override public ProcedureCall createStoredProcedureQuery(String procedureName, Class... resultClasses) { - return delegate.createStoredProcedureQuery( procedureName, resultClasses ); + return queryDelegate().createStoredProcedureQuery( procedureName, resultClasses ); } @Override public ProcedureCall createStoredProcedureQuery(String procedureName, String... resultSetMappings) { - return delegate.createStoredProcedureQuery( procedureName, resultSetMappings ); + return queryDelegate().createStoredProcedureQuery( procedureName, resultSetMappings ); } @Override public ProcedureCall getNamedProcedureCall(String name) { - return delegate.getNamedProcedureCall( name ); + return queryDelegate().getNamedProcedureCall( name ); } @Override public ProcedureCall createStoredProcedureCall(String procedureName) { - return delegate.createStoredProcedureCall( procedureName ); + return queryDelegate().createStoredProcedureCall( procedureName ); } @Override public ProcedureCall createStoredProcedureCall(String procedureName, Class... resultClasses) { - return delegate.createStoredProcedureCall( procedureName, resultClasses ); + return queryDelegate().createStoredProcedureCall( procedureName, resultClasses ); } @Override public ProcedureCall createStoredProcedureCall(String procedureName, String... resultSetMappings) { - return delegate.createStoredProcedureCall( procedureName, resultSetMappings ); + return queryDelegate().createStoredProcedureCall( procedureName, resultSetMappings ); } @Override @@ -328,6 +446,16 @@ public boolean isJoinedToTransaction() { return delegate.isJoinedToTransaction(); } + @Override + public Object find(String entityName, Object key, FindOption... findOptions) { + return delegate.find( entityName, key, findOptions ); + } + + @Override + public Object get(String entityName, Object key, FindOption... findOptions) { + return delegate.get( entityName, key, findOptions ); + } + @Override public HibernateCriteriaBuilder getCriteriaBuilder() { return delegate.getCriteriaBuilder(); diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java index 9e8a22ad96b7..55d9f7f2403a 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java @@ -4,8 +4,6 @@ */ package org.hibernate.event.internal; -import java.util.Map; - import org.hibernate.LockMode; import org.hibernate.NonUniqueObjectException; import org.hibernate.action.internal.AbstractEntityInsertAction; @@ -20,17 +18,17 @@ import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.Status; import org.hibernate.event.spi.EventSource; +import org.hibernate.generator.BeforeExecutionGenerator; import org.hibernate.id.CompositeNestedGeneratedValueGenerator; import org.hibernate.id.IdentifierGenerationException; -import org.hibernate.jpa.event.spi.CallbackRegistry; -import org.hibernate.jpa.event.spi.CallbackRegistryConsumer; import org.hibernate.persister.entity.EntityPersister; -import org.hibernate.generator.BeforeExecutionGenerator; import org.hibernate.type.Type; import org.hibernate.type.TypeHelper; -import static org.hibernate.engine.internal.ManagedTypeHelper.processIfSelfDirtinessTracker; +import java.util.Map; + import static org.hibernate.engine.internal.ManagedTypeHelper.processIfManagedEntity; +import static org.hibernate.engine.internal.ManagedTypeHelper.processIfSelfDirtinessTracker; import static org.hibernate.engine.internal.Versioning.getVersion; import static org.hibernate.engine.internal.Versioning.seedVersion; import static org.hibernate.event.internal.EventListenerLogging.EVENT_LISTENER_LOGGER; @@ -45,14 +43,7 @@ * * @author Steve Ebersole. */ -public abstract class AbstractSaveEventListener implements CallbackRegistryConsumer { - - private CallbackRegistry callbackRegistry; - - @Override - public void injectCallbackRegistry(CallbackRegistry callbackRegistry) { - this.callbackRegistry = callbackRegistry; - } +public abstract class AbstractSaveEventListener { /** * Prepares the persist call using the given requested id. @@ -192,7 +183,7 @@ protected Object performSave( // call this after generation of an id, // but before we retrieve an assigned id - callbackRegistry.preCreate( entity ); + persister.getEntityCallbacks().preCreate( entity ); processIfSelfDirtinessTracker( entity, SelfDirtinessTracker::$$_hibernate_clearDirtyAttributes ); processIfManagedEntity( entity, managedEntity -> managedEntity.$$_hibernate_setUseTracker( true ) ); diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultDeleteEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultDeleteEventListener.java index ab80d10ec677..e019a15705f4 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultDeleteEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultDeleteEventListener.java @@ -29,8 +29,6 @@ import org.hibernate.event.spi.DeleteEventListener; import org.hibernate.event.spi.EventSource; import org.hibernate.internal.EmptyInterceptor; -import org.hibernate.jpa.event.spi.CallbackRegistry; -import org.hibernate.jpa.event.spi.CallbackRegistryConsumer; import org.hibernate.jpa.event.spi.CallbackType; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl; @@ -51,14 +49,7 @@ * * @author Steve Ebersole */ -public class DefaultDeleteEventListener implements DeleteEventListener, CallbackRegistryConsumer { - - private CallbackRegistry callbackRegistry; - - @Override - public void injectCallbackRegistry(CallbackRegistry callbackRegistry) { - this.callbackRegistry = callbackRegistry; - } +public class DefaultDeleteEventListener implements DeleteEventListener { /** * Handle the given delete event. @@ -273,7 +264,7 @@ private void delete( Object id, Object version, EntityEntry entityEntry) { - callbackRegistry.preRemove( entity ); + persister.getEntityCallbacks().preRemove( entity ); deleteEntity( source, entity, @@ -314,9 +305,8 @@ private static boolean hasCustomEventListeners(EventSource source) { } private boolean hasRegisteredRemoveCallbacks(EntityPersister persister) { - final Class mappedClass = persister.getMappedClass(); - return callbackRegistry.hasRegisteredCallbacks( mappedClass, CallbackType.PRE_REMOVE ) - || callbackRegistry.hasRegisteredCallbacks( mappedClass, CallbackType.POST_REMOVE ); + return persister.getEntityCallbacks().hasRegisteredCallbacks( CallbackType.PRE_REMOVE ) + || persister.getEntityCallbacks().hasRegisteredCallbacks( CallbackType.POST_REMOVE ); } /** diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultFlushEntityEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultFlushEntityEventListener.java index 80b16701cd1c..ce574fef9446 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultFlushEntityEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultFlushEntityEventListener.java @@ -4,8 +4,6 @@ */ package org.hibernate.event.internal; -import java.util.Arrays; - import org.hibernate.AssertionFailure; import org.hibernate.CustomEntityDirtinessStrategy; import org.hibernate.HibernateException; @@ -25,19 +23,19 @@ import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.FlushEntityEvent; import org.hibernate.event.spi.FlushEntityEventListener; -import org.hibernate.jpa.event.spi.CallbackRegistry; -import org.hibernate.jpa.event.spi.CallbackRegistryConsumer; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.type.Type; +import java.util.Arrays; + import static org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer.UNFETCHED_PROPERTY; import static org.hibernate.engine.internal.ManagedTypeHelper.asManagedEntity; import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable; import static org.hibernate.engine.internal.ManagedTypeHelper.asSelfDirtinessTracker; import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable; import static org.hibernate.engine.internal.ManagedTypeHelper.isSelfDirtinessTracker; -import static org.hibernate.engine.internal.ManagedTypeHelper.processIfSelfDirtinessTracker; import static org.hibernate.engine.internal.ManagedTypeHelper.processIfManagedEntity; +import static org.hibernate.engine.internal.ManagedTypeHelper.processIfSelfDirtinessTracker; import static org.hibernate.engine.internal.Versioning.getVersion; import static org.hibernate.engine.internal.Versioning.incrementVersion; import static org.hibernate.engine.internal.Versioning.setVersion; @@ -50,14 +48,7 @@ * * @author Gavin King */ -public class DefaultFlushEntityEventListener implements FlushEntityEventListener, CallbackRegistryConsumer { - - private CallbackRegistry callbackRegistry; - - @Override - public void injectCallbackRegistry(CallbackRegistry callbackRegistry) { - this.callbackRegistry = callbackRegistry; - } +public class DefaultFlushEntityEventListener implements FlushEntityEventListener { /** * Make sure user didn't mangle the id. @@ -337,14 +328,13 @@ protected boolean invokeInterceptor(FlushEntityEvent event) { final Object[] values = event.getPropertyValues(); final var persister = entry.getPersister(); - final boolean isDirty = - entry.getStatus() != Status.DELETED && callbackRegistry.preUpdate( entity ) - && copyState( entity, persister.getPropertyTypes(), values, event.getFactory() ); + final boolean isDirty = entry.getStatus() != Status.DELETED + && persister.getEntityCallbacks().preUpdate( entity ) + && copyState( entity, persister.getPropertyTypes(), values, event.getFactory() ); - final boolean stateModified = - event.getSession().getInterceptor() - .onFlushDirty( entity, id, values, entry.getLoadedState(), - persister.getPropertyNames(), persister.getPropertyTypes() ); + final boolean stateModified = event.getSession() + .getInterceptor() + .onFlushDirty( entity, id, values, entry.getLoadedState(), persister.getPropertyNames(), persister.getPropertyTypes() ); return stateModified || isDirty; } diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java index 191f2f5f91ac..c7d653d8084f 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java @@ -417,7 +417,7 @@ protected void entityIsDetached(MergeEvent event, Object copiedId, Object origin final Object result = session.getLoadQueryInfluencers() .fromInternalFetchProfile( CascadingFetchProfile.MERGE, - () -> session.get( entityName, clonedIdentifier ) ); + () -> session.find( entityName, clonedIdentifier ) ); if ( result == null ) { EVENT_LISTENER_LOGGER.detachedInstanceNotFoundInDatabase(); diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPersistEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPersistEventListener.java index e942e6842dff..761fead08feb 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPersistEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPersistEventListener.java @@ -15,7 +15,6 @@ import org.hibernate.event.spi.PersistContext; import org.hibernate.event.spi.PersistEvent; import org.hibernate.event.spi.PersistEventListener; -import org.hibernate.jpa.event.spi.CallbackRegistryConsumer; import org.hibernate.persister.entity.EntityPersister; import static org.hibernate.engine.internal.ProxyUtil.assertInitialized; @@ -33,7 +32,7 @@ */ public class DefaultPersistEventListener extends AbstractSaveEventListener - implements PersistEventListener, CallbackRegistryConsumer { + implements PersistEventListener { @Override protected CascadingAction getCascadeAction() { diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPostLoadEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPostLoadEventListener.java index 0b6516e45cc1..93005c45d838 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPostLoadEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPostLoadEventListener.java @@ -13,8 +13,6 @@ import org.hibernate.event.spi.PostLoadEvent; import org.hibernate.event.spi.PostLoadEventListener; import org.hibernate.internal.OptimisticLockHelper; -import org.hibernate.jpa.event.spi.CallbackRegistry; -import org.hibernate.jpa.event.spi.CallbackRegistryConsumer; /** * Performs needed {@link EntityEntry#getLockMode()}-related processing. @@ -22,19 +20,11 @@ * @author Gavin King * @author Steve Ebersole */ -public class DefaultPostLoadEventListener implements PostLoadEventListener, CallbackRegistryConsumer { - private CallbackRegistry callbackRegistry; - - @Override - public void injectCallbackRegistry(CallbackRegistry callbackRegistry) { - this.callbackRegistry = callbackRegistry; - } - +public class DefaultPostLoadEventListener implements PostLoadEventListener { @Override public void onPostLoad(PostLoadEvent event) { final Object entity = event.getEntity(); - - callbackRegistry.postLoad( entity ); + event.getPersister().getEntityCallbacks().postLoad( entity ); final var session = event.getSession(); final var entry = session.getPersistenceContextInternal().getEntry( entity ); diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/PostDeleteEventListenerStandardImpl.java b/hibernate-core/src/main/java/org/hibernate/event/internal/PostDeleteEventListenerStandardImpl.java index 16b310704bd3..36113cf2d03a 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/PostDeleteEventListenerStandardImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/PostDeleteEventListenerStandardImpl.java @@ -6,8 +6,6 @@ import org.hibernate.event.spi.PostDeleteEvent; import org.hibernate.event.spi.PostDeleteEventListener; -import org.hibernate.jpa.event.spi.CallbackRegistryConsumer; -import org.hibernate.jpa.event.spi.CallbackRegistry; import org.hibernate.jpa.event.spi.CallbackType; import org.hibernate.persister.entity.EntityPersister; @@ -17,22 +15,15 @@ * @author Kabir Khan * @author Steve Ebersole */ -public class PostDeleteEventListenerStandardImpl implements PostDeleteEventListener, CallbackRegistryConsumer { - private CallbackRegistry callbackRegistry; - - @Override - public void injectCallbackRegistry(CallbackRegistry callbackRegistry) { - this.callbackRegistry = callbackRegistry; - } - +public class PostDeleteEventListenerStandardImpl implements PostDeleteEventListener { @Override public void onPostDelete(PostDeleteEvent event) { Object entity = event.getEntity(); - callbackRegistry.postRemove( entity ); + event.getPersister().getEntityCallbacks().postRemove( entity ); } @Override public boolean requiresPostCommitHandling(EntityPersister persister) { - return callbackRegistry.hasRegisteredCallbacks( persister.getMappedClass(), CallbackType.POST_REMOVE ); + return persister.getEntityCallbacks().hasRegisteredCallbacks( CallbackType.POST_REMOVE ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/PostInsertEventListenerStandardImpl.java b/hibernate-core/src/main/java/org/hibernate/event/internal/PostInsertEventListenerStandardImpl.java index 224bc5866e4a..85b00d5b8849 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/PostInsertEventListenerStandardImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/PostInsertEventListenerStandardImpl.java @@ -6,8 +6,6 @@ import org.hibernate.event.spi.PostInsertEvent; import org.hibernate.event.spi.PostInsertEventListener; -import org.hibernate.jpa.event.spi.CallbackRegistryConsumer; -import org.hibernate.jpa.event.spi.CallbackRegistry; import org.hibernate.jpa.event.spi.CallbackType; import org.hibernate.persister.entity.EntityPersister; @@ -15,25 +13,15 @@ * @author Kabir Khan * @author Steve Ebersole */ -public class PostInsertEventListenerStandardImpl implements PostInsertEventListener, CallbackRegistryConsumer { - private CallbackRegistry callbackRegistry; - - public PostInsertEventListenerStandardImpl() { - } - - @Override - public void injectCallbackRegistry(CallbackRegistry callbackRegistry) { - this.callbackRegistry = callbackRegistry; - } - +public class PostInsertEventListenerStandardImpl implements PostInsertEventListener { @Override public void onPostInsert(PostInsertEvent event) { Object entity = event.getEntity(); - callbackRegistry.postCreate( entity ); + event.getPersister().getEntityCallbacks().postCreate( entity ); } @Override public boolean requiresPostCommitHandling(EntityPersister persister) { - return callbackRegistry.hasRegisteredCallbacks( persister.getMappedClass(), CallbackType.POST_PERSIST ); + return persister.getEntityCallbacks().hasRegisteredCallbacks( CallbackType.POST_PERSIST ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/PostUpdateEventListenerStandardImpl.java b/hibernate-core/src/main/java/org/hibernate/event/internal/PostUpdateEventListenerStandardImpl.java index 116642872621..5097d6f4ad03 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/PostUpdateEventListenerStandardImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/PostUpdateEventListenerStandardImpl.java @@ -8,37 +8,28 @@ import org.hibernate.engine.spi.Status; import org.hibernate.event.spi.PostUpdateEvent; import org.hibernate.event.spi.PostUpdateEventListener; -import org.hibernate.jpa.event.spi.CallbackRegistry; -import org.hibernate.jpa.event.spi.CallbackRegistryConsumer; import org.hibernate.jpa.event.spi.CallbackType; import org.hibernate.persister.entity.EntityPersister; /** * @author Steve Ebersole */ -public class PostUpdateEventListenerStandardImpl implements PostUpdateEventListener, CallbackRegistryConsumer { - private CallbackRegistry callbackRegistry; - - @Override - public void injectCallbackRegistry(CallbackRegistry callbackRegistry) { - this.callbackRegistry = callbackRegistry; - } - +public class PostUpdateEventListenerStandardImpl implements PostUpdateEventListener { @Override public void onPostUpdate(PostUpdateEvent event) { - handlePostUpdate( event.getEntity(), event.getSession() ); + handlePostUpdate( event.getEntity(), event.getPersister(), event.getSession() ); } - private void handlePostUpdate(Object entity, SharedSessionContractImplementor source) { + private void handlePostUpdate(Object entity, EntityPersister persister, SharedSessionContractImplementor source) { // mimic the preUpdate filter if ( source.isStateless() || source.getPersistenceContextInternal().getEntry( entity ).getStatus() != Status.DELETED ) { - callbackRegistry.postUpdate(entity); + persister.getEntityCallbacks().postUpdate(entity); } } @Override public boolean requiresPostCommitHandling(EntityPersister persister) { - return callbackRegistry.hasRegisteredCallbacks( persister.getMappedClass(), CallbackType.POST_UPDATE ); + return persister.getEntityCallbacks().hasRegisteredCallbacks( CallbackType.POST_UPDATE ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/PostUpsertEventListenerStandardImpl.java b/hibernate-core/src/main/java/org/hibernate/event/internal/PostUpsertEventListenerStandardImpl.java index 3cbd7abc909a..88bf778cb1ad 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/PostUpsertEventListenerStandardImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/PostUpsertEventListenerStandardImpl.java @@ -7,8 +7,6 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.event.spi.PostUpsertEvent; import org.hibernate.event.spi.PostUpsertEventListener; -import org.hibernate.jpa.event.spi.CallbackRegistry; -import org.hibernate.jpa.event.spi.CallbackRegistryConsumer; import org.hibernate.persister.entity.EntityPersister; /** @@ -16,14 +14,7 @@ * * @author Gavin King */ -public class PostUpsertEventListenerStandardImpl implements PostUpsertEventListener, CallbackRegistryConsumer { - private CallbackRegistry callbackRegistry; - - @Override - public void injectCallbackRegistry(CallbackRegistry callbackRegistry) { - this.callbackRegistry = callbackRegistry; - } - +public class PostUpsertEventListenerStandardImpl implements PostUpsertEventListener { @Override public void onPostUpsert(PostUpsertEvent event) { handlePostUpsert( event.getEntity(), event.getSession() ); @@ -39,6 +30,7 @@ private void handlePostUpsert(Object entity, SharedSessionContractImplementor so @Override public boolean requiresPostCommitHandling(EntityPersister persister) { - return false; //callbackRegistry.hasRegisteredCallbacks( persister.getMappedClass(), CallbackType.POST_UPDATE ); + //callbackRegistry.hasRegisteredCallbacks( persister.getMappedClass(), CallbackType.POST_UPDATE ); + return false; } } diff --git a/hibernate-core/src/main/java/org/hibernate/event/jpa/internal/AddedCallbackImpl.java b/hibernate-core/src/main/java/org/hibernate/event/jpa/internal/AddedCallbackImpl.java new file mode 100644 index 000000000000..6e469950de61 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/event/jpa/internal/AddedCallbackImpl.java @@ -0,0 +1,33 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.event.jpa.internal; + +import org.hibernate.event.jpa.spi.Callback; +import org.hibernate.jpa.event.spi.CallbackType; + +import java.util.function.Consumer; + +/** + * @author Steve Ebersole + */ +public class AddedCallbackImpl implements Callback { + private final CallbackType callbackType; + private final Consumer listener; + + public AddedCallbackImpl(CallbackType callbackType, Consumer listener) { + this.callbackType = callbackType; + this.listener = listener; + } + + @Override + public CallbackType getCallbackType() { + return callbackType; + } + + @Override + public void performCallback(S entity) { + listener.accept( entity ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/event/jpa/internal/EntityCallbacksFactory.java b/hibernate-core/src/main/java/org/hibernate/event/jpa/internal/EntityCallbacksFactory.java new file mode 100644 index 000000000000..628b3931838d --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/event/jpa/internal/EntityCallbacksFactory.java @@ -0,0 +1,38 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.event.jpa.internal; + +import org.hibernate.boot.spi.SessionFactoryOptions; +import org.hibernate.event.jpa.spi.EntityCallbacks; +import org.hibernate.internal.util.collections.CollectionHelper; +import org.hibernate.jpa.boot.spi.CallbackDefinition; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.resource.beans.spi.ManagedBeanRegistry; +import org.hibernate.service.ServiceRegistry; + +/// Builds Jakarta Persistence callbacks for an entity +/// +/// @author Steve Ebersole +public class EntityCallbacksFactory { + public static EntityCallbacks buildCallbacks( + PersistentClass persistentClass, + SessionFactoryOptions options, + ServiceRegistry serviceRegistry) { + if ( !options.areJPACallbacksEnabled() || persistentClass.getClassName() == null ) { + return NoCallbacks.NO_CALLBACKS; + } + + final var beanRegistry = serviceRegistry.requireService( ManagedBeanRegistry.class ); + final var callbacksCollector = new EntityCallbacksImpl.Builder(); + + if ( CollectionHelper.isNotEmpty( persistentClass.getCallbackDefinitions() ) ) { + for ( CallbackDefinition definition : persistentClass.getCallbackDefinitions() ) { + callbacksCollector.registerCallback( definition.createCallback( beanRegistry ) ); + } + } + + return callbacksCollector.build(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/event/jpa/internal/EntityCallbacksImpl.java b/hibernate-core/src/main/java/org/hibernate/event/jpa/internal/EntityCallbacksImpl.java new file mode 100644 index 000000000000..245d4fb88a2b --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/event/jpa/internal/EntityCallbacksImpl.java @@ -0,0 +1,176 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.event.jpa.internal; + +import jakarta.persistence.EntityListenerRegistration; +import org.hibernate.event.jpa.spi.EntityCallbacks; +import org.hibernate.internal.util.collections.CollectionHelper; +import org.hibernate.event.jpa.spi.Callback; +import org.hibernate.jpa.event.spi.CallbackType; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +/// Implementation of EntityCallbacks +/// +/// @author Steve Ebersole +public class EntityCallbacksImpl implements EntityCallbacks, Serializable { + private final List> preCreateCallbacks; + private final List> postCreateCallbacks; + + private final List> preUpdateCallbacks; + private final List> postUpdateCallbacks; + + private final List> preRemoveCallbacks; + private final List> postRemoveCallbacks; + + private final List> postLoadCallbacks; + + private EntityCallbacksImpl( + List> preCreateCallbacks, + List> postCreateCallbacks, + List> preUpdateCallbacks, + List> postUpdateCallbacks, + List> preRemoveCallbacks, + List> postRemoveCallbacks, + List> postLoadCallbacks) { + this.preCreateCallbacks = preCreateCallbacks; + this.postCreateCallbacks = postCreateCallbacks; + this.preUpdateCallbacks = preUpdateCallbacks; + this.postUpdateCallbacks = postUpdateCallbacks; + this.preRemoveCallbacks = preRemoveCallbacks; + this.postRemoveCallbacks = postRemoveCallbacks; + this.postLoadCallbacks = postLoadCallbacks; + } + + private List> getCallbacks(CallbackType callbackType) { + return switch ( callbackType ) { + case PRE_PERSIST -> preCreateCallbacks; + case POST_PERSIST -> postCreateCallbacks; + case PRE_UPDATE -> preUpdateCallbacks; + case POST_UPDATE -> postUpdateCallbacks; + case PRE_REMOVE -> preRemoveCallbacks; + case POST_REMOVE -> postRemoveCallbacks; + case POST_LOAD -> postLoadCallbacks; + }; + } + + @Override + public boolean hasRegisteredCallbacks(CallbackType callbackType) { + return CollectionHelper.isNotEmpty( getCallbacks( callbackType ) ); + } + + @Override + public boolean preCreate(S entity) { + return callback( preCreateCallbacks, entity ); + } + + @Override + public boolean postCreate(S entity) { + return callback( postCreateCallbacks, entity ); + } + + @Override + public boolean preUpdate(S entity) { + return callback( preUpdateCallbacks, entity ); + } + + @Override + public boolean postUpdate(S entity) { + return callback( postUpdateCallbacks, entity ); + } + + @Override + public boolean preRemove(S entity) { + return callback( preRemoveCallbacks, entity ); + } + + @Override + public boolean postRemove(S entity) { + return callback( postRemoveCallbacks, entity ); + } + + @Override + public boolean postLoad(S entity) { + return callback( postLoadCallbacks, entity ); + } + + private boolean callback(List> callbacks, E entity) { + if ( CollectionHelper.isNotEmpty( callbacks ) ) { + for ( Callback callback : callbacks ) { + callback.performCallback( entity ); + } + return true; + } + else { + return false; + } + } + + /// @see jakarta.persistence.EntityManagerFactory#addListener + public EntityListenerRegistration addListener(CallbackType type, Consumer listener) { + final List> callbacks = getCallbacks( type ); + var callback = new AddedCallbackImpl<>( type, listener ); + callbacks.add( callback ); + return new EntityListenerRegistrationImpl<>( this, type, callback ); + } + + /// @see jakarta.persistence.EntityManagerFactory#addListener + public EntityListenerRegistration addListener(CallbackType type, Callback callback) { + final List> callbacks = getCallbacks( type ); + callbacks.add( callback ); + return new EntityListenerRegistrationImpl<>( this, type, callback ); + } + + /// package-protected access to remove a callback used to support + /// JPA's [jakarta.persistence.EntityListenerRegistration]. + void remove(CallbackType type, Callback callback) { + final List> callbacks = getCallbacks( type ); + callbacks.remove( callback ); + } + + public static class Builder { + private final List> preCreateCallbacks = new ArrayList<>(); + private final List> postCreateCallbacks = new ArrayList<>(); + + private final List> preUpdateCallbacks = new ArrayList<>(); + private final List> postUpdateCallbacks = new ArrayList<>(); + + private final List> preRemoveCallbacks = new ArrayList<>(); + private final List> postRemoveCallbacks = new ArrayList<>(); + + private final List> postLoadCallbacks = new ArrayList<>(); + + public void registerCallback(Callback callback) { + getCallbacks( callback.getCallbackType() ).add( callback ); + } + + private List> getCallbacks(CallbackType callbackType) { + return switch ( callbackType ) { + case PRE_PERSIST -> preCreateCallbacks; + case POST_PERSIST -> postCreateCallbacks; + case PRE_UPDATE -> preUpdateCallbacks; + case POST_UPDATE -> postUpdateCallbacks; + case PRE_REMOVE -> preRemoveCallbacks; + case POST_REMOVE -> postRemoveCallbacks; + case POST_LOAD -> postLoadCallbacks; + }; + } + + public EntityCallbacksImpl build() { + return new EntityCallbacksImpl<>( + preCreateCallbacks, + postCreateCallbacks, + preUpdateCallbacks, + postUpdateCallbacks, + preRemoveCallbacks, + postRemoveCallbacks, + postLoadCallbacks + ); + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/event/jpa/internal/EntityListenerRegistrationImpl.java b/hibernate-core/src/main/java/org/hibernate/event/jpa/internal/EntityListenerRegistrationImpl.java new file mode 100644 index 000000000000..299ea570ff75 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/event/jpa/internal/EntityListenerRegistrationImpl.java @@ -0,0 +1,32 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.event.jpa.internal; + +import jakarta.persistence.EntityListenerRegistration; +import org.hibernate.event.jpa.spi.Callback; +import org.hibernate.jpa.event.spi.CallbackType; + +/** + * @author Steve Ebersole + */ +public class EntityListenerRegistrationImpl implements EntityListenerRegistration { + private final EntityCallbacksImpl entityCallbacks; + private final CallbackType registeredCallbackType; + private final Callback registeredCallback; + + public EntityListenerRegistrationImpl( + EntityCallbacksImpl entityCallbacks, + CallbackType registeredCallbackType, + Callback registeredCallback) { + this.entityCallbacks = entityCallbacks; + this.registeredCallbackType = registeredCallbackType; + this.registeredCallback = registeredCallback; + } + + @Override + public void cancel() { + entityCallbacks.remove( registeredCallbackType, registeredCallback ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/event/jpa/internal/NoCallbacks.java b/hibernate-core/src/main/java/org/hibernate/event/jpa/internal/NoCallbacks.java new file mode 100644 index 000000000000..d1a6d03a7590 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/event/jpa/internal/NoCallbacks.java @@ -0,0 +1,78 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.event.jpa.internal; + +import jakarta.persistence.EntityListenerRegistration; +import org.hibernate.event.jpa.spi.EntityCallbacks; +import org.hibernate.event.jpa.spi.Callback; +import org.hibernate.jpa.event.spi.CallbackType; + +import java.util.function.Consumer; + +/** + * @author Steve Ebersole + */ +@SuppressWarnings("rawtypes") +public class NoCallbacks implements EntityCallbacks { + public static NoCallbacks NO_CALLBACKS = new NoCallbacks(); + + @Override + public boolean hasRegisteredCallbacks(CallbackType callbackType) { + return false; + } + + @Override + public boolean preCreate(Object entity) { + return false; + } + + @Override + public boolean postCreate(Object entity) { + return false; + } + + @Override + public boolean preUpdate(Object entity) { + return false; + } + + @Override + public boolean postUpdate(Object entity) { + return false; + } + + @Override + public boolean preRemove(Object entity) { + return false; + } + + @Override + public boolean postRemove(Object entity) { + return false; + } + + @Override + public boolean postLoad(Object entity) { + return false; + } + + @Override + public EntityListenerRegistration addListener(CallbackType type, Consumer listener) { + return RegistrationImpl.NO_REG; + } + + @Override + public EntityListenerRegistration addListener(CallbackType type, Callback callback) { + return RegistrationImpl.NO_REG; + } + + public static class RegistrationImpl implements EntityListenerRegistration { + public static RegistrationImpl NO_REG = new RegistrationImpl(); + + @Override + public void cancel() { + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/event/jpa/package-info.java b/hibernate-core/src/main/java/org/hibernate/event/jpa/package-info.java new file mode 100644 index 000000000000..31908d132e75 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/event/jpa/package-info.java @@ -0,0 +1,11 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ + +/** + * Support for Jakarta Persistence style listeners. + * + * @author Steve Ebersole + */ +package org.hibernate.event.jpa; diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/Callback.java b/hibernate-core/src/main/java/org/hibernate/event/jpa/spi/Callback.java similarity index 80% rename from hibernate-core/src/main/java/org/hibernate/jpa/event/spi/Callback.java rename to hibernate-core/src/main/java/org/hibernate/event/jpa/spi/Callback.java index 910f94df2123..331035e576c6 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/Callback.java +++ b/hibernate-core/src/main/java/org/hibernate/event/jpa/spi/Callback.java @@ -2,7 +2,9 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.jpa.event.spi; +package org.hibernate.event.jpa.spi; + +import org.hibernate.jpa.event.spi.CallbackType; import java.io.Serializable; @@ -20,7 +22,7 @@ * @author Kabir Khan * @author Steve Ebersole */ -public interface Callback extends Serializable { +public interface Callback extends Serializable { /** * The type of callback (pre-update, pre-persist, etc) handled */ @@ -31,5 +33,5 @@ public interface Callback extends Serializable { * * @param entity Reference to the entity for which the callback is triggered. */ - void performCallback(Object entity); + void performCallback(S entity); } diff --git a/hibernate-core/src/main/java/org/hibernate/event/jpa/spi/EntityCallbacks.java b/hibernate-core/src/main/java/org/hibernate/event/jpa/spi/EntityCallbacks.java new file mode 100644 index 000000000000..5a7c49d28c28 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/event/jpa/spi/EntityCallbacks.java @@ -0,0 +1,47 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.event.jpa.spi; + +import jakarta.persistence.EntityListenerRegistration; +import org.hibernate.jpa.event.spi.CallbackType; + +import java.util.function.Consumer; + +/// Jakarta Persistence style callbacks for a particular entity. +/// +/// @param The entity type +/// +/// @author Steve Ebersole +public interface EntityCallbacks { + /// Whether there are any callbacks registered for the entity of this type. + boolean hasRegisteredCallbacks(CallbackType callbackType); + + /// Handle [jakarta.persistence.PreInsert] callbacks. + boolean preCreate(S entity); + + /// Handle [jakarta.persistence.PostInsert] callbacks. + boolean postCreate(S entity); + + /// Handle [jakarta.persistence.PreUpdate] callbacks. + boolean preUpdate(S entity); + + /// Handle [jakarta.persistence.PostUpdate] callbacks. + boolean postUpdate(S entity); + + /// Handle [jakarta.persistence.PreRemove] callbacks. + boolean preRemove(S entity); + + /// Handle [jakarta.persistence.PostRemove] callbacks. + boolean postRemove(S entity); + + /// Handle [jakarta.persistence.PostLoad] callbacks. + boolean postLoad(S entity); + + /// @see jakarta.persistence.EntityManagerFactory#addListener + EntityListenerRegistration addListener(CallbackType type, Consumer listener); + + /// @see jakarta.persistence.EntityManagerFactory#addListener + EntityListenerRegistration addListener(CallbackType type, Callback callback); +} diff --git a/hibernate-core/src/main/java/org/hibernate/event/service/internal/EventListenerGroupImpl.java b/hibernate-core/src/main/java/org/hibernate/event/service/internal/EventListenerGroupImpl.java index 81e9fa72a644..9ce2ccd8b9f8 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/service/internal/EventListenerGroupImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/event/service/internal/EventListenerGroupImpl.java @@ -4,6 +4,14 @@ */ package org.hibernate.event.service.internal; +import org.hibernate.event.service.spi.DuplicationStrategy; +import org.hibernate.event.service.spi.EventActionWithParameter; +import org.hibernate.event.service.spi.EventListenerGroup; +import org.hibernate.event.service.spi.EventListenerRegistrationException; +import org.hibernate.event.service.spi.JpaBootstrapSensitive; +import org.hibernate.event.spi.EventType; +import org.hibernate.internal.build.AllowReflection; + import java.lang.reflect.Array; import java.util.LinkedHashSet; import java.util.List; @@ -16,16 +24,6 @@ import java.util.function.Function; import java.util.function.Supplier; -import org.hibernate.event.service.spi.DuplicationStrategy; -import org.hibernate.event.service.spi.EventActionWithParameter; -import org.hibernate.event.service.spi.EventListenerGroup; -import org.hibernate.event.service.spi.EventListenerRegistrationException; -import org.hibernate.event.service.spi.JpaBootstrapSensitive; -import org.hibernate.event.spi.EventType; -import org.hibernate.internal.build.AllowReflection; -import org.hibernate.jpa.event.spi.CallbackRegistry; -import org.hibernate.jpa.event.spi.CallbackRegistryConsumer; - import static java.lang.System.arraycopy; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; @@ -62,7 +60,6 @@ private static CompletableFuture nullCompletion() { } private final EventType eventType; - private final CallbackRegistry callbackRegistry; private final boolean isJpaBootstrap; //TODO at least the list of listeners should be made constant; @@ -72,9 +69,8 @@ private static CompletableFuture nullCompletion() { private volatile T[] listeners = null; private volatile List listenersAsList = emptyList(); - public EventListenerGroupImpl(EventType eventType, CallbackRegistry callbackRegistry, boolean isJpaBootstrap) { + public EventListenerGroupImpl(EventType eventType, boolean isJpaBootstrap) { this.eventType = eventType; - this.callbackRegistry = callbackRegistry; this.isJpaBootstrap = isJpaBootstrap; } @@ -360,9 +356,6 @@ private void prepareListener(T listener) { } private void performInjections(T listener) { - if ( listener instanceof CallbackRegistryConsumer consumer ) { - consumer.injectCallbackRegistry( callbackRegistry ); - } if ( listener instanceof JpaBootstrapSensitive sensitive ) { sensitive.wasJpaBootstrap( isJpaBootstrap ); } diff --git a/hibernate-core/src/main/java/org/hibernate/event/service/internal/EventListenerRegistryImpl.java b/hibernate-core/src/main/java/org/hibernate/event/service/internal/EventListenerRegistryImpl.java index 445ac91b47c8..0db74826b7e1 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/service/internal/EventListenerRegistryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/event/service/internal/EventListenerRegistryImpl.java @@ -39,7 +39,6 @@ import org.hibernate.event.service.spi.EventListenerRegistry; import org.hibernate.event.spi.EventType; import org.hibernate.internal.build.AllowReflection; -import org.hibernate.jpa.event.spi.CallbackRegistry; import static java.util.Comparator.comparing; import static org.hibernate.event.spi.EventType.AUTO_FLUSH; @@ -200,14 +199,12 @@ public final void prependListeners(EventType type, T... listeners) { // Builder public static class Builder { - private final CallbackRegistry callbackRegistry; private final boolean jpaBootstrap; private final Map,EventListenerGroup> listenerGroupMap = new TreeMap<>( comparing( EventType::ordinal ) ); - public Builder(CallbackRegistry callbackRegistry, boolean jpaBootstrap) { - this.callbackRegistry = callbackRegistry; + public Builder(boolean jpaBootstrap) { this.jpaBootstrap = jpaBootstrap; applyStandardListeners(); @@ -330,8 +327,8 @@ public void prepareListeners(EventType type, T defaultListener) { t -> type == EventType.POST_COMMIT_DELETE || type == EventType.POST_COMMIT_INSERT || type == EventType.POST_COMMIT_UPDATE - ? new PostCommitEventListenerGroupImpl<>( type, callbackRegistry, jpaBootstrap ) - : new EventListenerGroupImpl<>( type, callbackRegistry, jpaBootstrap ) + ? new PostCommitEventListenerGroupImpl<>( type, jpaBootstrap ) + : new EventListenerGroupImpl<>( type, jpaBootstrap ) ); } diff --git a/hibernate-core/src/main/java/org/hibernate/event/service/internal/PostCommitEventListenerGroupImpl.java b/hibernate-core/src/main/java/org/hibernate/event/service/internal/PostCommitEventListenerGroupImpl.java index e95e1dbf6665..c8b9581b4dc9 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/service/internal/PostCommitEventListenerGroupImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/event/service/internal/PostCommitEventListenerGroupImpl.java @@ -8,7 +8,6 @@ import org.hibernate.event.spi.PostCommitDeleteEventListener; import org.hibernate.event.spi.PostCommitInsertEventListener; import org.hibernate.event.spi.PostCommitUpdateEventListener; -import org.hibernate.jpa.event.spi.CallbackRegistry; import static org.hibernate.event.internal.EventListenerLogging.EVENT_LISTENER_LOGGER; @@ -27,9 +26,8 @@ class PostCommitEventListenerGroupImpl extends EventListenerGroupImpl { public PostCommitEventListenerGroupImpl( EventType eventType, - CallbackRegistry callbackRegistry, boolean isJpaBootstrap) { - super( eventType, callbackRegistry, isJpaBootstrap ); + super( eventType, isJpaBootstrap ); if ( eventType == EventType.POST_COMMIT_DELETE ) { extendedListenerContract = PostCommitDeleteEventListener.class; diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/EventEngine.java b/hibernate-core/src/main/java/org/hibernate/event/spi/EventEngine.java index 132f708c589f..ae0e61c40968 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/spi/EventEngine.java +++ b/hibernate-core/src/main/java/org/hibernate/event/spi/EventEngine.java @@ -4,11 +4,6 @@ */ package org.hibernate.event.spi; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Consumer; - import org.hibernate.HibernateException; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.spi.MetadataImplementor; @@ -17,13 +12,16 @@ import org.hibernate.event.service.internal.EventListenerRegistryImpl; import org.hibernate.event.service.spi.EventListenerGroup; import org.hibernate.event.service.spi.EventListenerRegistry; -import org.hibernate.jpa.event.spi.CallbackRegistry; import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.service.spi.Stoppable; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; + import static java.util.Collections.unmodifiableMap; import static org.hibernate.internal.util.collections.CollectionHelper.isNotEmpty; -import static org.hibernate.jpa.event.internal.CallbacksFactory.buildCallbackRegistry; /** * Composite for the things related to Hibernate's event system. @@ -35,8 +33,6 @@ public class EventEngine { private final Map> registeredEventTypes; private final EventListenerRegistry listenerRegistry; - private final CallbackRegistry callbackRegistry; - public EventEngine(MetadataImplementor mappings, SessionFactoryImplementor sessionFactory) { final SessionFactoryOptions sessionFactoryOptions = sessionFactory.getSessionFactoryOptions(); @@ -45,13 +41,10 @@ public EventEngine(MetadataImplementor mappings, SessionFactoryImplementor sessi // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // resolve (JPA) callback handlers - callbackRegistry = buildCallbackRegistry( sessionFactoryOptions, serviceRegistry, mappings.getEntityBindings() ); - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // resolve event types and listeners - final var listenerRegistryBuilder = - new EventListenerRegistryImpl.Builder( callbackRegistry, sessionFactoryOptions.isJpaBootstrap() ); + final var listenerRegistryBuilder = new EventListenerRegistryImpl.Builder( sessionFactoryOptions.isJpaBootstrap() ); final Map> eventTypes = new HashMap<>(); EventType.registerStandardTypes( eventTypes ); @@ -87,15 +80,10 @@ public EventListenerRegistry getListenerRegistry() { return listenerRegistry; } - public CallbackRegistry getCallbackRegistry() { - return callbackRegistry; - } - public void stop() { if ( listenerRegistry instanceof Stoppable stoppable ) { stoppable.stop(); } - callbackRegistry.release(); } private static class ContributionManager implements EventEngineContributions { diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/LoadEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/spi/LoadEventListener.java index fb03dfca8c87..bdfb5aeef8e2 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/spi/LoadEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/spi/LoadEventListener.java @@ -21,6 +21,16 @@ public interface LoadEventListener { */ void onLoad(LoadEvent event, LoadType loadType) throws HibernateException; + /** + * Normal {@linkplain org.hibernate.Session#find} (and by extension + * {@linkplain org.hibernate.Session#get}) handling. + */ + LoadType FIND = new LoadType( "FIND" ) + .setAllowNulls( true ) + .setAllowProxyCreation( true ) + .setCheckDeleted( true ) + .setNakedEntityReturned( false ); + LoadType RELOAD = new LoadType( "RELOAD" ) .setAllowNulls( false ) .setAllowProxyCreation( false ) diff --git a/hibernate-core/src/main/java/org/hibernate/generator/values/GeneratedValueBasicResultBuilder.java b/hibernate-core/src/main/java/org/hibernate/generator/values/GeneratedValueBasicResultBuilder.java index e28111be22f0..04d5329a3d1a 100644 --- a/hibernate-core/src/main/java/org/hibernate/generator/values/GeneratedValueBasicResultBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/generator/values/GeneratedValueBasicResultBuilder.java @@ -5,7 +5,7 @@ package org.hibernate.generator.values; import org.hibernate.metamodel.mapping.BasicValuedModelPart; -import org.hibernate.query.results.ResultBuilder; +import org.hibernate.query.results.spi.ResultBuilder; import org.hibernate.query.results.internal.DomainResultCreationStateImpl; import org.hibernate.query.results.internal.ResultsHelper; import org.hibernate.spi.NavigablePath; diff --git a/hibernate-core/src/main/java/org/hibernate/graph/AttributeNode.java b/hibernate-core/src/main/java/org/hibernate/graph/AttributeNode.java index b023feca0dbf..4b4c149dfa57 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/AttributeNode.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/AttributeNode.java @@ -78,7 +78,7 @@ public interface AttributeNode extends GraphNode, jakarta.persistence.Attr * @see #getSubGraphs() */ @Override - default @SuppressWarnings("rawtypes") Map getSubgraphs() { + default Map, Subgraph> getSubgraphs() { return unmodifiableMap( getSubGraphs() ); } @@ -92,7 +92,7 @@ public interface AttributeNode extends GraphNode, jakarta.persistence.Attr * @see #getKeySubGraphs() */ @Override - default @SuppressWarnings("rawtypes") Map getKeySubgraphs() { + default Map, Subgraph> getKeySubgraphs() { return unmodifiableMap( getKeySubGraphs() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/EntityGraphs.java b/hibernate-core/src/main/java/org/hibernate/graph/EntityGraphs.java index b59f589b284c..61c6483531cf 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/EntityGraphs.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/EntityGraphs.java @@ -327,8 +327,9 @@ else if ( a == null || b == null ) { return false; } else if ( a.getAttributeName().equals( b.getAttributeName() ) ) { - return areEqual( a.getSubgraphs(), b.getSubgraphs() ) - && areEqual( a.getKeySubgraphs(), b.getKeySubgraphs() ); + //noinspection rawtypes,unchecked + return areEqual( (Map) a.getSubgraphs(), (Map) b.getSubgraphs() ) + && areEqual( (Map) a.getKeySubgraphs(), (Map) b.getKeySubgraphs() ); } else { return false; diff --git a/hibernate-core/src/main/java/org/hibernate/graph/Graph.java b/hibernate-core/src/main/java/org/hibernate/graph/Graph.java index dce40cae039b..93f00de59f35 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/Graph.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/Graph.java @@ -267,8 +267,6 @@ SubGraph addSubgraph(Attribute attribute) * @param attribute An attribute of the represented type * @param type A subtype of the attribute type * - * @see #addSubgraph(Attribute, Class) - * * @since 7.0 */ @Override @@ -320,8 +318,6 @@ SubGraph addSubGraph(PersistentAttribute attribute) * @param attribute An attribute of the represented type * @param type A subtype of the attribute type * - * @see #addSubgraph(Attribute, Class) - * * @deprecated Use {@link #addTreatedSubgraph(Attribute, Class)} */ @Deprecated(since = "7.0") @@ -547,19 +543,4 @@ SubGraph addKeySubGraph(MapPersistentAttribute SubGraph addPluralSubgraph(PluralAttribute attribute) { return addSubGraph( attribute.getName(), attribute.getBindableJavaType() ); } - - @Override @Deprecated(forRemoval = true) - default SubGraph addSubgraph(Attribute attribute, Class type) { - return addSubGraph( (PersistentAttribute) attribute ).addTreatedSubgraph( type ); - } - - @Override @Deprecated(forRemoval = true) - default SubGraph addKeySubgraph(Attribute attribute) { - throw new UnsupportedOperationException( "This operation will be removed in JPA 4" ); - } - - @Override @Deprecated(forRemoval = true) - default SubGraph addKeySubgraph(Attribute attribute, Class type) { - throw new UnsupportedOperationException( "This operation will be removed in JPA 4" ); - } } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/RootGraph.java b/hibernate-core/src/main/java/org/hibernate/graph/RootGraph.java index a2f382cb6c33..00db9f272128 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/RootGraph.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/RootGraph.java @@ -32,13 +32,4 @@ public interface RootGraph extends Graph, EntityGraph { @Override @Deprecated(forRemoval = true) SubGraph makeSubGraph(boolean mutable); - - /** - * @deprecated Planned for removal in JPA 4 - */ - @Override @Deprecated(forRemoval = true) - @SuppressWarnings("unchecked") // The JPA method was defined with an incorrect generic signature - default SubGraph addSubclassSubgraph(Class type) { - return (SubGraph) addTreatedSubgraph( (Class) type ); - } } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java index dd25ee52bc47..3d246127df0b 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java @@ -48,6 +48,11 @@ public abstract sealed class AttributeNodeImpl protected SubGraphImplementor valueSubgraph; protected SubGraphImplementor keySubgraph; + @Override + public Attribute getAttribute() { + return attribute; + } + static AttributeNodeImpl create( PersistentAttribute attribute, boolean mutable) { if ( attribute instanceof PluralPersistentAttribute pluralAttribute ) { diff --git a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java index 907676485197..dfc1d8c9504a 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java @@ -4,12 +4,23 @@ */ package org.hibernate.internal; +import jakarta.persistence.CacheRetrieveMode; +import jakarta.persistence.CacheStoreMode; +import jakarta.persistence.ConnectionConsumer; +import jakarta.persistence.ConnectionFunction; import jakarta.persistence.EntityGraph; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityNotFoundException; +import jakarta.persistence.FindOption; import jakarta.persistence.TransactionRequiredException; import jakarta.persistence.TypedQueryReference; import jakarta.persistence.criteria.CriteriaDelete; import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.CriteriaSelect; import jakarta.persistence.criteria.CriteriaUpdate; +import jakarta.persistence.metamodel.Metamodel; +import jakarta.persistence.sql.EntityMapping; +import jakarta.persistence.sql.ResultSetMapping; import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.CacheMode; import org.hibernate.EntityNameResolver; @@ -54,6 +65,8 @@ import org.hibernate.graph.internal.RootGraphImpl; import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.id.uuid.StandardRandomStrategy; +import org.hibernate.internal.find.FindByKeyOperation; +import org.hibernate.internal.find.Helper; import org.hibernate.jdbc.ReturningWork; import org.hibernate.jdbc.Work; import org.hibernate.jdbc.WorkExecutorVisitable; @@ -109,17 +122,25 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serial; +import java.io.Serializable; import java.sql.Connection; import java.sql.SQLException; +import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Objects; import java.util.TimeZone; import java.util.UUID; import java.util.function.Function; import static java.lang.Boolean.TRUE; +import static org.hibernate.CacheMode.fromJpaModes; import static org.hibernate.boot.model.naming.Identifier.toIdentifier; +import static org.hibernate.cfg.CacheSettings.JAKARTA_SHARED_CACHE_RETRIEVE_MODE; +import static org.hibernate.cfg.CacheSettings.JAKARTA_SHARED_CACHE_STORE_MODE; +import static org.hibernate.cfg.CacheSettings.JPA_SHARED_CACHE_RETRIEVE_MODE; +import static org.hibernate.cfg.CacheSettings.JPA_SHARED_CACHE_STORE_MODE; import static org.hibernate.internal.SessionLogging.SESSION_LOGGER; import static org.hibernate.internal.util.StringHelper.isEmpty; import static org.hibernate.query.sqm.internal.SqmUtil.verifyIsSelectStatement; @@ -140,11 +161,14 @@ * @author Steve Ebersole */ abstract class AbstractSharedSessionContract implements SharedSessionContractImplementor { - private transient SessionFactoryImpl factory; private transient SessionFactoryOptions factoryOptions; private transient JdbcServices jdbcServices; + // Defaults to null, meaning the properties + // are the default properties of the factory. + private Map properties; + private UUID sessionIdentifier; private Object sessionToken; @@ -254,6 +278,313 @@ final SessionFactoryOptions getSessionFactoryOptions() { return factoryOptions; } + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // EntityHandler (JPA) + + @Override + public EntityManagerFactory getEntityManagerFactory() { + checkOpen(); + return getFactory(); + } + + @Override + public Metamodel getMetamodel() { + checkOpen(); + return factory.getJpaMetamodel(); + } + + @Override + public CacheStoreMode getCacheStoreMode() { + return getCacheMode().getJpaStoreMode(); + } + + @Override + public CacheRetrieveMode getCacheRetrieveMode() { + return getCacheMode().getJpaRetrieveMode(); + } + + @Override + public void setCacheStoreMode(CacheStoreMode cacheStoreMode) { + setCacheMode( fromJpaModes( getCacheMode().getJpaRetrieveMode(), cacheStoreMode ) ); + } + + @Override + public void setCacheRetrieveMode(CacheRetrieveMode cacheRetrieveMode) { + setCacheMode( fromJpaModes( cacheRetrieveMode, getCacheMode().getJpaStoreMode() ) ); + } + + protected Map properties() { + return properties; + } + + @Override + public Map getProperties() { + // EntityManager Javadoc implies that the + // returned map should be a mutable copy, + // not an unmodifiable map. There's no + // good reason to cache the initial + // properties, since we have to copy them + // each time this method is called. + return properties == null + ? getInitialProperties() + : new HashMap<>( properties ); + } + + protected abstract Map getInitialProperties(); + + @Override + public void setProperty(String propertyName, Object value) { + checkOpen(); + if ( propertyName == null ) { + SESSION_LOGGER.nullPropertyKey(); + } + else if ( !(value instanceof Serializable) ) { + SESSION_LOGGER.nonSerializableProperty( propertyName ); + } + else { + // store property for future reference + if ( properties == null ) { + properties = getInitialProperties(); + } + properties.put( propertyName, value ); + // now actually update the setting if + // it's one that affects this Session + interpretProperty( propertyName, value ); + } + } + + protected abstract void interpretProperty(String propertyName, Object value); + + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // loading + + /** + * Create a FindByKeyOperation to be used for {@code find()} and {@code get()} handling. + * + * @param entityDescriptor The entity type being loaded. + * @param options Any options to apply. + */ + protected abstract FindByKeyOperation byKey(EntityPersister entityDescriptor, FindOption... options); + + /** + * Create a FindByKeyOperation to be used for {@code find()} and {@code get()} handling. + * + * @param entityDescriptor The entity type being loaded. + * @param graphSemantic Semantic of the supplied {@code rootGraph}. + * @param rootGraph The EntityGraph to apply to the load. + * @param options Any options to apply. + */ + protected abstract FindByKeyOperation byKey( + EntityPersister entityDescriptor, + GraphSemantic graphSemantic, + RootGraphImplementor rootGraph, + FindOption... options); + + /** + * JPA requires {@code find()} and {@code get()} to throw {@linkplain IllegalArgumentException} + * if the specified {@code entityClass} is not actually a known entity class. + * However, Hibernate internals throw the much more meaningful {@linkplain UnknownEntityTypeException}. + * Here we catch {@linkplain UnknownEntityTypeException} and convert it to {@linkplain IllegalArgumentException}. + */ + protected EntityPersister requireEntityPersisterForLoad(Class entityClass) { + try { + return requireEntityPersister( entityClass ); + } + catch (UnknownEntityTypeException e) { + var iae = new IllegalArgumentException( e.getMessage() ); + iae.addSuppressed( e ); + throw iae; + } + } + + /** + * Corollary to {@linkplain #requireEntityPersisterForLoad(Class)}, but for + * dynamic models. + * + * @implNote Even though JPA does not define support for dynamic models, we want to be consistent here. + */ + protected EntityPersister requireEntityPersisterForLoad(String entityName) { + try { + return requireEntityPersister( entityName ); + } + catch (UnknownEntityTypeException e) { + var iae = new IllegalArgumentException( e.getMessage() ); + iae.addSuppressed( e ); + throw iae; + } + } + + protected static EntityNotFoundException notFound(String entityName, Object key) { + return new EntityNotFoundException( + String.format( + Locale.ROOT, + "No entity of type `%s` existed for key `%s`", + entityName, + key + ) + ); + } + + @Override + public T find(Class entityClass, Object id) { + checkOpen(); + + final var persister = requireEntityPersisterForLoad( entityClass.getName() ); + //noinspection unchecked + return (T) byKey( persister ).performFind( id ); + } + + @Override + public T find(Class entityClass, Object key, FindOption... findOptions) { + checkOpen(); + + final var persister = requireEntityPersisterForLoad( entityClass.getName() ); + //noinspection unchecked + return (T) byKey( persister, findOptions ).performFind( key ); + } + + @Override + public T find(EntityGraph entityGraph, Object key, FindOption... findOptions) { + checkOpen(); + + final var graph = (RootGraphImplementor) entityGraph; + final var type = graph.getGraphedType(); + + final EntityPersister entityDescriptor = switch ( type.getRepresentationMode() ) { + case POJO -> requireEntityPersisterForLoad( type.getJavaType() ); + case MAP -> requireEntityPersisterForLoad( type.getTypeName() ); + }; + + //noinspection unchecked + return (T) byKey( entityDescriptor, GraphSemantic.LOAD, graph, findOptions ).performFind( key ); + } + + @Override + public Object find(String entityName, Object key, FindOption... findOptions) { + checkOpen(); + var entityDescriptor = requireEntityPersisterForLoad( entityName ); + return byKey( entityDescriptor, findOptions ).performFind( key ); + } + + @Override + public T get(Class entityClass, Object id) { + var result = find( entityClass, id ); + if ( result == null ) { + throw notFound( entityClass.getName(), id ); + } + return result; + } + + @Override + public T get(Class entityClass, Object key, FindOption... findOptions) { + var result = find( entityClass, key, findOptions ); + if ( result == null ) { + throw notFound( entityClass.getName(), key ); + } + return result; + } + + @Override + public T get(EntityGraph entityGraph, Object key, FindOption... findOptions) { + var result = find( entityGraph, key, findOptions ); + if ( result == null ) { + final var graph = (RootGraphImplementor) entityGraph; + throw notFound( graph.getGraphedType().getTypeName(), key ); + } + return result; + } + + @Override + public Object get(String entityName, Object key, FindOption... findOptions) { + var result = find( entityName, key, findOptions ); + if ( result == null ) { + throw notFound( entityName, key ); + } + return result; + } + + @Override + public List getMultiple(Class entityClass, List keys, FindOption... findOptions) { + var results = findMultiple( entityClass, keys, findOptions ); + Helper.verifyGetMultipleResults( results, entityClass.getName(), keys, findOptions ); + return results; + } + + @Override + public List getMultiple(EntityGraph entityGraph, List keys, FindOption... findOptions) { + var results = findMultiple( entityGraph, keys, findOptions ); + Helper.verifyGetMultipleResults( results, ( (RootGraph) entityGraph ).getGraphedType().getTypeName(), keys ); + return results; + } + + @Override + public void runWithConnection(ConnectionConsumer action) { + doWork( connection -> { + try { + //noinspection unchecked + action.accept( (C) connection ); + } + catch (SQLException e) { + throw getJdbcServices().getSqlExceptionHelper().convert( e, "Error in runWithConnection" ); + } + catch (Exception e) { + throw new RuntimeException( e ); + } + } ); + } + + @Override + public T callWithConnection(ConnectionFunction function) { + return doReturningWork( connection -> { + try { + //noinspection unchecked + return function.apply( (C) connection ); + } + catch (SQLException e) { + throw getJdbcServices().getSqlExceptionHelper().convert( e, "Error in callWithConnection" ); + } + catch (Exception e) { + throw new RuntimeException( e ); + } + } ); + } + + @Override + public QueryImplementor createQuery(CriteriaSelect selectQuery) { + return createQuery( (CriteriaQuery) selectQuery ); + } + + @Override + public QueryImplementor createQuery(String hql, EntityGraph entityGraph) { + // by definition this HQL must be a selection query + return (QueryImplementor) createSelectionQuery( hql, entityGraph ); + } + + @Override + public NativeQueryImplementor createNativeQuery(String sql, ResultSetMapping resultSetMapping) { + final var query = new NativeQueryImpl<>( sql, resultSetMapping, this ); + if ( isEmpty( query.getComment() ) ) { + query.setComment( "dynamic native SQL query" ); + } + if ( resultSetMapping instanceof EntityMapping entityMapping ) { + var lockMode = LockMode.fromJpaLockMode( entityMapping.lockMode() ); + if ( lockMode.greaterThan( LockMode.READ ) ) { + query.setHibernateLockMode( lockMode ); + } + } + return query; + } + + @Override + public EntityGraph getEntityGraph(Class entityClass, String name) { + //noinspection unchecked + return (EntityGraph) factory.getNamedEntityGraphs( entityClass ).get( name ); + } + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Shared builders + @Override public SharedStatelessSessionBuilder statelessWithOptions() { return new SharedStatelessSessionBuilderImpl( this ) { @@ -914,12 +1245,11 @@ public void setNativeJdbcParametersIgnored(boolean nativeJdbcParametersIgnored) // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // dynamic HQL handling - @Override @Deprecated @SuppressWarnings({"rawtypes", "deprecation"}) + @Override @Deprecated @SuppressWarnings("rawtypes") public QueryImplementor createQuery(String queryString) { - return createQuery( queryString, null ); + return createQuery( queryString, (Class) null ); } - @Override public SelectionQuery createSelectionQuery(String hqlString) { return interpretAndCreateSelectionQuery( hqlString, null ); } @@ -1040,21 +1370,25 @@ else if ( typedQueryReference instanceof MutationSpecificationImpl specificat // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // dynamic native (SQL) query handling - @Override @Deprecated @SuppressWarnings("deprecation") + /** + * @deprecated This is a JPA defined method, but Hibernate considers it deprecated. + * Use {@linkplain #createNativeQuery(String, Class)} instead. + */ + @Override @Deprecated public NativeQueryImplementor createNativeQuery(String sqlString) { return createNativeQuery( sqlString, (Class) null ); } - - @Override @Deprecated @SuppressWarnings("deprecation") + /** + * @deprecated This is a JPA defined method, but Hibernate considers it deprecated. + * Use {@linkplain #createNativeQuery(String, String, Class)} instead. + */ + @Override @Deprecated public NativeQueryImplementor createNativeQuery(String sqlString, String resultSetMappingName) { checksBeforeQueryCreation(); return buildNativeQuery( sqlString, resultSetMappingName, null ); } - @Override @SuppressWarnings({"rawtypes", "unchecked"}) - //note: we're doing something a bit funny here to work around - // the clashing signatures declared by the supertypes - public NativeQueryImplementor createNativeQuery(String sqlString, @Nullable Class resultClass) { + public NativeQueryImplementor createNativeQuery(String sqlString, @Nullable Class resultClass) { checksBeforeQueryCreation(); return buildNativeQuery( sqlString, resultClass ); } @@ -1142,12 +1476,12 @@ public NativeQueryImplementor createNativeQuery(String sqlString, String // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // named query handling + /** + * @deprecated This is a JPA-defined method, but Hibernate considers it + * bad thus we deprecate it through our APIs. Use {@linkplain #createNamedQuery(String, Class)} + * instead. + */ @Override @Deprecated - public QueryImplementor getNamedQuery(String queryName) { - return createNamedQuery( queryName ); - } - - @Override @Deprecated @SuppressWarnings("deprecation") public QueryImplementor createNamedQuery(String name) { checksBeforeQueryCreation(); try { @@ -1177,8 +1511,15 @@ public QueryImplementor createNamedQuery(String name, Class resultClas } @Override - public SelectionQuery createNamedSelectionQuery(String queryName) { - return createNamedSelectionQuery( queryName, null ); + public NativeQueryImplementor createNamedQuery(String name, String resultSetMappingName) { + final NamedNativeQueryMemento queryMemento = getNativeQueryMemento( name ); + return queryMemento.toQuery( this, resultSetMappingName ); + } + + @Override + public NativeQueryImplementor createNamedQuery(String name, String resultSetMappingName, Class resultClass) { + final NamedNativeQueryMemento queryMemento = getNativeQueryMemento( name ); + return queryMemento.toQuery( this, resultSetMappingName ); } @Override @@ -1325,33 +1666,6 @@ protected SqmQueryImplementor createSqmQueryImplementor(Class resultTy return query; } - @Override @Deprecated @SuppressWarnings("deprecation") - public NativeQueryImplementor getNamedNativeQuery(String queryName) { - final var namedNativeDescriptor = getNativeQueryMemento( queryName ); - if ( namedNativeDescriptor != null ) { - return namedNativeDescriptor.toQuery( this ); - } - else { - throw noQueryForNameException( queryName ); - } - } - - @Override @Deprecated @SuppressWarnings("deprecation") - public NativeQueryImplementor getNamedNativeQuery(String queryName, String resultSetMapping) { - final var namedNativeDescriptor = getNativeQueryMemento( queryName ); - if ( namedNativeDescriptor != null ) { - return namedNativeDescriptor.toQuery( this, resultSetMapping ); - } - else { - throw noQueryForNameException( queryName ); - } - } - - private RuntimeException noQueryForNameException(String queryName) { - return getExceptionConverter() - .convert( new IllegalArgumentException( "No query with given name '" + queryName + "'" ) ); - } - @Override public MutationQuery createMutationQuery(String hqlString) { final var query = createQuery( hqlString ); @@ -1593,6 +1907,11 @@ public QueryImplementor createQuery(CriteriaQuery criteriaQuery) { } } + @Override + public SelectionQuery createSelectionQuery(CriteriaSelect criteria) { + return createSelectionQuery( (CriteriaQuery) criteria ); + } + @Override @Deprecated @SuppressWarnings("deprecation") public QueryImplementor createQuery(@SuppressWarnings("rawtypes") CriteriaUpdate criteriaUpdate) { checkOpen(); @@ -1774,4 +2093,19 @@ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFound entityNameResolver = new CoordinatingEntityNameResolver( factory, interceptor ); } + protected static CacheRetrieveMode determineCacheRetrieveMode(Map settings) { + final CacheRetrieveMode cacheRetrieveMode = + (CacheRetrieveMode) settings.get( JPA_SHARED_CACHE_RETRIEVE_MODE ); + return cacheRetrieveMode == null + ? (CacheRetrieveMode) settings.get( JAKARTA_SHARED_CACHE_RETRIEVE_MODE ) + : cacheRetrieveMode; + } + + protected static CacheStoreMode determineCacheStoreMode(Map settings) { + final CacheStoreMode cacheStoreMode = + (CacheStoreMode) settings.get( JPA_SHARED_CACHE_STORE_MODE ); + return cacheStoreMode == null + ? (CacheStoreMode) settings.get( JAKARTA_SHARED_CACHE_STORE_MODE ) + : cacheStoreMode; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/MultiIdentifierLoadAccessImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/MultiIdentifierLoadAccessImpl.java index 10b05f7fcc7f..c464da8e1565 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/MultiIdentifierLoadAccessImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/MultiIdentifierLoadAccessImpl.java @@ -23,7 +23,7 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.graph.GraphSemantic; import org.hibernate.graph.spi.RootGraphImplementor; -import org.hibernate.internal.find.FindMultipleByKeyOperation; +import org.hibernate.internal.find.StatefulFindMultipleByKeyOperation; import org.hibernate.loader.ast.spi.MultiIdLoadOptions; import org.hibernate.loader.internal.LoadAccessContext; import org.hibernate.persister.entity.EntityPersister; @@ -38,7 +38,7 @@ /// /// @author Steve Ebersole /// -/// @deprecated Use [FindMultipleByKeyOperation] instead. +/// @deprecated Use [StatefulFindMultipleByKeyOperation] instead. @Deprecated class MultiIdentifierLoadAccessImpl implements MultiIdentifierLoadAccess, MultiIdLoadOptions { private final SharedSessionContractImplementor session; @@ -172,12 +172,13 @@ public Boolean getReadOnly(SessionImplementor session) { @Override @SuppressWarnings( "unchecked" ) public List multiLoad(K... ids) { - return buildOperation().performFind( List.of( ids ), graphSemantic, rootGraph, (LoadAccessContext) session ); + return buildOperation().performFind( List.of( ids ), graphSemantic, rootGraph ); } - private FindMultipleByKeyOperation buildOperation() { - return new FindMultipleByKeyOperation( + private StatefulFindMultipleByKeyOperation buildOperation() { + return new StatefulFindMultipleByKeyOperation( entityPersister, + (LoadAccessContext) session, KeyType.IDENTIFIER, batchSize, sessionCheckMode, @@ -198,7 +199,7 @@ private FindMultipleByKeyOperation buildOperation() { public List multiLoad(List ids) { return ids.isEmpty() ? emptyList() - : buildOperation().performFind( (List)ids, graphSemantic, rootGraph, (LoadAccessContext) session ); + : buildOperation().performFind( (List)ids, graphSemantic, rootGraph ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/internal/NaturalIdMultiLoadAccessStandard.java b/hibernate-core/src/main/java/org/hibernate/internal/NaturalIdMultiLoadAccessStandard.java index ce8b2adca103..d205a86f283b 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/NaturalIdMultiLoadAccessStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/NaturalIdMultiLoadAccessStandard.java @@ -22,7 +22,7 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.graph.GraphSemantic; import org.hibernate.graph.spi.RootGraphImplementor; -import org.hibernate.internal.find.FindMultipleByKeyOperation; +import org.hibernate.internal.find.StatefulFindMultipleByKeyOperation; import org.hibernate.loader.ast.spi.MultiNaturalIdLoadOptions; import org.hibernate.loader.internal.LoadAccessContext; import org.hibernate.persister.entity.EntityPersister; @@ -31,7 +31,7 @@ /// Implementation of NaturalIdMultiLoadAccess. /// -/// @deprecated Use [FindMultipleByKeyOperation] instead. +/// @deprecated Use [StatefulFindMultipleByKeyOperation] instead. /// /// @author Steve Ebersole @Deprecated @@ -128,18 +128,19 @@ public void with(OrderingMode orderingMode) { @Override public List multiLoad(Object... ids) { return buildOperation() - .performFind( List.of( ids ), graphSemantic, rootGraph, (LoadAccessContext) session ); + .performFind( List.of( ids ), graphSemantic, rootGraph ); } @Override public List multiLoad(List ids) { return buildOperation() - .performFind( ids, graphSemantic, rootGraph, (LoadAccessContext) session ); + .performFind( ids, graphSemantic, rootGraph ); } - private FindMultipleByKeyOperation buildOperation() { - return new FindMultipleByKeyOperation( + private StatefulFindMultipleByKeyOperation buildOperation() { + return new StatefulFindMultipleByKeyOperation( entityDescriptor, + (LoadAccessContext) session, KeyType.NATURAL, batchSize == null ? null : new BatchSize( batchSize ), SessionCheckMode.ENABLED, diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index 4c29bcfc4df2..975bc40ab7b1 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -4,7 +4,10 @@ */ package org.hibernate.internal; +import jakarta.persistence.EntityAgent; import jakarta.persistence.EntityGraph; +import jakarta.persistence.EntityHandler; +import jakarta.persistence.EntityListenerRegistration; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceException; import jakarta.persistence.PersistenceUnitTransactionType; @@ -13,6 +16,7 @@ import jakarta.persistence.SynchronizationType; import jakarta.persistence.TypedQuery; import jakarta.persistence.TypedQueryReference; +import jakarta.persistence.sql.ResultSetMapping; import org.hibernate.CustomEntityDirtinessStrategy; import org.hibernate.EntityNameResolver; import org.hibernate.FlushMode; @@ -65,6 +69,7 @@ import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.integrator.spi.Integrator; import org.hibernate.integrator.spi.IntegratorService; +import org.hibernate.jpa.event.spi.CallbackType; import org.hibernate.jpa.internal.PersistenceUnitUtilImpl; import org.hibernate.mapping.GeneratorSettings; import org.hibernate.mapping.PersistentClass; @@ -108,6 +113,7 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serial; +import java.lang.annotation.Annotation; import java.sql.Connection; import java.util.ArrayList; import java.util.Collection; @@ -383,6 +389,18 @@ public EventListenerGroups getEventListenerGroups() { return eventListenerGroups; } + @Override + public EntityListenerRegistration addListener( + Class entityClass, + Class callbackType, + Consumer callback) { + //noinspection unchecked + return getMappingMetamodel() + .getEntityDescriptor( entityClass ) + .getEntityCallbacks() + .addListener( CallbackType.fromCallbackAnnotation( callbackType ), callback ); + } + @Override public ParameterMarkerStrategy getParameterMarkerStrategy() { return parameterMarkerStrategy; @@ -701,6 +719,24 @@ public Session createEntityManager(SynchronizationType synchronizationType, Map< return buildEntityManager( synchronizationType, map ); } + @Override + public EntityAgent createEntityAgent() { + validateNotClosed(); + return openStatelessSession(); + } + + @Override + public EntityAgent createEntityAgent(Map map) { + assert map != null; + var agent = createEntityAgent(); + map.forEach( (key,val) -> { + if ( key instanceof String prop ) { + agent.setProperty( prop, val ); + } + } ); + return agent; + } + @Override public NodeBuilder getCriteriaBuilder() { validateNotClosed(); @@ -926,16 +962,57 @@ public Map> getNamedEntityGraphs(Class e return getJpaMetamodel().getNamedEntityGraphs( entityType ); } + @Override + public Map> getResultSetMappings(Class resultType) { + final var result = new HashMap>(); + queryEngine.getNamedObjectRepository().visitResultSetMappingMementos( (memento) -> { + if ( memento.canBeTreatedAsResultSetMapping( resultType, this ) ) { + result.put( memento.getName(), memento.toJpaMapping( this ) ); + } + } ); + return result; + } + @Override public void runInTransaction(Consumer work) { inTransaction( work ); } + @Override + public void runInTransaction(Class handlerType, Consumer consumer) { + if ( EntityManager.class.isAssignableFrom( handlerType ) ) { + //noinspection unchecked + inTransaction( (Consumer) consumer ); + } + else if ( EntityAgent.class.isAssignableFrom( handlerType ) ) { + //noinspection unchecked + inStatelessTransaction( (Consumer) consumer ); + } + else { + throw new IllegalArgumentException( "Unknown EntityHandler type passed : " + handlerType.getName() ); + } + } + @Override public R callInTransaction(Function work) { return fromTransaction( work ); } + @Override + public R callInTransaction(Class handlerType, Function function) { + if ( EntityManager.class.isAssignableFrom( handlerType ) ) { + //noinspection unchecked + return fromTransaction( (Function) function ); + } + else if ( EntityAgent.class.isAssignableFrom( handlerType ) ) { + //noinspection unchecked + return fromStatelessTransaction( (Function) function ); + } + else { + throw new IllegalArgumentException( "Unknown EntityHandler type passed : " + handlerType.getName() ); + } + } + @Override public boolean isClosed() { return status == Status.CLOSED; diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java index 24eaf1848cb0..d98308e5022a 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -8,7 +8,6 @@ import jakarta.persistence.CacheStoreMode; import jakarta.persistence.Entity; import jakarta.persistence.EntityGraph; -import jakarta.persistence.EntityNotFoundException; import jakarta.persistence.FindOption; import jakarta.persistence.FlushModeType; import jakarta.persistence.LockModeType; @@ -18,10 +17,7 @@ import jakarta.persistence.RefreshOption; import jakarta.persistence.Timeout; import jakarta.persistence.TransactionRequiredException; -import jakarta.persistence.criteria.CriteriaQuery; -import jakarta.persistence.criteria.CriteriaSelect; import jakarta.persistence.metamodel.EntityType; -import jakarta.persistence.metamodel.Metamodel; import org.hibernate.*; import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor; import org.hibernate.collection.spi.PersistentCollection; @@ -34,7 +30,6 @@ import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.PersistenceContext; -import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.event.service.spi.EventListenerGroups; @@ -43,8 +38,13 @@ import org.hibernate.graph.GraphSemantic; import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.internal.find.FindByKeyOperation; -import org.hibernate.internal.find.FindMultipleByKeyOperation; +import org.hibernate.internal.find.Helper; +import org.hibernate.internal.find.StatefulFindByKeyOperation; +import org.hibernate.internal.find.StatefulFindMultipleByKeyOperation; import org.hibernate.internal.util.ExceptionHelper; +import org.hibernate.internal.util.collections.CollectionHelper; +import org.hibernate.jpa.HibernateHints; +import org.hibernate.jpa.SpecHints; import org.hibernate.jpa.internal.LegacySpecHelper; import org.hibernate.jpa.internal.util.ConfigurationHelper; import org.hibernate.jpa.internal.util.FlushModeTypeHelper; @@ -63,6 +63,7 @@ import org.hibernate.query.UnknownSqlResultSetMappingException; import org.hibernate.query.spi.QueryImplementor; import org.hibernate.query.spi.QueryParameterBindings; +import org.hibernate.query.sql.spi.NativeQueryImplementor; import org.hibernate.resource.jdbc.spi.JdbcSessionOwner; import org.hibernate.resource.transaction.spi.TransactionCoordinator; import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder; @@ -78,9 +79,11 @@ import java.io.Serial; import java.io.Serializable; import java.sql.SQLException; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; @@ -158,10 +161,6 @@ public class SessionImpl implements Serializable, SharedSessionContractImplementor, JdbcSessionOwner, SessionImplementor, EventSource, TransactionCoordinatorBuilder.Options, WrapperOptions, LoadAccessContext { - // Defaults to null, meaning the properties - // are the default properties of the factory. - private Map properties; - private transient ActionQueue actionQueue; private transient EventListenerGroups eventListenerGroups; private transient PersistenceContext persistenceContext; @@ -248,9 +247,9 @@ private FlushMode getInitialFlushMode(SessionCreationOptions options) { return initialSessionFlushMode; } else { - return properties == null + return properties() == null ? getSessionFactoryOptions().getInitialSessionFlushMode() - : ConfigurationHelper.getFlushMode( properties.get( HINT_FLUSH_MODE ), FlushMode.AUTO ); + : ConfigurationHelper.getFlushMode( properties().get( HINT_FLUSH_MODE ), FlushMode.AUTO ); } } @@ -324,9 +323,9 @@ private Integer getHintedLockTimeout() { } private Object getSessionProperty(String propertyName) { - return properties == null + return properties() == null ? getDefaultProperties().get( propertyName ) - : properties.get( propertyName ); + : properties().get( propertyName ); } private Map getDefaultProperties() { @@ -928,18 +927,14 @@ private void fireDelete(final DeleteEvent deleteEvent, final DeleteContext trans } - // load()/get() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - @Override - public void load(Object object, Object id) { - fireLoad( new LoadEvent( id, object, this, getReadOnlyFromLoadQueryInfluencers() ), LoadEventListener.RELOAD ); - } + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // find()/get()/load() operations @Override public List findMultiple(Class entityType, List keys, FindOption... options) { //noinspection unchecked return findMultiple( - requireEntityPersister( entityType ), + requireEntityPersisterForLoad( entityType ), loadQueryInfluencers.getEffectiveEntityGraph().getSemantic(), (RootGraphImplementor) loadQueryInfluencers.getEffectiveEntityGraph().getGraph(), (List) keys, @@ -953,15 +948,16 @@ private List findMultiple( RootGraphImplementor rootGraph, List keys, FindOption... options) { - final var operation = new FindMultipleByKeyOperation( + final var operation = new StatefulFindMultipleByKeyOperation( entityDescriptor, + this, lockOptions, getCacheMode(), isDefaultReadOnly(), getFactory(), options ); - return operation.performFind( keys, graphSemantic, rootGraph, this ); + return operation.performFind( keys, graphSemantic, rootGraph ); } @Override @@ -969,8 +965,8 @@ public List findMultiple(EntityGraph entityGraph, List keys, FindOp final var rootGraph = (RootGraphImplementor) entityGraph; final var type = rootGraph.getGraphedType(); final var entityDescriptor = switch ( type.getRepresentationMode() ) { - case POJO -> requireEntityPersister( type.getJavaType() ); - case MAP -> requireEntityPersister( type.getTypeName() ); + case POJO -> requireEntityPersisterForLoad( type.getJavaType() ); + case MAP -> requireEntityPersisterForLoad( type.getTypeName() ); }; //noinspection unchecked @@ -978,13 +974,8 @@ public List findMultiple(EntityGraph entityGraph, List keys, FindOp } @Override - public T get(Class entityClass, Object id) { - return byId( entityClass ).load( id ); - } - - @Override - public Object get(String entityName, Object id) { - return byId( entityName ).load( id ); + public void load(Object object, Object id) { + fireLoad( new LoadEvent( id, object, this, getReadOnlyFromLoadQueryInfluencers() ), LoadEventListener.RELOAD ); } /** @@ -1178,7 +1169,7 @@ public IdentifierLoadAccessImpl byId(String entityName) { @Override public IdentifierLoadAccessImpl byId(Class entityClass) { - return new IdentifierLoadAccessImpl<>( this, requireEntityPersister( entityClass ) ); + return new IdentifierLoadAccessImpl<>( this, requireEntityPersisterForLoad( entityClass ) ); } @Override @@ -1730,11 +1721,6 @@ public ProcedureCall createStoredProcedureCall(String procedureName, Class... return super.createStoredProcedureCall( procedureName, resultClasses ); } - @Override - public QueryImplementor createQuery(CriteriaSelect selectQuery) { - return createQuery( (CriteriaQuery) selectQuery ); - } - @Override public void initializeCollection(PersistentCollection collection, boolean writing) { checkOpenOrWaitingForAutoClose(); @@ -2101,7 +2087,6 @@ public SessionImplementor getSession() { return this; } - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // EntityManager impl @@ -2120,122 +2105,163 @@ public void remove(Object entity) { } } + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // loading + @Override - public T find(Class entityClass, Object primaryKey) { - return find( entityClass, primaryKey, (LockOptions) null, null ); + protected StatefulFindByKeyOperation byKey(EntityPersister entityDescriptor, FindOption... options) { + return byKey( entityDescriptor, null, null, options ); } @Override - public T find(Class entityClass, Object primaryKey, Map properties) { - return find( entityClass, primaryKey, (LockOptions) null, properties ); + protected StatefulFindByKeyOperation byKey( + EntityPersister entityDescriptor, + GraphSemantic graphSemantic, + RootGraphImplementor rootGraph, + FindOption... options) { + return new StatefulFindByKeyOperation<>( + entityDescriptor, + this, + graphSemantic, + rootGraph, + lockOptions, + getCacheMode(), + isDefaultReadOnly(), + getFactory(), + options + ); } @Override - public T find(Class entityClass, Object primaryKey, LockModeType lockModeType) { - return find( entityClass, primaryKey, lockModeType, null ); + public T find(Class entityClass, Object primaryKey, Map properties) { + return doFind( entityClass, primaryKey, LockMode.NONE, properties ); } @Override public T find(Class entityClass, Object primaryKey, LockModeType lockModeType, Map properties) { - checkOpen(); if ( lockModeType == null ) { throw new IllegalArgumentException("Given LockModeType was null"); } - final var lockMode = LockModeTypeHelper.getLockMode( lockModeType ); - checkTransactionNeededForLock( lockMode ); - return find( entityClass, primaryKey, buildLockOptions( lockMode, properties ), properties ); + return doFind( entityClass, primaryKey, LockMode.fromJpaLockMode( lockModeType ), properties ); } - private T find(Class entityClass, Object primaryKey, LockOptions lockOptions, Map properties) { - try { - loadQueryInfluencers.getEffectiveEntityGraph().applyConfiguredGraph( properties ); - loadQueryInfluencers.setReadOnly( readOnlyHint( properties ) ); - return byId( entityClass ) - .with( determineAppropriateLocalCacheMode( properties ) ) - .with( lockOptions ) - .load( primaryKey ); - } - catch ( FetchNotFoundException e ) { - // This may happen if the entity has an association mapped with - // @NotFound(action = NotFoundAction.EXCEPTION) and this associated - // entity is not found - throw e; - } - catch ( EntityFilterException e ) { - // This may happen if the entity has an association which is - // filtered by a FilterDef and this associated entity is not found - throw e; - } - catch ( EntityNotFoundException e ) { - // We swallow other sorts of EntityNotFoundException and return null - // For example, DefaultLoadEventListener.proxyImplementation() throws - // EntityNotFoundException if there's an existing proxy in the session, - // but the underlying database row has been deleted (see HHH-7861) - logIgnoringEntityNotFound( entityClass, primaryKey ); - return null; + private T doFind(Class entityClass, Object primaryKey, LockMode lockMode, Map properties) { + checkOpen(); + + final FindOption[] options = determineFindOptions( lockMode, properties ); + + final EntityPersister entityDescriptor = requireEntityPersisterForLoad( entityClass ); + //noinspection unchecked + return (T) byKeyWithGraph( entityDescriptor, properties, options ).performFind( primaryKey ); + } + + private FindByKeyOperation byKeyWithGraph(EntityPersister entityDescriptor, Map properties, FindOption[] options) { + var fetchHint = (RootGraphImplementor) properties.get( GraphSemantic.FETCH.getJpaHintName() ); + var loadHint = (RootGraphImplementor) properties.get( GraphSemantic.LOAD.getJpaHintName() ); + if ( fetchHint == null ) { + fetchHint = (RootGraphImplementor) properties.get( GraphSemantic.FETCH.getJakartaHintName() ); } - catch ( ObjectDeletedException e ) { - // the spec is silent about people doing remove() find() on the same PC - return null; + if ( loadHint == null ) { + loadHint = (RootGraphImplementor) properties.get( GraphSemantic.LOAD.getJakartaHintName() ); } - catch ( ObjectNotFoundException e ) { - // should not happen on the entity itself with get - // TODO: in fact this will occur instead of EntityNotFoundException - // when using StandardEntityNotFoundDelegate, so probably we - // should return null here, as we do above - throw new IllegalArgumentException( e.getMessage(), e ); + + GraphSemantic graphSemantic = null; + RootGraphImplementor graph = null; + + if ( fetchHint != null ) { + if ( loadHint != null ) { + // can't have both + throw new IllegalArgumentException( + "Passed properties contained both a LOAD and a FETCH graph which is illegal - " + + "only one should be passed" + ); + } + graphSemantic = GraphSemantic.FETCH; + graph = fetchHint; } - catch ( MappingException | TypeMismatchException | ClassCastException e ) { - throw getExceptionConverter().convert( new IllegalArgumentException( e.getMessage(), e ) ); + else if ( loadHint != null ) { + graphSemantic = GraphSemantic.LOAD; + graph = loadHint; } - catch ( JDBCException e ) { - if ( accessTransaction().isActive() && accessTransaction().getRollbackOnly() ) { - // Assume situation HHH-12472 running on WildFly - // Just log the exception and return null - SESSION_LOGGER.jdbcExceptionThrownWithTransactionRolledBack( e ); - return null; - } - else { - throw getExceptionConverter().convert( e, lockOptions ); - } + + return byKey( entityDescriptor, graphSemantic, graph, options ); + } + + private FindOption[] determineFindOptions(LockMode lockMode, Map properties) { + if ( !lockMode.greaterThan( LockMode.READ ) && CollectionHelper.isEmpty( properties ) ) { + return Helper.NO_OPTIONS; } - catch ( RuntimeException e ) { - throw getExceptionConverter().convert( e, lockOptions ); + + var options = new ArrayList(); + + if ( lockMode.greaterThan( LockMode.READ ) ) { + options.add( lockMode ); } - finally { - loadQueryInfluencers.getEffectiveEntityGraph().clear(); - loadQueryInfluencers.setReadOnly( null ); + + applyPropertiesAndHints( options, properties ); + + return options.toArray( new FindOption[0] ); + } + + private void applyPropertiesAndHints(ArrayList options, Map properties) { + if ( CollectionHelper.isEmpty( properties ) ) { + return; } + + applyFollowOnLocking( options, properties ); + applyTimeout( options, properties ); + applyLockScope( options, properties ); + + if ( readOnlyHint( properties ) == Boolean.TRUE ) { + options.add( ReadOnlyMode.READ_ONLY ); + } + + options.add( determineAppropriateLocalCacheMode( properties ) ); } - // Hibernate Reactive calls this - protected static void logIgnoringEntityNotFound(Class entityClass, Object primaryKey) { - if ( SESSION_LOGGER.isDebugEnabled() ) { - SESSION_LOGGER.ignoringEntityNotFound( - entityClass != null ? entityClass.getName(): null, - primaryKey != null ? primaryKey.toString() : null - ); + private void applyLockScope(List options, Map properties) { + final Object scopeRef = properties.get( SpecHints.HINT_SPEC_LOCK_SCOPE ); + if ( scopeRef != null ) { + options.add( Locking.Scope.fromHint( scopeRef ) ); } } - @Override - public T find(Class entityClass, Object key, FindOption... options) { - //noinspection unchecked - return (T) byKey( requireEntityPersister( entityClass ), options ).performFind( key, this ); + private void applyTimeout(List options, Map properties) { + var lockTimeout = Timeouts.lockTimeoutFromHints( properties ); + if ( lockTimeout != null ) { + options.add( lockTimeout ); + } +// else { +// var timeout = Timeouts.statementTimeoutFromHints( properties ); +// if ( timeout != null ) { +// options.add( timeout ); +// } +// } } - @Override - public T find(EntityGraph entityGraph, Object key, FindOption... options) { - final var graph = (RootGraphImplementor) entityGraph; - final var type = graph.getGraphedType(); + private void applyFollowOnLocking(List options, Map properties) { + Locking.FollowOn followOn = null; - final EntityPersister entityDescriptor = switch ( type.getRepresentationMode() ) { - case POJO -> requireEntityPersister( type.getJavaType() ); - case MAP -> requireEntityPersister( type.getTypeName() ); - }; + final Object followOnStrategyRef = properties.get( HibernateHints.HINT_FOLLOW_ON_STRATEGY ); + if ( followOnStrategyRef != null ) { + if ( followOnStrategyRef instanceof Locking.FollowOn value ) { + followOn = value; + } + else { + followOn = Locking.FollowOn.interpret( followOnStrategyRef.toString() ); + } + } + else { + final Object followOnLockingRef = properties.get( HibernateHints.HINT_FOLLOW_ON_LOCKING ); + if ( followOnLockingRef != null ) { + followOn = Locking.FollowOn.fromLegacyValue( getBoolean( followOnLockingRef ) ); + } + } - //noinspection unchecked - return (T) byKey( entityDescriptor, GraphSemantic.LOAD, graph, options ).performFind( key, this ); + if ( followOn != null ) { + options.add( followOn ); + } } // Hibernate Reactive may need to use this @@ -2268,66 +2294,19 @@ protected CacheMode determineAppropriateLocalCacheMode(Map local } if ( retrieveMode == null ) { // use the EM setting - retrieveMode = getSessionFactoryOptions().getCacheRetrieveMode( properties ); + retrieveMode = getSessionFactoryOptions().getCacheRetrieveMode( properties() ); } if ( storeMode == null ) { // use the EM setting - storeMode = getSessionFactoryOptions().getCacheStoreMode( properties ); + storeMode = getSessionFactoryOptions().getCacheStoreMode( properties() ); } return interpretCacheMode( storeMode, retrieveMode ); } - private static CacheRetrieveMode determineCacheRetrieveMode(Map settings) { - final CacheRetrieveMode cacheRetrieveMode = - (CacheRetrieveMode) settings.get( JPA_SHARED_CACHE_RETRIEVE_MODE ); - return cacheRetrieveMode == null - ? (CacheRetrieveMode) settings.get( JAKARTA_SHARED_CACHE_RETRIEVE_MODE ) - : cacheRetrieveMode; - } - - private static CacheStoreMode determineCacheStoreMode(Map settings) { - final CacheStoreMode cacheStoreMode = - (CacheStoreMode) settings.get( JPA_SHARED_CACHE_STORE_MODE ); - return cacheStoreMode == null - ? (CacheStoreMode) settings.get( JAKARTA_SHARED_CACHE_STORE_MODE ) - : cacheStoreMode; - } - private void checkTransactionNeededForUpdateOperation() { checkTransactionNeededForUpdateOperation( "No active transaction" ); } - @Override - public Object find(String entityName, Object key) { - return byKey( requireEntityPersister( entityName ) ).performFind( key, this ); - } - - @Override - public Object find(String entityName, Object key, FindOption... options) { - return byKey( requireEntityPersister( entityName ), options ).performFind( key, this ); - } - - private FindByKeyOperation byKey(EntityPersister entityDescriptor, FindOption... options) { - return byKey( entityDescriptor, null, null, options ); - } - - private FindByKeyOperation byKey( - EntityPersister entityDescriptor, - GraphSemantic graphSemantic, - RootGraphImplementor rootGraph, - FindOption... options) { - return new FindByKeyOperation<>( - entityDescriptor, - graphSemantic, - rootGraph, - lockOptions, - getCacheMode(), - isReadOnly(), - getFactory(), - options - ); - } - @Override public T getReference(Class entityClass, Object id) { checkOpen(); @@ -2404,11 +2383,6 @@ private LockOptions copySessionLockOptions() { return copiedLockOptions; } - @Override - public void refresh(Object entity, LockModeType lockModeType) { - refresh( entity, LockModeTypeHelper.getLockMode( lockModeType ) ); - } - @Override public void refresh(Object entity, Map properties) { refresh( entity, null, properties ); @@ -2502,63 +2476,55 @@ public LockModeType getLockMode(Object entity) { } - @Override - public void setProperty(String propertyName, Object value) { - checkOpen(); - if ( propertyName == null ) { - SESSION_LOGGER.nullPropertyKey(); - } - else if ( !(value instanceof Serializable) ) { - SESSION_LOGGER.nonSerializableProperty( propertyName ); - } - else { - // store property for future reference - if ( properties == null ) { - properties = getInitialProperties(); - } - properties.put( propertyName, value ); - // now actually update the setting if - // it's one that affects this Session - interpretProperty( propertyName, value ); - } + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // After the "un seal" PR is applied, this should all be consolidated + // with the Session forms on SharedSessionContract + + protected Map getInitialProperties() { + final var map = new HashMap<>( getDefaultProperties() ); + //The FLUSH_MODE is always set at Session creation time, + //so it needs special treatment to not eagerly initialize this Map: + map.put( HINT_FLUSH_MODE, getHibernateFlushMode() ); + return map; } - private void interpretProperty(String propertyName, Object value) { + @Override + protected void interpretProperty(String propertyName, Object value) { switch ( propertyName ) { case HINT_FLUSH_MODE: setHibernateFlushMode( ConfigurationHelper.getFlushMode( value, FlushMode.AUTO ) ); break; case JPA_LOCK_SCOPE: case JAKARTA_LOCK_SCOPE: - properties.put( JPA_LOCK_SCOPE, value); - properties.put( JAKARTA_LOCK_SCOPE, value); - applyPropertiesToLockOptions( properties, this::getLockOptionsForWrite ); + properties().put( JPA_LOCK_SCOPE, value); + properties().put( JAKARTA_LOCK_SCOPE, value); + applyPropertiesToLockOptions( properties(), this::getLockOptionsForWrite ); break; case JPA_LOCK_TIMEOUT: case JAKARTA_LOCK_TIMEOUT: - properties.put( JPA_LOCK_TIMEOUT, value ); - properties.put( JAKARTA_LOCK_TIMEOUT, value ); - applyPropertiesToLockOptions( properties, this::getLockOptionsForWrite ); + properties().put( JPA_LOCK_TIMEOUT, value ); + properties().put( JAKARTA_LOCK_TIMEOUT, value ); + applyPropertiesToLockOptions( properties(), this::getLockOptionsForWrite ); break; case JPA_SHARED_CACHE_RETRIEVE_MODE: case JAKARTA_SHARED_CACHE_RETRIEVE_MODE: - properties.put( JPA_SHARED_CACHE_RETRIEVE_MODE, value ); - properties.put( JAKARTA_SHARED_CACHE_RETRIEVE_MODE, value ); + properties().put( JPA_SHARED_CACHE_RETRIEVE_MODE, value ); + properties().put( JAKARTA_SHARED_CACHE_RETRIEVE_MODE, value ); setCacheMode( interpretCacheMode( - determineCacheStoreMode( properties ), + determineCacheStoreMode( properties() ), (CacheRetrieveMode) value ) ); break; case JPA_SHARED_CACHE_STORE_MODE: case JAKARTA_SHARED_CACHE_STORE_MODE: - properties.put( JPA_SHARED_CACHE_STORE_MODE, value ); - properties.put( JAKARTA_SHARED_CACHE_STORE_MODE, value ); + properties().put( JPA_SHARED_CACHE_STORE_MODE, value ); + properties().put( JAKARTA_SHARED_CACHE_STORE_MODE, value ); setCacheMode( interpretCacheMode( (CacheStoreMode) value, - determineCacheRetrieveMode( properties ) + determineCacheRetrieveMode( properties() ) ) ); break; @@ -2580,29 +2546,15 @@ private void interpretProperty(String propertyName, Object value) { case HINT_JDBC_BATCH_SIZE: setJdbcBatchSize( parseInt( value.toString() ) ); break; + default: + SESSION_LOGGER.tracef( "Unsupported property : %s", propertyName ); + break; } } - private Map getInitialProperties() { - final var map = new HashMap<>( getDefaultProperties() ); - //The FLUSH_MODE is always set at Session creation time, - //so it needs special treatment to not eagerly initialize this Map: - map.put( HINT_FLUSH_MODE, getHibernateFlushMode() ); - return map; - } - @Override - public Map getProperties() { - // EntityManager Javadoc implies that the - // returned map should be a mutable copy, - // not an unmodifiable map. There's no - // good reason to cache the initial - // properties, since we have to copy them - // each time this method is called. - return properties == null - ? getInitialProperties() - : new HashMap<>( properties ); - } + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + @Override public ProcedureCall createNamedStoredProcedureQuery(String name) { @@ -2679,18 +2631,6 @@ public Object getDelegate() { return this; } - @Override - public SessionFactoryImplementor getEntityManagerFactory() { - checkOpen(); - return getFactory(); - } - - @Override - public Metamodel getMetamodel() { - checkOpen(); - return getFactory().getJpaMetamodel(); - } - @Override public Collection getManagedEntities() { return persistenceContext.getEntityHoldersByKey() @@ -2781,4 +2721,18 @@ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFound protected Boolean getReadOnlyFromLoadQueryInfluencers() { return loadQueryInfluencers == null ? null : loadQueryInfluencers.getReadOnly(); } + + @SuppressWarnings("rawtypes") + @Override + public NativeQueryImplementor getNamedNativeQuery(String name) { + final QueryImplementor query = createNamedQuery( name ); + if ( !(query instanceof NativeQueryImplementor) ) { + throw new IllegalStateException( String.format( Locale.ROOT, + "Named query (%s) was not a native-query", + name + ) ); + } + //noinspection unchecked + return (NativeQueryImplementor) query; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java index e0bfcc253a1f..94a47e01821b 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java @@ -4,17 +4,19 @@ */ package org.hibernate.internal; +import jakarta.persistence.CacheRetrieveMode; +import jakarta.persistence.CacheStoreMode; import jakarta.persistence.EntityGraph; +import jakarta.persistence.FindOption; +import jakarta.persistence.LockModeType; import jakarta.persistence.PersistenceException; import jakarta.transaction.SystemException; import org.hibernate.AssertionFailure; +import org.hibernate.CacheMode; import org.hibernate.FlushMode; import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.LockOptions; -import org.hibernate.OrderingMode; -import org.hibernate.RemovalsMode; -import org.hibernate.SessionCheckMode; import org.hibernate.SessionException; import org.hibernate.StatelessSession; import org.hibernate.TransientObjectException; @@ -28,7 +30,6 @@ import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.PersistenceContext; -import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.StatelessSessionImplementor; import org.hibernate.engine.spi.TransactionCompletionCallbacks; import org.hibernate.engine.spi.TransactionCompletionCallbacksImplementor; @@ -63,19 +64,32 @@ import org.hibernate.graph.GraphSemantic; import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.id.IdentifierGenerationException; +import org.hibernate.internal.find.FindByKeyOperation; +import org.hibernate.internal.find.StatelessFindByKeyOperation; +import org.hibernate.internal.find.StatelessFindMultipleByKeyOperation; +import org.hibernate.internal.find.StatelessLoadAccessContext; import org.hibernate.loader.ast.internal.LoaderHelper; import org.hibernate.loader.ast.spi.CascadingFetchProfile; -import org.hibernate.loader.ast.spi.MultiIdLoadOptions; import org.hibernate.loader.internal.CacheLoadHelper; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.query.spi.QueryParameterBindings; import org.hibernate.stat.spi.StatisticsImplementor; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.function.BiConsumer; +import static java.lang.Boolean.parseBoolean; +import static java.lang.Integer.parseInt; +import static org.hibernate.cfg.BatchSettings.STATEMENT_BATCH_SIZE; +import static org.hibernate.cfg.CacheSettings.JAKARTA_SHARED_CACHE_RETRIEVE_MODE; +import static org.hibernate.cfg.CacheSettings.JAKARTA_SHARED_CACHE_STORE_MODE; +import static org.hibernate.cfg.CacheSettings.JPA_SHARED_CACHE_RETRIEVE_MODE; +import static org.hibernate.cfg.CacheSettings.JPA_SHARED_CACHE_STORE_MODE; +import static org.hibernate.cfg.QuerySettings.CRITERIA_COPY_TREE; import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable; import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable; import static org.hibernate.engine.internal.PersistenceContexts.createPersistenceContext; @@ -87,6 +101,8 @@ import static org.hibernate.generator.EventType.INSERT; import static org.hibernate.internal.SessionLogging.SESSION_LOGGER; import static org.hibernate.internal.util.NullnessUtil.castNonNull; +import static org.hibernate.jpa.HibernateHints.HINT_JDBC_BATCH_SIZE; +import static org.hibernate.jpa.internal.util.CacheModeHelper.interpretCacheMode; import static org.hibernate.loader.internal.CacheLoadHelper.initializeCollectionFromCache; import static org.hibernate.pretty.MessageHelper.collectionInfoString; import static org.hibernate.pretty.MessageHelper.infoString; @@ -117,9 +133,9 @@ * @author Steve Ebersole */ // Extended by Hibernate Reactive -public class StatelessSessionImpl extends AbstractSharedSessionContract implements StatelessSessionImplementor { - - public static final MultiIdLoadOptions MULTI_ID_LOAD_OPTIONS = new MultiLoadOptions(); +public class StatelessSessionImpl + extends AbstractSharedSessionContract + implements StatelessSessionImplementor, StatelessLoadAccessContext { private final LoadQueryInfluencers influencers; private final PersistenceContext temporaryPersistenceContext; @@ -129,6 +145,10 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen private final FlushMode flushMode; private final EventListenerGroups eventListenerGroups; + // Defaults to null, meaning the properties + // are the default properties of the factory. + private Map properties; + public StatelessSessionImpl(SessionFactoryImpl factory, SessionCreationOptions options) { super( factory, options ); connectionProvided = options.getConnection() != null; @@ -157,6 +177,64 @@ public StatelessSessionImpl(SessionFactoryImpl factory, SessionCreationOptions o setJdbcBatchSize( 0 ); } + @Override + public StatelessSessionImplementor getStatelessSession() { + return this; + } + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // After the "un seal" PR is applied, this should all be consolidated + // with the Session forms on SharedSessionContract + + @Override + protected Map getInitialProperties() { + return new HashMap<>(); + } + + /** + * NOTE : this one should be abstract on AbstractSharedSessionContract + * and implemented here and SessionImpl... + */ + @SuppressWarnings("deprecation") + protected void interpretProperty(String propertyName, Object value) { + switch ( propertyName ) { + case JPA_SHARED_CACHE_RETRIEVE_MODE: + case JAKARTA_SHARED_CACHE_RETRIEVE_MODE: + properties.put( JPA_SHARED_CACHE_RETRIEVE_MODE, value ); + properties.put( JAKARTA_SHARED_CACHE_RETRIEVE_MODE, value ); + setCacheMode( + interpretCacheMode( + determineCacheStoreMode( properties ), + (CacheRetrieveMode) value + ) + ); + break; + case JPA_SHARED_CACHE_STORE_MODE: + case JAKARTA_SHARED_CACHE_STORE_MODE: + properties.put( JPA_SHARED_CACHE_STORE_MODE, value ); + properties.put( JAKARTA_SHARED_CACHE_STORE_MODE, value ); + setCacheMode( + interpretCacheMode( + (CacheStoreMode) value, + determineCacheRetrieveMode( properties ) + ) + ); + break; + case CRITERIA_COPY_TREE: + setCriteriaCopyTreeEnabled( parseBoolean( value.toString() ) ); + break; + case STATEMENT_BATCH_SIZE: + case HINT_JDBC_BATCH_SIZE: + setJdbcBatchSize( parseInt( value.toString() ) ); + break; + default: + SESSION_LOGGER.tracef( "Unsupported property : %s", propertyName ); + break; + } + } + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + @Override public boolean shouldAutoJoinTransaction() { return true; @@ -172,11 +250,38 @@ private StatisticsImplementor getStatistics() { return getFactory().getStatistics(); } + private CacheMode getCacheModeSafely() { + var mode = getCacheMode(); + return mode == null ? CacheMode.NORMAL : mode; + } + + @Override + public void setCacheRetrieveMode(CacheRetrieveMode cacheRetrieveMode) { + var currentMode = getCacheModeSafely(); + setCacheMode( CacheMode.fromJpaModes( cacheRetrieveMode, currentMode.getJpaStoreMode() ) ); + } + + @Override + public void setCacheStoreMode(CacheStoreMode cacheStoreMode) { + var currentMode = getCacheModeSafely(); + setCacheMode( CacheMode.fromJpaModes( currentMode.getJpaRetrieveMode(), cacheStoreMode ) ); + } + + @Override + public CacheRetrieveMode getCacheRetrieveMode() { + return getCacheModeSafely().getJpaRetrieveMode(); + } + + @Override + public CacheStoreMode getCacheStoreMode() { + return getCacheModeSafely().getJpaStoreMode(); + } + // inserts ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override - public Object insert(Object entity) { - return insert( null, entity ); + public void insert(Object entity) { + insert( null, entity ); } @Override @@ -575,7 +680,7 @@ protected Object idToUpsert(Object entity, EntityPersister persister) { // Hibernate Reactive may need to call this protected boolean firePreInsert(Object entity, Object id, Object[] state, EntityPersister persister) { - getFactory().getEventEngine().getCallbackRegistry().preCreate( entity ); + persister.getEntityCallbacks().preCreate( entity ); if ( eventListenerGroups.eventListenerGroup_PRE_INSERT.isEmpty() ) { return false; @@ -592,7 +697,7 @@ protected boolean firePreInsert(Object entity, Object id, Object[] state, Entity // Hibernate Reactive may need to call this protected boolean firePreUpdate(Object entity, Object id, Object[] state, EntityPersister persister) { - getFactory().getEventEngine().getCallbackRegistry().preUpdate( entity ); + persister.getEntityCallbacks().preUpdate( entity ); if ( eventListenerGroups.eventListenerGroup_PRE_UPDATE.isEmpty() ) { return false; @@ -624,7 +729,7 @@ protected boolean firePreUpsert(Object entity, Object id, Object[] state, Entity // Hibernate Reactive may need to call this protected boolean firePreDelete(Object entity, Object id, EntityPersister persister) { - getFactory().getEventEngine().getCallbackRegistry().preRemove( entity ); + persister.getEntityCallbacks().preRemove( entity ); if ( eventListenerGroups.eventListenerGroup_PRE_DELETE.isEmpty() ) { return false; @@ -788,51 +893,70 @@ protected PersistentCollection wrap(CollectionPersister descriptor, Object co return wrapped; } - // loading ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // loading - @Override @SuppressWarnings("unchecked") - public T get(Class entityClass, Object id) { - return (T) get( entityClass.getName(), id ); + @Override + protected FindByKeyOperation byKey(EntityPersister entityDescriptor, FindOption... options) { + return byKey( entityDescriptor, null, null, options ); } - @Override @SuppressWarnings("unchecked") - public T get(Class entityClass, Object id, LockMode lockMode) { - return (T) get( entityClass.getName(), id, lockMode ); + @Override + protected FindByKeyOperation byKey( + EntityPersister entityDescriptor, + GraphSemantic graphSemantic, + RootGraphImplementor rootGraph, + FindOption... options) { + return new StatelessFindByKeyOperation<>( + entityDescriptor, + this, + graphSemantic, + rootGraph, + null, + getCacheMode(), + isDefaultReadOnly(), + getFactory(), + options + ); } @Override - public Object get(String entityName, Object id) { - return get( entityName, id, LockMode.NONE ); + public T get(Class entityClass, Object id, LockMode lockMode) { + return get( entityClass, id, (FindOption) lockMode ); } @Override - public Object get(String entityName, Object id, LockMode lockMode) { - checkOpen(); - - final var persister = requireEntityPersister( entityName ); - if ( persister.canReadFromCache() ) { - final Object cachedEntity = - loadFromSecondLevelCache( persister, generateEntityKey( id, persister ), null, lockMode ); - if ( cachedEntity != null ) { - temporaryPersistenceContext.clear(); - return cachedEntity; - } - } - final Object result = persister.load( id, null, getNullSafeLockMode( lockMode ), this ); - if ( temporaryPersistenceContext.isLoadFinished() ) { - temporaryPersistenceContext.clear(); + public Object get(String entityName, Object key, FindOption... findOptions) { + var result = find( entityName, key, findOptions ); + if ( result == null ) { + throw notFound( entityName, key ); } return result; } @Override - public T get(EntityGraph graph, Object id) { - return get( graph, GraphSemantic.LOAD , id); + public Object get(String entityName, Object id, LockMode lockMode) { + return get( entityName, id, (FindOption) lockMode ); } @Override - public T get(EntityGraph graph, Object id, LockMode lockMode) { - return get( graph, GraphSemantic.LOAD, id, lockMode); + public T get(EntityGraph entityGraph, Object id) { + var result = find( entityGraph, id ); + if ( result == null ) { + final var graph = (RootGraphImplementor) entityGraph; + throw notFound( graph.getGraphedType().getTypeName(), id ); + } + return result; + } + + @Override + public T get(EntityGraph entityGraph, Object id, LockMode lockMode) { + var result = find( entityGraph, id, lockMode ); + if ( result == null ) { + final var graph = (RootGraphImplementor) entityGraph; + throw notFound( graph.getGraphedType().getTypeName(), id ); + } + return result; } @Override @@ -858,19 +982,63 @@ public T get( } } + @Override + public List findMultiple(Class entityClass, List keys, FindOption... findOptions) { + checkOpen(); + + final var entityDescriptor = requireEntityPersister( entityClass.getName() ); + var operation = new StatelessFindMultipleByKeyOperation( + entityDescriptor, + this, + null, + getCacheMode(), + isDefaultReadOnly(), + getFactory(), + findOptions + ); + return operation.performFind( keys, null, null ); + } + + @Override + public List findMultiple(EntityGraph entityGraph, List keys, FindOption... findOptions) { + checkOpen(); + + final var graph = (RootGraphImplementor) entityGraph; + final var type = graph.getGraphedType(); + + final EntityPersister entityDescriptor = switch ( type.getRepresentationMode() ) { + case POJO -> requireEntityPersister( type.getJavaType() ); + case MAP -> requireEntityPersister( type.getTypeName() ); + }; + var operation = new StatelessFindMultipleByKeyOperation( + entityDescriptor, + this, + null, + getCacheMode(), + isDefaultReadOnly(), + getFactory(), + findOptions + ); + return operation.performFind( keys, GraphSemantic.LOAD, graph ); + } + @Override public List getMultiple(Class entityClass, List ids, LockMode lockMode) { - for ( Object id : ids ) { - if ( id == null ) { - throw new IllegalArgumentException( "Null id" ); - } - } + checkOpen(); final var persister = requireEntityPersister( entityClass.getName() ); - final var results = persister.multiLoad( ids.toArray(), this, new MultiLoadOptions(lockMode) ); - //noinspection unchecked - return (List) results; + var operation = new StatelessFindMultipleByKeyOperation( + persister, + this, + null, + getCacheMode(), + isDefaultReadOnly(), + getFactory(), + lockMode + ); + return operation.performFind( ids, null, null ); } + @Override public List getMultiple(EntityGraph entityGraph, List ids) { return getMultiple( entityGraph, GraphSemantic.LOAD, ids ); @@ -878,78 +1046,31 @@ public List getMultiple(EntityGraph entityGraph, List ids) { @Override public List getMultiple(EntityGraph entityGraph, GraphSemantic graphSemantic, List ids) { - for ( Object id : ids ) { - if ( id == null ) { - throw new IllegalArgumentException( "Null id" ); - } - } - final var rootGraph = (RootGraphImplementor) entityGraph; - - final var effectiveEntityGraph = getLoadQueryInfluencers().getEffectiveEntityGraph(); - effectiveEntityGraph.applyGraph( rootGraph, graphSemantic ); - - try { - final var persister = requireEntityPersister( rootGraph.getGraphedType().getTypeName() ); - final var results = persister.multiLoad( ids.toArray(), this, MULTI_ID_LOAD_OPTIONS ); - //noinspection unchecked - return (List) results; - } - finally { - effectiveEntityGraph.clear(); - } + final var entityDescriptor = requireEntityPersister( rootGraph.getGraphedType().getTypeName() ); + var operation = new StatelessFindMultipleByKeyOperation( + entityDescriptor, + this, + null, + getCacheMode(), + isDefaultReadOnly(), + getFactory() + ); + return operation.performFind( ids, GraphSemantic.LOAD, rootGraph ); } @Override public List getMultiple(Class entityClass, List ids) { - for ( Object id : ids ) { - if ( id == null ) { - throw new IllegalArgumentException("Null id"); - } - } - - final var persister = requireEntityPersister( entityClass.getName() ); - final var results = persister.multiLoad( ids.toArray(), this, MULTI_ID_LOAD_OPTIONS ); - //noinspection unchecked - return (List) results; - -// final List uncachedIds; -// final List list = new ArrayList<>( ids.size() ); -// if ( persister.canReadFromCache() ) { -// uncachedIds = new ArrayList<>( ids.size() ); -// for (Object id : ids) { -// final Object cachedEntity = -// loadFromSecondLevelCache( persister, generateEntityKey( id, persister ), null, LockMode.NONE ); -// if ( cachedEntity == null ) { -// uncachedIds.add( id ); -// list.add( null ); -// } -// else { -// //noinspection unchecked -// list.add( (T) cachedEntity ); -// } -// } -// } -// else { -// uncachedIds = unmodifiableList(ids); -// for (int i = 0; i < ids.size(); i++) { -// list.add( null ); -// } -// } -// -// final JpaCriteriaQuery query = getCriteriaBuilder().createQuery(entityClass); -// final JpaRoot from = query.from(entityClass); -// query.where( from.get( persister.getIdentifierPropertyName() ).in(uncachedIds) ); -// final List resultList = createSelectionQuery(query).getResultList(); -// for (int i = 0; i < ids.size(); i++) { -// if ( list.get(i) == null ) { -// final Object id = ids.get(i); -// list.set( i, resultList.stream() -// .filter( entity -> entity != null && persister.getIdentifier( entity, this ).equals(id) ) -// .findFirst().orElse( null ) ); -// } -// } -// return list; + final var entityDescriptor = requireEntityPersister( entityClass.getName() ); + var operation = new StatelessFindMultipleByKeyOperation( + entityDescriptor, + this, + null, + getCacheMode(), + isDefaultReadOnly(), + getFactory() + ); + return operation.performFind( ids, null, null ); } @Override @@ -1001,6 +1122,24 @@ public void refresh(String entityName, Object entity, LockMode lockMode) { } } + @Override + public void refresh(Object entity, LockModeType lockModeType) { + refresh( bestGuessEntityName( entity ), entity, LockMode.fromJpaLockMode( lockModeType ) ); + } + + @Override + public void refreshMultiple(List entities) { + checkOpen(); + + // NOTE: the incoming list of entities can be heterogeneous - the elements + // need not be all the same type. + + // for now, a simple implementation - + // todo (jpa4) : we will definitely want to improve this. + + entities.forEach( this::refresh ); + } + @Override public Object immediateLoad(String entityName, Object id) { if ( getPersistenceContextInternal().isLoadFinished() ) { @@ -1146,7 +1285,7 @@ private Object createProxy(EntityKey entityKey) { } @Override - public void fetch(Object association) { + public T fetch(T association) { checkOpen(); final var persistenceContext = getPersistenceContext(); final var initializer = extractLazyInitializer( association ); @@ -1220,6 +1359,9 @@ else if ( association instanceof PersistentCollection collection ) { } } } + + // per JPA, always just returns the argument + return association; } @Override @@ -1528,51 +1670,4 @@ public T unwrap(Class type) { + "' as '" + type.getName() + "'" ); } - private static final class MultiLoadOptions implements MultiIdLoadOptions { - private final LockOptions lockOptions; - - private MultiLoadOptions() { - this.lockOptions = null; - } - - private MultiLoadOptions(LockMode lockMode) { - this.lockOptions = new LockOptions( lockMode ); - } - - @Override - public SessionCheckMode getSessionCheckMode() { - return SessionCheckMode.DISABLED; - } - - @Override - public boolean isSecondLevelCacheCheckingEnabled() { - return true; - } - - @Override - public Boolean getReadOnly(SessionImplementor session) { - return null; - } - - @Override - public RemovalsMode getRemovalsMode() { - return RemovalsMode.REPLACE; - } - - @Override - public OrderingMode getOrderingMode() { - return OrderingMode.ORDERED; - } - - @Override - public LockOptions getLockOptions() { - return lockOptions; - } - - @Override - public Integer getBatchSize() { - return null; - } - } - } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/find/AbstractFindByKeyOperation.java b/hibernate-core/src/main/java/org/hibernate/internal/find/AbstractFindByKeyOperation.java new file mode 100644 index 000000000000..0fe2395d1550 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/internal/find/AbstractFindByKeyOperation.java @@ -0,0 +1,313 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.internal.find; + +import jakarta.persistence.CacheRetrieveMode; +import jakarta.persistence.CacheStoreMode; +import jakarta.persistence.EntityNotFoundException; +import jakarta.persistence.FindOption; +import jakarta.persistence.LockModeType; +import jakarta.persistence.PessimisticLockScope; +import jakarta.persistence.Timeout; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.hibernate.CacheMode; +import org.hibernate.EnabledFetchProfile; +import org.hibernate.EntityFilterException; +import org.hibernate.FetchNotFoundException; +import org.hibernate.FindMultipleOption; +import org.hibernate.JDBCException; +import org.hibernate.KeyType; +import org.hibernate.LockMode; +import org.hibernate.LockOptions; +import org.hibernate.Locking; +import org.hibernate.MappingException; +import org.hibernate.NaturalIdSynchronization; +import org.hibernate.ObjectDeletedException; +import org.hibernate.ObjectNotFoundException; +import org.hibernate.ReadOnlyMode; +import org.hibernate.Timeouts; +import org.hibernate.Transaction; +import org.hibernate.TypeMismatchException; +import org.hibernate.engine.spi.ExceptionConverter; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.exception.LockTimeoutException; +import org.hibernate.graph.GraphSemantic; +import org.hibernate.graph.spi.RootGraphImplementor; +import org.hibernate.jpa.internal.util.LockModeTypeHelper; +import org.hibernate.loader.ast.spi.NaturalIdLoader; +import org.hibernate.persister.entity.EntityPersister; + +import java.util.HashSet; +import java.util.Set; +import java.util.function.Supplier; + +import static org.hibernate.Timeouts.WAIT_FOREVER; +import static org.hibernate.internal.SessionLogging.SESSION_LOGGER; +import static org.hibernate.jpa.SpecHints.HINT_SPEC_LOCK_TIMEOUT; + +/// Base support for loading a single entity by key (either [id][KeyType#IDENTIFIER] or [natural-id][KeyType#NATURAL]). +/// +/// @see KeyType +/// +/// @author Steve Ebersole +public abstract class AbstractFindByKeyOperation implements FindByKeyOperation, NaturalIdLoader.Options { + private final EntityPersister entityDescriptor; + + private KeyType keyType = KeyType.IDENTIFIER; + + private CacheStoreMode cacheStoreMode; + private CacheRetrieveMode cacheRetrieveMode; + + private LockMode lockMode; + private Locking.Scope lockScope; + private Locking.FollowOn lockFollowOn; + private Timeout lockTimeout = WAIT_FOREVER; + + private ReadOnlyMode readOnlyMode; + + private RootGraphImplementor rootGraph; + private GraphSemantic graphSemantic; + + private Set enabledFetchProfiles; + + private NaturalIdSynchronization naturalIdSynchronization; + + public AbstractFindByKeyOperation( + @NonNull EntityPersister entityDescriptor, + @Nullable GraphSemantic graphSemantic, + @Nullable RootGraphImplementor rootGraph, + @Nullable LockOptions defaultLockOptions, + @Nullable CacheMode defaultCacheMode, + boolean defaultReadOnly, + @NonNull SessionFactoryImplementor sessionFactory, + FindOption... findOptions) { + this.entityDescriptor = entityDescriptor; + + this.graphSemantic = graphSemantic; + this.rootGraph = rootGraph; + + if ( defaultCacheMode != null ) { + cacheStoreMode = defaultCacheMode.getJpaStoreMode(); + cacheRetrieveMode = defaultCacheMode.getJpaRetrieveMode(); + } + + if ( defaultLockOptions != null ) { + lockMode = defaultLockOptions.getLockMode(); + lockScope = defaultLockOptions.getScope(); + lockTimeout = defaultLockOptions.getTimeout(); + lockFollowOn = defaultLockOptions.getFollowOnStrategy(); + } + if ( lockTimeout == WAIT_FOREVER ) { + final Object factoryTimeoutHint = sessionFactory.getProperties().get( HINT_SPEC_LOCK_TIMEOUT ); + if ( factoryTimeoutHint != null ) { + lockTimeout = Timeouts.fromHintTimeout( factoryTimeoutHint ); + } + } + + readOnlyMode = defaultReadOnly ? ReadOnlyMode.READ_ONLY : ReadOnlyMode.READ_WRITE; + + for ( FindOption option : findOptions ) { + if ( option instanceof KeyType keyType ) { + this.keyType = keyType; + } + else if ( option instanceof CacheStoreMode cacheStoreMode ) { + this.cacheStoreMode = cacheStoreMode; + } + else if ( option instanceof CacheRetrieveMode cacheRetrieveMode ) { + this.cacheRetrieveMode = cacheRetrieveMode; + } + else if ( option instanceof CacheMode cacheMode ) { + this.cacheStoreMode = cacheMode.getJpaStoreMode(); + this.cacheRetrieveMode = cacheMode.getJpaRetrieveMode(); + } + else if ( option instanceof LockModeType lockModeType ) { + this.lockMode = LockModeTypeHelper.getLockMode( lockModeType ); + } + else if ( option instanceof LockMode lockMode ) { + this.lockMode = lockMode; + } + else if ( option instanceof Locking.Scope lockScope ) { + this.lockScope = lockScope; + } + else if ( option instanceof PessimisticLockScope pessimisticLockScope ) { + this.lockScope = Locking.Scope.fromJpaScope( pessimisticLockScope ); + } + else if ( option instanceof Locking.FollowOn followOn ) { + this.lockFollowOn = followOn; + } + else if ( option instanceof Timeout timeout ) { + this.lockTimeout = timeout; + } + else if ( option instanceof ReadOnlyMode readOnlyMode) { + this.readOnlyMode = readOnlyMode; + } + else if ( option instanceof EnabledFetchProfile enabledFetchProfile ) { + this.enabledFetchProfile( enabledFetchProfile.profileName() ); + } + else if ( option instanceof NaturalIdSynchronization naturalIdSynchronization ) { + this.naturalIdSynchronization = naturalIdSynchronization; + } + else if ( option instanceof FindMultipleOption findMultipleOption ) { + throw new IllegalArgumentException( "Option '" + findMultipleOption + "' can only be used in 'findMultiple()'" ); + } + } + } + + private void enabledFetchProfile(String profileName) { + if ( enabledFetchProfiles == null ) { + enabledFetchProfiles = new HashSet<>(); + } + enabledFetchProfiles.add( profileName ); + } + + public EntityPersister getEntityDescriptor() { + return entityDescriptor; + } + + public KeyType getKeyType() { + return keyType; + } + + public CacheStoreMode getCacheStoreMode() { + return cacheStoreMode; + } + + public CacheRetrieveMode getCacheRetrieveMode() { + return cacheRetrieveMode; + } + + public ReadOnlyMode getReadOnlyMode() { + return readOnlyMode; + } + + public RootGraphImplementor getRootGraph() { + return rootGraph; + } + + public GraphSemantic getGraphSemantic() { + return graphSemantic; + } + + public Set getEnabledFetchProfiles() { + return enabledFetchProfiles; + } + + public NaturalIdSynchronization getNaturalIdSynchronization() { + return naturalIdSynchronization; + } + + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // NaturalIdLoader.Options + + @Override + public LockMode getLockMode() { + return lockMode; + } + + @Override + public Timeout getLockTimeout() { + return lockTimeout; + } + + @Override + public Locking.Scope getLockScope() { + return lockScope; + } + + @Override + public Locking.FollowOn getLockFollowOn() { + return lockFollowOn; + } + + protected boolean needsTransaction(LockMode lockMode) { + return lockMode != null && lockMode.greaterThan( LockMode.NONE ); + } + + protected LockOptions makeLockOptions() { + return Helper.makeLockOptions( getLockMode(), getLockScope(), getLockTimeout(), getLockFollowOn() ); + } + + protected void logIgnoringEntityNotFound(Object key) { + if ( SESSION_LOGGER.isDebugEnabled() ) { + SESSION_LOGGER.ignoringEntityNotFound( getEntityDescriptor().getEntityName(), key ); + } + } + + + protected T withExceptionHandling( + Object key, + LockOptions lockOptions, + Supplier action) { + try { + return action.get(); + } + catch ( FetchNotFoundException e ) { + // This may happen if the entity has an association mapped with + // @NotFound(action = NotFoundAction.EXCEPTION) and this associated + // entity is not found + throw e; + } + catch ( EntityFilterException e ) { + // This may happen if the entity has an association which is + // filtered by a FilterDef and this associated entity is not found + throw e; + } + catch ( EntityNotFoundException e ) { + // We swallow other sorts of EntityNotFoundException and return null + // For example, DefaultLoadEventListener.proxyImplementation() throws + // EntityNotFoundException if there's an existing proxy in the session, + // but the underlying database row has been deleted (see HHH-7861) + logIgnoringEntityNotFound( key ); + return null; + } + catch ( ObjectDeletedException e ) { + // the spec is silent about people doing remove() find() on the same PC + return null; + } + catch ( ObjectNotFoundException e ) { + // should not happen on the entity itself with get + // TODO: in fact this will occur instead of EntityNotFoundException + // when using StandardEntityNotFoundDelegate, so probably we + // should return null here, as we do above + throw new IllegalArgumentException( e.getMessage(), e ); + } + catch (MappingException | TypeMismatchException | ClassCastException e ) { + throw getExceptionConverter().convert( new IllegalArgumentException( e.getMessage(), e ) ); + } + catch (jakarta.persistence.LockTimeoutException e) { + throw e; + } + catch (LockTimeoutException e) { + throw getExceptionConverter().convert( e, lockOptions ); + } + catch ( JDBCException e ) { + if ( accessTransaction().isActive() ) { + if ( accessTransaction().getRollbackOnly() ) { + // Assume situation HHH-12472 running on WildFly + // Just log the exception and return null + SESSION_LOGGER.jdbcExceptionThrownWithTransactionRolledBack( e ); + return null; + } + } + throw getExceptionConverter().convert( e, lockOptions ); + } + catch ( RuntimeException e ) { + throw getExceptionConverter().convert( e, lockOptions ); + } + } + + protected abstract SharedSessionContractImplementor getEntityHandler(); + + protected Transaction accessTransaction() { + return getEntityHandler().accessTransaction(); + } + + protected ExceptionConverter getExceptionConverter() { + return getEntityHandler().getExceptionConverter(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/internal/find/FindMultipleByKeyOperation.java b/hibernate-core/src/main/java/org/hibernate/internal/find/AbstractFindMultipleByKeyOperation.java similarity index 66% rename from hibernate-core/src/main/java/org/hibernate/internal/find/FindMultipleByKeyOperation.java rename to hibernate-core/src/main/java/org/hibernate/internal/find/AbstractFindMultipleByKeyOperation.java index 76c073b66d8a..5d957ed372e8 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/find/FindMultipleByKeyOperation.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/find/AbstractFindMultipleByKeyOperation.java @@ -27,30 +27,23 @@ import org.hibernate.Timeouts; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionImplementor; -import org.hibernate.graph.GraphSemantic; -import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.jpa.internal.util.LockModeTypeHelper; import org.hibernate.loader.ast.spi.MultiIdLoadOptions; import org.hibernate.loader.ast.spi.MultiNaturalIdLoadOptions; -import org.hibernate.loader.internal.LoadAccessContext; import org.hibernate.persister.entity.EntityPersister; import java.util.HashSet; -import java.util.List; import java.util.Set; -import java.util.function.Supplier; import static org.hibernate.Timeouts.WAIT_FOREVER; -import static org.hibernate.internal.NaturalIdHelper.performAnyNeededCrossReferenceSynchronizations; import static org.hibernate.jpa.SpecHints.HINT_SPEC_LOCK_TIMEOUT; -/// Support for loading multiple entities (of a type) by key (either [id][KeyType#IDENTIFIER] or [natural-id][KeyType#NATURAL]). +/// Base support for loading multiple entities (of a type) by key (either [id][KeyType#IDENTIFIER] or [natural-id][KeyType#NATURAL]). /// -/// @see org.hibernate.Session#findMultiple /// @see KeyType /// /// @author Steve Ebersole -public class FindMultipleByKeyOperation implements MultiIdLoadOptions, MultiNaturalIdLoadOptions { +public abstract class AbstractFindMultipleByKeyOperation implements MultiIdLoadOptions, MultiNaturalIdLoadOptions { private final EntityPersister entityDescriptor; private KeyType keyType = KeyType.IDENTIFIER; @@ -76,7 +69,7 @@ public class FindMultipleByKeyOperation implements MultiIdLoadOptions, MultiN private NaturalIdSynchronization naturalIdSynchronization; @SuppressWarnings("PatternVariableHidesField") - public FindMultipleByKeyOperation( + public AbstractFindMultipleByKeyOperation( @NonNull EntityPersister entityDescriptor, @Nullable LockOptions defaultLockOptions, @Nullable CacheMode defaultCacheMode, @@ -168,95 +161,52 @@ private void enabledFetchProfile(String profileName) { enabledFetchProfiles.add( profileName ); } - public List performFind( - List keys, - @Nullable GraphSemantic graphSemantic, - @Nullable RootGraphImplementor rootGraph, - LoadAccessContext loadAccessContext) { - // todo (natural-id-class) : these impls are temporary - // longer term, move the logic here as much of it can be shared - return keyType == KeyType.NATURAL - ? findByNaturalIds( keys, graphSemantic, rootGraph, loadAccessContext ) - : findByIds( keys, graphSemantic, rootGraph, loadAccessContext ); + public EntityPersister getEntityDescriptor() { + return entityDescriptor; } - private List findByNaturalIds(List keys, GraphSemantic graphSemantic, RootGraphImplementor rootGraph, LoadAccessContext loadAccessContext) { - final var naturalIdMapping = entityDescriptor.requireNaturalIdMapping(); - final var session = loadAccessContext.getSession(); - - performAnyNeededCrossReferenceSynchronizations( - naturalIdSynchronization != NaturalIdSynchronization.DISABLED, - entityDescriptor, - session - ); - - return withOptions( loadAccessContext, graphSemantic, rootGraph, () -> { - // normalize the incoming natural-id values and get them in array form as needed - // by MultiNaturalIdLoader - final int size = keys.size(); - final var naturalIds = new Object[size]; - for ( int i = 0; i < size; i++ ) { - naturalIds[i] = naturalIdMapping.normalizeInput( keys.get( i ) ); - } - //noinspection unchecked - return (List) - entityDescriptor.getMultiNaturalIdLoader() - .multiLoad( naturalIds, this, session ); - } ); + public KeyType getKeyType() { + return keyType; } - private List withOptions( - LoadAccessContext loadAccessContext, - GraphSemantic graphSemantic, - RootGraphImplementor rootGraph, - Supplier> action) { - final var session = loadAccessContext.getSession(); - final var influencers = session.getLoadQueryInfluencers(); - final var fetchProfiles = - influencers.adjustFetchProfiles( disabledFetchProfiles, enabledFetchProfiles ); - final var effectiveEntityGraph = - rootGraph == null - ? null - : influencers.applyEntityGraph( rootGraph, graphSemantic ); - - final var readOnly = session.isDefaultReadOnly(); - session.setDefaultReadOnly( readOnlyMode == ReadOnlyMode.READ_ONLY ); - - final var cacheMode = session.getCacheMode(); - session.setCacheMode( CacheMode.fromJpaModes( cacheRetrieveMode, cacheStoreMode ) ); - - try { - return action.get(); - } - finally { - loadAccessContext.delayedAfterCompletion(); - if ( effectiveEntityGraph != null ) { - effectiveEntityGraph.clear(); - } - influencers.setEnabledFetchProfileNames( fetchProfiles ); - session.setDefaultReadOnly( readOnly ); - session.setCacheMode( cacheMode ); - } + public CacheStoreMode getCacheStoreMode() { + return cacheStoreMode; + } + + public CacheRetrieveMode getCacheRetrieveMode() { + return cacheRetrieveMode; + } + + public LockMode getLockMode() { + return lockMode; + } + + public Locking.Scope getLockScope() { + return lockScope; + } + + public Locking.FollowOn getLockFollowOn() { + return lockFollowOn; + } + + public Timeout getLockTimeout() { + return lockTimeout; + } + + public ReadOnlyMode getReadOnlyMode() { + return readOnlyMode; + } + + public Set getEnabledFetchProfiles() { + return enabledFetchProfiles; + } + + public Set getDisabledFetchProfiles() { + return disabledFetchProfiles; } -// private Object getCachedNaturalIdResolution( -// Object normalizedNaturalIdValue, -// LoadAccessContext loadAccessContext) { -// loadAccessContext.checkOpenOrWaitingForAutoClose(); -// loadAccessContext.pulseTransactionCoordinator(); -// -// return loadAccessContext -// .getSession() -// .getPersistenceContextInternal() -// .getNaturalIdResolutions() -// .findCachedIdByNaturalId( normalizedNaturalIdValue, entityDescriptor ); -// } - - private List findByIds(List keys, GraphSemantic graphSemantic, RootGraphImplementor rootGraph, LoadAccessContext loadAccessContext) { - final var ids = keys.toArray( new Object[0] ); - //noinspection unchecked - return withOptions( loadAccessContext, graphSemantic, rootGraph, - () -> (List) entityDescriptor.multiLoad( ids, loadAccessContext.getSession(), this ) ); + public NaturalIdSynchronization getNaturalIdSynchronization() { + return naturalIdSynchronization; } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -305,7 +255,7 @@ public Integer getBatchSize() { /// @deprecated [org.hibernate.MultiIdentifierLoadAccess] and [org.hibernate.MultiIdentifierLoadAccess] /// are both also deprecated. @Deprecated - public FindMultipleByKeyOperation( + public AbstractFindMultipleByKeyOperation( EntityPersister entityDescriptor, KeyType keyType, BatchSize batchSize, diff --git a/hibernate-core/src/main/java/org/hibernate/internal/find/FindByKeyContext.java b/hibernate-core/src/main/java/org/hibernate/internal/find/FindByKeyContext.java new file mode 100644 index 000000000000..e7a242a08000 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/internal/find/FindByKeyContext.java @@ -0,0 +1,14 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.internal.find; + +import org.hibernate.engine.spi.SharedSessionContractImplementor; + +/// Context for find by primary or natural key operations. +/// +/// @author Steve Ebersole +public interface FindByKeyContext { + SharedSessionContractImplementor getOrigin(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/internal/find/FindByKeyOperation.java b/hibernate-core/src/main/java/org/hibernate/internal/find/FindByKeyOperation.java index ab27646b3bf9..5bb2b73e6110 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/find/FindByKeyOperation.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/find/FindByKeyOperation.java @@ -4,335 +4,19 @@ */ package org.hibernate.internal.find; -import jakarta.persistence.CacheRetrieveMode; -import jakarta.persistence.CacheStoreMode; -import jakarta.persistence.FindOption; -import jakarta.persistence.LockModeType; -import jakarta.persistence.PessimisticLockScope; -import jakarta.persistence.Timeout; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.hibernate.CacheMode; -import org.hibernate.EnabledFetchProfile; -import org.hibernate.KeyType; -import org.hibernate.FindMultipleOption; -import org.hibernate.LockMode; -import org.hibernate.LockOptions; -import org.hibernate.Locking; -import org.hibernate.NaturalIdSynchronization; -import org.hibernate.ObjectNotFoundException; -import org.hibernate.ReadOnlyMode; -import org.hibernate.Timeouts; -import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor; -import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.engine.spi.SessionImplementor; -import org.hibernate.engine.spi.Status; -import org.hibernate.event.spi.LoadEventListener; -import org.hibernate.graph.GraphSemantic; -import org.hibernate.graph.spi.RootGraphImplementor; -import org.hibernate.jpa.internal.util.LockModeTypeHelper; -import org.hibernate.loader.ast.spi.NaturalIdLoader; -import org.hibernate.loader.internal.LoadAccessContext; -import org.hibernate.metamodel.mapping.NaturalIdMapping; -import org.hibernate.persister.entity.EntityPersister; -import org.hibernate.proxy.HibernateProxy; - -import java.util.HashSet; -import java.util.Set; -import java.util.function.Supplier; - -import static org.hibernate.Timeouts.WAIT_FOREVER; -import static org.hibernate.engine.spi.NaturalIdResolutions.INVALID_NATURAL_ID_REFERENCE; -import static org.hibernate.internal.NaturalIdHelper.performAnyNeededCrossReferenceSynchronizations; -import static org.hibernate.jpa.SpecHints.HINT_SPEC_LOCK_TIMEOUT; -import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer; - -/// Support for loading a single entity by key (either [id][KeyType#IDENTIFIER] or [natural-id][KeyType#NATURAL]). -/// -/// @see org.hibernate.Session#find -/// @see KeyType -/// -/// @author Steve Ebersole -public class FindByKeyOperation implements NaturalIdLoader.Options { - private final EntityPersister entityDescriptor; - - private KeyType keyType = KeyType.IDENTIFIER; - - private CacheStoreMode cacheStoreMode; - private CacheRetrieveMode cacheRetrieveMode; - - private LockMode lockMode; - private Locking.Scope lockScope; - private Locking.FollowOn lockFollowOn; - private Timeout lockTimeout = WAIT_FOREVER; - - private ReadOnlyMode readOnlyMode; - - private RootGraphImplementor rootGraph; - private GraphSemantic graphSemantic; - - private Set enabledFetchProfiles; - - private NaturalIdSynchronization naturalIdSynchronization; - - public FindByKeyOperation( - @NonNull EntityPersister entityDescriptor, - @Nullable GraphSemantic graphSemantic, - @Nullable RootGraphImplementor rootGraph, - @Nullable LockOptions defaultLockOptions, - @Nullable CacheMode defaultCacheMode, - boolean defaultReadOnly, - @NonNull SessionFactoryImplementor sessionFactory, - FindOption... findOptions) { - this.entityDescriptor = entityDescriptor; - - this.graphSemantic = graphSemantic; - this.rootGraph = rootGraph; - - if ( defaultCacheMode != null ) { - cacheStoreMode = defaultCacheMode.getJpaStoreMode(); - cacheRetrieveMode = defaultCacheMode.getJpaRetrieveMode(); - } - - if ( defaultLockOptions != null ) { - lockMode = defaultLockOptions.getLockMode(); - lockScope = defaultLockOptions.getScope(); - lockTimeout = defaultLockOptions.getTimeout(); - lockFollowOn = defaultLockOptions.getFollowOnStrategy(); - } - if ( lockTimeout == WAIT_FOREVER ) { - final Object factoryTimeoutHint = sessionFactory.getProperties().get( HINT_SPEC_LOCK_TIMEOUT ); - if ( factoryTimeoutHint != null ) { - lockTimeout = Timeouts.fromHintTimeout( factoryTimeoutHint ); - } - } - - readOnlyMode = defaultReadOnly ? ReadOnlyMode.READ_ONLY : ReadOnlyMode.READ_WRITE; - - for ( FindOption option : findOptions ) { - if ( option instanceof KeyType keyType ) { - this.keyType = keyType; - } - else if ( option instanceof CacheStoreMode cacheStoreMode ) { - this.cacheStoreMode = cacheStoreMode; - } - else if ( option instanceof CacheRetrieveMode cacheRetrieveMode ) { - this.cacheRetrieveMode = cacheRetrieveMode; - } - else if ( option instanceof CacheMode cacheMode ) { - this.cacheStoreMode = cacheMode.getJpaStoreMode(); - this.cacheRetrieveMode = cacheMode.getJpaRetrieveMode(); - } - else if ( option instanceof LockModeType lockModeType ) { - this.lockMode = LockModeTypeHelper.getLockMode( lockModeType ); - } - else if ( option instanceof LockMode lockMode ) { - this.lockMode = lockMode; - } - else if ( option instanceof Locking.Scope lockScope ) { - this.lockScope = lockScope; - } - else if ( option instanceof PessimisticLockScope pessimisticLockScope ) { - this.lockScope = Locking.Scope.fromJpaScope( pessimisticLockScope ); - } - else if ( option instanceof Locking.FollowOn followOn ) { - this.lockFollowOn = followOn; - } - else if ( option instanceof Timeout timeout ) { - this.lockTimeout = timeout; - } - else if ( option instanceof ReadOnlyMode readOnlyMode) { - this.readOnlyMode = readOnlyMode; - } - else if ( option instanceof EnabledFetchProfile enabledFetchProfile ) { - this.enabledFetchProfile( enabledFetchProfile.profileName() ); - } - else if ( option instanceof NaturalIdSynchronization naturalIdSynchronization ) { - this.naturalIdSynchronization = naturalIdSynchronization; - } - else if ( option instanceof FindMultipleOption findMultipleOption ) { - throw new IllegalArgumentException( "Option '" + findMultipleOption + "' can only be used in 'findMultiple()'" ); - } - } - } - - private void enabledFetchProfile(String profileName) { - if ( enabledFetchProfiles == null ) { - enabledFetchProfiles = new HashSet<>(); - } - enabledFetchProfiles.add( profileName ); - } - - public T performFind(Object key, LoadAccessContext loadAccessContext) { - if ( keyType == KeyType.NATURAL ) { - return findByNaturalId( key, loadAccessContext ); - } - else { - return findById( key, loadAccessContext ); - } - - } - - private T findByNaturalId(Object key, LoadAccessContext loadAccessContext) { - final NaturalIdMapping naturalIdMapping = entityDescriptor.requireNaturalIdMapping(); - final SessionImplementor session = loadAccessContext.getSession(); - - performAnyNeededCrossReferenceSynchronizations( - naturalIdSynchronization != NaturalIdSynchronization.DISABLED, - entityDescriptor, - session - ); - - final var normalizedKey = naturalIdMapping.normalizeInput( key ); - - final Object cachedResolution = getCachedNaturalIdResolution( normalizedKey, loadAccessContext ); - if ( cachedResolution == INVALID_NATURAL_ID_REFERENCE ) { - return null; - } - - if ( cachedResolution != null ) { - return findById( cachedResolution, loadAccessContext ); - } - - return withOptions( loadAccessContext, () -> { - @SuppressWarnings("unchecked") - final T loaded = (T) entityDescriptor.getNaturalIdLoader() - .load( normalizedKey, this, session ); - if ( loaded != null ) { - final var persistenceContext = session.getPersistenceContextInternal(); - final var lazyInitializer = HibernateProxy.extractLazyInitializer( loaded ); - final var entity = lazyInitializer != null ? lazyInitializer.getImplementation() : loaded; - final var entry = persistenceContext.getEntry( entity ); - assert entry != null; - if ( entry.getStatus() == Status.DELETED ) { - return null; - } - } - return loaded; - } ); - } - - private T withOptions(LoadAccessContext loadAccessContext, Supplier action) { - final var session = loadAccessContext.getSession(); - final var influencers = session.getLoadQueryInfluencers(); - final var fetchProfiles = influencers.adjustFetchProfiles( null, enabledFetchProfiles ); - final var effectiveEntityGraph = rootGraph == null - ? null - : influencers.applyEntityGraph( rootGraph, graphSemantic ); - - final var readOnly = session.isDefaultReadOnly(); - session.setDefaultReadOnly( readOnlyMode == ReadOnlyMode.READ_ONLY ); - - final var cacheMode = session.getCacheMode(); - session.setCacheMode( CacheMode.fromJpaModes( cacheRetrieveMode, cacheStoreMode ) ); - - try { - return action.get(); - } - finally { - loadAccessContext.delayedAfterCompletion(); - if ( effectiveEntityGraph != null ) { - effectiveEntityGraph.clear(); - } - influencers.setEnabledFetchProfileNames( fetchProfiles ); - session.setDefaultReadOnly( readOnly ); - session.setCacheMode( cacheMode ); - } - } - - private Object getCachedNaturalIdResolution( - Object normalizedNaturalIdValue, - LoadAccessContext loadAccessContext) { - loadAccessContext.checkOpenOrWaitingForAutoClose(); - loadAccessContext.pulseTransactionCoordinator(); - - return loadAccessContext - .getSession() - .getPersistenceContextInternal() - .getNaturalIdResolutions() - .findCachedIdByNaturalId( normalizedNaturalIdValue, entityDescriptor ); - } - - private T findById(Object key, LoadAccessContext loadAccessContext) { - return withOptions( loadAccessContext, () -> { - final var session = loadAccessContext.getSession(); - Object result; - try { - result = loadAccessContext.load( - LoadEventListener.GET, - coerceId( key, session.getFactory() ), - entityDescriptor.getEntityName(), - makeLockOptions(), - readOnlyMode == ReadOnlyMode.READ_ONLY - ); - } - catch (ObjectNotFoundException notFoundException) { - // if session cache contains proxy for nonexisting object - result = null; - } - initializeIfNecessary( result ); - //noinspection unchecked - return (T) result; - } ); - } - - private LockOptions makeLockOptions() { - return Helper.makeLockOptions( lockMode, lockScope, lockTimeout, lockFollowOn ); - } - - // Used by Hibernate Reactive - protected Object coerceId(Object id, SessionFactoryImplementor factory) { - if ( factory.getSessionFactoryOptions().getJpaCompliance().isLoadByIdComplianceEnabled() ) { - return id; - } - - try { - return entityDescriptor.getIdentifierMapping().getJavaType().coerce( id ); - } - catch ( Exception e ) { - throw new IllegalArgumentException( "Argument '" + id - + "' could not be converted to the identifier type of entity '" - + entityDescriptor.getEntityName() + "'" - + " [" + e.getMessage() + "]", e ); - } - } - - private void initializeIfNecessary(Object result) { - if ( result != null ) { - final var lazyInitializer = extractLazyInitializer( result ); - if ( lazyInitializer != null ) { - if ( lazyInitializer.isUninitialized() ) { - lazyInitializer.initialize(); - } - } - else { - final var enhancementMetadata = entityDescriptor.getBytecodeEnhancementMetadata(); - if ( enhancementMetadata.isEnhancedForLazyLoading() - && enhancementMetadata.extractLazyInterceptor( result ) - instanceof EnhancementAsProxyLazinessInterceptor lazinessInterceptor ) { - lazinessInterceptor.forceInitialize( result, null ); - } - } - } - } - - @Override - public LockMode getLockMode() { - return lockMode; - } - - @Override - public Timeout getLockTimeout() { - return lockTimeout; - } - - @Override - public Locking.Scope getLockScope() { - return lockScope; - } - - @Override - public Locking.FollowOn getLockFollowOn() { - return lockFollowOn; - } +/** + * Models the ability to load an entity by a key, either primary or natural. + * + * @apiNote It is obviously expected that the entity-type and all options are + * defined on the implementors of this contract. + * + * @param The entity type. + * + * @author Steve Ebersole + */ +public interface FindByKeyOperation { + /// Perform the find operation for the given key. + /// + /// @param key The primary or natural key by which to load the entity. + T performFind(Object key); } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/find/Helper.java b/hibernate-core/src/main/java/org/hibernate/internal/find/Helper.java index 7a43743efbf5..228a6c69073d 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/find/Helper.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/find/Helper.java @@ -4,16 +4,83 @@ */ package org.hibernate.internal.find; +import jakarta.persistence.EntityNotFoundException; +import jakarta.persistence.FindOption; import jakarta.persistence.Timeout; import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.Locking; +import org.hibernate.OrderingMode; import org.hibernate.Timeouts; +import org.hibernate.TypeMismatchException; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.type.descriptor.java.CoercionException; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; /** * @author Steve Ebersole */ public class Helper { + public static final FindOption[] NO_OPTIONS = new FindOption[0]; + + public static Object coerceId(EntityPersister entityPersister, Object id, SessionFactoryImplementor factory) { + if ( isLoadByIdComplianceEnabled( factory ) ) { + final var identifierMapping = entityPersister.getIdentifierMapping(); + if ( !identifierMapping.getJavaType().isInstance( id ) ) { + // per expectation of EntityHandler#find / EntityHandler#get + throw new IllegalArgumentException( String.format( Locale.ROOT, + "Given value (%s) did not match expected identifier type for entity (%s) : %s", + id, + entityPersister.getEntityName(), + identifierMapping.getJavaType().getTypeName() + ) ); + } + return id; + } + else { + try { + final var identifierMapping = entityPersister.getIdentifierMapping(); + return identifierMapping.isVirtual() + ? id // special case for a class with an @IdClass + : identifierMapping.getJavaType().coerce( id ); + } + catch ( Exception e ) { + throw new IllegalArgumentException( + String.format( + Locale.ROOT, + "Argument `%s` could not be converted to the identifier type of entity `%s` : %s", + id, + entityPersister.getEntityName(), + e.getMessage() + ), + e + ); + } + } + } + + public static Object coerceNaturalId(EntityPersister entityPersister, Object key) { + var naturalIdMapping = entityPersister.getNaturalIdMapping(); + assert naturalIdMapping != null; + try { + return naturalIdMapping.normalizeInput( key ); + } + catch (TypeMismatchException | CoercionException e) { + // per expectation of EntityHandler#find / EntityHandler#get + var iae = new IllegalArgumentException( e.getMessage() ); + iae.addSuppressed( e ); + throw iae; + } + } + + private static boolean isLoadByIdComplianceEnabled(SessionFactoryImplementor factory) { + return factory.getSessionFactoryOptions().getJpaCompliance().isLoadByIdComplianceEnabled(); + } + public static LockOptions makeLockOptions(LockMode lockMode, Locking.Scope lockScope, Timeout lockTimeout, Locking.FollowOn lockFollowOn) { if ( lockMode == null || lockMode == LockMode.NONE ) { return LockOptions.NONE; @@ -28,4 +95,62 @@ public static LockOptions makeLockOptions(LockMode lockMode, Locking.Scope lockS lockOptions.setFollowOnStrategy( lockFollowOn != null ? lockFollowOn : Locking.FollowOn.ALLOW ); return lockOptions; } + + public static void verifyGetMultipleResults( + List results, + String entityName, + List keys, + FindOption... findOptions) { + // how detailed we can get with the error message depends on whether + // results are ordered or unordered, defined by the OrderingMode option + final OrderingMode orderingMode = determineOrderingMode( findOptions ); + + if ( orderingMode == OrderingMode.UNORDERED ) { + for ( int i = 0; i < results.size(); i++ ) { + if ( results.get( i ) == null ) { + throw new EntityNotFoundException( + String.format( + Locale.ROOT, + "One or more ids could not be found - `%s`", + entityName + ) + ); + } + } + } + else { + List missingKeys = null; + for ( int i = 0; i < results.size(); i++ ) { + if ( results.get( i ) == null ) { + if ( missingKeys == null ) { + missingKeys = new ArrayList<>(); + } + missingKeys.add( keys.get( i ) ); + } + } + if ( missingKeys != null ) { + throw new EntityNotFoundException( + String.format( + Locale.ROOT, + "No entity of type `%s` existed for keys `%s`", + entityName, + missingKeys + ) + ); + } + } + } + + private static OrderingMode determineOrderingMode(FindOption[] findOptions) { + var mode = OrderingMode.ORDERED; + if ( findOptions != null ) { + for ( FindOption findOption : findOptions ) { + if ( findOption instanceof OrderingMode requestedMode ) { + mode = requestedMode; + break; + } + } + } + return mode; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/find/StatefulFindByKeyOperation.java b/hibernate-core/src/main/java/org/hibernate/internal/find/StatefulFindByKeyOperation.java new file mode 100644 index 000000000000..fe7264e0e799 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/internal/find/StatefulFindByKeyOperation.java @@ -0,0 +1,236 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.internal.find; + +import jakarta.persistence.FindOption; +import jakarta.persistence.TransactionRequiredException; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.hibernate.CacheMode; +import org.hibernate.KeyType; +import org.hibernate.LockOptions; +import org.hibernate.NaturalIdSynchronization; +import org.hibernate.ObjectNotFoundException; +import org.hibernate.ReadOnlyMode; +import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor; +import org.hibernate.engine.spi.EffectiveEntityGraph; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.engine.spi.Status; +import org.hibernate.event.spi.LoadEventListener; +import org.hibernate.graph.GraphSemantic; +import org.hibernate.graph.spi.RootGraphImplementor; +import org.hibernate.loader.internal.LoadAccessContext; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.proxy.HibernateProxy; + +import java.util.HashSet; +import java.util.Locale; +import java.util.function.Supplier; + +import static org.hibernate.engine.spi.NaturalIdResolutions.INVALID_NATURAL_ID_REFERENCE; +import static org.hibernate.internal.NaturalIdHelper.performAnyNeededCrossReferenceSynchronizations; +import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer; + +/// Support for loading a single entity by key (either [id][KeyType#IDENTIFIER] or [natural-id][KeyType#NATURAL]) +/// from a [[org.hibernate.Session] stateful session]. +/// +/// @see org.hibernate.Session#find +/// @see KeyType +/// +/// @author Steve Ebersole +public class StatefulFindByKeyOperation extends AbstractFindByKeyOperation { + private final LoadAccessContext loadAccessContext; + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // options + + public StatefulFindByKeyOperation( + @NonNull EntityPersister entityDescriptor, + @NonNull LoadAccessContext loadAccessContext, + @Nullable GraphSemantic graphSemantic, + @Nullable RootGraphImplementor rootGraph, + @Nullable LockOptions defaultLockOptions, + @Nullable CacheMode defaultCacheMode, + boolean defaultReadOnly, + @NonNull SessionFactoryImplementor sessionFactory, + FindOption... findOptions) { + super( entityDescriptor, graphSemantic, rootGraph, + defaultLockOptions, defaultCacheMode, defaultReadOnly, + sessionFactory, findOptions ); + this.loadAccessContext = loadAccessContext; + } + + @Override + protected SharedSessionContractImplementor getEntityHandler() { + return loadAccessContext.getSession(); + } + + @Override + public T performFind(Object key) { + if ( needsTransaction( getLockMode() ) ) { + if ( !loadAccessContext.getSession().isTransactionInProgress() ) { + throw new TransactionRequiredException( String.format( Locale.ROOT, + "Transaction required to load entity (%s#%s) with lock-mode (%s)", + getEntityDescriptor().getEntityName(), + key, + getLockMode() + ) ); + } + } + + return withExceptionHandling( key, makeLockOptions(), () -> { + if ( getKeyType() == KeyType.NATURAL ) { + return findByNaturalId( key ); + } + else { + return findById( key ); + } + } ); + } + + private T findByNaturalId(Object key) { + final SessionImplementor session = loadAccessContext.getSession(); + + performAnyNeededCrossReferenceSynchronizations( + getNaturalIdSynchronization() != NaturalIdSynchronization.DISABLED, + getEntityDescriptor(), + session + ); + + final var normalizedKey = Helper.coerceNaturalId( getEntityDescriptor(), key ); + + final Object cachedResolution = getCachedNaturalIdResolution( normalizedKey, loadAccessContext ); + if ( cachedResolution == INVALID_NATURAL_ID_REFERENCE ) { + return null; + } + + if ( cachedResolution != null ) { + return findById( cachedResolution ); + } + + return withOptions( loadAccessContext, () -> { + @SuppressWarnings("unchecked") + final T loaded = (T) getEntityDescriptor().getNaturalIdLoader() + .load( normalizedKey, this, session ); + if ( loaded != null ) { + final var persistenceContext = session.getPersistenceContextInternal(); + final var lazyInitializer = HibernateProxy.extractLazyInitializer( loaded ); + final var entity = lazyInitializer != null ? lazyInitializer.getImplementation() : loaded; + final var entry = persistenceContext.getEntry( entity ); + assert entry != null; + if ( entry.getStatus() == Status.DELETED ) { + return null; + } + } + return loaded; + } ); + } + + private T withOptions(LoadAccessContext loadAccessContext, Supplier action) { + final var session = loadAccessContext.getSession(); + + final var sessionCacheMode = session.getCacheMode(); + final var cacheMode = CacheMode.fromJpaModes( getCacheRetrieveMode(), getCacheStoreMode() ); + boolean cacheModeChanged = false; + try { + if ( cacheMode != null ) { + if ( cacheMode != sessionCacheMode ) { + session.setCacheMode( cacheMode ); + cacheModeChanged = true; + } + } + + final var influencers = session.getLoadQueryInfluencers(); + HashSet fetchProfiles = null; + EffectiveEntityGraph effectiveEntityGraph = null; + + try { + fetchProfiles = influencers.adjustFetchProfiles( null, getEnabledFetchProfiles() ); + effectiveEntityGraph = getRootGraph() == null + ? null + : influencers.applyEntityGraph( getRootGraph(), getGraphSemantic() ); + + return action.get(); + } + finally { + if ( effectiveEntityGraph != null ) { + effectiveEntityGraph.clear(); + } + if ( fetchProfiles != null ) { + influencers.setEnabledFetchProfileNames( fetchProfiles ); + } + } + } + finally { + if ( cacheModeChanged ) { + // change it back + session.setCacheMode( sessionCacheMode ); + } + } + } + + private Object getCachedNaturalIdResolution( + Object normalizedNaturalIdValue, + LoadAccessContext loadAccessContext) { + loadAccessContext.checkOpenOrWaitingForAutoClose(); + loadAccessContext.pulseTransactionCoordinator(); + + return loadAccessContext + .getSession() + .getPersistenceContextInternal() + .getNaturalIdResolutions() + .findCachedIdByNaturalId( normalizedNaturalIdValue, getEntityDescriptor() ); + } + + private T findById(Object key) { + return withOptions( loadAccessContext, () -> { + final var session = loadAccessContext.getSession(); + + Object result; + try { + result = loadAccessContext.load( + LoadEventListener.GET, + coerceId( key, session.getFactory() ), + getEntityDescriptor().getEntityName(), + makeLockOptions(), + getReadOnlyMode() == ReadOnlyMode.READ_ONLY + ); + } + catch (ObjectNotFoundException notFoundException) { + // if session cache contains proxy for nonexisting object + result = null; + } + initializeIfNecessary( result ); + //noinspection unchecked + return (T) result; + } ); + } + + // Used by Hibernate Reactive + protected Object coerceId(Object id, SessionFactoryImplementor factory) { + return Helper.coerceId( getEntityDescriptor(), id, factory ); + } + + private void initializeIfNecessary(Object result) { + if ( result != null ) { + final var lazyInitializer = extractLazyInitializer( result ); + if ( lazyInitializer != null ) { + if ( lazyInitializer.isUninitialized() ) { + lazyInitializer.initialize(); + } + } + else { + final var enhancementMetadata = getEntityDescriptor().getBytecodeEnhancementMetadata(); + if ( enhancementMetadata.isEnhancedForLazyLoading() + && enhancementMetadata.extractLazyInterceptor( result ) + instanceof EnhancementAsProxyLazinessInterceptor lazinessInterceptor ) { + lazinessInterceptor.forceInitialize( result, null ); + } + } + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/internal/find/StatefulFindMultipleByKeyOperation.java b/hibernate-core/src/main/java/org/hibernate/internal/find/StatefulFindMultipleByKeyOperation.java new file mode 100644 index 000000000000..68c548c5cfd8 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/internal/find/StatefulFindMultipleByKeyOperation.java @@ -0,0 +1,185 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.internal.find; + +import jakarta.persistence.FindOption; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.hibernate.BatchSize; +import org.hibernate.CacheMode; +import org.hibernate.KeyType; +import org.hibernate.LockOptions; +import org.hibernate.NaturalIdSynchronization; +import org.hibernate.OrderingMode; +import org.hibernate.ReadOnlyMode; +import org.hibernate.RemovalsMode; +import org.hibernate.SessionCheckMode; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.graph.GraphSemantic; +import org.hibernate.graph.spi.RootGraphImplementor; +import org.hibernate.loader.internal.LoadAccessContext; +import org.hibernate.metamodel.mapping.NaturalIdMapping; +import org.hibernate.persister.entity.EntityPersister; + +import java.util.List; +import java.util.Set; +import java.util.function.Supplier; + +import static org.hibernate.internal.NaturalIdHelper.performAnyNeededCrossReferenceSynchronizations; + +/// Support for loading multiple entities (of a type) by key (either [id][KeyType#IDENTIFIER] or [natural-id][KeyType#NATURAL]). +/// +/// @see org.hibernate.Session#findMultiple +/// @see KeyType +/// +/// @author Steve Ebersole +public class StatefulFindMultipleByKeyOperation extends AbstractFindMultipleByKeyOperation { + private final LoadAccessContext loadAccessContext; + + public StatefulFindMultipleByKeyOperation( + @NonNull EntityPersister entityDescriptor, + @NonNull LoadAccessContext loadAccessContext, + @Nullable LockOptions defaultLockOptions, + @Nullable CacheMode defaultCacheMode, + boolean defaultReadOnly, + @NonNull SessionFactoryImplementor sessionFactory, + FindOption... findOptions) { + super( entityDescriptor, + defaultLockOptions, defaultCacheMode, defaultReadOnly, + sessionFactory, findOptions ); + this.loadAccessContext = loadAccessContext; + } + + public List performFind( + List keys, + @Nullable GraphSemantic graphSemantic, + @Nullable RootGraphImplementor rootGraph) { + // todo (natural-id-class) : these impls are temporary + // longer term, move the logic here as much of it can be shared + if ( getKeyType() == KeyType.NATURAL ) { + return findByNaturalIds( keys, graphSemantic, rootGraph, loadAccessContext ); + } + else { + return findByIds( keys, graphSemantic, rootGraph, loadAccessContext ); + } + } + + private List findByNaturalIds(List keys, GraphSemantic graphSemantic, RootGraphImplementor rootGraph, LoadAccessContext loadAccessContext) { + final NaturalIdMapping naturalIdMapping = getEntityDescriptor().requireNaturalIdMapping(); + final SessionImplementor session = loadAccessContext.getSession(); + + performAnyNeededCrossReferenceSynchronizations( + getNaturalIdSynchronization() != NaturalIdSynchronization.DISABLED, + getEntityDescriptor(), + session + ); + + return withOptions( loadAccessContext, graphSemantic, rootGraph, () -> { + // normalize the incoming natural-id values and get them in array form as needed + // by MultiNaturalIdLoader + final Object[] naturalIds = new Object[keys.size()]; + for ( int i = 0; i < keys.size(); i++ ) { + final Object key = keys.get( i ); + naturalIds[i] = naturalIdMapping.normalizeInput( key ); + } + + //noinspection unchecked + return (List)getEntityDescriptor().getMultiNaturalIdLoader() + .multiLoad( naturalIds, this, session ); + } ); + } + + private List withOptions( + LoadAccessContext loadAccessContext, + GraphSemantic graphSemantic, + RootGraphImplementor rootGraph, + Supplier> action) { + final var session = loadAccessContext.getSession(); + final var influencers = session.getLoadQueryInfluencers(); + final var fetchProfiles = influencers.adjustFetchProfiles( getDisabledFetchProfiles(), getEnabledFetchProfiles() ); + final var effectiveEntityGraph = rootGraph == null + ? null + : influencers.applyEntityGraph( rootGraph, graphSemantic ); + + final var readOnly = session.isDefaultReadOnly(); + session.setDefaultReadOnly( getReadOnlyMode() == ReadOnlyMode.READ_ONLY ); + + final var cacheMode = session.getCacheMode(); + session.setCacheMode( CacheMode.fromJpaModes( getCacheRetrieveMode(), getCacheStoreMode() ) ); + + try { + return action.get(); + } + finally { + loadAccessContext.delayedAfterCompletion(); + if ( effectiveEntityGraph != null ) { + effectiveEntityGraph.clear(); + } + influencers.setEnabledFetchProfileNames( fetchProfiles ); + session.setDefaultReadOnly( readOnly ); + session.setCacheMode( cacheMode ); + } + } + + private Object getCachedNaturalIdResolution( + Object normalizedNaturalIdValue, + LoadAccessContext loadAccessContext) { + loadAccessContext.checkOpenOrWaitingForAutoClose(); + loadAccessContext.pulseTransactionCoordinator(); + + return loadAccessContext + .getSession() + .getPersistenceContextInternal() + .getNaturalIdResolutions() + .findCachedIdByNaturalId( normalizedNaturalIdValue, getEntityDescriptor() ); + } + + private List findByIds(List keys, GraphSemantic graphSemantic, RootGraphImplementor rootGraph, LoadAccessContext loadAccessContext) { + final Object[] ids = keys.toArray( new Object[0] ); + //noinspection unchecked + return withOptions( loadAccessContext, graphSemantic, rootGraph, + () -> (List) getEntityDescriptor().multiLoad( ids, loadAccessContext.getSession(), this ) ); + } + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + /// Temporarily defined full constructor in support of + /// [org.hibernate.MultiIdentifierLoadAccess] and [org.hibernate.MultiIdentifierLoadAccess]. + /// + /// @deprecated [org.hibernate.MultiIdentifierLoadAccess] and [org.hibernate.MultiIdentifierLoadAccess] + /// are both also deprecated. + @Deprecated + public StatefulFindMultipleByKeyOperation( + @NonNull EntityPersister entityDescriptor, + @NonNull LoadAccessContext loadAccessContext, + KeyType keyType, + BatchSize batchSize, + SessionCheckMode sessionCheckMode, + RemovalsMode removalsMode, + OrderingMode orderingMode, + CacheMode cacheMode, + LockOptions lockOptions, + ReadOnlyMode readOnlyMode, + Set enabledFetchProfiles, + Set disabledFetchProfiles, + NaturalIdSynchronization naturalIdSynchronization) { + super( + entityDescriptor, + keyType, + batchSize, + sessionCheckMode, + removalsMode, + orderingMode, + cacheMode, + lockOptions, + readOnlyMode, + enabledFetchProfiles, + disabledFetchProfiles, + naturalIdSynchronization + ); + this.loadAccessContext = loadAccessContext; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/internal/find/StatelessFindByKeyOperation.java b/hibernate-core/src/main/java/org/hibernate/internal/find/StatelessFindByKeyOperation.java new file mode 100644 index 000000000000..d314697f6710 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/internal/find/StatelessFindByKeyOperation.java @@ -0,0 +1,206 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.internal.find; + +import jakarta.persistence.FindOption; +import jakarta.persistence.TransactionRequiredException; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.hibernate.CacheMode; +import org.hibernate.KeyType; +import org.hibernate.LockMode; +import org.hibernate.LockOptions; +import org.hibernate.NaturalIdSynchronization; +import org.hibernate.engine.spi.EffectiveEntityGraph; +import org.hibernate.engine.spi.EntityKey; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.engine.spi.StatelessSessionImplementor; +import org.hibernate.graph.GraphSemantic; +import org.hibernate.graph.spi.RootGraphImplementor; +import org.hibernate.loader.internal.CacheLoadHelper; +import org.hibernate.persister.entity.EntityPersister; + +import java.util.HashSet; +import java.util.Locale; +import java.util.function.Supplier; + +import static org.hibernate.engine.spi.NaturalIdResolutions.INVALID_NATURAL_ID_REFERENCE; +import static org.hibernate.internal.NaturalIdHelper.performAnyNeededCrossReferenceSynchronizations; + +/** + * @author Steve Ebersole + */ +@SuppressWarnings("unchecked") +public class StatelessFindByKeyOperation extends AbstractFindByKeyOperation { + private final StatelessLoadAccessContext loadAccessContext; + + public StatelessFindByKeyOperation( + @NonNull EntityPersister entityDescriptor, + @NonNull StatelessLoadAccessContext loadAccessContext, + @Nullable GraphSemantic graphSemantic, + @Nullable RootGraphImplementor rootGraph, + @Nullable LockOptions defaultLockOptions, + @Nullable CacheMode defaultCacheMode, + boolean defaultReadOnly, + @NonNull SessionFactoryImplementor sessionFactory, + FindOption... findOptions) { + super( entityDescriptor, graphSemantic, rootGraph, + defaultLockOptions, defaultCacheMode, defaultReadOnly, + sessionFactory, findOptions ); + this.loadAccessContext = loadAccessContext; + } + + @Override + protected SharedSessionContractImplementor getEntityHandler() { + return loadAccessContext.getStatelessSession(); + } + + @Override + public T performFind(Object key) { + if ( needsTransaction( getLockMode() ) ) { + if ( !loadAccessContext.getStatelessSession().isTransactionInProgress() ) { + throw new TransactionRequiredException( String.format( Locale.ROOT, + "Transaction required to load entity (%s#%s) with lock-mode (%s)", + getEntityDescriptor().getEntityName(), + key, + getLockMode() + ) ); + } + } + + return withExceptionHandling( key, makeLockOptions(), () -> { + if ( getKeyType() == KeyType.NATURAL ) { + return findByNaturalId( key ); + } + else { + return findById( key ); + } + } ); + } + + private T findByNaturalId(Object key) { + final StatelessSessionImplementor session = loadAccessContext.getStatelessSession(); + + performAnyNeededCrossReferenceSynchronizations( + getNaturalIdSynchronization() != NaturalIdSynchronization.DISABLED, + getEntityDescriptor(), + session + ); + + final var normalizedKey = Helper.coerceNaturalId( getEntityDescriptor(), key ); + + final Object cachedResolution = getCachedNaturalIdResolution( normalizedKey, session ); + if ( cachedResolution == INVALID_NATURAL_ID_REFERENCE ) { + return null; + } + + if ( cachedResolution != null ) { + return findById( cachedResolution ); + } + + return withOptions( session, () -> (T) getEntityDescriptor() + .getNaturalIdLoader() + .load( normalizedKey, this, session ) ); + } + + private T withOptions(StatelessSessionImplementor session, Supplier action) { + var persistenceContext = session.getPersistenceContextInternal(); + + final var sessionCacheMode = session.getCacheMode(); + final var cacheMode = CacheMode.fromJpaModes( getCacheRetrieveMode(), getCacheStoreMode() ); + boolean cacheModeChanged = false; + try { + if ( cacheMode != null ) { + if ( cacheMode != sessionCacheMode ) { + session.setCacheMode( cacheMode ); + cacheModeChanged = true; + } + } + + final var influencers = session.getLoadQueryInfluencers(); + HashSet fetchProfiles = null; + EffectiveEntityGraph effectiveEntityGraph = null; + + try { + fetchProfiles = influencers.adjustFetchProfiles( null, getEnabledFetchProfiles() ); + effectiveEntityGraph = getRootGraph() == null + ? null + : influencers.applyEntityGraph( getRootGraph(), getGraphSemantic() ); + + return action.get(); + } + finally { + if ( effectiveEntityGraph != null ) { + effectiveEntityGraph.clear(); + } + if ( fetchProfiles != null ) { + influencers.setEnabledFetchProfileNames( fetchProfiles ); + } + } + } + finally { + if ( cacheModeChanged ) { + // change it back + session.setCacheMode( sessionCacheMode ); + } + + if ( persistenceContext.isLoadFinished() ) { + persistenceContext.clear(); + } + } + } + + private Object getCachedNaturalIdResolution( + Object normalizedNaturalIdValue, + StatelessSessionImplementor session) { + return session + .getPersistenceContextInternal() + .getNaturalIdResolutions() + .findCachedIdByNaturalId( normalizedNaturalIdValue, getEntityDescriptor() ); + } + + private T findById(Object key) { + final Object keyToLoad = Helper.coerceId( getEntityDescriptor(), key, loadAccessContext.getStatelessSession().getFactory() ); + + var session = loadAccessContext.getStatelessSession(); + + var temporaryPersistenceContext = session.getPersistenceContext(); + if ( getEntityDescriptor().canReadFromCache() ) { + final Object cachedEntity = loadFromSecondLevelCache( key, loadAccessContext ); + if ( cachedEntity != null ) { + temporaryPersistenceContext.clear(); + //noinspection unchecked + return (T) cachedEntity; + } + } + + return withOptions( session, ()-> { + final Object result = getEntityDescriptor().load( + keyToLoad, + null, + getNullSafeLockMode(), + session + ); + return (T) result; + } ); + } + + private Object loadFromSecondLevelCache( + Object key, + StatelessLoadAccessContext context) { + return CacheLoadHelper.loadFromSecondLevelCache( + context.getStatelessSession(), + null, + getLockMode(), + getEntityDescriptor(), + new EntityKey( key, getEntityDescriptor() ) + ); + } + + private LockMode getNullSafeLockMode() { + return getLockMode() == null ? LockMode.NONE : getLockMode(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/internal/find/StatelessFindMultipleByKeyOperation.java b/hibernate-core/src/main/java/org/hibernate/internal/find/StatelessFindMultipleByKeyOperation.java new file mode 100644 index 000000000000..781faea917b4 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/internal/find/StatelessFindMultipleByKeyOperation.java @@ -0,0 +1,162 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.internal.find; + +import jakarta.persistence.FindOption; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.hibernate.CacheMode; +import org.hibernate.KeyType; +import org.hibernate.LockMode; +import org.hibernate.LockOptions; +import org.hibernate.OrderingMode; +import org.hibernate.RemovalsMode; +import org.hibernate.SessionCheckMode; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.engine.spi.StatelessSessionImplementor; +import org.hibernate.graph.GraphSemantic; +import org.hibernate.graph.spi.RootGraphImplementor; +import org.hibernate.loader.ast.spi.MultiIdLoadOptions; +import org.hibernate.persister.entity.EntityPersister; + +import java.util.List; +import java.util.function.Supplier; + +/** + * @author Steve Ebersole + */ +public class StatelessFindMultipleByKeyOperation extends AbstractFindMultipleByKeyOperation { + + public static final MultiIdLoadOptions MULTI_ID_LOAD_OPTIONS = new MultiLoadOptions(); + @NonNull + private final StatelessLoadAccessContext loadAccessContext; + + public StatelessFindMultipleByKeyOperation( + @NonNull EntityPersister entityDescriptor, + @NonNull StatelessLoadAccessContext loadAccessContext, + @Nullable LockOptions defaultLockOptions, + @Nullable CacheMode defaultCacheMode, + boolean defaultReadOnly, + @NonNull SessionFactoryImplementor sessionFactory, + FindOption... findOptions) { + super( entityDescriptor, + defaultLockOptions, defaultCacheMode, defaultReadOnly, + sessionFactory, findOptions ); + this.loadAccessContext = loadAccessContext; + } + + public List performFind( + List keys, + @Nullable GraphSemantic graphSemantic, + @Nullable RootGraphImplementor rootGraph) { + // todo (jpa4) : allow for loading from cache + + for ( Object key : keys ) { + if ( key == null ) { + throw new IllegalArgumentException( "Null key" ); + } + } + + if ( getKeyType() == KeyType.NATURAL ) { + return findByNaturalIds( keys, graphSemantic, rootGraph ); + } + else { + return findByIds( keys, graphSemantic, rootGraph ); + } + } + + private List findByNaturalIds( + List keys, + GraphSemantic graphSemantic, + RootGraphImplementor rootGraph) { + throw new UnsupportedOperationException( "Not implemented yet" ); + } + + private List findByIds( + List keys, + GraphSemantic graphSemantic, + RootGraphImplementor rootGraph) { + var session = loadAccessContext.getStatelessSession(); + return withOptions( session, graphSemantic, rootGraph, () -> { + final var results = getEntityDescriptor().multiLoad( keys.toArray(), session, multiLoadOptions( getLockMode() ) ); + //noinspection unchecked + return (List) results; + } ); + } + + private MultiIdLoadOptions multiLoadOptions(LockMode lockMode) { + return lockMode == null ? MULTI_ID_LOAD_OPTIONS : new MultiLoadOptions( lockMode ); + } + + private List withOptions( + StatelessSessionImplementor session, + GraphSemantic graphSemantic, + RootGraphImplementor rootGraph, + Supplier> action) { + final var influencers = session.getLoadQueryInfluencers(); + final var fetchProfiles = influencers.adjustFetchProfiles( getDisabledFetchProfiles(), getEnabledFetchProfiles() ); + final var effectiveEntityGraph = rootGraph == null + ? null + : influencers.applyEntityGraph( rootGraph, graphSemantic ); + + try { + return action.get(); + } + finally { + if ( effectiveEntityGraph != null ) { + effectiveEntityGraph.clear(); + } + influencers.setEnabledFetchProfileNames( fetchProfiles ); + } + } + + private static final class MultiLoadOptions implements MultiIdLoadOptions { + private final LockOptions lockOptions; + + private MultiLoadOptions() { + this.lockOptions = null; + } + + private MultiLoadOptions(LockMode lockMode) { + this.lockOptions = new LockOptions( lockMode ); + } + + @Override + public SessionCheckMode getSessionCheckMode() { + return SessionCheckMode.DISABLED; + } + + @Override + public boolean isSecondLevelCacheCheckingEnabled() { + return true; + } + + @Override + public Boolean getReadOnly(SessionImplementor session) { + return null; + } + + @Override + public RemovalsMode getRemovalsMode() { + return RemovalsMode.REPLACE; + } + + @Override + public OrderingMode getOrderingMode() { + return OrderingMode.ORDERED; + } + + @Override + public LockOptions getLockOptions() { + return lockOptions; + } + + @Override + public Integer getBatchSize() { + return null; + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/internal/find/StatelessLoadAccessContext.java b/hibernate-core/src/main/java/org/hibernate/internal/find/StatelessLoadAccessContext.java new file mode 100644 index 000000000000..0464dba8d887 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/internal/find/StatelessLoadAccessContext.java @@ -0,0 +1,14 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.internal.find; + +import org.hibernate.engine.spi.StatelessSessionImplementor; + +/** + * @author Steve Ebersole + */ +public interface StatelessLoadAccessContext { + StatelessSessionImplementor getStatelessSession(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/StringHelper.java b/hibernate-core/src/main/java/org/hibernate/internal/util/StringHelper.java index c0127039985c..165c7ac7ddd4 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/StringHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/StringHelper.java @@ -874,6 +874,15 @@ public static String coalesce(@NonNull String fallbackValue, String value) { return fallbackValue; } + public static String coalesce(String... values) { + for ( int i = 0; i < values.length; i++ ) { + if ( isNotEmpty( values[i] ) ) { + return values[i]; + } + } + return null; + } + public interface Renderer { String render(T value); } diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/HibernatePersistenceProvider.java b/hibernate-core/src/main/java/org/hibernate/jpa/HibernatePersistenceProvider.java index 97f76df178c7..9552b63c2b39 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/HibernatePersistenceProvider.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/HibernatePersistenceProvider.java @@ -4,29 +4,45 @@ */ package org.hibernate.jpa; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import jakarta.persistence.EntityManagerFactory; import jakarta.persistence.PersistenceConfiguration; import jakarta.persistence.PersistenceException; +import jakarta.persistence.spi.ClassTransformer; import jakarta.persistence.spi.LoadState; import jakarta.persistence.spi.PersistenceProvider; import jakarta.persistence.spi.PersistenceUnitInfo; import jakarta.persistence.spi.ProviderUtil; - +import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; -import org.hibernate.jpa.boot.spi.PersistenceConfigurationDescriptor; -import org.hibernate.jpa.boot.spi.PersistenceXmlParser; +import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext; +import org.hibernate.bytecode.enhance.spi.EnhancementContext; +import org.hibernate.bytecode.enhance.spi.UnloadedClass; +import org.hibernate.bytecode.enhance.spi.UnloadedField; +import org.hibernate.bytecode.spi.BytecodeProvider; import org.hibernate.jpa.boot.spi.Bootstrap; import org.hibernate.jpa.boot.spi.EntityManagerFactoryBuilder; +import org.hibernate.jpa.boot.spi.PersistenceConfigurationDescriptor; import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor; +import org.hibernate.jpa.boot.spi.PersistenceXmlParser; +import org.hibernate.jpa.internal.enhance.EnhancingClassTransformerImpl; import org.hibernate.jpa.internal.util.PersistenceUtilHelper; import org.hibernate.jpa.internal.util.PersistenceUtilHelper.MetadataCache; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.HashMap; +import java.util.Set; + import static java.util.Collections.emptyMap; import static java.util.Collections.unmodifiableMap; +import static org.hibernate.cfg.BytecodeSettings.BYTECODE_PROVIDER_INSTANCE; +import static org.hibernate.cfg.BytecodeSettings.ENHANCER_ENABLE_ASSOCIATION_MANAGEMENT; +import static org.hibernate.cfg.BytecodeSettings.ENHANCER_ENABLE_DIRTY_TRACKING; +import static org.hibernate.cfg.BytecodeSettings.ENHANCER_ENABLE_LAZY_INITIALIZATION; +import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER; import static org.hibernate.jpa.boot.spi.ProviderChecker.isProvider; import static org.hibernate.jpa.internal.JpaLogger.JPA_LOGGER; @@ -38,8 +54,7 @@ * @author Brett Meyer */ public class HibernatePersistenceProvider implements PersistenceProvider { - - private final MetadataCache cache = new MetadataCache(); + private final Set unitsWithTransformer = new HashSet<>(); /** * {@inheritDoc} @@ -70,31 +85,11 @@ protected EntityManagerFactoryBuilder getEntityManagerFactoryBuilderOrNull( ); } - protected EntityManagerFactoryBuilder getEntityManagerFactoryBuilderOrNull( - String persistenceUnitName, Map properties, - ClassLoader providedClassLoader) { - return getEntityManagerFactoryBuilderOrNull( - persistenceUnitName, - properties, - providedClassLoader, - null - ); - } - - protected EntityManagerFactoryBuilder getEntityManagerFactoryBuilderOrNull( - String persistenceUnitName, Map properties, - ClassLoaderService providedClassLoaderService) { - return getEntityManagerFactoryBuilderOrNull( - persistenceUnitName, - properties, - null, - providedClassLoaderService - ); - } - private EntityManagerFactoryBuilder getEntityManagerFactoryBuilderOrNull( - String persistenceUnitName, Map properties, - ClassLoader providedClassLoader, ClassLoaderService providedClassLoaderService) { + String persistenceUnitName, + Map properties, + @Nullable ClassLoader providedClassLoader, + @Nullable ClassLoaderService providedClassLoaderService) { JPA_LOGGER.attemptingToObtainEmfBuilder( persistenceUnitName ); final var integration = wrap( properties ); final var units = locatePersistenceUnits( integration, providedClassLoader, providedClassLoaderService ); @@ -212,6 +207,14 @@ public boolean generateSchema(String persistenceUnitName, Map map) { } } + @Override + public boolean generateSchema(PersistenceConfiguration persistenceConfiguration) { + JPA_LOGGER.startingGenerateSchema( persistenceConfiguration.name() ); + final var builder = getEntityManagerFactoryBuilder(persistenceConfiguration); + builder.generateSchema(); + return true; + } + private static Map settingsMap(Map integration) { final Map result = new HashMap<>(); integration.forEach( (key, value) -> { @@ -244,21 +247,6 @@ protected EntityManagerFactoryBuilder getEntityManagerFactoryBuilder( settingsMap( integration ), providedClassLoaderService ); } - private final ProviderUtil providerUtil = new ProviderUtil() { - @Override - public LoadState isLoadedWithoutReference(Object proxy, String property) { - return PersistenceUtilHelper.isLoadedWithoutReference( proxy, property, cache ); - } - @Override - public LoadState isLoadedWithReference(Object proxy, String property) { - return PersistenceUtilHelper.isLoadedWithReference( proxy, property, cache ); - } - @Override - public LoadState isLoaded(Object object) { - return PersistenceUtilHelper.getLoadState( object ); - } - }; - @Override public EntityManagerFactory createEntityManagerFactory(PersistenceConfiguration configuration) { return getEntityManagerFactoryBuilder( configuration ).build(); @@ -274,7 +262,202 @@ private EntityManagerFactoryBuilder getEntityManagerFactoryBuilder(PersistenceCo @Override public ProviderUtil getProviderUtil() { - return providerUtil; + return ProviderUtilImpl.INSTANCE; } + private record TransformerKey(String puName, String loaderName) {} + + @Override + public ClassTransformer getClassTransformer(PersistenceUnitInfo persistenceUnit, Map integrationSettings) { + // todo (jpa4) : If this method is called, be sure to not push the transform via `PersistentUnitInfo#addTransformer`. + // See usage of `PersistenceUnitDescriptor#pushClassTransformer` in `EntityManagerFactoryBuilderImpl`. + // Leverage `unitsWithTransformer` in `#createContainerEntityManagerFactory` + var transformerKey = new TransformerKey( persistenceUnit.getPersistenceUnitName(), persistenceUnit.getClassLoader().getName() ); + if ( !unitsWithTransformer.add( transformerKey ) ) { + if ( JPA_LOGGER.isTraceEnabled() ) { + JPA_LOGGER.duplicatedRequestForClassTransformer( transformerKey.puName, transformerKey.loaderName ); + } + return null; + } + + if ( JPA_LOGGER.isTraceEnabled() ) { + JPA_LOGGER.requestForClassTransformer( transformerKey.puName, transformerKey.loaderName ); + } + + //noinspection removal + final boolean dirtyTrackingEnabled = resolveEnhancementProperty( + ENHANCER_ENABLE_DIRTY_TRACKING, + integrationSettings, + persistenceUnit, + true + ); + //noinspection removal + final boolean lazyInitializationEnabled = resolveEnhancementProperty( + ENHANCER_ENABLE_LAZY_INITIALIZATION, + integrationSettings, + persistenceUnit, + true + ); + final boolean associationManagementEnabled = resolveEnhancementProperty( + ENHANCER_ENABLE_ASSOCIATION_MANAGEMENT, + integrationSettings, + persistenceUnit, + false + ); + + if ( !lazyInitializationEnabled ) { + //noinspection removal + DEPRECATION_LOGGER.deprecatedSettingForRemoval( ENHANCER_ENABLE_LAZY_INITIALIZATION, "true" ); + } + if ( !dirtyTrackingEnabled ) { + //noinspection removal + DEPRECATION_LOGGER.deprecatedSettingForRemoval( ENHANCER_ENABLE_DIRTY_TRACKING, "true" ); + } + + if ( dirtyTrackingEnabled || lazyInitializationEnabled || associationManagementEnabled ) { + final var classLoader = persistenceUnit.getNewTempClassLoader(); + if ( classLoader == null ) { + throw new PersistenceException( String.format( Locale.ROOT, + "[persistence unit: %s] Enhancement requires a temp class loader, but none was given", + persistenceUnit.getPersistenceUnitName() + ) ); + } + + final var enhancementContext = createEnhancementContext( + dirtyTrackingEnabled, + lazyInitializationEnabled, + associationManagementEnabled, + integrationSettings, + persistenceUnit + ); + + final EnhancingClassTransformerImpl classTransformer = + new EnhancingClassTransformerImpl( enhancementContext ); + + // NOTE : the ClassTransformer method is called discoverType, but in reality it + // pre-enhances the classes... + persistenceUnit.getAllManagedClassNames().forEach( (className) -> { + classTransformer.discoverTypes( classLoader, className ); + } ); + + return classTransformer; + } + + return null; + } + + private boolean resolveEnhancementProperty( + String propertyName, + Map integrationSettings, + PersistenceUnitInfo persistenceUnitInfo, + boolean defaultValue) { + // prefer integration settings + var integrationSetting = integrationSettings.get( propertyName ); + if ( integrationSetting != null ) { + return Boolean.parseBoolean( integrationSetting.toString() ); + } + + // check the persistence unit config + var unitSetting = persistenceUnitInfo.getProperties().get( propertyName ); + if ( unitSetting != null ) { + return Boolean.parseBoolean( unitSetting.toString() ); + } + + return defaultValue; + } + + protected EnhancementContext createEnhancementContext( + final boolean dirtyTrackingEnabled, + final boolean lazyInitializationEnabled, + final boolean associationManagementEnabled, + Map integrationSettings, + PersistenceUnitInfo persistenceUnit) { + var overriddenBytecodeProvider = getExplicitBytecodeProvider( integrationSettings, persistenceUnit ); + + return new DefaultEnhancementContext() { + @Override + public boolean isEntityClass(UnloadedClass classDescriptor) { + return persistenceUnit.getAllManagedClassNames().contains( classDescriptor.getName() ) + && super.isEntityClass( classDescriptor ); + } + + @Override + public boolean isCompositeClass(UnloadedClass classDescriptor) { + return persistenceUnit.getAllManagedClassNames().contains( classDescriptor.getName() ) + && super.isCompositeClass( classDescriptor ); + } + + @Override + public boolean doBiDirectionalAssociationManagement(UnloadedField field) { + return associationManagementEnabled; + } + + @Override + public boolean doDirtyCheckingInline(UnloadedClass classDescriptor) { + return dirtyTrackingEnabled; + } + + @Override + public boolean hasLazyLoadableAttributes(UnloadedClass classDescriptor) { + return lazyInitializationEnabled; + } + + @Override + public boolean isLazyLoadable(UnloadedField field) { + return lazyInitializationEnabled; + } + + @Override + public boolean doExtendedEnhancement(UnloadedClass classDescriptor) { + // doesn't make any sense to have extended enhancement enabled at runtime. we only enhance entities anyway. + return false; + } + + @Override + public BytecodeProvider getBytecodeProvider() { + return overriddenBytecodeProvider; + } + }; + } + + private BytecodeProvider getExplicitBytecodeProvider( + Map integrationSettings, + PersistenceUnitInfo persistenceUnit) { + // again, prefer integration settings + var setting = integrationSettings.get( BYTECODE_PROVIDER_INSTANCE ); + if ( setting == null ) { + setting = persistenceUnit.getProperties().get( BYTECODE_PROVIDER_INSTANCE ); + } + + if ( setting != null && ! (setting instanceof BytecodeProvider) ) { + throw new PersistenceException( String.format( Locale.ROOT, + "Property %s was set to `%s`, which is not compatible with the expected type %s", + BYTECODE_PROVIDER_INSTANCE, + setting, + BytecodeProvider.class.getName() + ) ); + } + + return (BytecodeProvider) setting; + } + + + private static class ProviderUtilImpl implements ProviderUtil { + public static final ProviderUtilImpl INSTANCE = new ProviderUtilImpl(); + + private final MetadataCache cache = new MetadataCache(); + + @Override + public LoadState isLoadedWithoutReference(Object proxy, String property) { + return PersistenceUtilHelper.isLoadedWithoutReference( proxy, property, cache ); + } + @Override + public LoadState isLoadedWithReference(Object proxy, String property) { + return PersistenceUtilHelper.isLoadedWithReference( proxy, property, cache ); + } + @Override + public LoadState isLoaded(Object object) { + return PersistenceUtilHelper.getLoadState( object ); + } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/SpecHints.java b/hibernate-core/src/main/java/org/hibernate/jpa/SpecHints.java index f467344e80b9..db62aea8c094 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/SpecHints.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/SpecHints.java @@ -40,7 +40,7 @@ public interface SpecHints { String HINT_SPEC_LOAD_GRAPH = "jakarta.persistence.loadgraph"; /** - * Hint requesting a pessimistic lock timeout (in milliseconds). + * The Jakarta Persistence defined hint requesting a pessimistic lock timeout (in milliseconds). */ String HINT_SPEC_LOCK_TIMEOUT = "jakarta.persistence.lock.timeout"; @@ -52,7 +52,7 @@ public interface SpecHints { String HINT_SPEC_LOCK_SCOPE = "jakarta.persistence.lock.scope"; /** - * The Jakarta Persistence defined hint for requesting a timeout + * The Jakarta Persistence defined hint requesting a timeout (in milliseconds) * be applied to a {@link jakarta.persistence.Query} executions. * * @implSpec Not valid for load and/or lock operations diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbackDefinitionResolver.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/CallbackDefinitionResolver.java similarity index 63% rename from hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbackDefinitionResolver.java rename to hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/CallbackDefinitionResolver.java index 474c0dc99118..1b822b337c85 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbackDefinitionResolver.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/CallbackDefinitionResolver.java @@ -2,43 +2,37 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.jpa.event.internal; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Target; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; +package org.hibernate.jpa.boot.internal; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.ExcludeDefaultListeners; +import jakarta.persistence.ExcludeSuperclassListeners; +import jakarta.persistence.MappedSuperclass; +import jakarta.persistence.PersistenceException; import org.hibernate.boot.models.spi.JpaEventListener; -import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.spi.InFlightMetadataCollector; import org.hibernate.internal.util.ReflectHelper; -import org.hibernate.jpa.event.spi.CallbackDefinition; +import org.hibernate.jpa.boot.spi.CallbackDefinition; +import org.hibernate.jpa.boot.spi.EntityCallbackDefinition; +import org.hibernate.jpa.boot.spi.ListenerCallbackDefinition; import org.hibernate.jpa.event.spi.CallbackType; -import org.hibernate.mapping.Component; import org.hibernate.mapping.PersistentClass; -import org.hibernate.mapping.Property; import org.hibernate.models.spi.ClassDetails; import org.hibernate.models.spi.MethodDetails; import org.hibernate.models.spi.ModelsContext; -import org.hibernate.property.access.spi.Getter; -import jakarta.persistence.Entity; -import jakarta.persistence.EntityListeners; -import jakarta.persistence.ExcludeDefaultListeners; -import jakarta.persistence.ExcludeSuperclassListeners; -import jakarta.persistence.MappedSuperclass; -import jakarta.persistence.PersistenceException; +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; -import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER; import static org.hibernate.internal.util.collections.CollectionHelper.isNotEmpty; -/** - * Resolves JPA callback definitions - * - * @author Steve Ebersole - */ +/// Resolves JPA callback definitions +/// +/// @author Steve Ebersole public final class CallbackDefinitionResolver { private static List resolveEntityCallbacks( @@ -64,7 +58,7 @@ private static List resolveEntityCallbacks( //overridden method, remove the superclass overridden method if ( callbackDefinition == null ) { final Method javaMethod = (Method) methodDetails.toJavaMember(); - callbackDefinition = new EntityCallback.Definition( javaMethod, callbackType ); + callbackDefinition = new EntityCallbackDefinition( javaMethod, callbackType ); final Class returnType = javaMethod.getReturnType(); final Class[] args = javaMethod.getParameterTypes(); if ( returnType != Void.TYPE || args.length != 0 ) { @@ -123,7 +117,7 @@ private static List resolveEntityCallbacks( if ( callbackDefinition == null ) { final Method method = (Method) methodDetails.toJavaMember(); final Class listenerClass = listenerClassDetails.toJavaClass(); - callbackDefinition = new ListenerCallback.Definition( listenerClass, method, callbackType ); + callbackDefinition = new ListenerCallbackDefinition( listenerClass, method, callbackType ); final Class returnType = method.getReturnType(); final Class[] args = method.getParameterTypes(); @@ -151,70 +145,6 @@ private static List resolveEntityCallbacks( return callbackDefinitions; } - /** - * @deprecated See discussion in {@link EmbeddableCallback}. - */ - @Deprecated(since = "7") - private static List resolveEmbeddableCallbacks( - InFlightMetadataCollector metadataCollector, - Class entityClass, - Property embeddableProperty, - CallbackType callbackType) { - - final ModelsContext modelsContext = metadataCollector.getBootstrapContext().getModelsContext(); - final Class embeddableClass = embeddableProperty.getType().getReturnedClass(); - final ClassDetails embeddableClassDetails = modelsContext.getClassDetailsRegistry().getClassDetails( embeddableClass.getName() ); - - final Getter embeddableGetter = embeddableProperty.getGetter( entityClass ); - final List callbackDefinitions = new ArrayList<>(); - final List callbacksMethodNames = new ArrayList<>(); - ClassDetails currentClass = embeddableClassDetails; - do { - CallbackDefinition callbackDefinition = null; - final List methodsDetailsList = currentClass.getMethods(); - for ( MethodDetails methodDetails : methodsDetailsList ) { - if ( methodDetails.hasDirectAnnotationUsage( callbackType.getCallbackAnnotation() ) ) { - final Method method = methodDetails.toJavaMember(); - final String methodName = method.getName(); - final String callbackName = callbackType.getCallbackAnnotation().getName(); - final String currentClassName = currentClass.getName(); - - DEPRECATION_LOGGER.embeddableLifecycleCallback( callbackName, currentClassName ); - - if ( callbacksMethodNames.contains( methodName ) ) { - throw new PersistenceException( "Multiple callback methods annotated '@" + callbackName - + "' in bean class '" + currentClassName + "'" ); - } - - //overridden method, remove the superclass overridden method - if ( callbackDefinition == null ) { - callbackDefinition = new EmbeddableCallback.Definition( embeddableGetter, method, callbackType ); - final Class returnType = method.getReturnType(); - final Class[] args = method.getParameterTypes(); - if ( returnType != Void.TYPE || args.length != 0 ) { - throw new RuntimeException( - "Callback methods annotated on the bean class must return void and take no arguments: " - + callbackName + " - " + methodDetails - ); - } - ReflectHelper.ensureAccessibility( method ); - callbackDefinitions.add( 0, callbackDefinition ); //superclass first - callbacksMethodNames.add( 0, methodName ); - } - } - - } - - do { - currentClass = currentClass.getSuperClass(); - } - while ( currentClass != null && !currentClass.hasDirectAnnotationUsage( MappedSuperclass.class ) ); - } - while ( currentClass != null ); - - return callbackDefinitions; - } - private static boolean useAnnotationAnnotatedByListener; static { @@ -269,27 +199,5 @@ public static void resolveLifecycleCallbacks( for ( CallbackType callbackType : CallbackType.values() ) { persistentClass.addCallbackDefinitions( resolveEntityCallbacks( collector, entityClass, callbackType ) ); } - - // Note: @Embeddable classes are not supposed to have entity callbacks according to - // the JPA specification, and it doesn't even really make sense to allow them - // to, since they don't have a well-defined "lifecycle", but unfortunately this - // code was added by HHH-12326 - collector.addSecondPass( persistentClasses -> { - for ( Property property : persistentClass.getDeclaredProperties() ) { - if ( property.getValue() instanceof Component component - // embedded components don't have their own class, so no need to check callbacks (see HHH-19671) - && !component.isEmbedded() ) { - try { - final Class mappedClass = persistentClass.getMappedClass(); - for ( CallbackType type : CallbackType.values() ) { - property.addCallbackDefinitions( resolveEmbeddableCallbacks( collector, mappedClass, property, type ) ); - } - } - catch (ClassLoadingException ignore) { - // a dynamic embeddable... cannot define listener methods - } - } - } - } ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java index b768e2bed31b..4bd0bfa2d1da 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java @@ -300,6 +300,10 @@ private void setupValidation() { } private void setupEnhancement(PersistenceUnitDescriptor persistenceUnit, MetadataSources metadataSources) { + if ( persistenceUnit.isClassTransformerRegistrationDisabled() ) { + return; + } + final boolean dirtyTrackingEnabled = readBooleanConfigurationValueDefaultTrue( ENHANCER_ENABLE_DIRTY_TRACKING ); final boolean lazyInitializationEnabled = @@ -321,8 +325,7 @@ private void setupEnhancement(PersistenceUnitDescriptor persistenceUnit, Metadat associationManagementEnabled ); // push back class transformation to the environment; for the time being this only has any effect in EE // container situations, calling back into PersistenceUnitInfo#addClassTransformer - persistenceUnit.pushClassTransformer( enhancementContext ); - final var classTransformer = persistenceUnit.getClassTransformer(); + final var classTransformer = persistenceUnit.pushClassTransformer( enhancementContext ); if ( classTransformer != null ) { final var classLoader = persistenceUnit.getTempClassLoader(); if ( classLoader == null ) { @@ -827,7 +830,9 @@ private static PersistenceUnitTransactionType determineTransactionType( } private static PersistenceUnitTransactionType configuredTransactionType( - PersistenceUnitDescriptor persistenceUnit, Map integrationSettingsCopy, MergedSettings mergedSettings) { + PersistenceUnitDescriptor persistenceUnit, + Map integrationSettingsCopy, + MergedSettings mergedSettings) { Object intgTxnType = integrationSettingsCopy.remove( JAKARTA_TRANSACTION_TYPE ); if ( intgTxnType == null ) { intgTxnType = integrationSettingsCopy.remove( JPA_TRANSACTION_TYPE ); diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/ParsedPersistenceXmlDescriptor.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/ParsedPersistenceXmlDescriptor.java index 2b35582b16b7..b543e89cd381 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/ParsedPersistenceXmlDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/ParsedPersistenceXmlDescriptor.java @@ -10,6 +10,7 @@ import java.util.List; import java.util.Properties; +import jakarta.persistence.FetchType; import jakarta.persistence.spi.PersistenceUnitInfo; import org.hibernate.bytecode.enhance.spi.EnhancementContext; import org.hibernate.bytecode.spi.ClassTransformer; @@ -18,9 +19,9 @@ import jakarta.persistence.ValidationMode; import jakarta.persistence.PersistenceUnitTransactionType; import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor; -import org.hibernate.jpa.internal.util.PersistenceUnitTransactionTypeHelper; import static org.hibernate.boot.archive.internal.ArchiveHelper.getURLFromPath; +import static org.hibernate.jpa.internal.JpaLogger.JPA_LOGGER; /** * Describes the information gleaned from a {@code } @@ -44,6 +45,7 @@ public class ParsedPersistenceXmlDescriptor implements PersistenceUnitDescriptor private boolean useQuotedIdentifiers; private boolean excludeUnlistedClasses; private ValidationMode validationMode; + private FetchType defaultToOneFetchType; private SharedCacheMode sharedCacheMode; private final Properties properties = new Properties(); @@ -70,6 +72,15 @@ public void setName(String name) { this.name = name; } + @Override + public FetchType getDefaultToOneFetchType() { + return defaultToOneFetchType; + } + + public void setDefaultToOneFetchType(FetchType defaultToOneFetchType) { + this.defaultToOneFetchType = defaultToOneFetchType; + } + @Override public Object getNonJtaDataSource() { return nonJtaDataSource; @@ -102,11 +113,6 @@ public PersistenceUnitTransactionType getPersistenceUnitTransactionType() { return transactionType; } - @Override @SuppressWarnings("removal") - public jakarta.persistence.spi.PersistenceUnitTransactionType getTransactionType() { - return PersistenceUnitTransactionTypeHelper.toDeprecatedForm( transactionType ); - } - public void setTransactionType(PersistenceUnitTransactionType transactionType) { this.transactionType = transactionType; } @@ -210,12 +216,15 @@ public ClassLoader getTempClassLoader() { } @Override - public void pushClassTransformer(EnhancementContext enhancementContext) { - // todo : log a message that this is currently not supported... + public boolean isClassTransformerRegistrationDisabled() { + return true; } @Override - public ClassTransformer getClassTransformer() { + public ClassTransformer pushClassTransformer(EnhancementContext enhancementContext) { + if ( JPA_LOGGER.isDebugEnabled() ) { + JPA_LOGGER.pushingClassTransformerUnsupported( getName() ); + } return null; } } diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/PersistenceUnitInfoDescriptor.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/PersistenceUnitInfoDescriptor.java index 5ff760f5535c..05d845a770c5 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/PersistenceUnitInfoDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/PersistenceUnitInfoDescriptor.java @@ -8,6 +8,7 @@ import java.util.List; import java.util.Properties; +import jakarta.persistence.FetchType; import org.hibernate.bytecode.enhance.spi.EnhancementContext; import org.hibernate.bytecode.spi.ClassTransformer; import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor; @@ -19,20 +20,24 @@ import jakarta.persistence.spi.PersistenceUnitInfo; import jakarta.persistence.PersistenceUnitTransactionType; -import org.hibernate.jpa.internal.util.PersistenceUnitTransactionTypeHelper; import static org.hibernate.jpa.internal.JpaLogger.JPA_LOGGER; -/** - * @author Steve Ebersole - */ +/// Wraps a JPA {@linkplain PersistenceUnitInfo} as Hibernate's {@linkplain PersistenceUnitDescriptor} +/// +/// @author Steve Ebersole public class PersistenceUnitInfoDescriptor implements PersistenceUnitDescriptor { - private final PersistenceUnitInfo persistenceUnitInfo; + private final boolean disableClassTransformerRegistration; private ClassTransformer classTransformer; public PersistenceUnitInfoDescriptor(PersistenceUnitInfo persistenceUnitInfo) { + this( persistenceUnitInfo, false ); + } + + public PersistenceUnitInfoDescriptor(PersistenceUnitInfo persistenceUnitInfo, boolean disableClassTransformerRegistration) { this.persistenceUnitInfo = persistenceUnitInfo; + this.disableClassTransformerRegistration = disableClassTransformerRegistration; } @Override @@ -62,11 +67,6 @@ public String getProviderClassName() { @Override public PersistenceUnitTransactionType getPersistenceUnitTransactionType() { - return PersistenceUnitTransactionTypeHelper.toNewForm( getTransactionType() ); - } - - @Override @SuppressWarnings("removal") - public jakarta.persistence.spi.PersistenceUnitTransactionType getTransactionType() { return persistenceUnitInfo.getTransactionType(); } @@ -95,6 +95,11 @@ public boolean isExcludeUnlistedClasses() { return persistenceUnitInfo.excludeUnlistedClasses(); } + @Override + public FetchType getDefaultToOneFetchType() { + return persistenceUnitInfo.getDefaultToOneFetchType(); + } + @Override public ValidationMode getValidationMode() { return persistenceUnitInfo.getValidationMode(); @@ -121,7 +126,12 @@ public List getJarFileUrls() { } @Override - public void pushClassTransformer(EnhancementContext enhancementContext) { + public boolean isClassTransformerRegistrationDisabled() { + return disableClassTransformerRegistration; + } + + @Override + public ClassTransformer pushClassTransformer(EnhancementContext enhancementContext) { if ( this.classTransformer != null ) { throw new PersistenceException( "Persistence unit [" + persistenceUnitInfo.getPersistenceUnitName() @@ -138,10 +148,7 @@ public void pushClassTransformer(EnhancementContext enhancementContext) { this.classTransformer = classTransformer; persistenceUnitInfo.addTransformer( classTransformer ); } - } - @Override - public ClassTransformer getClassTransformer() { return classTransformer; } } diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/Bootstrap.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/Bootstrap.java index 7d0f7f3cfb82..e6fa51b26e88 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/Bootstrap.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/Bootstrap.java @@ -98,7 +98,17 @@ public static EntityManagerFactoryBuilder getEntityManagerFactoryBuilder( public static EntityManagerFactoryBuilder getEntityManagerFactoryBuilder( PersistenceUnitInfo persistenceUnitInfo, Map integration) { - return getEntityManagerFactoryBuilder( new PersistenceUnitInfoDescriptor( persistenceUnitInfo ), integration ); + return getEntityManagerFactoryBuilder( persistenceUnitInfo, false, integration ); + } + + public static EntityManagerFactoryBuilder getEntityManagerFactoryBuilder( + PersistenceUnitInfo persistenceUnitInfo, + boolean classTransformerRegistrationDisabled, + Map integration) { + return getEntityManagerFactoryBuilder( + new PersistenceUnitInfoDescriptor( persistenceUnitInfo, classTransformerRegistrationDisabled ), + integration + ); } public static EntityManagerFactoryBuilder getEntityManagerFactoryBuilder( diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackDefinition.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/CallbackDefinition.java similarity index 57% rename from hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackDefinition.java rename to hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/CallbackDefinition.java index e449f9be17ba..b7e201bc8656 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackDefinition.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/CallbackDefinition.java @@ -2,14 +2,17 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.jpa.event.spi; +package org.hibernate.jpa.boot.spi; import java.io.Serializable; +import org.hibernate.event.jpa.spi.Callback; import org.hibernate.resource.beans.spi.ManagedBeanRegistry; +/// Boot model definition of a Jakarta Persistence style callback. +/// +/// @author Steve Ebersole public interface CallbackDefinition extends Serializable { - + /// Create the corresponding runtime callback. Callback createCallback(ManagedBeanRegistry beanRegistry); - } diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/EntityCallbackDefinition.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/EntityCallbackDefinition.java new file mode 100644 index 000000000000..19208da19ee4 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/EntityCallbackDefinition.java @@ -0,0 +1,39 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.jpa.boot.spi; + +import org.hibernate.event.jpa.spi.Callback; +import org.hibernate.jpa.event.internal.EntityCallback; +import org.hibernate.jpa.event.spi.CallbackType; +import org.hibernate.models.spi.MethodDetails; +import org.hibernate.resource.beans.spi.ManagedBeanRegistry; + +import java.lang.reflect.Method; + +/// Boot model representation of a Jakarta Persistence style callback defined on an entity class. +/// +/// @see EntityCallback +/// +/// @author Steve Ebersole +/// @author Kabir Khan +public class EntityCallbackDefinition implements CallbackDefinition { + private final Method callbackMethod; + private final CallbackType callbackType; + + public EntityCallbackDefinition(Method callbackMethod, CallbackType callbackType) { + this.callbackMethod = callbackMethod; + this.callbackType = callbackType; + } + + public EntityCallbackDefinition(MethodDetails callbackMethod, CallbackType callbackType) { + this.callbackMethod = (Method) callbackMethod.toJavaMember(); + this.callbackType = callbackType; + } + + @Override + public Callback createCallback(ManagedBeanRegistry beanRegistry) { + return new EntityCallback( callbackMethod, callbackType ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/ListenerCallbackDefinition.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/ListenerCallbackDefinition.java new file mode 100644 index 000000000000..2d5166d66849 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/ListenerCallbackDefinition.java @@ -0,0 +1,36 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.jpa.boot.spi; + +import org.hibernate.event.jpa.spi.Callback; +import org.hibernate.jpa.event.internal.ListenerCallback; +import org.hibernate.jpa.event.spi.CallbackType; +import org.hibernate.resource.beans.spi.ManagedBeanRegistry; + +import java.lang.reflect.Method; + +/// Boot model representation of a Jakarta Persistence style callback defined as a separate listener class. +/// +/// @see jakarta.persistence.EntityListeners +/// @see ListenerCallback +/// +/// @author Steve Ebersole +/// @author Kabir Khan +public class ListenerCallbackDefinition implements CallbackDefinition { + private final Class listenerClass; + private final Method callbackMethod; + private final CallbackType callbackType; + + public ListenerCallbackDefinition(Class listenerClass, Method callbackMethod, CallbackType callbackType) { + this.listenerClass = listenerClass; + this.callbackMethod = callbackMethod; + this.callbackType = callbackType; + } + + @Override + public Callback createCallback(ManagedBeanRegistry beanRegistry) { + return new ListenerCallback( beanRegistry.getBean( listenerClass ), callbackMethod, callbackType ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/PersistenceConfigurationDescriptor.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/PersistenceConfigurationDescriptor.java index 256cd5f500e8..4949c24ba1d9 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/PersistenceConfigurationDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/PersistenceConfigurationDescriptor.java @@ -8,6 +8,7 @@ import java.util.List; import java.util.Properties; +import jakarta.persistence.FetchType; import org.hibernate.bytecode.enhance.spi.EnhancementContext; import org.hibernate.bytecode.spi.ClassTransformer; import org.hibernate.cfg.AvailableSettings; @@ -19,7 +20,8 @@ import jakarta.persistence.SharedCacheMode; import jakarta.persistence.ValidationMode; import jakarta.persistence.PersistenceUnitTransactionType; -import org.hibernate.jpa.internal.util.PersistenceUnitTransactionTypeHelper; + +import static org.hibernate.jpa.internal.JpaLogger.JPA_LOGGER; /** * PersistenceUnitDescriptor wrapper around {@linkplain PersistenceConfiguration} @@ -65,9 +67,9 @@ public boolean isExcludeUnlistedClasses() { || configuration.rootUrl() == null && configuration.jarFileUrls().isEmpty(); } - @Override @SuppressWarnings("removal") - public jakarta.persistence.spi.PersistenceUnitTransactionType getTransactionType() { - return PersistenceUnitTransactionTypeHelper.toDeprecatedForm( getPersistenceUnitTransactionType() ); + @Override + public FetchType getDefaultToOneFetchType() { + return persistenceConfiguration.defaultToOneFetchType(); } @Override @@ -116,12 +118,15 @@ public ClassLoader getTempClassLoader() { } @Override - public void pushClassTransformer(EnhancementContext enhancementContext) { - + public boolean isClassTransformerRegistrationDisabled() { + return true; } @Override - public ClassTransformer getClassTransformer() { + public ClassTransformer pushClassTransformer(EnhancementContext enhancementContext) { + if ( JPA_LOGGER.isDebugEnabled() ) { + JPA_LOGGER.pushingClassTransformerUnsupported( getName() ); + } return null; } diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/PersistenceUnitDescriptor.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/PersistenceUnitDescriptor.java index 87ac3229c54e..5de4c96a045d 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/PersistenceUnitDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/PersistenceUnitDescriptor.java @@ -7,6 +7,8 @@ import java.net.URL; import java.util.List; import java.util.Properties; + +import jakarta.persistence.FetchType; import jakarta.persistence.SharedCacheMode; import jakarta.persistence.ValidationMode; import jakarta.persistence.PersistenceUnitTransactionType; @@ -14,87 +16,96 @@ import org.hibernate.bytecode.enhance.spi.EnhancementContext; import org.hibernate.bytecode.spi.ClassTransformer; -/** - * Abstraction for dealing with {@code } information - * specified in the {@code persistence.xml} file, which might be: - *
    - *
  • passed by the Jakarta EE container as an instance of - * {@link jakarta.persistence.spi.PersistenceUnitInfo}, or, - *
  • in an SE environment, parsed by Hibernate itself. - *
- * - * @author Steve Ebersole - */ +/// Abstraction for dealing with `` information +/// specified in the `persistence.xml` file. This information can +/// come from either: +/// +/// - from the Jakarta EE container as an instance of +/// [jakarta.persistence.spi.PersistenceUnitInfo] +/// - in an SE environment, parsed by Hibernate itself +/// +/// @see jakarta.persistence.spi.PersistenceUnitInfo +/// @see org.hibernate.boot.jaxb.configuration.spi.JaxbPersistenceImpl.JaxbPersistenceUnitImpl +/// +/// @author Steve Ebersole public interface PersistenceUnitDescriptor { - /** - * Get the root url for the persistence unit. Intended to describe the base for scanning. - * - * @return The root url - */ + /// The root url for the persistence unit. + /// + /// @implNote When Hibernate performs scanning, this URL is used as the base for scanning. URL getPersistenceUnitRootUrl(); - /** - * Get the persistence unit name, - * - * @return The persistence unit name, - */ + /// The persistence unit name. + /// + /// @see org.hibernate.boot.jaxb.configuration.spi.JaxbPersistenceImpl.JaxbPersistenceUnitImpl#getName String getName(); - /** - * Get the explicitly specified provider class name, or {@code null} if not specified. - * - * @return The specified provider class name - */ + /// The explicitly specified provider class name, or `null` if not specified. + /// + /// @see jakarta.persistence.spi.PersistenceUnitInfo#getPersistenceProviderClassName + /// @see org.hibernate.boot.jaxb.configuration.spi.JaxbPersistenceImpl.JaxbPersistenceUnitImpl#getProvider String getProviderClassName(); - /** - * Is the use of quoted identifiers in effect for this whole persistence unit? - * - * @return {@code true} is quoted identifiers should be used throughout the unit. - */ + /// Whether the use of identifier quoting is in effect for this whole persistence unit. boolean isUseQuotedIdentifiers(); - /** - * Essentially should scanning for classes be performed? If not, the list of classes available is limited to:
    - *
  • classes listed in {@link #getManagedClassNames()}
  • - *
  • classes named in all {@link #getMappingFileNames}
  • - *
  • classes discovered in {@link #getJarFileUrls}
  • - *
- * - * @return {@code true} if the root url should not be scanned for classes. - */ + /// Whether scanning for classes should be performed. If not, the list of classes available is limited to: + /// - classes listed in [#getManagedClassNames()] + /// - classes named in all [#getMappingFileNames] + /// - classes discovered in [#getJarFileUrls] + /// + /// @see jakarta.persistence.spi.PersistenceUnitInfo#excludeUnlistedClasses + /// @see org.hibernate.boot.jaxb.configuration.spi.JaxbPersistenceImpl.JaxbPersistenceUnitImpl#isExcludeUnlistedClasses boolean isExcludeUnlistedClasses(); - PersistenceUnitTransactionType getPersistenceUnitTransactionType(); + /// @see jakarta.persistence.spi.PersistenceUnitInfo#getDefaultToOneFetchType() + /// @see org.hibernate.boot.jaxb.configuration.spi.JaxbPersistenceImpl.JaxbPersistenceUnitImpl#getDefaultToOneFetchType + /// + /// @since 8.0 + FetchType getDefaultToOneFetchType(); - /** - * @deprecated since {@link jakarta.persistence.spi.PersistenceUnitTransactionType} - * will be removed in JPA 4 - */ - @Deprecated(since = "7", forRemoval = true) @SuppressWarnings("removal") - jakarta.persistence.spi.PersistenceUnitTransactionType getTransactionType(); + /// @see jakarta.persistence.spi.PersistenceUnitInfo#getTransactionType() + /// @see org.hibernate.boot.jaxb.configuration.spi.JaxbPersistenceImpl.JaxbPersistenceUnitImpl#getTransactionType + PersistenceUnitTransactionType getPersistenceUnitTransactionType(); + /// @see jakarta.persistence.spi.PersistenceUnitInfo#getValidationMode + /// @see org.hibernate.boot.jaxb.configuration.spi.JaxbPersistenceImpl.JaxbPersistenceUnitImpl#getValidationMode ValidationMode getValidationMode(); + /// @see jakarta.persistence.spi.PersistenceUnitInfo#getSharedCacheMode + /// @see org.hibernate.boot.jaxb.configuration.spi.JaxbPersistenceImpl.JaxbPersistenceUnitImpl#getSharedCacheMode SharedCacheMode getSharedCacheMode(); + /// @see jakarta.persistence.spi.PersistenceUnitInfo#getManagedClassNames + /// @see org.hibernate.boot.jaxb.configuration.spi.JaxbPersistenceImpl.JaxbPersistenceUnitImpl#getClasses List getManagedClassNames(); + /// @see jakarta.persistence.spi.PersistenceUnitInfo#getMappingFileNames + /// @see org.hibernate.boot.jaxb.configuration.spi.JaxbPersistenceImpl.JaxbPersistenceUnitImpl#getMappingFiles List getMappingFileNames(); + /// @see jakarta.persistence.spi.PersistenceUnitInfo#getJarFileUrls + /// @see org.hibernate.boot.jaxb.configuration.spi.JaxbPersistenceImpl.JaxbPersistenceUnitImpl#getJarFiles List getJarFileUrls(); + /// @see jakarta.persistence.spi.PersistenceUnitInfo#getNonJtaDataSource + /// @see org.hibernate.boot.jaxb.configuration.spi.JaxbPersistenceImpl.JaxbPersistenceUnitImpl#getNonJtaDataSource Object getNonJtaDataSource(); + /// @see jakarta.persistence.spi.PersistenceUnitInfo#getJtaDataSource + /// @see org.hibernate.boot.jaxb.configuration.spi.JaxbPersistenceImpl.JaxbPersistenceUnitImpl#getJtaDataSource Object getJtaDataSource(); + /// @see jakarta.persistence.spi.PersistenceUnitInfo#getProperties + /// @see org.hibernate.boot.jaxb.configuration.spi.JaxbPersistenceImpl.JaxbPersistenceUnitImpl#getPropertyContainer Properties getProperties(); + /// @see jakarta.persistence.spi.PersistenceUnitInfo#getClassLoader ClassLoader getClassLoader(); + /// @see jakarta.persistence.spi.PersistenceUnitInfo#getNewTempClassLoader ClassLoader getTempClassLoader(); - void pushClassTransformer(EnhancementContext enhancementContext); + boolean isClassTransformerRegistrationDisabled(); - ClassTransformer getClassTransformer(); + ClassTransformer pushClassTransformer(EnhancementContext enhancementContext); } diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/PersistenceXmlParser.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/PersistenceXmlParser.java index 98b0256f5c4a..f3eafc6c6c0e 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/PersistenceXmlParser.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/PersistenceXmlParser.java @@ -26,7 +26,6 @@ import jakarta.persistence.PersistenceException; import jakarta.persistence.PersistenceUnitTransactionType; -import org.hibernate.jpa.internal.util.PersistenceUnitTransactionTypeHelper; import static jakarta.persistence.PersistenceUnitTransactionType.JTA; import static jakarta.persistence.PersistenceUnitTransactionType.RESOURCE_LOCAL; @@ -194,6 +193,7 @@ private void bindPersistenceUnit( setTransactionType( jaxbPersistenceUnit, persistenceUnitDescriptor ); persistenceUnitDescriptor.setProviderClassName( jaxbPersistenceUnit.getProvider() ); + persistenceUnitDescriptor.setDefaultToOneFetchType( jaxbPersistenceUnit.getDefaultToOneFetchType() ); persistenceUnitDescriptor.setNonJtaDataSource( jaxbPersistenceUnit.getNonJtaDataSource() ); persistenceUnitDescriptor.setJtaDataSource( jaxbPersistenceUnit.getJtaDataSource() ); persistenceUnitDescriptor.setSharedCacheMode( jaxbPersistenceUnit.getSharedCacheMode() ); @@ -217,8 +217,7 @@ private static void setTransactionType( ParsedPersistenceXmlDescriptor persistenceUnitDescriptor) { final var transactionType = jaxbPersistenceUnit.getTransactionType(); if ( transactionType != null ) { - persistenceUnitDescriptor.setTransactionType( - PersistenceUnitTransactionTypeHelper.toNewForm( transactionType ) ); + persistenceUnitDescriptor.setTransactionType( transactionType ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/AbstractCallback.java b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/AbstractCallback.java index 8997d0f00c5c..a88973e7c958 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/AbstractCallback.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/AbstractCallback.java @@ -4,16 +4,13 @@ */ package org.hibernate.jpa.event.internal; -import org.hibernate.jpa.event.spi.Callback; +import org.hibernate.event.jpa.spi.Callback; import org.hibernate.jpa.event.spi.CallbackType; -/** - * Abstract support for Callback implementations - * - * @author Steve Ebersole - */ +/// Base support for [Callback] implementations. +/// +/// @author Steve Ebersole abstract class AbstractCallback implements Callback { - private final CallbackType callbackType; AbstractCallback(CallbackType callbackType) { diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbackRegistryImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbackRegistryImpl.java deleted file mode 100644 index 9296259ae33d..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbackRegistryImpl.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.jpa.event.internal; - -import java.util.HashMap; -import java.util.Map; - - -import org.hibernate.internal.build.AllowReflection; -import org.hibernate.internal.util.collections.ArrayHelper; -import org.hibernate.internal.util.collections.MapBackedClassValue; -import org.hibernate.internal.util.collections.ReadOnlyMap; -import org.hibernate.jpa.event.spi.Callback; -import org.hibernate.jpa.event.spi.CallbackRegistry; -import org.hibernate.jpa.event.spi.CallbackType; - -/** - * Keep track of all lifecycle callbacks and listeners for a given persistence unit - * - * @author Kabir Khan - * @author Steve Ebersole - * @author Sanne Grinovero - */ -final class CallbackRegistryImpl implements CallbackRegistry { - - private final ReadOnlyMap,Callback[]> preCreates; - private final ReadOnlyMap,Callback[]> postCreates; - private final ReadOnlyMap,Callback[]> preRemoves; - private final ReadOnlyMap,Callback[]> postRemoves; - private final ReadOnlyMap,Callback[]> preUpdates; - private final ReadOnlyMap,Callback[]> postUpdates; - private final ReadOnlyMap,Callback[]> postLoads; - - public CallbackRegistryImpl( - Map, Callback[]> preCreates, - Map, Callback[]> postCreates, - Map, Callback[]> preRemoves, - Map, Callback[]> postRemoves, - Map, Callback[]> preUpdates, - Map, Callback[]> postUpdates, - Map, Callback[]> postLoads) { - this.preCreates = createBackingMap( preCreates ); - this.postCreates = createBackingMap( postCreates ); - this.preRemoves = createBackingMap( preRemoves ); - this.postRemoves = createBackingMap( postRemoves ); - this.preUpdates = createBackingMap( preUpdates ); - this.postUpdates = createBackingMap( postUpdates ); - this.postLoads = createBackingMap( postLoads ); - } - - private static ReadOnlyMap, Callback[]> createBackingMap(final Map, Callback[]> src) { - return src == null || src.isEmpty() - ? ReadOnlyMap.EMPTY - : new MapBackedClassValue<>( src ); - } - - @Override - public boolean hasRegisteredCallbacks(Class entityClass, CallbackType callbackType) { - return notEmpty( getCallbackMap( callbackType ).get( entityClass ) ); - } - - @Override - public void preCreate(Object bean) { - callback( preCreates.get( bean.getClass() ), bean ); - } - - private boolean notEmpty(Callback[] callbacks) { - return callbacks != null && callbacks.length > 0; - } - - @Override - public void postCreate(Object bean) { - callback( postCreates.get( bean.getClass() ), bean ); - } - - @Override - public boolean preUpdate(Object bean) { - return callback( preUpdates.get( bean.getClass() ), bean ); - } - - @Override - public void postUpdate(Object bean) { - callback( postUpdates.get( bean.getClass() ), bean ); - } - - @Override - public void preRemove(Object bean) { - callback( preRemoves.get( bean.getClass() ), bean ); - } - - @Override - public void postRemove(Object bean) { - callback( postRemoves.get( bean.getClass() ), bean ); - } - - @Override - public boolean postLoad(Object bean) { - return callback( postLoads.get( bean.getClass() ), bean ); - } - - @Override - public void release() { - this.preCreates.dispose(); - this.postCreates.dispose(); - this.preRemoves.dispose(); - this.postRemoves.dispose(); - this.preUpdates.dispose(); - this.postUpdates.dispose(); - this.postLoads.dispose(); - } - - private boolean callback(Callback[] callbacks, Object bean) { - if ( callbacks != null && callbacks.length != 0 ) { - for ( Callback callback : callbacks ) { - callback.performCallback( bean ); - } - return true; - } - else { - return false; - } - } - - private ReadOnlyMap,Callback[]> getCallbackMap(CallbackType callbackType) { - return switch ( callbackType ) { - case PRE_PERSIST -> preCreates; - case POST_PERSIST -> postCreates; - case PRE_REMOVE -> preRemoves; - case POST_REMOVE -> postRemoves; - case PRE_UPDATE -> preUpdates; - case POST_UPDATE -> postUpdates; - case POST_LOAD -> postLoads; - }; - } - - public static class Builder { - private static final Callback[] NO_CALLBACKS = new Callback[0]; - - private final Map, Callback[]> preCreates = new HashMap<>(); - private final Map, Callback[]> postCreates = new HashMap<>(); - private final Map, Callback[]> preRemoves = new HashMap<>(); - private final Map, Callback[]> postRemoves = new HashMap<>(); - private final Map, Callback[]> preUpdates = new HashMap<>(); - private final Map, Callback[]> postUpdates = new HashMap<>(); - private final Map, Callback[]> postLoads = new HashMap<>(); - - @AllowReflection - public void registerCallbacks(Class entityClass, Callback[] callbacks) { - if ( callbacks != null ) { - for ( Callback callback : callbacks ) { - addCallback( entityClass, callback ); - } - } - } - - public void addCallback(Class entityClass, Callback callback) { - final var callbackMap = getCallbackMap( callback.getCallbackType() ); - final Callback[] existingCallbacks = callbackMap.getOrDefault( entityClass, NO_CALLBACKS ); - callbackMap.put( entityClass, ArrayHelper.add( existingCallbacks, callback ) ); - } - - private Map, Callback[]> getCallbackMap(CallbackType callbackType) { - return switch ( callbackType ) { - case PRE_PERSIST -> preCreates; - case POST_PERSIST -> postCreates; - case PRE_REMOVE -> preRemoves; - case POST_REMOVE -> postRemoves; - case PRE_UPDATE -> preUpdates; - case POST_UPDATE -> postUpdates; - case POST_LOAD -> postLoads; - }; - } - - protected CallbackRegistry build() { - return new CallbackRegistryImpl( preCreates, postCreates, preRemoves, postRemoves, preUpdates, postUpdates, postLoads ); - } - - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbacksFactory.java b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbacksFactory.java deleted file mode 100644 index b7457d8adf66..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbacksFactory.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.jpa.event.internal; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.hibernate.boot.spi.SessionFactoryOptions; -import org.hibernate.jpa.event.spi.Callback; -import org.hibernate.jpa.event.spi.CallbackDefinition; -import org.hibernate.jpa.event.spi.CallbackRegistry; -import org.hibernate.mapping.PersistentClass; -import org.hibernate.mapping.Property; -import org.hibernate.resource.beans.spi.ManagedBeanRegistry; -import org.hibernate.service.ServiceRegistry; - -import org.jboss.logging.Logger; - -/** - * The intent of this class is to use a lighter implementation - * when standard JPA entity lifecycle callbacks are disabled via - * {@link SessionFactoryOptions#areJPACallbacksEnabled()}. - */ -public final class CallbacksFactory { - private static final Logger LOG = Logger.getLogger( CallbacksFactory.class ); - - public static CallbackRegistry buildCallbackRegistry( - SessionFactoryOptions options, ServiceRegistry serviceRegistry, Collection entityBindings) { - if ( !options.areJPACallbacksEnabled() ) { - return new EmptyCallbackRegistryImpl(); - } - final ManagedBeanRegistry beanRegistry = serviceRegistry.getService( ManagedBeanRegistry.class ); - final CallbackRegistryImpl.Builder registryBuilder = new CallbackRegistryImpl.Builder(); - final Set> entityClasses = new HashSet<>(); - - for ( PersistentClass persistentClass : entityBindings ) { - if ( persistentClass.getClassName() != null ) { - final Class entityClass = persistentClass.getMappedClass(); - if ( !entityClasses.add( entityClass ) ) { - // this most likely means we have a class mapped multiple - // times using the hbm.xml "entity name" feature - if ( LOG.isDebugEnabled() ) { - LOG.debugf( - "Class [%s] already has callbacks registered; " + - "assuming this means the class was mapped twice " + - "(using hbm.xml entity-name support) - skipping subsequent registrations" + - "to avoid duplicates", - entityClass.getName() - ); - } - } - else { - registerAllCallbacks( persistentClass, registryBuilder, entityClass, beanRegistry ); - } - } - // else we can have dynamic (non-java class) mapping - } - - return registryBuilder.build(); - } - - private static void registerAllCallbacks( - PersistentClass persistentClass, - CallbackRegistryImpl.Builder registryBuilder, - Class entityClass, - ManagedBeanRegistry beanRegistry) { - registryBuilder.registerCallbacks( entityClass, - buildCallbacks( persistentClass.getCallbackDefinitions(), beanRegistry ) ); - - for ( Property property : persistentClass.getDeclaredProperties() ) { - registryBuilder.registerCallbacks( entityClass, - buildCallbacks( property.getCallbackDefinitions(), beanRegistry ) ); - } - } - - private static Callback[] buildCallbacks(List callbackDefinitions, - ManagedBeanRegistry beanRegistry) { - if ( callbackDefinitions == null || callbackDefinitions.isEmpty() ) { - return null; - } - else { - final List callbacks = new ArrayList<>(); - for ( CallbackDefinition definition : callbackDefinitions ) { - callbacks.add( definition.createCallback( beanRegistry ) ); - } - return callbacks.toArray( new Callback[0] ); - } - } - -} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/EmbeddableCallback.java b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/EmbeddableCallback.java deleted file mode 100644 index 39e51b7fb04b..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/EmbeddableCallback.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.jpa.event.internal; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Locale; - -import org.hibernate.jpa.event.spi.Callback; -import org.hibernate.jpa.event.spi.CallbackDefinition; -import org.hibernate.jpa.event.spi.CallbackType; -import org.hibernate.property.access.spi.Getter; -import org.hibernate.resource.beans.spi.ManagedBeanRegistry; - -/** - * Represents a JPA callback method declared by an embeddable type. - * - * @deprecated The JPA specification does not require that we allow - * entity lifecycle callbacks on embeddable classes, and this is a - * misfeature since: - *
    - *
  • an embeddable objects doesn't have a well-defined lifecycle, - *
  • it's difficult to understand what this means for composite - * collection elements, and - *
  • currently, the {@code PreUpdate}/{@code PostUpdate} callbacks - * get called when the embeddable object is not itself being - * updated. - *
- * It would be OK to simply remove this capability, since fortunately - * we never documented it. - * - * @author Vlad Mihalcea - */ -@Deprecated(since = "7") -public class EmbeddableCallback extends AbstractCallback { - - public static class Definition implements CallbackDefinition { - private final Getter embeddableGetter; - private final Method callbackMethod; - private final CallbackType callbackType; - - public Definition(Getter embeddableGetter, Method callbackMethod, CallbackType callbackType) { - this.embeddableGetter = embeddableGetter; - this.callbackMethod = callbackMethod; - this.callbackType = callbackType; - } - - @Override - public Callback createCallback(ManagedBeanRegistry beanRegistry) { - return new EmbeddableCallback( embeddableGetter, callbackMethod, callbackType ); - } - } - - private final Getter embeddableGetter; - private final Method callbackMethod; - - private EmbeddableCallback(Getter embeddableGetter, Method callbackMethod, CallbackType callbackType) { - super( callbackType ); - this.embeddableGetter = embeddableGetter; - this.callbackMethod = callbackMethod; - } - - @Override - public void performCallback(Object entity) { - try { - final Object embeddable = embeddableGetter.get( entity ); - if ( embeddable != null ) { - callbackMethod.invoke( embeddable ); - } - } - catch (InvocationTargetException e) { - //keep runtime exceptions as is - if ( e.getTargetException() instanceof RuntimeException runtimeException ) { - throw runtimeException; - } - else { - throw new RuntimeException( e.getTargetException() ); - } - } - catch (Exception e) { - throw new RuntimeException( e ); - } - } - - @Override - public String toString() { - return String.format( - Locale.ROOT, - "EmbeddableCallback([%s] %s.%s)", - getCallbackType().name(), - callbackMethod.getDeclaringClass().getName(), - callbackMethod.getName() - ); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/EmptyCallbackRegistryImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/EmptyCallbackRegistryImpl.java deleted file mode 100644 index cc944a4b6bb2..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/EmptyCallbackRegistryImpl.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.jpa.event.internal; - -import org.hibernate.jpa.event.spi.CallbackRegistry; -import org.hibernate.jpa.event.spi.CallbackType; - -final class EmptyCallbackRegistryImpl implements CallbackRegistry { - - @Override - public boolean hasRegisteredCallbacks(final Class entityClass, final CallbackType callbackType) { - return false; - } - - @Override - public void preCreate(final Object entity) { - //no-op - } - - @Override - public void postCreate(final Object entity) { - //no-op - } - - @Override - public boolean preUpdate(final Object entity) { - return false; - } - - @Override - public void postUpdate(final Object entity) { - //no-op - } - - @Override - public void preRemove(final Object entity) { - //no-op - } - - @Override - public void postRemove(final Object entity) { - //no-op - } - - @Override - public boolean postLoad(final Object entity) { - return false; - } - - @Override - public void release() { - //no-op - } - -} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/EntityCallback.java b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/EntityCallback.java index a7efb64d9701..7fe2a84a8d54 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/EntityCallback.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/EntityCallback.java @@ -4,47 +4,20 @@ */ package org.hibernate.jpa.event.internal; +import org.hibernate.jpa.event.spi.CallbackType; + import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Locale; -import org.hibernate.jpa.event.spi.Callback; -import org.hibernate.jpa.event.spi.CallbackDefinition; -import org.hibernate.jpa.event.spi.CallbackType; -import org.hibernate.models.spi.MethodDetails; -import org.hibernate.resource.beans.spi.ManagedBeanRegistry; - -/** - * Represents a JPA callback method declared by the entity itself. - * - * @author Kabir Khan - * @author Steve Ebersole - */ +/// Runtime handling for Jakarta Persistence style callback defined on an entity class. +/// +/// @author Kabir Khan +/// @author Steve Ebersole public class EntityCallback extends AbstractCallback { - - public static class Definition implements CallbackDefinition { - private final Method callbackMethod; - private final CallbackType callbackType; - - public Definition(Method callbackMethod, CallbackType callbackType) { - this.callbackMethod = callbackMethod; - this.callbackType = callbackType; - } - - public Definition(MethodDetails callbackMethod, CallbackType callbackType) { - this.callbackMethod = (Method) callbackMethod.toJavaMember(); - this.callbackType = callbackType; - } - - @Override - public Callback createCallback(ManagedBeanRegistry beanRegistry) { - return new EntityCallback( callbackMethod, callbackType ); - } - } - private final Method callbackMethod; - private EntityCallback(Method callbackMethod, CallbackType callbackType) { + public EntityCallback(Method callbackMethod, CallbackType callbackType) { super( callbackType ); this.callbackMethod = callbackMethod; } diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/ListenerCallback.java b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/ListenerCallback.java index 6c50dcc22c08..32df203eb24c 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/ListenerCallback.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/ListenerCallback.java @@ -4,16 +4,13 @@ */ package org.hibernate.jpa.event.internal; +import org.hibernate.jpa.event.spi.CallbackType; +import org.hibernate.resource.beans.spi.ManagedBean; + import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Locale; -import org.hibernate.jpa.event.spi.Callback; -import org.hibernate.jpa.event.spi.CallbackDefinition; -import org.hibernate.jpa.event.spi.CallbackType; -import org.hibernate.resource.beans.spi.ManagedBean; -import org.hibernate.resource.beans.spi.ManagedBeanRegistry; - /** * Represents a JPA callback method declared by an entity listener class. * @@ -23,28 +20,10 @@ * @author Steve Ebersole */ public class ListenerCallback extends AbstractCallback { - - public static class Definition implements CallbackDefinition { - private final Class listenerClass; - private final Method callbackMethod; - private final CallbackType callbackType; - - public Definition(Class listenerClass, Method callbackMethod, CallbackType callbackType) { - this.listenerClass = listenerClass; - this.callbackMethod = callbackMethod; - this.callbackType = callbackType; - } - - @Override - public Callback createCallback(ManagedBeanRegistry beanRegistry) { - return new ListenerCallback( beanRegistry.getBean( listenerClass ), callbackMethod, callbackType ); - } - } - private final Method callbackMethod; private final ManagedBean listenerManagedBean; - ListenerCallback(ManagedBean listenerManagedBean, Method callbackMethod, CallbackType callbackType) { + public ListenerCallback(ManagedBean listenerManagedBean, Method callbackMethod, CallbackType callbackType) { super( callbackType ); this.listenerManagedBean = listenerManagedBean; this.callbackMethod = callbackMethod; diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/package-info.java b/hibernate-core/src/main/java/org/hibernate/jpa/event/package-info.java index 810cb6315fda..c376f8cff061 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/package-info.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/event/package-info.java @@ -3,18 +3,16 @@ * Copyright Red Hat Inc. and Hibernate Authors */ -/** - * Support for Jakarta Persistence entity listeners. - * - * @see jakarta.persistence.EntityListeners - * @see jakarta.persistence.PrePersist - * @see jakarta.persistence.PreUpdate - * @see jakarta.persistence.PreRemove - * @see jakarta.persistence.PostPersist - * @see jakarta.persistence.PostUpdate - * @see jakarta.persistence.PostRemove - * @see jakarta.persistence.PostLoad - * - * @author Steve Ebersole - */ +/// Support for Jakarta Persistence entity listeners. +/// +/// @see jakarta.persistence.EntityListeners +/// @see jakarta.persistence.PrePersist +/// @see jakarta.persistence.PreUpdate +/// @see jakarta.persistence.PreRemove +/// @see jakarta.persistence.PostPersist +/// @see jakarta.persistence.PostUpdate +/// @see jakarta.persistence.PostRemove +/// @see jakarta.persistence.PostLoad +/// +/// @author Steve Ebersole package org.hibernate.jpa.event; diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackRegistry.java b/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackRegistry.java deleted file mode 100644 index 4b1c1965fd1e..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackRegistry.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.jpa.event.spi; - -/** - * Registry of JPA entity lifecycle callbacks by entity and type. - * - * @author Steve Ebersole - */ -public interface CallbackRegistry { - /** - * Do we have any registered callbacks of the given type for the given entity? - * - * @param entityClass The entity Class to check against - * @param callbackType The type of callback to look for - * - * @return {@code true} indicates there are already registered callbacks of - * that type for that class; {@code false} indicates there are not. - */ - boolean hasRegisteredCallbacks(Class entityClass, CallbackType callbackType); - - void preCreate(Object entity); - void postCreate(Object entity); - - boolean preUpdate(Object entity); - void postUpdate(Object entity); - - void preRemove(Object entity); - void postRemove(Object entity); - - boolean postLoad(Object entity); - - /** - * Signals that the CallbackRegistry will no longer be used. - * In particular, it is important to release references to class types - * to avoid classloader leaks. - */ - void release(); - -} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackRegistryConsumer.java b/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackRegistryConsumer.java deleted file mode 100644 index 4b00efc55bc8..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackRegistryConsumer.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.jpa.event.spi; - -/** - * Contract for injecting the registry of Callbacks into event listeners. - * - * @author Emmanuel Bernard - * @author Steve Ebersole - */ -public interface CallbackRegistryConsumer { - /** - * Injection of the CallbackRegistry - * - * @param callbackRegistry The CallbackRegistry - */ - void injectCallbackRegistry(CallbackRegistry callbackRegistry); -} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackType.java b/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackType.java index 6f7c9a3cd85d..68b4e7f1a90d 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackType.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackType.java @@ -13,45 +13,58 @@ import jakarta.persistence.PreRemove; import jakarta.persistence.PreUpdate; -/** - * Enumerates the entity lifecycle callback types defined by JPA. - * - * @author Steve Ebersole - */ +/// Enumerates the Jakarta Persistence style lifecycle callback types. +/// +/// @author Steve Ebersole public enum CallbackType { - /** - * @see PreUpdate - */ + /// @see PreUpdate PRE_UPDATE, - /** - * @see PostUpdate - */ + + /// @see PostUpdate POST_UPDATE, - /** - * @see PrePersist - */ + + /// @see PrePersist PRE_PERSIST, - /** - * @see PostPersist - */ + + /// @see PostPersist POST_PERSIST, - /** - * @see PreRemove - */ + + /// @see PreRemove PRE_REMOVE, - /** - * @see PostRemove - */ + + /// @see PostRemove POST_REMOVE, - /** - * @see PostLoad - */ + + /// @see PostLoad POST_LOAD; - /** - * The JPA-defined callback annotation type corresponding - * to this lifecycle event type. - */ + /// Returns the callback type for a given callback annotation. + public static CallbackType fromCallbackAnnotation(Class ann) { + if ( PrePersist.class.equals( ann ) ) { + return PRE_PERSIST; + } + if ( PostPersist.class.equals( ann ) ) { + return POST_PERSIST; + } + if ( PreUpdate.class.equals( ann ) ) { + return PRE_UPDATE; + } + if ( PostUpdate.class.equals( ann ) ) { + return POST_UPDATE; + } + if ( PreRemove.class.equals( ann ) ) { + return PRE_REMOVE; + } + if ( PostRemove.class.equals( ann ) ) { + return POST_REMOVE; + } + if ( PostLoad.class.equals( ann ) ) { + return POST_LOAD; + } + throw new IllegalArgumentException( "Unknown callback annotation : " + ann ); + } + + /// The callback annotation type corresponding to this lifecycle callback type. public Class getCallbackAnnotation() { return switch ( this ) { case PRE_PERSIST -> PrePersist.class; diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/package-info.java b/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/package-info.java index 523e434a37f3..a7a8f3f9df6d 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/package-info.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/package-info.java @@ -3,17 +3,15 @@ * Copyright Red Hat Inc. and Hibernate Authors */ -/** - * The SPI contracts for supporting JPA lifecycle callbacks and - * {@link jakarta.persistence.EntityListeners entity listeners}. - * - * @see jakarta.persistence.EntityListeners - * @see jakarta.persistence.PrePersist - * @see jakarta.persistence.PreUpdate - * @see jakarta.persistence.PreRemove - * @see jakarta.persistence.PostPersist - * @see jakarta.persistence.PostUpdate - * @see jakarta.persistence.PostRemove - * @see jakarta.persistence.PostLoad - */ +/// The SPI contracts for supporting JPA lifecycle callbacks and +/// [entity listeners][jakarta.persistence.EntityListeners]. +/// +/// @see jakarta.persistence.EntityListeners +/// @see jakarta.persistence.PrePersist +/// @see jakarta.persistence.PreUpdate +/// @see jakarta.persistence.PreRemove +/// @see jakarta.persistence.PostPersist +/// @see jakarta.persistence.PostUpdate +/// @see jakarta.persistence.PostRemove +/// @see jakarta.persistence.PostLoad package org.hibernate.jpa.event.spi; diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/internal/JpaLogger.java b/hibernate-core/src/main/java/org/hibernate/jpa/internal/JpaLogger.java index 9024e217f5bc..328364cacc9d 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/internal/JpaLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/internal/JpaLogger.java @@ -182,4 +182,16 @@ public interface JpaLogger extends BasicLogger { @LogMessage(level = TRACE) @Message(id = 8549, value = "Attempting to interpret external setting [%s] as FlushModeType name") void attemptingToInterpretExternalSettingAsFlushModeTypeName(String externalName); + + @LogMessage(level = TRACE) + @Message(id = 8550, value = "PersistenceProvider#getClassTransformer called for PU named '%s' on classloader %s") + void requestForClassTransformer(String persistenceUnitName, String loadingClassLoader); + + @LogMessage(level = TRACE) + @Message(id = 8551, value = "PersistenceProvider#getClassTransformer called multiple times for PU named '%s' on classloader %s") + void duplicatedRequestForClassTransformer(String persistenceUnitName, String loadingClassLoader); + + @LogMessage(level = DEBUG) + @Message(id = 8552, value = "Pushing class transformers not supported for PU named '%s'") + void pushingClassTransformerUnsupported(String persistenceUnitName); } diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/internal/util/PersistenceUnitTransactionTypeHelper.java b/hibernate-core/src/main/java/org/hibernate/jpa/internal/util/PersistenceUnitTransactionTypeHelper.java index 8382c151637d..da6802f30726 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/internal/util/PersistenceUnitTransactionTypeHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/internal/util/PersistenceUnitTransactionTypeHelper.java @@ -6,11 +6,18 @@ import jakarta.persistence.PersistenceException; import jakarta.persistence.PersistenceUnitTransactionType; +import org.hibernate.cfg.PersistenceSettings; import static jakarta.persistence.PersistenceUnitTransactionType.JTA; import static jakarta.persistence.PersistenceUnitTransactionType.RESOURCE_LOCAL; /** + * Helper for dealing with {@linkplain PersistenceUnitTransactionType}, mainly + * {@linkplain #interpretTransactionType interpretting} settings based on + * {@value PersistenceSettings#JAKARTA_TRANSACTION_TYPE}. + * + * @see org.hibernate.boot.jaxb.cfg.internal.TransactionTypeMarshalling + * * @author Steve Ebersole * @author Gavin King */ @@ -41,20 +48,4 @@ else if ( RESOURCE_LOCAL.name().equalsIgnoreCase( stringValue ) ) { } } } - - @SuppressWarnings("removal") - public static jakarta.persistence.spi.PersistenceUnitTransactionType toDeprecatedForm(PersistenceUnitTransactionType type) { - return type == null ? null : switch (type) { - case JTA -> jakarta.persistence.spi.PersistenceUnitTransactionType.JTA; - case RESOURCE_LOCAL -> jakarta.persistence.spi.PersistenceUnitTransactionType.RESOURCE_LOCAL; - }; - } - - @SuppressWarnings("removal") - public static PersistenceUnitTransactionType toNewForm(jakarta.persistence.spi.PersistenceUnitTransactionType type) { - return type == null ? null : switch (type) { - case JTA -> PersistenceUnitTransactionType.JTA; - case RESOURCE_LOCAL -> PersistenceUnitTransactionType.RESOURCE_LOCAL; - }; - } } diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderSqlAstCreationState.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderSqlAstCreationState.java index 6f6e364364e5..e8fc9cb81650 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderSqlAstCreationState.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderSqlAstCreationState.java @@ -14,6 +14,7 @@ import jakarta.persistence.CacheRetrieveMode; import jakarta.persistence.CacheStoreMode; +import jakarta.persistence.Timeout; import org.hibernate.FlushMode; import org.hibernate.LockMode; import org.hibernate.LockOptions; @@ -248,7 +249,7 @@ public SqlAstProcessingState getParentState() { } @Override - public Integer getTimeout() { + public Timeout getTimeout() { return null; } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java b/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java index 70076a3369df..419d7707d373 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java @@ -25,7 +25,7 @@ import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle; import org.hibernate.internal.util.collections.JoinedList; import org.hibernate.jdbc.Expectation; -import org.hibernate.jpa.event.spi.CallbackDefinition; +import org.hibernate.jpa.boot.spi.CallbackDefinition; import org.hibernate.metamodel.spi.RuntimeModelCreationContext; import org.hibernate.service.ServiceRegistry; import org.hibernate.sql.Alias; diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Property.java b/hibernate-core/src/main/java/org/hibernate/mapping/Property.java index b8089fea91d6..11219bbae85b 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Property.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Property.java @@ -4,12 +4,6 @@ */ package org.hibernate.mapping; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.Map; -import java.util.StringTokenizer; - import org.hibernate.HibernateException; import org.hibernate.Internal; import org.hibernate.MappingException; @@ -20,8 +14,9 @@ import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementHelper; import org.hibernate.engine.spi.CascadeStyle; import org.hibernate.engine.spi.CascadeStyles; -import org.hibernate.jpa.event.internal.EmbeddableCallback; -import org.hibernate.jpa.event.spi.CallbackDefinition; +import org.hibernate.generator.Generator; +import org.hibernate.generator.GeneratorCreationContext; +import org.hibernate.jpa.boot.spi.CallbackDefinition; import org.hibernate.metamodel.RepresentationMode; import org.hibernate.metamodel.spi.RuntimeModelCreationContext; import org.hibernate.models.spi.MemberDetails; @@ -31,17 +26,18 @@ import org.hibernate.property.access.spi.PropertyAccessStrategyResolver; import org.hibernate.property.access.spi.Setter; import org.hibernate.service.ServiceRegistry; -import org.hibernate.generator.Generator; -import org.hibernate.generator.GeneratorCreationContext; import org.hibernate.type.AnyType; import org.hibernate.type.CollectionType; import org.hibernate.type.ComponentType; +import org.hibernate.type.MappingContext; import org.hibernate.type.Type; import org.hibernate.type.WrapperArrayHandling; -import org.hibernate.type.MappingContext; -import static java.util.Collections.emptyList; -import static java.util.Collections.unmodifiableList; +import java.io.Serializable; +import java.util.EnumSet; +import java.util.Map; +import java.util.StringTokenizer; + import static org.hibernate.boot.model.internal.BinderHelper.renderCascadeTypeList; import static org.hibernate.cfg.MappingSettings.WRAPPER_ARRAY_HANDLING; import static org.hibernate.internal.util.StringHelper.isBlank; @@ -512,27 +508,6 @@ public void setLob(boolean lob) { this.lob = lob; } - /** - * @deprecated See discussion in {@link EmbeddableCallback}. - */ - @Deprecated(since = "7") - public void addCallbackDefinitions(java.util.List callbackDefinitions) { - if ( callbackDefinitions != null && !callbackDefinitions.isEmpty() ) { - if ( this.callbackDefinitions == null ) { - this.callbackDefinitions = new ArrayList<>(); - } - this.callbackDefinitions.addAll( callbackDefinitions ); - } - } - - /** - * @deprecated See discussion in {@link EmbeddableCallback}. - */ - @Deprecated(since = "7") - public java.util.List getCallbackDefinitions() { - return callbackDefinitions == null ? emptyList() : unmodifiableList( callbackDefinitions ); - } - public String getReturnedClassName() { return returnedClassName; } @@ -570,7 +545,6 @@ public Property copy() { property.setGeneric( isGeneric() ); property.setGenericSpecialization( isGenericSpecialization() ); property.setLob( isLob() ); - property.addCallbackDefinitions( getCallbackDefinitions() ); property.setReturnedClassName( getReturnedClassName() ); return property; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityMappingType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityMappingType.java index 6d39f18ec885..4b39146fe777 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityMappingType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityMappingType.java @@ -15,6 +15,7 @@ import org.hibernate.engine.OptimisticLockStyle; import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.event.jpa.spi.EntityCallbacks; import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.loader.ast.spi.Loadable; import org.hibernate.loader.ast.spi.MultiNaturalIdLoader; @@ -102,6 +103,13 @@ default EntityRepresentationStrategy getRepresentationStrategy() { */ TableDetails getIdentifierTableDetails(); + /** + * Access to the Jakarta Persistence style callbacks for this entity. + */ + default EntityCallbacks getEntityCallbacks() { + return getEntityPersister().getEntityCallbacks(); + } + /** * Visit details for each table associated with the entity. */ diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntityTypeImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntityTypeImpl.java index 6a7a91821778..49b1cee3209b 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntityTypeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntityTypeImpl.java @@ -11,10 +11,13 @@ import java.util.Collection; import java.util.List; import java.util.Locale; +import java.util.Map; +import jakarta.persistence.EntityGraph; import jakarta.persistence.metamodel.EntityType; import org.checkerframework.checker.nullness.qual.Nullable; +import org.hibernate.graph.internal.RootGraphImpl; import org.hibernate.mapping.PersistentClass; import org.hibernate.metamodel.UnsupportedMappingException; import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; @@ -125,6 +128,20 @@ public String getName() { return jpaEntityName; } + @Override + public EntityGraph createEntityGraph() { + return new RootGraphImpl<>( null, this, true ); + } + + @Override + public Map> getNamedEntityGraphs() { + if ( getJavaType() == null || getJavaType() == Map.class ) { + return Map.of(); + } + //noinspection unchecked,rawtypes + return (Map) metamodel.getNamedEntityGraphs( getJavaType() ); + } + @Override public Class getBindableJavaType() { return getJavaType(); 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 dee04d4063bd..d6d9b371f575 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 @@ -58,6 +58,8 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.event.jpa.internal.EntityCallbacksFactory; +import org.hibernate.event.jpa.spi.EntityCallbacks; import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.MergeContext; import org.hibernate.generator.BeforeExecutionGenerator; @@ -326,6 +328,8 @@ public abstract class AbstractEntityPersister private final String sqlAliasStem; private final String jpaEntityName; + private final EntityCallbacks jpaCallbacks; + private SingleIdEntityLoader singleIdLoader; private MultiIdEntityLoader multiIdLoader; private NaturalIdLoader naturalIdLoader; @@ -459,10 +463,17 @@ public AbstractEntityPersister( final PersistentClass persistentClass, final EntityDataAccess cacheAccessStrategy, final NaturalIdDataAccess naturalIdRegionAccessStrategy, - final RuntimeModelCreationContext creationContext) - throws HibernateException { + final RuntimeModelCreationContext creationContext) throws HibernateException { super( persistentClass, creationContext ); - jpaEntityName = persistentClass.getJpaEntityName(); + + final var factoryOptions = creationContext.getSessionFactoryOptions(); + + this.jpaEntityName = persistentClass.getJpaEntityName(); + this.jpaCallbacks = EntityCallbacksFactory.buildCallbacks( + persistentClass, + factoryOptions, + creationContext.getServiceRegistry() + ); //set it here, but don't call it, since it's still uninitialized! factory = creationContext.getSessionFactory(); @@ -471,8 +482,6 @@ public AbstractEntityPersister( navigableRole = new NavigableRole( persistentClass.getEntityName() ); - final var factoryOptions = creationContext.getSessionFactoryOptions(); - if ( factoryOptions.isSecondLevelCacheEnabled() ) { this.cacheAccessStrategy = cacheAccessStrategy; this.naturalIdRegionAccessStrategy = naturalIdRegionAccessStrategy; @@ -572,7 +581,7 @@ public AbstractEntityPersister( } else { sqlWhereStringTableExpression = - determineTableName( getCountainingClass( persistentClass ).getTable() ); + determineTableName( getContainingClass( persistentClass ).getTable() ); sqlWhereStringTemplate = renderSqlWhereStringTemplate( persistentClass, dialect, typeConfiguration ); } @@ -769,6 +778,11 @@ else if ( selectable instanceof Column column ) { } } + @Override + public EntityCallbacks getEntityCallbacks() { + return jpaCallbacks; + } + private static String renderSqlWhereStringTemplate( PersistentClass persistentClass, Dialect dialect, TypeConfiguration typeConfiguration) { return Template.renderWhereStringTemplate( @@ -778,7 +792,7 @@ private static String renderSqlWhereStringTemplate( ); } - private static PersistentClass getCountainingClass(PersistentClass persistentClass) { + private static PersistentClass getContainingClass(PersistentClass persistentClass) { var containingClass = persistentClass; while ( containingClass.getSuperclass() != null ) { final var superclass = containingClass.getSuperclass(); diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/ProcedureCall.java b/hibernate-core/src/main/java/org/hibernate/procedure/ProcedureCall.java index 4b884023b6c1..c081de464f87 100644 --- a/hibernate-core/src/main/java/org/hibernate/procedure/ProcedureCall.java +++ b/hibernate-core/src/main/java/org/hibernate/procedure/ProcedureCall.java @@ -8,11 +8,13 @@ import java.util.Date; import java.util.List; +import jakarta.persistence.AttributeConverter; import jakarta.persistence.FlushModeType; import jakarta.persistence.Parameter; import jakarta.persistence.ParameterMode; import jakarta.persistence.StoredProcedureQuery; import jakarta.persistence.TemporalType; +import jakarta.persistence.Timeout; import jakarta.persistence.metamodel.Type; import org.hibernate.Incubating; @@ -254,6 +256,15 @@ default void close() { /* Covariant overrides */ + @Override + ProcedureCall setTimeout(Integer integer); + + @Override + ProcedureCall setTimeout(int timeout); + + @Override + ProcedureCall setTimeout(Timeout timeout); + @Override ProcedureCall addSynchronizedQuerySpace(String querySpace); @@ -284,9 +295,27 @@ default void close() { @Override @Deprecated ProcedureCall setParameter(String name, Date value, TemporalType temporalType); + @Override +

ProcedureCall setParameter(String name, P value, Class

type); + + @Override +

ProcedureCall setParameter(String name, P value, Type

type); + + @Override +

ProcedureCall setConvertedParameter(String name, P value, Class> converter); + @Override ProcedureCall setParameter(int position, Object value); + @Override +

ProcedureCall setConvertedParameter(int position, P value, Class> converter); + + @Override +

ProcedureCall setParameter(int position, P value, Class

type); + + @Override +

ProcedureCall setParameter(int position, P value, Type

type); + @Override @Deprecated ProcedureCall setParameter(int position, Calendar value, TemporalType temporalType); diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/internal/EntityDomainResultBuilder.java b/hibernate-core/src/main/java/org/hibernate/procedure/internal/EntityDomainResultBuilder.java index f5b77b6f44b2..dd47544f4f6f 100644 --- a/hibernate-core/src/main/java/org/hibernate/procedure/internal/EntityDomainResultBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/procedure/internal/EntityDomainResultBuilder.java @@ -7,8 +7,8 @@ import org.hibernate.LockMode; import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; import org.hibernate.metamodel.mapping.EntityMappingType; -import org.hibernate.query.results.FetchBuilderBasicValued; -import org.hibernate.query.results.ResultBuilder; +import org.hibernate.query.results.spi.FetchBuilderBasicValued; +import org.hibernate.query.results.spi.ResultBuilder; import org.hibernate.query.results.internal.complete.EntityResultImpl; import org.hibernate.query.results.internal.implicit.ImplicitFetchBuilderBasic; import org.hibernate.spi.NavigablePath; diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/internal/NamedCallableQueryMementoImpl.java b/hibernate-core/src/main/java/org/hibernate/procedure/internal/NamedCallableQueryMementoImpl.java index b019056b1285..0194f97c3150 100644 --- a/hibernate-core/src/main/java/org/hibernate/procedure/internal/NamedCallableQueryMementoImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/procedure/internal/NamedCallableQueryMementoImpl.java @@ -9,7 +9,7 @@ import java.util.Set; import jakarta.persistence.ParameterMode; -import org.hibernate.CacheMode; +import jakarta.persistence.Timeout;import org.hibernate.CacheMode; import org.hibernate.FlushMode; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.type.BindableType; @@ -56,7 +56,7 @@ public NamedCallableQueryMementoImpl( CacheMode cacheMode, FlushMode flushMode, Boolean readOnly, - Integer timeout, + Timeout timeout, Integer fetchSize, String comment, Map hints) { diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureCallImpl.java b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureCallImpl.java index 17f2f6dd7c0c..9f0575700583 100644 --- a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureCallImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureCallImpl.java @@ -17,6 +17,7 @@ import java.util.stream.Stream; import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Timeout; import org.hibernate.HibernateException; import org.hibernate.LockOptions; import org.hibernate.ScrollMode; @@ -47,7 +48,7 @@ import org.hibernate.query.QueryParameter; import org.hibernate.query.internal.QueryOptionsImpl; import org.hibernate.procedure.ProcedureParameter; -import org.hibernate.query.results.ResultSetMapping; +import org.hibernate.query.results.spi.ResultSetMapping; import org.hibernate.query.spi.AbstractQuery; import org.hibernate.query.spi.MutableQueryOptions; import org.hibernate.query.spi.QueryImplementor; @@ -93,7 +94,7 @@ import static org.hibernate.procedure.internal.Util.resolveResultSetMappingClasses; import static org.hibernate.procedure.internal.Util.resolveResultSetMappingNames; import static org.hibernate.procedure.internal.Util.resolveResultSetMappings; -import static org.hibernate.query.results.ResultSetMapping.resolveResultSetMapping; +import static org.hibernate.query.results.spi.ResultSetMapping.resolveResultSetMapping; /** * Standard implementation of {@link ProcedureCall} @@ -119,22 +120,6 @@ public class ProcedureCallImpl private ProcedureOutputsImpl outputs; - private static String mappingId(String procedureName, Class[] resultClasses) { - assert resultClasses != null && resultClasses.length > 0; - return procedureName + ":" + join( ",", resultClasses ); - } - - private static String mappingId(String procedureName, String[] resultSetMappingNames) { - assert resultSetMappingNames != null && resultSetMappingNames.length > 0; - return procedureName + ":" + join( ",", resultSetMappingNames ); - } - - private void registerParameters(SharedSessionContractImplementor session, NamedCallableQueryMemento memento) { - for ( var parameterMemento : memento.getParameterMementos() ) { - registerParameter( parameterMemento.resolve( session ) ); - } - } - private ProcedureCallImpl( SharedSessionContractImplementor session, String procedureName, @@ -276,6 +261,22 @@ public ProcedureCallImpl( applyOptions( memento ); } + private static String mappingId(String procedureName, Class[] resultClasses) { + assert resultClasses != null && resultClasses.length > 0; + return procedureName + ":" + join( ",", resultClasses ); + } + + private static String mappingId(String procedureName, String[] resultSetMappingNames) { + assert resultSetMappingNames != null && resultSetMappingNames.length > 0; + return procedureName + ":" + join( ",", resultSetMappingNames ); + } + + private void registerParameters(SharedSessionContractImplementor session, NamedCallableQueryMemento memento) { + for ( var parameterMemento : memento.getParameterMementos() ) { + registerParameter( parameterMemento.resolve( session ) ); + } + } + private void applyCallableFunctionHint() { final List> resultTypes = new ArrayList<>(); resultSetMapping.visitResultBuilders( @@ -341,6 +342,14 @@ private void markAsFunctionCallRefRefCursor() { functionReturn = new FunctionReturnImpl<>( this, Types.REF_CURSOR ); } + @Override + public Parameter registerResultParameter(Class aClass) { + //noinspection resource + markAsFunctionCall( aClass ); + //noinspection unchecked + return (Parameter) functionReturn; + } + @Override public ProcedureCallImpl markAsFunctionCall(Class resultType) { final var basicType = getTypeConfiguration().getBasicTypeForJavaType( resultType ); @@ -543,6 +552,16 @@ public ProcedureParameterImplementor registerParameter(String name, Class return parameter; } + @Override + public Parameter registerConvertedParameter(int position, Class> converter, ParameterMode mode) { + throw new UnsupportedOperationException( "Not implemented yet" ); + } + + @Override + public Parameter registerConvertedParameter(String parameterName, Class> converter, ParameterMode mode) { + throw new UnsupportedOperationException( "Not implemented yet" ); + } + private Class getExpressibleJavaType(Type parameterType) { if ( parameterType == null ) { return null; @@ -793,7 +812,7 @@ public NamedCallableQueryMemento toMemento(String name) { getCacheMode(), getQueryOptions().getFlushMode(), isReadOnly(), - getTimeout(), + getQueryOptions().getTimeout(), getFetchSize(), getComment(), getHints() @@ -886,6 +905,11 @@ public Object getOutputParameterValue(String parameterName) { } } + @Override + public T getOutputParameterValue(Parameter parameter) { + return getOutputs().getOutputParameterValue( (ProcedureParameter) parameter ); + } + @Override public boolean hasMoreResults() { final var outputs = getOutputs(); @@ -975,6 +999,18 @@ public List getResultList() { return doList(); } + @Override + public List getResultList(Class type) { + //noinspection unchecked + return (List) doList(); + } + + @Override + public List getResultList(jakarta.persistence.sql.ResultSetMapping resultSetMapping) { + //noinspection unchecked + return (List) doList(); + } + @Override public R getSingleResult() { final var resultList = getResultList(); @@ -989,6 +1025,18 @@ else if ( resultList.size() > 1 ) { return resultList.get( 0 ); } + @Override + public R1 getSingleResult(Class aClass) { + //noinspection unchecked + return (R1) getSingleResult(); + } + + @Override + public R1 getSingleResult(jakarta.persistence.sql.ResultSetMapping resultSetMapping) { + //noinspection unchecked + return (R1) getSingleResult(); + } + @Override public R getSingleResultOrNull() { final var resultList = getResultList(); @@ -1002,6 +1050,18 @@ else if ( resultList.size() > 1 ) { return resultList.get( 0 ); } + @Override + public R1 getSingleResultOrNull(Class aClass) { + //noinspection unchecked + return (R1) getSingleResultOrNull(); + } + + @Override + public R1 getSingleResultOrNull(jakarta.persistence.sql.ResultSetMapping resultSetMapping) { + //noinspection unchecked + return (R1) getSingleResultOrNull(); + } + @Override public T unwrap(Class type) { if ( type.isInstance( this ) ) { @@ -1051,6 +1111,18 @@ public ProcedureCallImplementor setTimeout(Integer timeout) { return this; } + @Override + public ProcedureCallImplementor setTimeout(int timeout) { + super.setTimeout( timeout ); + return this; + } + + @Override + public ProcedureCallImplementor setTimeout(Timeout timeout) { + super.setTimeout( timeout ); + return this; + } + @Override public LockModeType getLockMode() { // the JPA spec requires IllegalStateException here, even @@ -1126,12 +1198,36 @@ public ProcedureCallImplementor setParameter(String name, Object value) { return this; } + @Override + public

ProcedureCallImplementor setParameter(String name, P value, Class

javaTypeClass) { + super.setParameter( name, value, javaTypeClass ); + return this; + } + + @Override + public

ProcedureCallImplementor setConvertedParameter(String name, P value, Class> converter) { + super.setConvertedParameter( name, value, converter ); + return this; + } + @Override public ProcedureCallImplementor setParameter(int position, Object value) { super.setParameter( position, value ); return this; } + @Override + public

ProcedureCallImplementor setParameter(int position, P value, Class

javaTypeClass) { + super.setParameter( position, value, javaTypeClass ); + return this; + } + + @Override + public

ProcedureCallImplementor setConvertedParameter(int position, P value, Class> converter) { + super.setConvertedParameter( position, value, converter ); + return this; + } + @Override public

ProcedureCallImplementor setParameter( QueryParameter

parameter, diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ScalarDomainResultBuilder.java b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ScalarDomainResultBuilder.java index 27508941a6bc..b9614fb54cdd 100644 --- a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ScalarDomainResultBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ScalarDomainResultBuilder.java @@ -5,7 +5,7 @@ package org.hibernate.procedure.internal; import org.hibernate.metamodel.mapping.BasicValuedMapping; -import org.hibernate.query.results.ResultBuilder; +import org.hibernate.query.results.spi.ResultBuilder; import org.hibernate.query.results.internal.ResultSetMappingSqlSelection; import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResultCreationState; diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/internal/Util.java b/hibernate-core/src/main/java/org/hibernate/procedure/internal/Util.java index 319ff33ac5ca..bca8a403030c 100644 --- a/hibernate-core/src/main/java/org/hibernate/procedure/internal/Util.java +++ b/hibernate-core/src/main/java/org/hibernate/procedure/internal/Util.java @@ -8,7 +8,7 @@ import org.hibernate.query.UnknownSqlResultSetMappingException; import org.hibernate.query.internal.ResultSetMappingResolutionContext; -import org.hibernate.query.results.ResultSetMapping; +import org.hibernate.query.results.spi.ResultSetMapping; import static org.hibernate.internal.util.collections.ArrayHelper.isEmpty; diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/spi/ProcedureCallImplementor.java b/hibernate-core/src/main/java/org/hibernate/procedure/spi/ProcedureCallImplementor.java index f9530c711aec..e6117a45a5d7 100644 --- a/hibernate-core/src/main/java/org/hibernate/procedure/spi/ProcedureCallImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/procedure/spi/ProcedureCallImplementor.java @@ -8,6 +8,8 @@ import java.util.Date; import java.util.List; +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Timeout; import org.hibernate.procedure.ProcedureCall; import org.hibernate.query.named.NameableQuery; import org.hibernate.query.spi.ProcedureParameterMetadataImplementor; @@ -74,6 +76,15 @@ default List getResultList() { @Override @Deprecated ProcedureCallImplementor setParameter(String name, Date value, TemporalType temporalType); + @Override +

ProcedureCallImplementor setParameter(String name, P value, Class

type); + + @Override +

ProcedureCallImplementor setParameter(String name, P value, Type

type); + + @Override +

ProcedureCallImplementor setConvertedParameter(String name, P value, Class> converter); + @Override ProcedureCallImplementor setParameter(int position, Object value); @@ -83,6 +94,15 @@ default List getResultList() { @Override @Deprecated ProcedureCallImplementor setParameter(int position, Date value, TemporalType temporalType); + @Override +

ProcedureCallImplementor setConvertedParameter(int position, P value, Class> converter); + + @Override +

ProcedureCallImplementor setParameter(int position, P value, Class

type); + + @Override +

ProcedureCallImplementor setParameter(int position, P value, Type

type); + @Override ProcedureCallImplementor setFlushMode(FlushModeType flushMode); @@ -94,6 +114,8 @@ default List getResultList() { @Override ProcedureCallImplementor setTimeout(Integer timeout); + ProcedureCallImplementor setTimeout(int timeout); + ProcedureCallImplementor setTimeout(Timeout timeout); @Override NamedCallableQueryMemento toMemento(String name); diff --git a/hibernate-core/src/main/java/org/hibernate/query/CommonQueryContract.java b/hibernate-core/src/main/java/org/hibernate/query/CommonQueryContract.java index 4986bcaaf28f..b6020d6e55eb 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/CommonQueryContract.java +++ b/hibernate-core/src/main/java/org/hibernate/query/CommonQueryContract.java @@ -10,6 +10,7 @@ import java.util.Date; import java.util.Map; +import jakarta.persistence.AttributeConverter; import jakarta.persistence.Timeout; import org.hibernate.FlushMode; import org.hibernate.Session; @@ -268,6 +269,10 @@ public interface CommonQueryContract { */

CommonQueryContract setParameter(String parameter, P value, Type

type); +

CommonQueryContract setConvertedParameter(String name, P value, Class> converter); + +

CommonQueryContract setConvertedParameter(int position, P value, Class> converter); + /** * Bind an {@link Instant} to the named query parameter using just the * portion indicated by the given {@link TemporalType}. diff --git a/hibernate-core/src/main/java/org/hibernate/query/MutationQuery.java b/hibernate-core/src/main/java/org/hibernate/query/MutationQuery.java index 2826c65f07b5..931e7be42127 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/MutationQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/MutationQuery.java @@ -10,6 +10,7 @@ import java.util.Date; import java.util.Map; +import jakarta.persistence.AttributeConverter; import org.hibernate.FlushMode; import org.hibernate.Incubating; @@ -27,14 +28,14 @@ * A {@code MutationQuery} may be obtained from the {@link org.hibernate.Session} * by calling: *

    - *
  • {@link QueryProducer#createMutationQuery(String)}, passing the HQL as a + *
  • {@link org.hibernate.SharedSessionContract#createMutationQuery(String)}, passing the HQL as a * string, - *
  • {@link QueryProducer#createNativeMutationQuery(String)}, passing native + *
  • {@link org.hibernate.SharedSessionContract#createNativeMutationQuery(String)}, passing native * SQL as a string, - *
  • {@link QueryProducer#createMutationQuery(jakarta.persistence.criteria.CriteriaUpdate)} or - * {@link QueryProducer#createMutationQuery(jakarta.persistence.criteria.CriteriaDelete)}, + *
  • {@link org.hibernate.SharedSessionContract#createMutationQuery(jakarta.persistence.criteria.CriteriaUpdate)} or + * {@link org.hibernate.SharedSessionContract#createMutationQuery(jakarta.persistence.criteria.CriteriaDelete)}, * passing a criteria update or delete object, or - *
  • {@link QueryProducer#createNamedMutationQuery(String)}, passing the + *
  • {@link org.hibernate.SharedSessionContract#createNamedMutationQuery(String)}, passing the * name of a query defined using {@link jakarta.persistence.NamedQuery} or * {@link jakarta.persistence.NamedNativeQuery}. *
@@ -63,18 +64,18 @@ public interface MutationQuery extends CommonQueryContract { * number of affected entities. *

* For use with instances of {@code MutationQuery} created using - * {@link QueryProducer#createMutationQuery(String)}, - * {@link QueryProducer#createNamedMutationQuery(String)}, - * {@link QueryProducer#createNativeMutationQuery(String)}, - * {@link QueryProducer#createQuery(jakarta.persistence.criteria.CriteriaUpdate)}, or - * {@link QueryProducer#createQuery(jakarta.persistence.criteria.CriteriaDelete)}. + * {@link org.hibernate.SharedSessionContract#createMutationQuery(String)}, + * {@link org.hibernate.SharedSessionContract#createNamedMutationQuery(String)}, + * {@link org.hibernate.SharedSessionContract#createNativeMutationQuery(String)}, + * {@link org.hibernate.SharedSessionContract#createQuery(jakarta.persistence.criteria.CriteriaUpdate)}, or + * {@link org.hibernate.SharedSessionContract#createQuery(jakarta.persistence.criteria.CriteriaDelete)}. * * @return the number of affected entity instances * (may differ from the number of affected rows) * - * @see QueryProducer#createMutationQuery(String) - * @see QueryProducer#createNamedMutationQuery(String) - * @see QueryProducer#createNativeMutationQuery(String) + * @see org.hibernate.SharedSessionContract#createMutationQuery(String) + * @see org.hibernate.SharedSessionContract#createNamedMutationQuery(String) + * @see org.hibernate.SharedSessionContract#createNativeMutationQuery(String) * * @see jakarta.persistence.Query#executeUpdate() */ @@ -99,6 +100,12 @@ public interface MutationQuery extends CommonQueryContract { @Override MutationQuery setHint(String hintName, Object value); + @Override +

MutationQuery setConvertedParameter(String name, P value, Class> converter); + + @Override +

MutationQuery setConvertedParameter(int position, P value, Class> converter); + @Override MutationQuery setParameter(String name, Object value); diff --git a/hibernate-core/src/main/java/org/hibernate/query/Query.java b/hibernate-core/src/main/java/org/hibernate/query/Query.java index 6ba4694b6871..a1bc78a1c1f1 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/Query.java +++ b/hibernate-core/src/main/java/org/hibernate/query/Query.java @@ -13,6 +13,7 @@ import java.util.Optional; import java.util.stream.Stream; +import jakarta.persistence.AttributeConverter; import jakarta.persistence.EntityGraph; import jakarta.persistence.PessimisticLockScope; import jakarta.persistence.Timeout; @@ -60,12 +61,12 @@ * A {@code Query} may be obtained from the {@link org.hibernate.Session} by * calling: *

    - *
  • {@link QueryProducer#createQuery(String, Class)}, passing the HQL as a + *
  • {@link org.hibernate.SharedSessionContract#createQuery(String, Class)}, passing the HQL as a * string, - *
  • {@link QueryProducer#createQuery(jakarta.persistence.criteria.CriteriaQuery)}, + *
  • {@link org.hibernate.SharedSessionContract#createQuery(jakarta.persistence.criteria.CriteriaQuery)}, * passing a {@linkplain jakarta.persistence.criteria.CriteriaQuery criteria * object}, or - *
  • {@link QueryProducer#createNamedQuery(String, Class)} passing the name + *
  • {@link org.hibernate.SharedSessionContract#createNamedQuery(String, Class)} passing the name * of a query defined using {@link jakarta.persistence.NamedQuery} or * {@link jakarta.persistence.NamedNativeQuery}. *
@@ -89,8 +90,6 @@ * @author Steve Ebersole * * @param The result type, for typed queries, or {@link Object} for untyped queries - * - * @see QueryProducer */ @Incubating public interface Query extends SelectionQuery, MutationQuery, TypedQuery { @@ -227,11 +226,11 @@ default Stream stream() { * number of affected entities. *

* For use with instances of {@link MutationQuery} created using - * {@link QueryProducer#createMutationQuery(String)}, - * {@link QueryProducer#createNamedMutationQuery(String)}, - * {@link QueryProducer#createNativeMutationQuery(String)}, - * {@link QueryProducer#createMutationQuery(jakarta.persistence.criteria.CriteriaUpdate)}, or - * {@link QueryProducer#createMutationQuery(jakarta.persistence.criteria.CriteriaDelete)}. + * {@link org.hibernate.SharedSessionContract#createMutationQuery(String)}, + * {@link org.hibernate.SharedSessionContract#createNamedMutationQuery(String)}, + * {@link org.hibernate.SharedSessionContract#createNativeMutationQuery(String)}, + * {@link org.hibernate.SharedSessionContract#createMutationQuery(jakarta.persistence.criteria.CriteriaUpdate)}, or + * {@link org.hibernate.SharedSessionContract#createMutationQuery(jakarta.persistence.criteria.CriteriaDelete)}. * * @return the number of affected entity instances * (may differ from the number of affected rows) @@ -240,21 +239,13 @@ default Stream stream() { * {@link jakarta.persistence.Query}, which defines this method. * See {@link MutationQuery} and {@link SelectionQuery}. * - * @see QueryProducer#createMutationQuery - * @see QueryProducer#createMutationQuery(String) - * @see QueryProducer#createNamedMutationQuery(String) - * @see QueryProducer#createNativeMutationQuery(String) - * @see QueryProducer#createMutationQuery(jakarta.persistence.criteria.CriteriaUpdate) - * @see QueryProducer#createMutationQuery(jakarta.persistence.criteria.CriteriaDelete) - * * @see jakarta.persistence.Query#executeUpdate() */ @Override int executeUpdate(); /** - * Get the {@link QueryProducer} which produced this {@code Query}, - * that is, the {@link org.hibernate.Session} or + * Get the {@link org.hibernate.Session} or * {@link org.hibernate.StatelessSession} that was used to create * this {@code Query} instance. * @@ -430,6 +421,12 @@ default Query applyLoadGraph(@SuppressWarnings("rawtypes") RootGraph graph) { */ QueryOptions getQueryOptions(); + @Override +

Query setConvertedParameter(String name, P value, Class> converter); + + @Override +

Query setConvertedParameter(int position, P value, Class> converter); + /** * Bind the given argument to a named query parameter. *

@@ -922,6 +919,11 @@ default Query setPage(Page page) { @Override Query setHint(String hintName, Object value); + @Override + default Query setEntityGraph(EntityGraph entityGraph) { + return setEntityGraph( entityGraph, GraphSemantic.LOAD ); + } + @Override Query setEntityGraph(EntityGraph graph, GraphSemantic semantic); diff --git a/hibernate-core/src/main/java/org/hibernate/query/QueryProducer.java b/hibernate-core/src/main/java/org/hibernate/query/QueryProducer.java deleted file mode 100644 index 1c211239818b..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/query/QueryProducer.java +++ /dev/null @@ -1,620 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.query; - -import jakarta.persistence.EntityGraph; -import jakarta.persistence.TypedQueryReference; -import jakarta.persistence.criteria.CriteriaDelete; -import jakarta.persistence.criteria.CriteriaQuery; -import jakarta.persistence.criteria.CriteriaUpdate; -import org.hibernate.query.criteria.JpaCriteriaInsert; - -/** - * An object which can produce instances of {@link SelectionQuery} and {@link MutationQuery}. - * Implementors include {@link org.hibernate.Session} and {@link org.hibernate.StatelessSession}. - * Many operations of the interface have the same or very similar signatures to operations of - * {@link jakarta.persistence.EntityManager}. They are declared here to allow reuse by - * {@code StatelessSession}. - *

- * There are three fundamental ways to express a query: - *

    - *
  • in Hibernate Query Language, an object-oriented query dialect of SQL which is - * a superset of the Jakarta Persistence Query Language, - *
  • in the native SQL dialect of the database, or - *
  • using the {@linkplain jakarta.persistence.criteria.CriteriaBuilder Criteria API} defined - * by JPA, along with {@linkplain org.hibernate.query.criteria.HibernateCriteriaBuilder - * extensions} defined by Hibernate. - *
- *

- * In each case, the object used to execute the query depends on whether the query is a - * selection query or a mutation query. - *

    - *
  • selection queries are executed via an instance of {@link SelectionQuery}, while - *
  • mutation queries are executed via an instance of {@link MutationQuery}, but - *
  • since JPA makes no such distinction within its API, the type {@link Query} is a mixin of - * {@code SelectionQuery}, {@code MutationQuery}, and {@link jakarta.persistence.TypedQuery}. - *
- * This interface declares operations for creating instances of these objects. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
SelectionMutation
HQL{@link #createSelectionQuery(String,Class)} and - * {@link #createSelectionQuery(String,EntityGraph)}{@link #createMutationQuery(String)}
SQL{@link #createNativeQuery(String,Class)} and - * {@link #createNativeQuery(String,String,Class)}{@link #createNativeMutationQuery(String)}
Criteria{@link #createSelectionQuery(CriteriaQuery)}{@link #createMutationQuery(CriteriaUpdate)}, - * {@link #createMutationQuery(CriteriaDelete)}, and - * {@link #createMutationQuery(JpaCriteriaInsert)}
Named queries{@link #createNamedSelectionQuery(String,Class)}{@link #createNamedMutationQuery(String)}
- *

- * Operations like {@link #createSelectionQuery(String, Class) createSelectionQuery()}, - * {@link #createNamedSelectionQuery(String, Class) createNamedSelectionQuery()}, and - * {@link #createNativeQuery(String, Class) createNativeQuery()} accept a Java - * {@linkplain Class class object} indicating the result type of the query. - *

    - *
  • The result type might be an {@linkplain jakarta.persistence.Entity entity} class, when - * the query returns an entity: - *
    - * List<Book> allBooks =
    - *         session.createNativeQuery("select * from books order by title", Book.class)
    - *                 .getResultList();
    - * 
    - *
  • It might be a {@linkplain org.hibernate.type.descriptor.java.JavaType basic type} like - * {@code String} or {@code Long}: - *
    - * List<String> allTitles =
    - *         session.createNativeQuery("select distinct title from books order by title", String.class)
    - *                 .getResultList();
    - * 
    - *
  • Finally, the result type might be a class used to package the elements of a {@code select} - * list, such as a Java record with an appropriate constructor, {@code Map}, {@code List}, or - * {@code Object[]}: - *
    - * record IsbnAndTitle(String isbn, String title) {}
    - *
    - * List<IsbnAndTitle> allBooks =
    - *         session.createNativeQuery("select isbn, title from books order by title", IsbnAndTitle.class)
    - *                 .getResultList();
    - * 
    - *
- * For a {@linkplain #createQuery(CriteriaQuery) criteria query}, the result type is already - * determined by {@link CriteriaQuery#getResultType()}. - * - * @apiNote Unlike the corresponding operations of {@code EntityManager}, operations for creating - * untyped instances of {@code Query} are all marked as deprecated. Clients must migrate to the - * use of the equivalent operations which accept a {@link Class} and return a typed {@code Query}. - * - * @author Steve Ebersole - */ -public interface QueryProducer { - /** - * Create a {@link Query} instance for the given HQL query, or - * HQL insert, update, or delete statement. - *

- * If a query has no explicit {@code select} list, the select list - * is inferred: - *

    - *
  • if there is exactly one root entity in the {@code from} - * clause, and it has no non-{@code fetch} joins, then that - * root entity is the only element of the select list, or - *
  • if there is an entity with the alias {@code this}, then - * that entity is the only element of the select list, or - *
  • otherwise, the query is considered ambiguous, and this - * method throws a {@link SemanticException}. - *
- *

- * The query must have an explicit {@code from} clause, which - * can never be inferred. - * - * @deprecated The overloaded form - * {@link #createQuery(String, Class)} which takes a result type - * is strongly recommended in preference to this method, since it - * returns a typed {@code Query} object, and because it is able to - * use the given result type to infer the {@code select} list, and - * even sometimes the {@code from} clause. Alternatively, - * {@link #createSelectionQuery(String, Class)} is preferred for - * queries, and {@link #createMutationQuery(String)} for insert, - * update, and delete statements. - * - * @apiNote Returns a raw {@code Query} type instead of a wildcard - * type {@code Query}, to match the signature of the JPA method - * {@link jakarta.persistence.EntityManager#createQuery(String)}. - * - * @param queryString The HQL query - * - * @return The {@link Query} instance for manipulation and execution - * - * @see jakarta.persistence.EntityManager#createQuery(String) - */ - @Deprecated(since = "6.0") @SuppressWarnings("rawtypes") - Query createQuery(String queryString); - - /** - * Create a typed {@link Query} instance for the given HQL query - * string and given query result type. - *

    - *
  • If the query has a single item in the {@code select} list, - * then the select item must be assignable to the given result - * type. - *
  • Otherwise, if there are multiple select items, then the - * select items will be packaged into an instance of the - * result type. The result type must have an appropriate - * constructor with parameter types matching the select items, - * or it must be one of the types {@code Object[]}, - * {@link java.util.List}, {@link java.util.Map}, or - * {@link jakarta.persistence.Tuple}. - *
- *

- * If a query has no explicit {@code select} list, the select list - * is inferred from the given query result type: - *

    - *
  • if the result type is an entity type, the query must have - * exactly one root entity in the {@code from} clause, it must - * be assignable to the result type, and the inferred select - * list will contain just that entity, or - *
  • otherwise, the select list contains every root entity and - * every non-{@code fetch} joined entity, and each query result - * will be packaged into an instance of the result type, just - * as specified above. - *
- *

- * If a query has no explicit {@code from} clause, and the given - * result type is an entity type, the root entity is inferred to - * be the result type. - *

- * Passing {@code Object.class} as the query result type is not - * recommended. In this special case, this method has the same - * semantics as the overload {@link #createQuery(String)}. - *

- * The returned {@code Query} may be executed by calling - * {@link Query#getResultList()} or {@link Query#getSingleResult()}. - * - * @param queryString The HQL query - * @param resultClass The {@link Class} object representing the - * query result type, which should not be - * {@code Object.class} - * @return The {@link Query} instance for manipulation and execution - * - * @see jakarta.persistence.EntityManager#createQuery(String,Class) - */ - Query createQuery(String queryString, Class resultClass); - - /** - * Create a typed {@link Query} instance for the given typed query reference. - * - * @param typedQueryReference the type query reference - * - * @return The {@link Query} instance for execution - * - * @throws IllegalArgumentException if a query has not been - * defined with the name of the typed query reference or if - * the query result is found to not be assignable to - * result class of the typed query reference - * - * @see jakarta.persistence.EntityManager#createQuery(TypedQueryReference) - */ - Query createQuery(TypedQueryReference typedQueryReference); - - /** - * Create a {@link Query} for the given JPA {@link CriteriaQuery}. - */ - Query createQuery(CriteriaQuery criteriaQuery); - - /** - * Create a {@link MutationQuery} for the given JPA {@link CriteriaUpdate} - * - * @deprecated use {@link #createMutationQuery(CriteriaUpdate)} - */ - @Deprecated(since = "6.0") @SuppressWarnings("rawtypes") - Query createQuery(CriteriaUpdate updateQuery); - - /** - * Create a {@link MutationQuery} for the given JPA {@link CriteriaDelete} - * - * @deprecated use {@link #createMutationQuery(CriteriaDelete)} - */ - @Deprecated(since = "6.0") @SuppressWarnings("rawtypes") - Query createQuery(CriteriaDelete deleteQuery); - - /** - * Create a {@link NativeQuery} instance for the given native SQL query. - * - * @param sqlString a native SQL query string - * - * @return The {@link NativeQuery} instance for manipulation and execution - * - * @see jakarta.persistence.EntityManager#createNativeQuery(String) - * - * @deprecated use {@link #createNativeQuery(String, Class)} - */ - @Deprecated(since = "6.0") @SuppressWarnings("rawtypes") - NativeQuery createNativeQuery(String sqlString); - - /** - * Create a {@link NativeQuery} instance for the given native SQL query - * using an implicit mapping to the specified Java type. - *

    - *
  • If the given class is an entity class, this method is equivalent - * to {@code createNativeQuery(sqlString).addEntity(resultClass)}. - *
  • If the given class has a registered - * {@link org.hibernate.type.descriptor.java.JavaType}, then the - * query must return a result set with a single column whose - * {@code JdbcType} is compatible with that {@code JavaType}. - *
  • Otherwise, the select items will be packaged into an instance of - * the result type. The result type must have an appropriate - * constructor with parameter types matching the select items, or it - * must be one of the types {@code Object[]}, {@link java.util.List}, - * {@link java.util.Map}, or {@link jakarta.persistence.Tuple}. - *
- * - * @param sqlString The native (SQL) query string - * @param resultClass The Java type to map results to - * - * @return The {@link NativeQuery} instance for manipulation and execution - * - * @see jakarta.persistence.EntityManager#createNativeQuery(String,Class) - */ - NativeQuery createNativeQuery(String sqlString, Class resultClass); - - /** - * Create a {@link NativeQuery} instance for the given native SQL query - * using an implicit mapping to the specified Java entity type. - *

- * The given class must be an entity class. This method is equivalent to - * {@code createNativeQuery(sqlString).addEntity(tableAlias, resultClass)}. - * - * @param sqlString Native (SQL) query string - * @param resultClass The Java entity class to map results to - * @param tableAlias The table alias for columns in the result set - * - * @return The {@link NativeQuery} instance for manipulation and execution - * - * @see jakarta.persistence.EntityManager#createNativeQuery(String,Class) - */ - NativeQuery createNativeQuery(String sqlString, Class resultClass, String tableAlias); - - /** - * Create a {@link NativeQuery} instance for the given native SQL query - * using an explicit mapping to the specified Java type. - *

- * The given result set mapping name must identify a mapping defined by - * a {@link jakarta.persistence.SqlResultSetMapping} annotation. - * - * @param sqlString The native (SQL) query string - * @param resultSetMappingName The explicit result mapping name - * - * @return The {@link NativeQuery} instance for manipulation and execution - * - * @see jakarta.persistence.EntityManager#createNativeQuery(String,Class) - * @see jakarta.persistence.SqlResultSetMapping - * - * @deprecated use {@link #createNativeQuery(String, String, Class)} - */ - @Deprecated(since = "6.0") @SuppressWarnings("rawtypes") - NativeQuery createNativeQuery(String sqlString, String resultSetMappingName); - - /** - * Create a {@link NativeQuery} instance for the given native SQL query - * using an explicit mapping to the specified Java type. - *

- * The given result set mapping name must identify a mapping defined by - * a {@link jakarta.persistence.SqlResultSetMapping} annotation. - * - * @param sqlString The native (SQL) query string - * @param resultSetMappingName The explicit result mapping name - * - * @return The {@link NativeQuery} instance for manipulation and execution - * - * @see jakarta.persistence.EntityManager#createNativeQuery(String,Class) - * @see jakarta.persistence.SqlResultSetMapping - */ - NativeQuery createNativeQuery(String sqlString, String resultSetMappingName, Class resultClass); - - /** - * Create a {@link SelectionQuery} reference for the given HQL - * {@code select} statement. - *

- * If the statement has no explicit {@code select} list, the - * select list is inferred: - *

    - *
  • if there is exactly one root entity in the {@code from} - * clause, and it has no non-{@code fetch} joins, then that - * root entity is the only element of the select list, or - *
  • if there is an entity with the alias {@code this}, then - * that entity is the only element of the select list, or - *
  • otherwise, the query is considered ambiguous, and this - * method throws a {@link SemanticException}. - *
- *

- * The query must have an explicit {@code from} clause, which - * can never be inferred. - * - * @deprecated The overloaded form - * {@link #createSelectionQuery(String, Class)} which takes a - * result type is strongly recommended in preference to this - * method, since it returns a typed {@code SelectionQuery} object, - * and because it is able to use the given result type to infer - * the {@code select} list, and even sometimes the {@code from} - * clause. - * - * @throws IllegalSelectQueryException if the given HQL query - * is an {@code insert}, {@code update} or {@code delete} - * statement - */ - @Deprecated(since = "6.3") - SelectionQuery createSelectionQuery(String hqlString); - - /** - * Create a {@link SelectionQuery} instance for the given HQL query - * string and given query result type. - *

    - *
  • If the query has a single item in the {@code select} list, - * then the select item must be assignable to the given result - * type. - *
  • Otherwise, if there are multiple select items, then the - * select items will be packaged into an instance of the - * result type. The result type must have an appropriate - * constructor with parameter types matching the select items, - * or it must be one of the types {@code Object[]}, - * {@link java.util.List}, {@link java.util.Map}, or - * {@link jakarta.persistence.Tuple}. - *
- *

- * If a query has no explicit {@code select} list, the select list - * is inferred from the given query result type: - *

    - *
  • if the result type is an entity type, the query must have - * exactly one root entity in the {@code from} clause, it must - * be assignable to the result type, and the inferred select - * list will contain just that entity, or - *
  • otherwise, the select list contains every root entity and - * every non-{@code fetch} joined entity, and each query result - * will be packaged into an instance of the result type, just - * as specified above. - *
- *

- * If a query has no explicit {@code from} clause, and the given - * result type is an entity type, the root entity is inferred to - * be the result type. - *

- * Passing {@code Object.class} as the query result type is not - * recommended. In this special case, this method has the same - * semantics as the overload {@link #createSelectionQuery(String)}. - *

- * The returned {@code Query} may be executed by calling - * {@link Query#getResultList()} or {@link Query#getSingleResult()}. - - * @param hqlString The HQL {@code select} query as a string - * @param resultType The {@link Class} object representing the - * query result type, which should not be - * {@code Object.class} - * - * @see jakarta.persistence.EntityManager#createQuery(String) - * - * @throws IllegalSelectQueryException if the given HQL query - * is an {@code insert}, {@code update} or {@code delete} - * statement - */ - SelectionQuery createSelectionQuery(String hqlString, Class resultType); - - /** - * Create a {@link SelectionQuery} instance for the given HQL query - * string and given {@link EntityGraph}, which is interpreted as a - * {@linkplain org.hibernate.graph.GraphSemantic#LOAD load graph}. - * The query result type is the root entity of the given graph. - *

    - *
  • If the query has an explicit {@code select} clause, there must - * be a single item in the {@code select} list, and the select - * item must be assignable to the root type of the given graph. - *
  • Otherwise, if a query has no explicit {@code select} list, the - * select list is inferred from the given entity graph. The query - * must have exactly one root entity in the {@code from} clause, - * it must be assignable to the root type of the given graph, and - * the inferred select list will contain just that entity. - *
- *

- * If a query has no explicit {@code from} clause, and the given - * result type is an entity type, the root entity is inferred to - * be the result type. - *

- * The returned {@code Query} may be executed by calling - * {@link Query#getResultList()} or {@link Query#getSingleResult()}. - - * @param hqlString The HQL {@code select} query as a string - * @param resultGraph An {@link EntityGraph} whose root type is the - * query result type, which is interpreted as a - * {@linkplain org.hibernate.graph.GraphSemantic#LOAD - * load graph} - * - * @see jakarta.persistence.EntityManager#createQuery(String) - * - * @throws IllegalSelectQueryException if the given HQL query - * is an {@code insert}, {@code update} or {@code delete} - * statement - * - * @since 7.0 - */ - SelectionQuery createSelectionQuery(String hqlString, EntityGraph resultGraph); - - /** - * Create a {@link SelectionQuery} reference for the given - * {@link CriteriaQuery}. - * - * @see jakarta.persistence.EntityManager#createQuery(CriteriaQuery) - */ - SelectionQuery createSelectionQuery(CriteriaQuery criteria); - - /** - * Create a {@link MutationQuery} reference for the given HQL insert, - * update, or delete statement. - * - * @param hqlString The HQL {@code insert}, {@code update}, or - * {@code delete} statement - * - * @throws IllegalMutationQueryException if the given HQL query - * is a {@code select} query - */ - MutationQuery createMutationQuery(String hqlString); - - /** - * Create a {@link MutationQuery} from the given update criteria tree - */ - MutationQuery createMutationQuery(@SuppressWarnings("rawtypes") CriteriaUpdate updateQuery); - - /** - * Create a {@link MutationQuery} from the given delete criteria tree - */ - MutationQuery createMutationQuery(@SuppressWarnings("rawtypes") CriteriaDelete deleteQuery); - - /** - * Create a {@link MutationQuery} from the given insert criteria tree - */ - MutationQuery createMutationQuery(@SuppressWarnings("rawtypes") JpaCriteriaInsert insert); - - /** - * Create a {@link NativeQuery} instance for the given native SQL statement. - * - * @param sqlString a native SQL statement string - * - * @return The NativeQuery instance for manipulation and execution - */ - MutationQuery createNativeMutationQuery(String sqlString); - - /** - * Create a typed {@link Query} instance for the given named query. - * The named query might be defined in HQL or in native SQL. - * - * @param name the name of a predefined named query - * - * @return The {@link Query} instance for manipulation and execution - * - * @throws IllegalArgumentException if a query has not been - * defined with the given name or if the query string is - * found to be invalid - * - * @see jakarta.persistence.EntityManager#createNamedQuery(String) - * - * @deprecated use {@link #createNamedQuery(String, Class)} - */ - @Deprecated(since = "6.0") @SuppressWarnings("rawtypes") - Query createNamedQuery(String name); - - /** - * Create a typed {@link Query} instance for the given named query. - * The named query might be defined in HQL or in native SQL. - * - * @param name the name of a query defined in metadata - * @param resultClass the type of the query result - * - * @return The {@link Query} instance for manipulation and execution - * - * @throws IllegalArgumentException if a query has not been - * defined with the given name or if the query string is - * found to be invalid or if the query result is found to - * not be assignable to the specified type - * - * @see jakarta.persistence.EntityManager#createNamedQuery(String,Class) - */ - Query createNamedQuery(String name, Class resultClass); - - /** - * Create a {@link SelectionQuery} instance for the named - * {@link jakarta.persistence.NamedQuery}. - * - * @implNote This method interprets some queries with an implicit - * {@code select} list in a quite unintuitive way. In some future - * release, this method will be modified to throw an exception - * when passed a query with a missing {@code select}. For now, use - * {@link #createNamedSelectionQuery(String, Class)} to avoid - * ambiguity. - * - * @throws IllegalSelectQueryException if the given HQL query is not a select query - * @throws UnknownNamedQueryException if no query has been defined with the given name - * - * @deprecated use {@link #createNamedSelectionQuery(String, Class)} - */ - @Deprecated(since = "6.3") - SelectionQuery createNamedSelectionQuery(String name); - - /** - * Create a {@link SelectionQuery} instance for the named - * {@link jakarta.persistence.NamedQuery} with the given result type. - * - * @throws IllegalSelectQueryException if the given HQL query is not a select query - * @throws UnknownNamedQueryException if no query has been defined with the given name - */ - SelectionQuery createNamedSelectionQuery(String name, Class resultType); - - /** - * Create a {@link MutationQuery} instance for the given named insert, - * update, or delete HQL query. The named query might be defined as - * {@linkplain jakarta.persistence.NamedQuery HQL}) or - * {@linkplain jakarta.persistence.NamedNativeQuery native-SQL}. - * - * @throws IllegalMutationQueryException if the given HQL query is a select query - * @throws UnknownNamedQueryException if no query has been defined with the given name - */ - MutationQuery createNamedMutationQuery(String name); - - /** - * Create a {@link Query} instance for the named query. - * - * @param queryName the name of a predefined named query - * - * @return The {@link Query} instance for manipulation and execution - * - * @throws IllegalArgumentException if a query has not been - * defined with the given name or if the query string is - * found to be invalid - * - * @deprecated use {@link #createNamedQuery(String, Class)} - */ - @Deprecated(since = "6.0") @SuppressWarnings("rawtypes") - Query getNamedQuery(String queryName); - - /** - * Get a {@link NativeQuery} instance for a named native SQL query - * - * @param name The name of the predefined query - * - * @return The {@link NativeQuery} instance for manipulation and execution - * - * @deprecated use {@link #createNamedQuery(String, Class)} - */ - @Deprecated(since = "6.0") @SuppressWarnings("rawtypes") - NativeQuery getNamedNativeQuery(String name); - - /** - * Get a {@link NativeQuery} instance for a named native SQL query - * - * @param name The name of the predefined query - * - * @return The {@link NativeQuery} instance for manipulation and execution - * - * @deprecated use {@link #createNamedQuery(String, Class)} - */ - @Deprecated(since = "6.0") @SuppressWarnings("rawtypes") - NativeQuery getNamedNativeQuery(String name, String resultSetMapping); -} diff --git a/hibernate-core/src/main/java/org/hibernate/query/SelectionQuery.java b/hibernate-core/src/main/java/org/hibernate/query/SelectionQuery.java index 03ae5640af3d..5564f09ffddd 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/SelectionQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/SelectionQuery.java @@ -4,6 +4,7 @@ */ package org.hibernate.query; +import jakarta.persistence.AttributeConverter; import jakarta.persistence.CacheRetrieveMode; import jakarta.persistence.CacheStoreMode; import jakarta.persistence.EntityGraph; @@ -45,12 +46,12 @@ * A {@code SelectionQuery} may be obtained from the {@link org.hibernate.Session} * by calling: *

    - *
  • {@link QueryProducer#createSelectionQuery(String, Class)}, passing the + *
  • {@link org.hibernate.SharedSessionContract#createSelectionQuery(String, Class)}, passing the * HQL as a string, - *
  • {@link QueryProducer#createSelectionQuery(jakarta.persistence.criteria.CriteriaQuery)}, + *
  • {@link org.hibernate.SharedSessionContract#createSelectionQuery(jakarta.persistence.criteria.CriteriaQuery)}, * passing a {@linkplain jakarta.persistence.criteria.CriteriaQuery criteria * query object}, or - *
  • {@link QueryProducer#createNamedSelectionQuery(String, Class)} passing + *
  • {@link org.hibernate.SharedSessionContract#createNamedSelectionQuery(String, Class)} passing * the name of a query defined using {@link jakarta.persistence.NamedQuery} * or {@link jakarta.persistence.NamedNativeQuery}. *
@@ -650,6 +651,12 @@ default Stream stream() { */ SelectionQuery setResultListTransformer(ResultListTransformer transformer); + @Override +

SelectionQuery setConvertedParameter(String name, P value, Class> converter); + + @Override +

SelectionQuery setConvertedParameter(int position, P value, Class> converter); + @Override SelectionQuery setParameter(String name, Object value); diff --git a/hibernate-core/src/main/java/org/hibernate/query/criteria/CriteriaDefinition.java b/hibernate-core/src/main/java/org/hibernate/query/criteria/CriteriaDefinition.java index a556231b4e46..2ffbf215b384 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/criteria/CriteriaDefinition.java +++ b/hibernate-core/src/main/java/org/hibernate/query/criteria/CriteriaDefinition.java @@ -13,7 +13,6 @@ import org.hibernate.Incubating; import org.hibernate.SessionFactory; import org.hibernate.SharedSessionContract; -import org.hibernate.query.QueryProducer; import org.hibernate.query.SelectionQuery; import org.hibernate.query.criteria.spi.HibernateCriteriaBuilderDelegate; import org.hibernate.query.common.FetchClauseType; @@ -214,7 +213,7 @@ public CriteriaDefinition(EntityManager entityManager, CriteriaQuery baseQuer this( entityManager.getEntityManagerFactory(), baseQuery ); } - public SelectionQuery createSelectionQuery(QueryProducer session) { + public SelectionQuery createSelectionQuery(SharedSessionContract session) { return session.createQuery( query ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaFetch.java b/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaFetch.java index aff2b1250b98..39cecaa74333 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaFetch.java +++ b/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaFetch.java @@ -30,10 +30,10 @@ public interface JpaFetch extends JpaFetchParent, Fetch { JpaFetch fetch(PluralAttribute attribute, JoinType jt); @Override - JpaFetch fetch(String attributeName); + JpaFetch fetch(String attributeName); @Override - JpaFetch fetch(String attributeName, JoinType jt); + JpaFetch fetch(String attributeName, JoinType jt); /** * Add a restriction to the fetch. diff --git a/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaFetchParent.java b/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaFetchParent.java index d697da7a1be8..a338b7bd0578 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaFetchParent.java +++ b/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaFetchParent.java @@ -31,8 +31,8 @@ public interface JpaFetchParent extends FetchParent { JpaFetch fetch(PluralAttribute attribute, JoinType jt); @Override - JpaFetch fetch(String attributeName); + JpaFetch fetch(String attributeName); @Override - JpaFetch fetch(String attributeName, JoinType jt); + JpaFetch fetch(String attributeName, JoinType jt); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaFrom.java b/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaFrom.java index 77e7fc827316..08782a60bdad 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaFrom.java +++ b/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaFrom.java @@ -290,34 +290,34 @@ default JpaJoin join(JpaCteCriteria cte, org.hibernate.query.common JpaMapJoin join(MapAttribute map, JoinType jt); @Override - JpaJoin join(String attributeName); + JpaJoin join(String attributeName); @Override - JpaCollectionJoin joinCollection(String attributeName); + JpaCollectionJoin joinCollection(String attributeName); @Override - JpaSetJoin joinSet(String attributeName); + JpaSetJoin joinSet(String attributeName); @Override - JpaListJoin joinList(String attributeName); + JpaListJoin joinList(String attributeName); @Override - JpaMapJoin joinMap(String attributeName); + JpaMapJoin joinMap(String attributeName); @Override - JpaJoin join(String attributeName, JoinType jt); + JpaJoin join(String attributeName, JoinType jt); @Override - JpaCollectionJoin joinCollection(String attributeName, JoinType jt); + JpaCollectionJoin joinCollection(String attributeName, JoinType jt); @Override - JpaSetJoin joinSet(String attributeName, JoinType jt); + JpaSetJoin joinSet(String attributeName, JoinType jt); @Override - JpaListJoin joinList(String attributeName, JoinType jt); + JpaListJoin joinList(String attributeName, JoinType jt); @Override - JpaMapJoin joinMap(String attributeName, JoinType jt); + JpaMapJoin joinMap(String attributeName, JoinType jt); @Override JpaTreatedFrom treatAs(Class treatJavaType); diff --git a/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/NamedCriteriaQueryMementoImpl.java b/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/NamedCriteriaQueryMementoImpl.java index 6651d19609b6..226943a96f21 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/NamedCriteriaQueryMementoImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/NamedCriteriaQueryMementoImpl.java @@ -4,10 +4,10 @@ */ package org.hibernate.query.criteria.internal; -import java.io.Serializable; -import java.util.Locale; -import java.util.Map; - +import jakarta.persistence.LockModeType; +import jakarta.persistence.PessimisticLockScope; +import jakarta.persistence.Timeout; +import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.CacheMode; import org.hibernate.FlushMode; import org.hibernate.LockOptions; @@ -22,10 +22,12 @@ import org.hibernate.query.sqm.internal.SqmSelectionQueryImpl; import org.hibernate.query.sqm.spi.NamedSqmQueryMemento; import org.hibernate.query.sqm.tree.SqmStatement; - -import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.query.sqm.tree.select.SqmSelectStatement; +import java.io.Serializable; +import java.util.Locale; +import java.util.Map; + public class NamedCriteriaQueryMementoImpl extends AbstractNamedQueryMemento implements NamedSqmQueryMemento, Serializable { @@ -48,7 +50,7 @@ public NamedCriteriaQueryMementoImpl( FlushMode flushMode, Boolean readOnly, LockOptions lockOptions, - Integer timeout, + Timeout timeout, Integer fetchSize, String comment, Map parameterTypes, @@ -67,6 +69,20 @@ public void validate(QueryEngine queryEngine) { // nothing to do } + @Override + public LockModeType getLockMode() { + return lockOptions == null + ? LockModeType.NONE + : lockOptions.getLockMode().toJpaLockMode(); + } + + @Override + public PessimisticLockScope getPessimisticLockScope() { + return lockOptions == null + ? PessimisticLockScope.NORMAL + : lockOptions.getScope().getCorrespondingJpaScope(); + } + private static void checkResultType(Class resultType, SqmSelectStatement selectStatement) { final Class expectedResultType = selectStatement.getResultType(); if ( expectedResultType != Object.class @@ -134,7 +150,7 @@ public LockOptions getLockOptions() { } @Override - public Map getParameterTypes() { + public Map getAnticipatedParameterTypes() { return parameterTypes; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/criteria/spi/HibernateCriteriaBuilderDelegate.java b/hibernate-core/src/main/java/org/hibernate/query/criteria/spi/HibernateCriteriaBuilderDelegate.java index 71e4cd403596..9ddec60018e6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/criteria/spi/HibernateCriteriaBuilderDelegate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/criteria/spi/HibernateCriteriaBuilderDelegate.java @@ -22,6 +22,8 @@ import java.util.Map; import java.util.Set; +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.criteria.ParameterExpression; import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.Incubating; import org.hibernate.query.NullPrecedence; @@ -665,6 +667,11 @@ public JpaParameterExpression parameter(Class paramClass, String name) return criteriaBuilder.parameter( paramClass, name ); } + @Override + public ParameterExpression convertedParameter(Class> converter) { + return criteriaBuilder.convertedParameter( converter ); + } + @Override public JpaExpression concat(Expression x, Expression y) { return criteriaBuilder.concat( x, y ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/NamedHqlQueryMementoImpl.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/NamedHqlQueryMementoImpl.java index 34acdd382f86..2e7bba1c2569 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/NamedHqlQueryMementoImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/NamedHqlQueryMementoImpl.java @@ -4,9 +4,10 @@ */ package org.hibernate.query.hql.internal; -import java.io.Serializable; -import java.util.Map; - +import jakarta.persistence.LockModeType; +import jakarta.persistence.PessimisticLockScope; +import jakarta.persistence.Timeout; +import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.CacheMode; import org.hibernate.FlushMode; import org.hibernate.LockOptions; @@ -20,7 +21,8 @@ import org.hibernate.query.sqm.spi.NamedSqmQueryMemento; import org.hibernate.query.sqm.tree.SqmStatement; -import org.checkerframework.checker.nullness.qual.Nullable; +import java.io.Serializable; +import java.util.Map; /** * Definition of a named query, defined in the mapping metadata. @@ -53,7 +55,7 @@ public NamedHqlQueryMementoImpl( FlushMode flushMode, Boolean readOnly, LockOptions lockOptions, - Integer timeout, + Timeout timeout, Integer fetchSize, String comment, Map parameterTypes, @@ -99,10 +101,24 @@ public LockOptions getLockOptions() { } @Override - public Map getParameterTypes() { + public Map getAnticipatedParameterTypes() { return parameterTypes; } + @Override + public LockModeType getLockMode() { + return lockOptions == null + ? LockModeType.NONE + : lockOptions.getLockMode().toJpaLockMode(); + } + + @Override + public PessimisticLockScope getPessimisticLockScope() { + return lockOptions == null + ? PessimisticLockScope.NORMAL + : lockOptions.getScope().getCorrespondingJpaScope(); + } + @Override public NamedSqmQueryMemento makeCopy(String name) { return new NamedHqlQueryMementoImpl<>( diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/FetchMementoBasicStandard.java b/hibernate-core/src/main/java/org/hibernate/query/internal/FetchMementoBasicStandard.java index 86a0a2f757b4..1a353d536c91 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/FetchMementoBasicStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/FetchMementoBasicStandard.java @@ -6,10 +6,17 @@ import java.util.function.Consumer; +import jakarta.persistence.sql.FieldMapping; +import jakarta.persistence.sql.MemberMapping; +import jakarta.persistence.sql.ResultSetMapping; +import org.hibernate.SessionFactory; +import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.metamodel.mapping.BasicValuedModelPart; +import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping; +import org.hibernate.persister.entity.EntityPersister; import org.hibernate.spi.NavigablePath; import org.hibernate.query.named.FetchMementoBasic; -import org.hibernate.query.results.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilder; import org.hibernate.query.results.internal.complete.CompleteFetchBuilderBasicPart; /** @@ -32,6 +39,15 @@ public FetchMementoBasicStandard( this.columnAlias = columnAlias; } + public static FetchMementoBasicStandard from( + FieldMapping basicMapping, + NavigablePath attributePath, + EntityPersister entityDescriptor, + BasicAttributeMapping attributeMapping, + SessionFactoryImplementor factory) { + return null; + } + @Override public NavigablePath getNavigablePath() { return navigablePath; @@ -52,4 +68,14 @@ public FetchBuilder resolve( ResultSetMappingResolutionContext context) { return new CompleteFetchBuilderBasicPart( navigablePath, fetchedAttribute, columnAlias ); } + + @Override + public MemberMapping toJpaMemberMapping(Parent container, SessionFactory sessionFactory) { + return ResultSetMapping.field( + container.getResultJavaType(), + fetchedAttribute.getJavaType().getJavaTypeClass(), + fetchedAttribute.getFetchableName(), + fetchedAttribute.getSelectableName() + ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/FetchMementoEmbeddableStandard.java b/hibernate-core/src/main/java/org/hibernate/query/internal/FetchMementoEmbeddableStandard.java index a9222dd527ed..b00f065beee5 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/FetchMementoEmbeddableStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/FetchMementoEmbeddableStandard.java @@ -9,7 +9,7 @@ import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart; import org.hibernate.query.named.FetchMemento; -import org.hibernate.query.results.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilder; import org.hibernate.query.results.internal.complete.CompleteFetchBuilderEmbeddableValuedModelPart; import org.hibernate.spi.NavigablePath; diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/FetchMementoEntityStandard.java b/hibernate-core/src/main/java/org/hibernate/query/internal/FetchMementoEntityStandard.java index 6d5b0fce20d1..ae0ffe4dc55a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/FetchMementoEntityStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/FetchMementoEntityStandard.java @@ -9,7 +9,7 @@ import org.hibernate.spi.NavigablePath; import org.hibernate.query.named.FetchMemento; -import org.hibernate.query.results.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilder; import org.hibernate.query.results.internal.complete.CompleteFetchBuilderEntityValuedModelPart; import org.hibernate.sql.results.graph.entity.EntityValuedFetchable; diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/FetchMementoHbmStandard.java b/hibernate-core/src/main/java/org/hibernate/query/internal/FetchMementoHbmStandard.java index 0f10294cf2a3..4ae3dc663b11 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/FetchMementoHbmStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/FetchMementoHbmStandard.java @@ -19,7 +19,7 @@ import org.hibernate.query.results.internal.dynamic.DynamicResultBuilderEntityStandard; import org.hibernate.spi.NavigablePath; import org.hibernate.query.named.FetchMemento; -import org.hibernate.query.results.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilder; import org.hibernate.query.results.internal.dynamic.DynamicFetchBuilderLegacy; import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.FetchableContainer; @@ -70,6 +70,11 @@ public NavigablePath getNavigablePath() { return navigablePath; } + @Override + public Class getResultJavaType() { + return fetchable.getJavaType().getJavaTypeClass(); + } + @Override public FetchBuilder resolve( Parent parent, diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/ModelPartResultMementoBasicImpl.java b/hibernate-core/src/main/java/org/hibernate/query/internal/ModelPartResultMementoBasicImpl.java index 7ea6d1f7a9a7..6199ecf3aec5 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/ModelPartResultMementoBasicImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/ModelPartResultMementoBasicImpl.java @@ -4,13 +4,15 @@ */ package org.hibernate.query.internal; -import java.util.function.Consumer; - +import jakarta.persistence.sql.ColumnMapping; +import org.hibernate.SessionFactory; import org.hibernate.metamodel.mapping.BasicValuedModelPart; -import org.hibernate.spi.NavigablePath; import org.hibernate.query.named.ModelPartResultMementoBasic; -import org.hibernate.query.results.ResultBuilderBasicValued; +import org.hibernate.query.results.spi.ResultBuilderBasicValued; import org.hibernate.query.results.internal.complete.CompleteResultBuilderBasicModelPart; +import org.hibernate.spi.NavigablePath; + +import java.util.function.Consumer; /** * @author Steve Ebersole @@ -34,10 +36,26 @@ public NavigablePath getNavigablePath() { return navigablePath; } + @Override + public Class getResultJavaType() { + return modelPart.getJavaType().getJavaTypeClass(); + } + @Override public ResultBuilderBasicValued resolve( Consumer querySpaceConsumer, ResultSetMappingResolutionContext context) { return new CompleteResultBuilderBasicModelPart( navigablePath, modelPart, columnName ); } + + @Override + public ColumnMapping toJpaMapping(SessionFactory sessionFactory) { + return toJpaMappingElement( sessionFactory ); + } + + @Override + public ColumnMapping toJpaMappingElement(SessionFactory sessionFactory) { + //noinspection unchecked + return ColumnMapping.of( columnName, (Class) getResultJavaType() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/NamedResultSetMappingMementoImpl.java b/hibernate-core/src/main/java/org/hibernate/query/internal/NamedResultSetMappingMementoImpl.java index 0e0dc72703de..0711963ed1b1 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/NamedResultSetMappingMementoImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/NamedResultSetMappingMementoImpl.java @@ -4,12 +4,13 @@ */ package org.hibernate.query.internal; -import java.util.List; -import java.util.function.Consumer; - +import org.hibernate.SessionFactory; import org.hibernate.query.named.NamedResultSetMappingMemento; import org.hibernate.query.named.ResultMemento; -import org.hibernate.query.results.ResultSetMapping; +import org.hibernate.query.results.spi.ResultSetMapping; + +import java.util.List; +import java.util.function.Consumer; import static java.util.Collections.unmodifiableList; @@ -34,6 +35,7 @@ public String getName() { return name; } + @Override public List getResultMementos() { return unmodifiableList( resultMementos ); } @@ -47,4 +49,21 @@ public void resolve( memento -> resultSetMapping.addResultBuilder( memento.resolve( querySpaceConsumer, context ) ) ); } + + @Override + public boolean canBeTreatedAsResultSetMapping(Class resultType, SessionFactory sessionFactory) { + if ( getResultMementos().size() != 1 ) { + return false; + } + var resultMemento = getResultMementos().get( 0 ); + return resultMemento.canBeTreatedAsResultSetMapping( resultType, sessionFactory ); + } + + @Override + public jakarta.persistence.sql.ResultSetMapping toJpaMapping(SessionFactory sessionFactory) { + assert getResultMementos().size() == 1; + var resultMemento = getResultMementos().get( 0 ); + + return resultMemento.toJpaMapping( sessionFactory ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/QueryOptionsImpl.java b/hibernate-core/src/main/java/org/hibernate/query/internal/QueryOptionsImpl.java index 492b98c32e82..a7c20581aa89 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/QueryOptionsImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/QueryOptionsImpl.java @@ -11,6 +11,7 @@ import jakarta.persistence.CacheRetrieveMode; import jakarta.persistence.CacheStoreMode; +import jakarta.persistence.Timeout; import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.FlushMode; @@ -29,7 +30,7 @@ * @author Steve Ebersole */ public class QueryOptionsImpl implements MutableQueryOptions, AppliedGraph { - private Integer timeout; + private Timeout timeout; private FlushMode flushMode; private String comment; private List databaseHints; @@ -54,12 +55,23 @@ public class QueryOptionsImpl implements MutableQueryOptions, AppliedGraph { private Set disabledFetchProfiles; @Override - public Integer getTimeout() { + public Timeout getTimeout() { return timeout; } + @Override + public void setTimeout(int timeout) { + setTimeout( Timeout.seconds( timeout ) ); + } + public void setTimeout(Integer timeout) { + setTimeout( Timeout.seconds( timeout ) ); + } + + @Override + public void setTimeout(Timeout timeout) { this.timeout = timeout; + lockOptions.setTimeout( timeout ); } @Override @@ -184,11 +196,6 @@ public void setResultCacheRegionName(String resultCacheRegionName) { this.resultCacheRegionName = resultCacheRegionName; } - @Override - public void setTimeout(int timeout) { - this.timeout = timeout; - } - @Override public void setFetchSize(int fetchSize) { this.fetchSize = fetchSize; diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoBasicStandard.java b/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoBasicStandard.java index ff6270abf65e..09583a4047a1 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoBasicStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoBasicStandard.java @@ -4,15 +4,17 @@ */ package org.hibernate.query.internal; -import java.lang.reflect.Type; -import java.util.function.Consumer; - +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.ColumnResult; +import jakarta.persistence.sql.ColumnMapping; +import org.hibernate.SessionFactory; import org.hibernate.metamodel.mapping.BasicValuedMapping; import org.hibernate.query.named.ResultMementoBasic; -import org.hibernate.query.results.ResultBuilderBasicValued; import org.hibernate.query.results.internal.complete.CompleteResultBuilderBasicValuedConverted; import org.hibernate.query.results.internal.complete.CompleteResultBuilderBasicValuedStandard; +import org.hibernate.query.results.spi.ResultBuilderBasicValued; import org.hibernate.resource.beans.spi.ManagedBean; +import org.hibernate.resource.beans.spi.ManagedBeanRegistry; import org.hibernate.type.BasicType; import org.hibernate.type.CustomType; import org.hibernate.type.descriptor.java.BasicJavaType; @@ -21,8 +23,8 @@ import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.usertype.UserType; -import jakarta.persistence.AttributeConverter; -import jakarta.persistence.ColumnResult; +import java.lang.reflect.Type; +import java.util.function.Consumer; import static org.hibernate.internal.util.GenericsHelper.typeArguments; @@ -77,81 +79,98 @@ public ResultMementoBasicStandard( else { final var typeConfiguration = context.getTypeConfiguration(); final var managedBeanRegistry = context.getSessionFactory().getManagedBeanRegistry(); + builder = resolveBuilder( explicitColumnName, definedType, typeConfiguration, managedBeanRegistry ); + } + } + + public String getColumnName() { + return explicitColumnName; + } + + + + private static ResultBuilderBasicValued resolveBuilder( + String columnName, + Class definedType, + TypeConfiguration typeConfiguration, + ManagedBeanRegistry managedBeanRegistry) { + + if ( AttributeConverter.class.isAssignableFrom( definedType ) ) { + @SuppressWarnings("unchecked") + final var converterClass = (Class>) definedType; + final var converterBean = managedBeanRegistry.getBean( converterClass ); + final var converterJtd = typeConfiguration.getJavaTypeRegistry().resolveDescriptor( converterClass ); + + final var typeArguments = typeArguments( AttributeConverter.class, converterBean.getBeanClass() ); - if ( AttributeConverter.class.isAssignableFrom( definedType ) ) { - @SuppressWarnings("unchecked") - final var converterClass = (Class>) definedType; - final var converterBean = managedBeanRegistry.getBean( converterClass ); - final var converterJtd = - typeConfiguration.getJavaTypeRegistry() - .resolveDescriptor( converterClass ); - - final var typeArguments = - typeArguments( AttributeConverter.class, - converterBean.getBeanClass() ); - - builder = new CompleteResultBuilderBasicValuedConverted( - explicitColumnName, - converterBean, - converterJtd, - determineDomainJavaType( typeArguments, typeConfiguration.getJavaTypeRegistry() ), - resolveUnderlyingMapping( typeArguments, typeConfiguration ) - ); + //noinspection rawtypes,unchecked + return new CompleteResultBuilderBasicValuedConverted( + columnName, + converterBean, + converterJtd, + determineDomainJavaType( typeArguments, typeConfiguration.getJavaTypeRegistry() ), + resolveUnderlyingMapping( typeArguments, typeConfiguration ) + ); + } + else { + final BasicType explicitType; + final JavaType explicitJavaType; + + // see if this is a registered BasicType... + final var registeredBasicType = typeConfiguration.getBasicTypeRegistry() + .getRegisteredType( definedType.getName() ); + if ( registeredBasicType != null ) { + explicitType = registeredBasicType; + explicitJavaType = registeredBasicType.getJavaTypeDescriptor(); } else { - final BasicType explicitType; - final JavaType explicitJavaType; - - // see if this is a registered BasicType... - final var registeredBasicType = - typeConfiguration.getBasicTypeRegistry() - .getRegisteredType( definedType.getName() ); - if ( registeredBasicType != null ) { - explicitType = registeredBasicType; - explicitJavaType = registeredBasicType.getJavaTypeDescriptor(); + final var jtdRegistry = typeConfiguration.getJavaTypeRegistry(); + final var registeredJtd = jtdRegistry.resolveDescriptor( definedType ); + if ( BasicType.class.isAssignableFrom( registeredJtd.getJavaTypeClass() ) ) { + //noinspection unchecked + final var typeBean = + (ManagedBean>) + managedBeanRegistry.getBean( registeredJtd.getJavaTypeClass() ); + explicitType = typeBean.getBeanInstance(); + explicitJavaType = explicitType.getJavaTypeDescriptor(); + } + else if ( UserType.class.isAssignableFrom( registeredJtd.getJavaTypeClass() ) ) { + //noinspection unchecked + final var userTypeBean = + (ManagedBean>) + managedBeanRegistry.getBean( registeredJtd.getJavaTypeClass() ); + // todo (6.0) : is this the best approach? or should we keep a Class -> @Type mapping somewhere? + explicitType = new CustomType<>( userTypeBean.getBeanInstance(), typeConfiguration ); + explicitJavaType = explicitType.getJavaTypeDescriptor(); } else { - final var jtdRegistry = typeConfiguration.getJavaTypeRegistry(); - final var registeredJtd = jtdRegistry.resolveDescriptor( definedType ); - if ( BasicType.class.isAssignableFrom( registeredJtd.getJavaTypeClass() ) ) { - final var typeBean = - (ManagedBean>) - managedBeanRegistry.getBean( registeredJtd.getJavaTypeClass() ); - explicitType = typeBean.getBeanInstance(); - explicitJavaType = explicitType.getJavaTypeDescriptor(); - } - else if ( UserType.class.isAssignableFrom( registeredJtd.getJavaTypeClass() ) ) { - final var userTypeBean = - (ManagedBean>) - managedBeanRegistry.getBean( registeredJtd.getJavaTypeClass() ); - // todo (6.0) : is this the best approach? or should we keep a Class -> @Type mapping somewhere? - explicitType = new CustomType<>( userTypeBean.getBeanInstance(), typeConfiguration ); - explicitJavaType = explicitType.getJavaTypeDescriptor(); - } - else { - explicitType = null; - explicitJavaType = jtdRegistry.resolveDescriptor( definedType ); - } + explicitType = null; + explicitJavaType = jtdRegistry.resolveDescriptor( definedType ); } - - builder = new CompleteResultBuilderBasicValuedStandard( explicitColumnName, explicitType, explicitJavaType ); } + + return new CompleteResultBuilderBasicValuedStandard( columnName, explicitType, explicitJavaType ); } } - private BasicJavaType determineDomainJavaType( + private static BasicJavaType determineDomainJavaType( Type[] typeArguments, JavaTypeRegistry jtdRegistry) { final var domainClass = (Class) typeArguments[0]; return (BasicJavaType) jtdRegistry.resolveDescriptor( domainClass ); } - private BasicValuedMapping resolveUnderlyingMapping( + private static BasicValuedMapping resolveUnderlyingMapping( Type[] typeArguments, TypeConfiguration typeConfiguration) { return typeConfiguration.standardBasicTypeForJavaType( typeArguments[1] ); } + private ResultMementoBasicStandard(String explicitColumnName, ResultBuilderBasicValued builder) { + this.explicitColumnName = explicitColumnName; + this.builder = builder; + } + public ResultMementoBasicStandard( String explicitColumnName, BasicType explicitType) { @@ -171,4 +190,20 @@ public ResultBuilderBasicValued resolve( ResultSetMappingResolutionContext context) { return builder; } + + @Override + public ColumnMapping toJpaMapping(SessionFactory sessionFactory) { + return toJpaMappingElement( sessionFactory ); + } + + @Override + public ColumnMapping toJpaMappingElement(SessionFactory sessionFactory) { + //noinspection unchecked + return ColumnMapping.of( explicitColumnName, (Class) getResultJavaType() ); + } + + @Override + public Class getResultJavaType() { + return builder.getJavaType(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoCollectionStandard.java b/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoCollectionStandard.java index 1a53f76713b8..0d9bc6d7942e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoCollectionStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoCollectionStandard.java @@ -6,10 +6,13 @@ import java.util.function.Consumer; +import jakarta.persistence.sql.MappingElement; +import jakarta.persistence.sql.ResultSetMapping; +import org.hibernate.SessionFactory; import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.spi.NavigablePath; import org.hibernate.query.named.ModelPartResultMementoCollection; -import org.hibernate.query.results.ResultBuilder; +import org.hibernate.query.results.spi.ResultBuilder; import org.hibernate.query.results.internal.complete.CompleteResultBuilderCollectionStandard; /** @@ -39,6 +42,11 @@ public PluralAttributeMapping getPluralAttributeDescriptor() { return pluralAttributeDescriptor; } + @Override + public Class getResultJavaType() { + return pluralAttributeDescriptor.getJavaType().getJavaTypeClass(); + } + @Override public ResultBuilder resolve( Consumer querySpaceConsumer, @@ -49,4 +57,19 @@ public ResultBuilder resolve( pluralAttributeDescriptor ); } + + @Override + public boolean canBeTreatedAsResultSetMapping(Class resultType, SessionFactory sessionFactory) { + return false; + } + + @Override + public ResultSetMapping toJpaMapping(SessionFactory sessionFactory) { + throw new UnsupportedOperationException(); + } + + @Override + public MappingElement toJpaMappingElement(SessionFactory sessionFactory) { + throw new UnsupportedOperationException(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoEntityJpa.java b/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoEntityJpa.java index 3755ee787d6c..e12e4c74b5cf 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoEntityJpa.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoEntityJpa.java @@ -4,24 +4,29 @@ */ package org.hibernate.query.internal; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Consumer; - +import jakarta.persistence.sql.EntityMapping; +import jakarta.persistence.sql.MemberMapping; +import jakarta.persistence.sql.ResultSetMapping; import org.hibernate.LockMode; +import org.hibernate.SessionFactory; +import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.query.named.FetchMemento; import org.hibernate.query.named.FetchMementoBasic; import org.hibernate.query.named.ResultMementoEntity; -import org.hibernate.query.results.FetchBuilderBasicValued; -import org.hibernate.query.results.FetchBuilder; -import org.hibernate.query.results.ResultBuilderEntityValued; +import org.hibernate.query.results.spi.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilderBasicValued; +import org.hibernate.query.results.spi.ResultBuilderEntityValued; import org.hibernate.query.results.internal.complete.CompleteResultBuilderEntityJpa; import org.hibernate.query.results.internal.complete.DelayedFetchBuilderBasicPart; import org.hibernate.query.results.internal.implicit.ImplicitFetchBuilderBasic; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.results.graph.Fetchable; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; + /** * @author Steve Ebersole */ @@ -37,7 +42,21 @@ public ResultMementoEntityJpa( LockMode lockMode, FetchMementoBasic discriminatorMemento, Map explicitFetchMementoMap) { - this.navigablePath = new NavigablePath( entityDescriptor.getEntityName() ); + this( + new NavigablePath( entityDescriptor.getEntityName() ), + entityDescriptor, + lockMode, + discriminatorMemento, + explicitFetchMementoMap + ); + } + public ResultMementoEntityJpa( + NavigablePath navigablePath, + EntityMappingType entityDescriptor, + LockMode lockMode, + FetchMementoBasic discriminatorMemento, + Map explicitFetchMementoMap) { + this.navigablePath = navigablePath; this.entityDescriptor = entityDescriptor; this.lockMode = lockMode; this.discriminatorMemento = discriminatorMemento; @@ -49,6 +68,11 @@ public NavigablePath getNavigablePath() { return navigablePath; } + @Override + public Class getResultJavaType() { + return entityDescriptor.getJavaType().getJavaTypeClass(); + } + @Override public ResultBuilderEntityValued resolve( Consumer querySpaceConsumer, @@ -95,6 +119,32 @@ public ResultBuilderEntityValued resolve( ); } + @Override + public ResultSetMapping toJpaMapping(SessionFactory sessionFactory) { + //noinspection unchecked + return new EntityMapping<>( + (Class) getResultJavaType(), + lockMode.toJpaLockMode(), + entityDescriptor.getDiscriminatorMapping() == null ? null : entityDescriptor.getDiscriminatorMapping().getSelectableName(), + toJpaFieldMappings( sessionFactory ) + ); + } + + private static final MemberMapping[] NO_MEMBERS = new MemberMapping[0]; + + private MemberMapping[] toJpaFieldMappings(SessionFactory sessionFactory) { + if ( CollectionHelper.isEmpty( explicitFetchMementoMap ) ) { + return NO_MEMBERS; + } + + var memberMappings = new MemberMapping[ explicitFetchMementoMap.size() ]; + int index = 0; + for ( Map.Entry entry : explicitFetchMementoMap.entrySet() ) { + memberMappings[index++] = entry.getValue().toJpaMemberMapping( this, sessionFactory ); + } + return memberMappings; + } + private FetchBuilderBasicValued discriminatorFetchBuilder( Consumer querySpaceConsumer, ResultSetMappingResolutionContext context) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoEntityStandard.java b/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoEntityStandard.java index 81613128de55..b18a79864b23 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoEntityStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoEntityStandard.java @@ -8,23 +8,29 @@ import java.util.Map; import java.util.function.Consumer; +import jakarta.persistence.sql.ResultSetMapping; import org.hibernate.LockMode; +import org.hibernate.SessionFactory; import org.hibernate.metamodel.mapping.EntityMappingType; -import org.hibernate.query.results.FetchBuilderBasicValued; +import org.hibernate.query.results.spi.FetchBuilderBasicValued; import org.hibernate.spi.NavigablePath; import org.hibernate.query.named.FetchMemento; import org.hibernate.query.named.FetchMementoBasic; import org.hibernate.query.named.ResultMementoEntity; -import org.hibernate.query.results.FetchBuilder; -import org.hibernate.query.results.ResultBuilderEntityValued; +import org.hibernate.query.results.spi.FetchBuilder; +import org.hibernate.query.results.spi.ResultBuilderEntityValued; import org.hibernate.query.results.internal.complete.CompleteResultBuilderEntityStandard; import org.hibernate.sql.results.graph.Fetchable; import static org.hibernate.query.QueryLogging.QUERY_LOGGER; -/** - * @author Steve Ebersole - */ +/// ResultMementoEntity implementation from Hibernate's historical result-set mapping support. +/// +/// @see org.hibernate.query.NativeQuery#addEntity +/// @see org.hibernate.query.NativeQuery#addRoot +/// @see org.hibernate.boot.jaxb.hbm.spi.JaxbHbmNativeQueryReturnType +/// +/// @author Steve Ebersole public class ResultMementoEntityStandard implements ResultMementoEntity, FetchMemento.Parent { private final String tableAlias; private final NavigablePath navigablePath; @@ -54,6 +60,11 @@ public NavigablePath getNavigablePath() { return navigablePath; } + @Override + public Class getResultJavaType() { + return entityDescriptor.getJavaType().getJavaTypeClass(); + } + @Override public ResultBuilderEntityValued resolve( Consumer querySpaceConsumer, @@ -79,4 +90,14 @@ public ResultBuilderEntityValued resolve( fetchBuilderMap ); } + + @Override + public boolean canBeTreatedAsResultSetMapping(Class resultType, SessionFactory sessionFactory) { + return false; + } + + @Override + public ResultSetMapping toJpaMapping(SessionFactory sessionFactory) { + throw new UnsupportedOperationException( "Unsupported" ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoInstantiationStandard.java b/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoInstantiationStandard.java index 476ecd1c10f7..1886f5422284 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoInstantiationStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoInstantiationStandard.java @@ -7,8 +7,12 @@ import java.util.List; import java.util.function.Consumer; +import jakarta.persistence.sql.ConstructorMapping; +import jakarta.persistence.sql.MappingElement; +import jakarta.persistence.sql.ResultSetMapping; +import org.hibernate.SessionFactory; import org.hibernate.query.named.ResultMementoInstantiation; -import org.hibernate.query.results.ResultBuilder; +import org.hibernate.query.results.spi.ResultBuilder; import org.hibernate.query.results.internal.complete.CompleteResultBuilderInstantiation; import org.hibernate.type.descriptor.java.JavaType; @@ -38,6 +42,11 @@ public List getArgumentMementos() { return unmodifiableList( argumentMementos ); } + @Override + public Class getResultJavaType() { + return instantiatedJtd.getJavaTypeClass(); + } + @Override public ResultBuilder resolve( Consumer querySpaceConsumer, @@ -50,4 +59,22 @@ public ResultBuilder resolve( ); return new CompleteResultBuilderInstantiation( instantiatedJtd, argumentBuilders ); } + + @Override + public ResultSetMapping toJpaMapping(SessionFactory sessionFactory) { + //noinspection unchecked + return new ConstructorMapping<>( + (Class) instantiatedJtd.getJavaTypeClass(), + convertArguments( sessionFactory ) + ); + } + + private MappingElement[] convertArguments(SessionFactory sessionFactory) { + var arguments = new MappingElement[ argumentMementos.size() ]; + for ( int i = 0; i < arguments.length; i++ ) { + var argumentMemento = argumentMementos.get( i ); + arguments[i] = argumentMemento.toJpaMapping( sessionFactory ); + } + return arguments; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/named/AbstractNamedQueryMemento.java b/hibernate-core/src/main/java/org/hibernate/query/named/AbstractNamedQueryMemento.java index c23b82d79b95..0e860d460104 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/named/AbstractNamedQueryMemento.java +++ b/hibernate-core/src/main/java/org/hibernate/query/named/AbstractNamedQueryMemento.java @@ -4,12 +4,16 @@ */ package org.hibernate.query.named; -import java.util.Map; - +import jakarta.persistence.CacheRetrieveMode; +import jakarta.persistence.CacheStoreMode; +import jakarta.persistence.LockModeType; +import jakarta.persistence.PessimisticLockScope; +import jakarta.persistence.Timeout; +import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.CacheMode; import org.hibernate.FlushMode; -import org.checkerframework.checker.nullness.qual.Nullable; +import java.util.Map; /** * @author Steve Ebersole @@ -17,6 +21,7 @@ */ public abstract class AbstractNamedQueryMemento implements NamedQueryMemento { private final String name; + private final @Nullable Class resultType; private final Boolean cacheable; @@ -26,7 +31,7 @@ public abstract class AbstractNamedQueryMemento implements NamedQueryMemento< private final FlushMode flushMode; private final Boolean readOnly; - private final Integer timeout; + private final Timeout timeout; private final Integer fetchSize; private final String comment; @@ -41,7 +46,7 @@ protected AbstractNamedQueryMemento( CacheMode cacheMode, FlushMode flushMode, Boolean readOnly, - Integer timeout, + Timeout timeout, Integer fetchSize, String comment, Map hints) { @@ -68,6 +73,11 @@ public String getRegistrationName() { return resultType; } + @Override + public String getEntityGraphName() { + return null; + } + @Override public Boolean getCacheable() { return cacheable; @@ -94,7 +104,7 @@ public Boolean getReadOnly() { } @Override - public Integer getTimeout() { + public Timeout getTimeout() { return timeout; } @@ -108,9 +118,28 @@ public String getComment() { return comment; } + @Override + public CacheRetrieveMode getCacheRetrieveMode() { + return cacheMode == null ? null : cacheMode.getJpaRetrieveMode(); + } + + @Override + public CacheStoreMode getCacheStoreMode() { + return cacheMode == null ? null : cacheMode.getJpaStoreMode(); + } + + @Override + public LockModeType getLockMode() { + return LockModeType.NONE; + } + + @Override + public PessimisticLockScope getPessimisticLockScope() { + return PessimisticLockScope.NORMAL; + } + @Override public Map getHints() { return hints; } - } diff --git a/hibernate-core/src/main/java/org/hibernate/query/named/FetchMemento.java b/hibernate-core/src/main/java/org/hibernate/query/named/FetchMemento.java index 3aa70eb8120b..54724c4e7b06 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/named/FetchMemento.java +++ b/hibernate-core/src/main/java/org/hibernate/query/named/FetchMemento.java @@ -6,8 +6,10 @@ import java.util.function.Consumer; +import jakarta.persistence.sql.MemberMapping; +import org.hibernate.SessionFactory; import org.hibernate.query.internal.ResultSetMappingResolutionContext; -import org.hibernate.query.results.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilder; /** * @author Steve Ebersole @@ -17,10 +19,15 @@ public interface FetchMemento extends ModelPartReferenceMemento { * The parent node for the fetch */ interface Parent extends ModelPartReferenceMemento { + Class getResultJavaType(); } /** * Resolve the fetch-memento into the result-graph-node builder */ FetchBuilder resolve(Parent parent, Consumer querySpaceConsumer, ResultSetMappingResolutionContext context); + + default MemberMapping toJpaMemberMapping(Parent parent, SessionFactory sessionFactory) { + throw new UnsupportedOperationException( "Not implemented yet - " + getClass().getName() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/named/FetchMementoBasic.java b/hibernate-core/src/main/java/org/hibernate/query/named/FetchMementoBasic.java index 5398f1e7fb29..69bef8a251e5 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/named/FetchMementoBasic.java +++ b/hibernate-core/src/main/java/org/hibernate/query/named/FetchMementoBasic.java @@ -7,7 +7,7 @@ import java.util.function.Consumer; import org.hibernate.query.internal.ResultSetMappingResolutionContext; -import org.hibernate.query.results.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilder; /** * @author Steve Ebersole diff --git a/hibernate-core/src/main/java/org/hibernate/query/named/ModelPartResultMementoEntity.java b/hibernate-core/src/main/java/org/hibernate/query/named/ModelPartResultMementoEntity.java deleted file mode 100644 index 2e3abcd036d6..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/query/named/ModelPartResultMementoEntity.java +++ /dev/null @@ -1,11 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.query.named; - -/** - * @author Steve Ebersole - */ -public interface ModelPartResultMementoEntity extends ModelPartResultMemento, ResultMementoEntity { -} diff --git a/hibernate-core/src/main/java/org/hibernate/query/named/NamedQueryMemento.java b/hibernate-core/src/main/java/org/hibernate/query/named/NamedQueryMemento.java index 657038424d60..c4ffc26f1272 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/named/NamedQueryMemento.java +++ b/hibernate-core/src/main/java/org/hibernate/query/named/NamedQueryMemento.java @@ -4,16 +4,16 @@ */ package org.hibernate.query.named; -import java.util.Map; - +import jakarta.persistence.Timeout; import org.hibernate.CacheMode; import org.hibernate.FlushMode; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.query.spi.JpaTypedQueryReference; import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.spi.QueryImplementor; import org.hibernate.query.spi.QueryParameterImplementor; -import jakarta.persistence.TypedQueryReference; +import java.util.Map; /** * The runtime representation of named queries. They are stored in and @@ -23,7 +23,7 @@ * * @author Steve Ebersole */ -public interface NamedQueryMemento extends TypedQueryReference { +public interface NamedQueryMemento extends JpaTypedQueryReference { /** * The name under which the query is registered */ @@ -44,7 +44,7 @@ default String getName() { Boolean getReadOnly(); - Integer getTimeout(); + Timeout getTimeout(); Integer getFetchSize(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/named/NamedResultSetMappingMemento.java b/hibernate-core/src/main/java/org/hibernate/query/named/NamedResultSetMappingMemento.java index a3dd8c7a2011..0d775e3d525c 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/named/NamedResultSetMappingMemento.java +++ b/hibernate-core/src/main/java/org/hibernate/query/named/NamedResultSetMappingMemento.java @@ -4,11 +4,14 @@ */ package org.hibernate.query.named; +import java.util.List; import java.util.function.Consumer; import org.hibernate.Incubating; +import org.hibernate.SessionFactory; import org.hibernate.query.internal.ResultSetMappingResolutionContext; -import org.hibernate.query.results.ResultSetMapping; +import org.hibernate.query.results.spi.ResultBuilder; +import org.hibernate.query.results.spi.ResultSetMapping; /** * Used to keep information about named result mappings defined by the @@ -32,7 +35,12 @@ public interface NamedResultSetMappingMemento { String getName(); /** - * Resolve this memento. This involves building {@link org.hibernate.query.results.ResultBuilder} + * Obtain the memento for each result in the mapping. + */ + List getResultMementos(); + + /** + * Resolve this memento. This involves building {@link ResultBuilder} * instances for each defined result and registering them with the passed {@code resultSetMapping}. * Any known query spaces should be passed to the {@code querySpaceConsumer}. */ @@ -40,4 +48,22 @@ void resolve( ResultSetMapping resultSetMapping, Consumer querySpaceConsumer, ResultSetMappingResolutionContext context); + + /** + * Whether the "inferred result type is assignable to the given Java type". + * + * @see jakarta.persistence.EntityManagerFactory#getResultSetMappings + * + * @since 8.0 + */ + boolean canBeTreatedAsResultSetMapping(Class resultType, SessionFactory sessionFactory); + + /** + * Converts this named mapping into a {@linkplain jakarta.persistence.sql.ResultSetMapping}. + * + * @see jakarta.persistence.EntityManagerFactory#getResultSetMappings + * + * @since 8.0 + */ + jakarta.persistence.sql.ResultSetMapping toJpaMapping(SessionFactory sessionFactory); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/named/ResultMemento.java b/hibernate-core/src/main/java/org/hibernate/query/named/ResultMemento.java index 01653e10f1d4..8063c9b281ea 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/named/ResultMemento.java +++ b/hibernate-core/src/main/java/org/hibernate/query/named/ResultMemento.java @@ -6,16 +6,38 @@ import java.util.function.Consumer; +import jakarta.persistence.sql.MappingElement; +import jakarta.persistence.sql.ResultSetMapping; import org.hibernate.Incubating; +import org.hibernate.SessionFactory; import org.hibernate.query.internal.ResultSetMappingResolutionContext; -import org.hibernate.query.results.ResultBuilder; +import org.hibernate.query.results.spi.ResultBuilder; /** + * Models a SQL ResultSet mapping generally defined via {@linkplain jakarta.persistence.SqlResultSetMapping annotations}. + * May also be created via + * . + * + * [1] Or through + * * @since 6.0 * * @author Steve Ebersole */ @Incubating public interface ResultMemento extends ResultMappingMementoNode { + + Class getResultJavaType(); + ResultBuilder resolve(Consumer querySpaceConsumer, ResultSetMappingResolutionContext context); + + default boolean canBeTreatedAsResultSetMapping(Class resultType, SessionFactory sessionFactory) { + return resultType.isAssignableFrom( getResultJavaType() ); + } + + ResultSetMapping toJpaMapping(SessionFactory sessionFactory); + + default MappingElement toJpaMappingElement(SessionFactory sessionFactory) { + throw new UnsupportedOperationException(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/named/ResultMementoBasic.java b/hibernate-core/src/main/java/org/hibernate/query/named/ResultMementoBasic.java index 0b852d777d93..184dd1393ab6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/named/ResultMementoBasic.java +++ b/hibernate-core/src/main/java/org/hibernate/query/named/ResultMementoBasic.java @@ -7,7 +7,7 @@ import java.util.function.Consumer; import org.hibernate.query.internal.ResultSetMappingResolutionContext; -import org.hibernate.query.results.ResultBuilderBasicValued; +import org.hibernate.query.results.spi.ResultBuilderBasicValued; /** * @author Steve Ebersole diff --git a/hibernate-core/src/main/java/org/hibernate/query/named/ResultMementoEntity.java b/hibernate-core/src/main/java/org/hibernate/query/named/ResultMementoEntity.java index 95a165a10cf8..fbe12a550b80 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/named/ResultMementoEntity.java +++ b/hibernate-core/src/main/java/org/hibernate/query/named/ResultMementoEntity.java @@ -7,7 +7,7 @@ import java.util.function.Consumer; import org.hibernate.query.internal.ResultSetMappingResolutionContext; -import org.hibernate.query.results.ResultBuilderEntityValued; +import org.hibernate.query.results.spi.ResultBuilderEntityValued; /** * @author Steve Ebersole diff --git a/hibernate-core/src/main/java/org/hibernate/query/named/ResultMementoInstantiation.java b/hibernate-core/src/main/java/org/hibernate/query/named/ResultMementoInstantiation.java index d0056506128b..ac26ee5d7508 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/named/ResultMementoInstantiation.java +++ b/hibernate-core/src/main/java/org/hibernate/query/named/ResultMementoInstantiation.java @@ -6,8 +6,10 @@ import java.util.function.Consumer; +import jakarta.persistence.sql.MappingElement; +import org.hibernate.SessionFactory; import org.hibernate.query.internal.ResultSetMappingResolutionContext; -import org.hibernate.query.results.ResultBuilder; +import org.hibernate.query.results.spi.ResultBuilder; /** * @author Steve Ebersole @@ -23,5 +25,9 @@ public ArgumentMemento(ResultMemento argumentMemento) { public ResultBuilder resolve(Consumer querySpaceConsumer, ResultSetMappingResolutionContext context) { return argumentMemento.resolve( querySpaceConsumer, context ); } + + public MappingElement toJpaMapping(SessionFactory sessionFactory) { + return argumentMemento.toJpaMappingElement( sessionFactory ); + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/MissingSqlSelectionException.java b/hibernate-core/src/main/java/org/hibernate/query/results/MissingSqlSelectionException.java index 933576dbe44a..25c95f631c81 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/MissingSqlSelectionException.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/MissingSqlSelectionException.java @@ -5,6 +5,7 @@ package org.hibernate.query.results; import org.hibernate.HibernateException; +import org.hibernate.query.results.spi.ResultSetMapping; /** * Indicates that a column defined as part of a {@linkplain ResultSetMapping SQL ResultSet mapping} was not part diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/Builders.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/Builders.java index 80af905f3417..d7316188a45e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/Builders.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/Builders.java @@ -23,9 +23,9 @@ import org.hibernate.persister.entity.EntityPersister; import org.hibernate.query.NativeQuery; import org.hibernate.query.internal.ResultSetMappingResolutionContext; -import org.hibernate.query.results.FetchBuilder; -import org.hibernate.query.results.ResultBuilder; -import org.hibernate.query.results.ResultBuilderBasicValued; +import org.hibernate.query.results.spi.FetchBuilder; +import org.hibernate.query.results.spi.ResultBuilder; +import org.hibernate.query.results.spi.ResultBuilderBasicValued; import org.hibernate.query.results.internal.dynamic.DynamicFetchBuilderLegacy; import org.hibernate.query.results.internal.dynamic.DynamicResultBuilderAttribute; import org.hibernate.query.results.internal.dynamic.DynamicResultBuilderBasic; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/DomainResultCreationStateImpl.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/DomainResultCreationStateImpl.java index 8ad9b54376a1..8a0461f3fd22 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/DomainResultCreationStateImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/DomainResultCreationStateImpl.java @@ -17,8 +17,9 @@ import org.hibernate.metamodel.mapping.ForeignKeyDescriptor; import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.internal.CaseStatementDiscriminatorMappingImpl.CaseStatementDiscriminatorExpression; -import org.hibernate.query.results.FetchBuilder; -import org.hibernate.query.results.LegacyFetchBuilder; +import org.hibernate.query.results.spi.FetchBuilder; +import org.hibernate.query.results.spi.LegacyFetchBuilder; +import org.hibernate.query.results.spi.ResultSetMapping; import org.hibernate.spi.EntityIdentifierNavigablePath; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator; @@ -54,7 +55,7 @@ * Central implementation of {@linkplain DomainResultCreationState}, * {@linkplain SqlAstCreationState}, {@linkplain SqlAstProcessingState} and * {@linkplain SqlExpressionResolver} used while building - * {@linkplain org.hibernate.query.results.ResultSetMapping} references. + * {@linkplain ResultSetMapping} references. * * @author Steve Ebersole */ diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/FromClauseAccessImpl.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/FromClauseAccessImpl.java index 1f7ca19f94ea..b0776f57623b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/FromClauseAccessImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/FromClauseAccessImpl.java @@ -7,6 +7,7 @@ import java.util.HashMap; import java.util.Map; +import org.hibernate.query.results.spi.ResultSetMapping; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.ast.spi.FromClauseAccess; import org.hibernate.sql.ast.tree.from.TableGroup; @@ -15,7 +16,7 @@ /** * FromClauseAccess implementation used while building - * {@linkplain org.hibernate.query.results.ResultSetMapping} references. + * {@linkplain ResultSetMapping} references. * * @author Steve Ebersole */ diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/JdbcValuesMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/JdbcValuesMappingImpl.java index 60505b89dbd1..cfeecdfd4bd2 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/JdbcValuesMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/JdbcValuesMappingImpl.java @@ -6,6 +6,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.LockMode; +import org.hibernate.query.results.spi.ResultSetMapping; import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.jdbc.internal.StandardJdbcValuesMapping; @@ -15,7 +16,7 @@ /** * JdbcValuesMapping implementation used while building - * {@linkplain org.hibernate.query.results.ResultSetMapping} references. + * {@linkplain ResultSetMapping} references. * * @author Steve Ebersole */ diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/ResultSetMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/ResultSetMappingImpl.java index 696d56fa1bad..47039cdcde24 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/ResultSetMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/ResultSetMappingImpl.java @@ -9,9 +9,9 @@ import org.hibernate.loader.NonUniqueDiscoveredSqlAliasException; import org.hibernate.metamodel.mapping.BasicValuedMapping; import org.hibernate.query.named.NamedResultSetMappingMemento; -import org.hibernate.query.results.LegacyFetchBuilder; -import org.hibernate.query.results.ResultBuilder; -import org.hibernate.query.results.ResultSetMapping; +import org.hibernate.query.results.spi.LegacyFetchBuilder; +import org.hibernate.query.results.spi.ResultBuilder; +import org.hibernate.query.results.spi.ResultSetMapping; import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.Fetchable; @@ -38,7 +38,7 @@ /** * ResultSetMapping implementation used while building - * {@linkplain org.hibernate.query.results.ResultSetMapping} references. + * {@linkplain ResultSetMapping} references. * * @author Steve Ebersole */ diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/ResultSetMappingSqlSelection.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/ResultSetMappingSqlSelection.java index 544c885e89ee..ddf18c146d68 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/ResultSetMappingSqlSelection.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/ResultSetMappingSqlSelection.java @@ -8,6 +8,7 @@ import org.hibernate.metamodel.mapping.BasicValuedMapping; import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.MappingModelExpressible; +import org.hibernate.query.results.spi.ResultSetMapping; import org.hibernate.sql.ast.SqlAstWalker; import org.hibernate.sql.ast.spi.SqlExpressionAccess; import org.hibernate.sql.ast.spi.SqlSelection; @@ -17,7 +18,7 @@ /** * SqlSelection implementation used while building - * {@linkplain org.hibernate.query.results.ResultSetMapping} references. + * {@linkplain ResultSetMapping} references. * Doubles as its own {@link Expression} as well. * * @author Steve Ebersole diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/TableGroupImpl.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/TableGroupImpl.java index de16e794fd1c..6a34630f0d1e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/TableGroupImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/TableGroupImpl.java @@ -9,6 +9,7 @@ import java.util.function.Consumer; import org.hibernate.metamodel.mapping.ModelPartContainer; +import org.hibernate.query.results.spi.ResultSetMapping; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.ast.tree.from.AbstractTableGroup; import org.hibernate.sql.ast.tree.from.TableReference; @@ -16,7 +17,7 @@ /** * TableGroup implementation used while building - * {@linkplain org.hibernate.query.results.ResultSetMapping} references. + * {@linkplain ResultSetMapping} references. * * @author Steve Ebersole */ diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteFetchBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteFetchBuilder.java index 20bac450f0b2..1f2080d1915e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteFetchBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteFetchBuilder.java @@ -6,7 +6,7 @@ import java.util.List; -import org.hibernate.query.results.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilder; import org.hibernate.sql.results.graph.Fetchable; /** diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteFetchBuilderBasicPart.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteFetchBuilderBasicPart.java index 0ca9c312b9de..4f11c055be9d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteFetchBuilderBasicPart.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteFetchBuilderBasicPart.java @@ -8,8 +8,8 @@ import org.hibernate.engine.FetchTiming; import org.hibernate.metamodel.mapping.BasicValuedModelPart; import org.hibernate.metamodel.mapping.DiscriminatorMapping; -import org.hibernate.query.results.FetchBuilder; -import org.hibernate.query.results.FetchBuilderBasicValued; +import org.hibernate.query.results.spi.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilderBasicValued; import org.hibernate.query.results.MissingSqlSelectionException; import org.hibernate.query.results.internal.DomainResultCreationStateImpl; import org.hibernate.query.results.internal.ResultSetMappingSqlSelection; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteFetchBuilderEmbeddableValuedModelPart.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteFetchBuilderEmbeddableValuedModelPart.java index ed0d285799a1..59adfb75ecf4 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteFetchBuilderEmbeddableValuedModelPart.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteFetchBuilderEmbeddableValuedModelPart.java @@ -10,7 +10,7 @@ import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart; import org.hibernate.metamodel.mapping.SelectableMapping; import org.hibernate.query.results.internal.DomainResultCreationStateImpl; -import org.hibernate.query.results.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilder; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.results.graph.DomainResultCreationState; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteFetchBuilderEntityValuedModelPart.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteFetchBuilderEntityValuedModelPart.java index 76562a355f29..dece00e34fa4 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteFetchBuilderEntityValuedModelPart.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteFetchBuilderEntityValuedModelPart.java @@ -11,7 +11,7 @@ import org.hibernate.metamodel.mapping.ValuedModelPart; import org.hibernate.spi.NavigablePath; import org.hibernate.query.results.internal.DomainResultCreationStateImpl; -import org.hibernate.query.results.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilder; import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.Fetch; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilder.java index ab58b5137845..2959aae9e6b7 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilder.java @@ -4,7 +4,7 @@ */ package org.hibernate.query.results.internal.complete; -import org.hibernate.query.results.ResultBuilder; +import org.hibernate.query.results.spi.ResultBuilder; /** * @author Steve Ebersole diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderBasicModelPart.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderBasicModelPart.java index b2d091ef0666..1e7d51c7d3f8 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderBasicModelPart.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderBasicModelPart.java @@ -5,7 +5,7 @@ package org.hibernate.query.results.internal.complete; import org.hibernate.metamodel.mapping.BasicValuedModelPart; -import org.hibernate.query.results.ResultBuilder; +import org.hibernate.query.results.spi.ResultBuilder; import org.hibernate.query.results.internal.DomainResultCreationStateImpl; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.ast.spi.SqlSelection; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderBasicValued.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderBasicValued.java index 9f7cc908c2ff..44f8fb01d6b5 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderBasicValued.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderBasicValued.java @@ -4,7 +4,7 @@ */ package org.hibernate.query.results.internal.complete; -import org.hibernate.query.results.ResultBuilderBasicValued; +import org.hibernate.query.results.spi.ResultBuilderBasicValued; /** * Nominal extension to ResultBuilder for cases involving scalar results diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderBasicValuedConverted.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderBasicValuedConverted.java index 60c3ae9876ee..08b79747bba2 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderBasicValuedConverted.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderBasicValuedConverted.java @@ -6,7 +6,7 @@ import jakarta.persistence.AttributeConverter; import org.hibernate.metamodel.mapping.BasicValuedMapping; -import org.hibernate.query.results.ResultBuilder; +import org.hibernate.query.results.spi.ResultBuilder; import org.hibernate.query.results.internal.DomainResultCreationStateImpl; import org.hibernate.query.results.internal.ResultSetMappingSqlSelection; import org.hibernate.resource.beans.spi.ManagedBean; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderBasicValuedStandard.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderBasicValuedStandard.java index aca2d976e682..99154668d6de 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderBasicValuedStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderBasicValuedStandard.java @@ -5,7 +5,7 @@ package org.hibernate.query.results.internal.complete; import org.hibernate.metamodel.mapping.BasicValuedMapping; -import org.hibernate.query.results.ResultBuilder; +import org.hibernate.query.results.spi.ResultBuilder; import org.hibernate.query.results.internal.DomainResultCreationStateImpl; import org.hibernate.query.results.internal.ResultSetMappingSqlSelection; import org.hibernate.sql.ast.spi.SqlSelection; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderCollectionStandard.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderCollectionStandard.java index 7c467fb96eec..83c5be040a29 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderCollectionStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderCollectionStandard.java @@ -9,7 +9,7 @@ import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.metamodel.mapping.SelectableConsumer; import org.hibernate.query.NativeQuery; -import org.hibernate.query.results.ResultBuilder; +import org.hibernate.query.results.spi.ResultBuilder; import org.hibernate.query.results.internal.DomainResultCreationStateImpl; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.ast.spi.SqlAliasBaseConstant; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderEntityJpa.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderEntityJpa.java index 1070adf3356c..f1658289970e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderEntityJpa.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderEntityJpa.java @@ -7,9 +7,9 @@ import org.hibernate.LockMode; import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; import org.hibernate.metamodel.mapping.EntityMappingType; -import org.hibernate.query.results.FetchBuilder; -import org.hibernate.query.results.FetchBuilderBasicValued; -import org.hibernate.query.results.ResultBuilder; +import org.hibernate.query.results.spi.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilderBasicValued; +import org.hibernate.query.results.spi.ResultBuilder; import org.hibernate.query.results.internal.ResultsHelper; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.results.graph.DomainResultCreationState; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderEntityStandard.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderEntityStandard.java index d4f4960e0505..b08d93ced54f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderEntityStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderEntityStandard.java @@ -8,9 +8,9 @@ import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.query.NativeQuery; -import org.hibernate.query.results.FetchBuilder; -import org.hibernate.query.results.FetchBuilderBasicValued; -import org.hibernate.query.results.ResultBuilder; +import org.hibernate.query.results.spi.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilderBasicValued; +import org.hibernate.query.results.spi.ResultBuilder; import org.hibernate.query.results.internal.ResultsHelper; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.ast.spi.SqlAliasBaseConstant; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderEntityValued.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderEntityValued.java index 2a3284a0af7f..4c4aa72e3acd 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderEntityValued.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderEntityValued.java @@ -5,7 +5,7 @@ package org.hibernate.query.results.internal.complete; import org.hibernate.metamodel.mapping.EntityMappingType; -import org.hibernate.query.results.ResultBuilderEntityValued; +import org.hibernate.query.results.spi.ResultBuilderEntityValued; /** * @author Steve Ebersole diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderInstantiation.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderInstantiation.java index 73df68f9526f..1a750b9553f2 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderInstantiation.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/CompleteResultBuilderInstantiation.java @@ -4,8 +4,8 @@ */ package org.hibernate.query.results.internal.complete; -import org.hibernate.query.results.ResultBuilder; -import org.hibernate.query.results.ResultBuilderInstantiationValued; +import org.hibernate.query.results.spi.ResultBuilder; +import org.hibernate.query.results.spi.ResultBuilderInstantiationValued; import org.hibernate.query.sqm.DynamicInstantiationNature; import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResultCreationState; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/DelayedFetchBuilderBasicPart.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/DelayedFetchBuilderBasicPart.java index c96d76f4b8e6..9b8835c201c2 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/DelayedFetchBuilderBasicPart.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/DelayedFetchBuilderBasicPart.java @@ -6,8 +6,8 @@ import org.hibernate.engine.FetchTiming; import org.hibernate.metamodel.mapping.BasicValuedModelPart; -import org.hibernate.query.results.FetchBuilder; -import org.hibernate.query.results.FetchBuilderBasicValued; +import org.hibernate.query.results.spi.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilderBasicValued; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.FetchParent; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/ModelPartReference.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/ModelPartReference.java index 45518f4cee8e..cb55cf8294bd 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/ModelPartReference.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/complete/ModelPartReference.java @@ -6,8 +6,8 @@ import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.spi.NavigablePath; -import org.hibernate.query.results.FetchBuilder; -import org.hibernate.query.results.ResultBuilder; +import org.hibernate.query.results.spi.FetchBuilder; +import org.hibernate.query.results.spi.ResultBuilder; /** * A {@link ResultBuilder} or {@link FetchBuilder} that refers to some part diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/AbstractFetchBuilderContainer.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/AbstractFetchBuilderContainer.java index 4a9c1d222327..ce9b6eac7205 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/AbstractFetchBuilderContainer.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/AbstractFetchBuilderContainer.java @@ -9,7 +9,7 @@ import java.util.Map; import org.hibernate.internal.util.collections.ArrayHelper; -import org.hibernate.query.results.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilder; import org.hibernate.sql.results.graph.Fetchable; /** diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicFetchBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicFetchBuilder.java index cd04e0eab1ec..256709f5db52 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicFetchBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicFetchBuilder.java @@ -7,7 +7,7 @@ import java.util.List; import org.hibernate.query.NativeQuery; -import org.hibernate.query.results.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilder; /** * @author Steve Ebersole diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicFetchBuilderContainer.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicFetchBuilderContainer.java index 5192a0b337a9..1f5be6946120 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicFetchBuilderContainer.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicFetchBuilderContainer.java @@ -4,7 +4,7 @@ */ package org.hibernate.query.results.internal.dynamic; -import org.hibernate.query.results.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilder; import org.hibernate.sql.results.graph.Fetchable; /** diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicFetchBuilderLegacy.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicFetchBuilderLegacy.java index 77aa7173051f..b825368a6915 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicFetchBuilderLegacy.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicFetchBuilderLegacy.java @@ -16,8 +16,8 @@ import org.hibernate.metamodel.mapping.internal.EntityCollectionPart; import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; import org.hibernate.query.NativeQuery; -import org.hibernate.query.results.FetchBuilder; -import org.hibernate.query.results.LegacyFetchBuilder; +import org.hibernate.query.results.spi.FetchBuilder; +import org.hibernate.query.results.spi.LegacyFetchBuilder; import org.hibernate.query.results.internal.DomainResultCreationStateImpl; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.ast.SqlAstJoinType; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicResultBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicResultBuilder.java index 0b6b0b8e49c3..e511f2dfa631 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicResultBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicResultBuilder.java @@ -5,7 +5,7 @@ package org.hibernate.query.results.internal.dynamic; import org.hibernate.query.NativeQuery; -import org.hibernate.query.results.ResultBuilder; +import org.hibernate.query.results.spi.ResultBuilder; /** * ResultBuilder specialization for results added through the Hibernate-specific diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicResultBuilderBasic.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicResultBuilderBasic.java index bab7d4ad708a..dc4eab9170f3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicResultBuilderBasic.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicResultBuilderBasic.java @@ -4,7 +4,7 @@ */ package org.hibernate.query.results.internal.dynamic; -import org.hibernate.query.results.ResultBuilderBasicValued; +import org.hibernate.query.results.spi.ResultBuilderBasicValued; /** * @author Steve Ebersole diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicResultBuilderEntity.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicResultBuilderEntity.java index 3e1ec5b232fb..49ae419ae62e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicResultBuilderEntity.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicResultBuilderEntity.java @@ -4,7 +4,7 @@ */ package org.hibernate.query.results.internal.dynamic; -import org.hibernate.query.results.ResultBuilderEntityValued; +import org.hibernate.query.results.spi.ResultBuilderEntityValued; import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.entity.EntityResult; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicResultBuilderEntityStandard.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicResultBuilderEntityStandard.java index 65b80f7c4fff..214add6fb9c1 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicResultBuilderEntityStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicResultBuilderEntityStandard.java @@ -16,7 +16,7 @@ import org.hibernate.metamodel.mapping.SelectableMapping; import org.hibernate.metamodel.mapping.internal.ManyToManyCollectionPart; import org.hibernate.query.NativeQuery; -import org.hibernate.query.results.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilder; import org.hibernate.query.results.internal.complete.CompleteFetchBuilder; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.ast.spi.SqlAliasBaseConstant; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicResultBuilderInstantiation.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicResultBuilderInstantiation.java index 402d4ddcd2b6..54a18e7c1fe0 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicResultBuilderInstantiation.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/dynamic/DynamicResultBuilderInstantiation.java @@ -6,7 +6,7 @@ import org.hibernate.query.NativeQuery; import org.hibernate.query.results.internal.Builders; -import org.hibernate.query.results.ResultBuilderInstantiationValued; +import org.hibernate.query.results.spi.ResultBuilderInstantiationValued; import org.hibernate.query.sqm.DynamicInstantiationNature; import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResultCreationState; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitAttributeFetchBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitAttributeFetchBuilder.java index 56bac498d5e4..9475be2a1080 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitAttributeFetchBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitAttributeFetchBuilder.java @@ -6,7 +6,7 @@ import org.hibernate.engine.FetchTiming; import org.hibernate.metamodel.mapping.AttributeMapping; -import org.hibernate.query.results.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilder; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.Fetch; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilder.java index ef9f55f40fc3..ead0078aed80 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilder.java @@ -4,7 +4,7 @@ */ package org.hibernate.query.results.internal.implicit; -import org.hibernate.query.results.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilder; /** * @author Steve Ebersole diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilderBasic.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilderBasic.java index bbc96e3aca39..053111ffe14f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilderBasic.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilderBasic.java @@ -6,8 +6,8 @@ import org.hibernate.engine.FetchTiming; import org.hibernate.metamodel.mapping.BasicValuedModelPart; -import org.hibernate.query.results.FetchBuilder; -import org.hibernate.query.results.FetchBuilderBasicValued; +import org.hibernate.query.results.spi.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilderBasicValued; import org.hibernate.query.results.internal.ResultsHelper; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.ast.spi.SqlSelection; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilderDiscriminatedAssociation.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilderDiscriminatedAssociation.java index 7a76541aade3..f5c71104a67f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilderDiscriminatedAssociation.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilderDiscriminatedAssociation.java @@ -7,7 +7,7 @@ import org.hibernate.metamodel.mapping.internal.DiscriminatedAssociationAttributeMapping; import org.hibernate.query.results.internal.DomainResultCreationStateImpl; -import org.hibernate.query.results.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilder; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.ast.SqlAstJoinType; import org.hibernate.sql.results.graph.DomainResultCreationState; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilderEmbeddable.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilderEmbeddable.java index 756bd9771301..608b8f29abc6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilderEmbeddable.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilderEmbeddable.java @@ -5,7 +5,7 @@ package org.hibernate.query.results.internal.implicit; import org.hibernate.engine.FetchTiming; -import org.hibernate.query.results.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilder; import org.hibernate.query.results.internal.DomainResultCreationStateImpl; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.ast.SqlAstJoinType; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilderEntity.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilderEntity.java index 51ffe474b1b0..543ec6a95a3c 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilderEntity.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilderEntity.java @@ -7,7 +7,7 @@ import org.hibernate.metamodel.mapping.EmbeddableMappingType; import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; import org.hibernate.query.results.internal.Builders; -import org.hibernate.query.results.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilder; import org.hibernate.query.results.internal.DomainResultCreationStateImpl; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.results.graph.DomainResultCreationState; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilderEntityPart.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilderEntityPart.java index df8f6984bdf2..c76bd56d790e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilderEntityPart.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilderEntityPart.java @@ -8,7 +8,7 @@ import org.hibernate.engine.FetchTiming; import org.hibernate.metamodel.mapping.internal.EntityCollectionPart; import org.hibernate.spi.NavigablePath; -import org.hibernate.query.results.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilder; import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.FetchParent; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilderPlural.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilderPlural.java index 35b7b93e24b9..6473a08b5312 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilderPlural.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitFetchBuilderPlural.java @@ -7,7 +7,7 @@ import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.spi.NavigablePath; -import org.hibernate.query.results.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilder; import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.FetchParent; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitModelPartResultBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitModelPartResultBuilder.java index 8ab2d7e0d58a..37f0119b362b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitModelPartResultBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitModelPartResultBuilder.java @@ -4,7 +4,7 @@ */ package org.hibernate.query.results.internal.implicit; -import org.hibernate.query.results.ResultBuilder; +import org.hibernate.query.results.spi.ResultBuilder; /** * @author Steve Ebersole diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitModelPartResultBuilderEntity.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitModelPartResultBuilderEntity.java index 6a1503efa557..3269da07c02a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitModelPartResultBuilderEntity.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitModelPartResultBuilderEntity.java @@ -6,8 +6,8 @@ import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityValuedModelPart; -import org.hibernate.query.results.ResultBuilder; -import org.hibernate.query.results.ResultBuilderEntityValued; +import org.hibernate.query.results.spi.ResultBuilder; +import org.hibernate.query.results.spi.ResultBuilderEntityValued; import org.hibernate.query.results.internal.DomainResultCreationStateImpl; import org.hibernate.query.results.internal.ResultsHelper; import org.hibernate.spi.NavigablePath; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitResultClassBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitResultClassBuilder.java index 794511ddaed6..042bcbb14c4f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitResultClassBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/implicit/ImplicitResultClassBuilder.java @@ -6,7 +6,7 @@ import jakarta.persistence.NamedNativeQuery; import org.hibernate.metamodel.mapping.BasicValuedMapping; -import org.hibernate.query.results.ResultBuilder; +import org.hibernate.query.results.spi.ResultBuilder; import org.hibernate.query.results.internal.ResultSetMappingSqlSelection; import org.hibernate.sql.ast.spi.SqlExpressionResolver; import org.hibernate.sql.ast.spi.SqlSelection; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/AbstractMappingElementBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/AbstractMappingElementBuilder.java new file mode 100644 index 000000000000..9077c66709d9 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/AbstractMappingElementBuilder.java @@ -0,0 +1,38 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.query.results.internal.jpa; + +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.type.descriptor.java.JavaType; + +/** + * @author Steve Ebersole + */ +public abstract class AbstractMappingElementBuilder implements MappingElementBuilder { + protected final String alias; + protected final JavaType javaType; + + protected final SessionFactoryImplementor sessionFactory; + + public AbstractMappingElementBuilder(String alias, Class javaType, SessionFactoryImplementor sessionFactory) { + this( alias, sessionFactory.getTypeConfiguration().getJavaTypeRegistry().resolveDescriptor( javaType ), sessionFactory ); + } + + public AbstractMappingElementBuilder(String alias, JavaType javaType, SessionFactoryImplementor sessionFactory) { + this.alias = alias; + this.javaType = javaType; + this.sessionFactory = sessionFactory; + } + + @Override + public String getAlias() { + return alias; + } + + @Override + public Class getJavaType() { + return javaType.getJavaTypeClass(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/ColumnBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/ColumnBuilder.java new file mode 100644 index 000000000000..5b6e3aced49e --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/ColumnBuilder.java @@ -0,0 +1,66 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.query.results.internal.jpa; + +import jakarta.persistence.sql.ColumnMapping; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.metamodel.mapping.BasicValuedMapping; +import org.hibernate.query.results.internal.ResultSetMappingSqlSelection; +import org.hibernate.query.results.spi.ResultBuilder; +import org.hibernate.query.results.spi.ResultBuilderBasicValued; +import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.basic.BasicResult; +import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; + +import static org.hibernate.query.results.internal.ResultsHelper.jdbcPositionToValuesArrayPosition; +import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnReferenceKey; + +/// Support for [jakarta.persistence.sql.ColumnMapping]. +/// +/// @author Steve Ebersole +public class ColumnBuilder extends AbstractMappingElementBuilder implements ResultBuilderBasicValued { + private final String columnName; + + public ColumnBuilder(ColumnMapping columnMapping, SessionFactoryImplementor sessionFactory) { + super( columnMapping.getAlias(), columnMapping.getJavaType(), sessionFactory ); + columnName = columnMapping.columnName(); + } + + @Override + public ResultBuilder cacheKeyInstance() { + return this; + } + + @Override + public BasicResult buildResult( + JdbcValuesMetadata jdbcResultsMetadata, + int resultPosition, + DomainResultCreationState creationState) { + final var typeConfiguration = sessionFactory.getTypeConfiguration(); + final int jdbcPosition = jdbcResultsMetadata.resolveColumnPosition( columnName ); + final var sqlExprResolver = creationState.getSqlAstCreationState().getSqlExpressionResolver(); + var sqlSelection = sqlExprResolver.resolveSqlSelection( + sqlExprResolver.resolveSqlExpression( + createColumnReferenceKey( columnName ), + processingState -> new ResultSetMappingSqlSelection( + jdbcPositionToValuesArrayPosition( jdbcPosition ), + (BasicValuedMapping) jdbcResultsMetadata.resolveType( jdbcPosition, javaType, typeConfiguration ) + ) + ), + javaType, + null, + typeConfiguration + ); + + return new BasicResult<>( + sqlSelection.getValuesArrayPosition(), + columnName, + sqlSelection.getExpressionType().getSingleJdbcMapping(), + null, + false, + false + ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/ConstructorBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/ConstructorBuilder.java new file mode 100644 index 000000000000..611ea534b664 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/ConstructorBuilder.java @@ -0,0 +1,67 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.query.results.internal.jpa; + +import jakarta.persistence.sql.ConstructorMapping; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.query.results.spi.ResultBuilder; +import org.hibernate.query.results.spi.ResultBuilderInstantiationValued; +import org.hibernate.query.sqm.DynamicInstantiationNature; +import org.hibernate.sql.results.graph.DomainResult; +import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.instantiation.internal.ArgumentDomainResult; +import org.hibernate.sql.results.graph.instantiation.internal.DynamicInstantiationResultImpl; +import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; + +import java.util.List; + +import static org.hibernate.internal.util.collections.CollectionHelper.arrayList; + +/** + * @author Steve Ebersole + */ +public class ConstructorBuilder extends AbstractMappingElementBuilder implements ResultBuilderInstantiationValued { + private final MappingElementBuilder[] argumentElementBuilders; + + public ConstructorBuilder(ConstructorMapping constructorMapping, SessionFactoryImplementor sessionFactory) { + super( constructorMapping.getAlias(), constructorMapping.targetClass(), sessionFactory ); + + argumentElementBuilders = new MappingElementBuilder[constructorMapping.arguments().length]; + for ( int i = 0; i < constructorMapping.arguments().length; i++ ) { + argumentElementBuilders[i] = JpaMappingHelper.toHibernateBuilder( constructorMapping.arguments()[i], sessionFactory ); + } + } + + @Override + public DomainResult buildResult( + JdbcValuesMetadata jdbcResultsMetadata, + int resultPosition, + DomainResultCreationState creationState) { + return new DynamicInstantiationResultImpl<>( + null, + DynamicInstantiationNature.CLASS, + javaType, + argumentDomainResults( argumentElementBuilders, jdbcResultsMetadata, creationState ) + ); + } + + private static List> argumentDomainResults( + MappingElementBuilder[] argumentBuilders, + JdbcValuesMetadata jdbcResultsMetadata, + DomainResultCreationState creationState) { + final List> argumentDomainResults = arrayList( argumentBuilders.length ); + for ( int i = 0; i < argumentBuilders.length; i++ ) { + argumentDomainResults.add( new ArgumentDomainResult<>( + argumentBuilders[i].buildResult( jdbcResultsMetadata, i, creationState ) + ) ); + } + return argumentDomainResults; + } + + @Override + public ResultBuilder cacheKeyInstance() { + return this; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/EntityBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/EntityBuilder.java new file mode 100644 index 000000000000..396ce8da584f --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/EntityBuilder.java @@ -0,0 +1,292 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.query.results.internal.jpa; + +import jakarta.persistence.sql.EmbeddedMapping; +import jakarta.persistence.sql.EntityMapping; +import jakarta.persistence.sql.FieldMapping; +import jakarta.persistence.sql.MemberMapping; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.internal.util.StringHelper; +import org.hibernate.internal.util.collections.CollectionHelper; +import org.hibernate.metamodel.mapping.BasicValuedModelPart; +import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart; +import org.hibernate.metamodel.mapping.EntityMappingType; +import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping; +import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.query.results.internal.complete.CompleteFetchBuilderBasicPart; +import org.hibernate.query.results.internal.complete.CompleteFetchBuilderEmbeddableValuedModelPart; +import org.hibernate.query.results.spi.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilderBasicValued; +import org.hibernate.query.results.spi.ResultBuilder; +import org.hibernate.query.results.spi.ResultBuilderEntityValued; +import org.hibernate.spi.NavigablePath; +import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.entity.EntityResult; +import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; + +/// Support for [jakarta.persistence.sql.EntityMapping]. +/// +/// @see EntityResultImpl +/// +/// @author Steve Ebersole +public class EntityBuilder extends AbstractMappingElementBuilder implements ResultBuilderEntityValued { + private final EntityPersister entityDescriptor; + private final NavigablePath rootPath; + private final FetchBuilder identifierFetchBuilder; + private final FetchBuilderBasicValued discriminatorFetchBuilder; + private final Map attributeFetchBuilders = new HashMap<>(); + + public EntityBuilder(EntityMapping entityMapping, SessionFactoryImplementor sessionFactory) { + super( entityMapping.getAlias(), entityMapping.getJavaType(), sessionFactory ); + + this.entityDescriptor = sessionFactory.getMappingMetamodel().getEntityDescriptor( entityMapping.entityClass() ); + this.rootPath = new NavigablePath( entityDescriptor.getRootPathName() ); + + if ( StringHelper.isBlank( entityMapping.discriminatorColumn() ) ) { + discriminatorFetchBuilder = null; + } + else { + var discriminatorDescriptor = entityDescriptor.getDiscriminatorMapping(); + discriminatorFetchBuilder = new CompleteFetchBuilderBasicPart( + rootPath.append( discriminatorDescriptor.getPartName() ), + discriminatorDescriptor, + entityMapping.discriminatorColumn() + ); + } + + final IdentifierFetchHandler identifierFetchHandler = buildIdentifierFetchHandler( + entityDescriptor, + rootPath + ); + for ( int i = 0; i < entityMapping.fields().length; i++ ) { + final MemberMapping memberMapping = entityMapping.fields()[i]; + if ( memberMapping instanceof FieldMapping basicMapping ) { + if ( !identifierFetchHandler.handleMember( basicMapping ) ) { + final BasicValuedModelPart modelPart = entityDescriptor + .findSubPart( basicMapping.name() ) + .asBasicValuedModelPart(); + attributeFetchBuilders.put( basicMapping.name(), new CompleteFetchBuilderBasicPart( + rootPath.append( basicMapping.name() ), + modelPart, + basicMapping.columnName() + ) ); + } + } + else { + final EmbeddedMapping embeddedMapping = (EmbeddedMapping) memberMapping; + final EmbeddableValuedModelPart attributeMapping = + (EmbeddableValuedModelPart) entityDescriptor.findSubPart( embeddedMapping.name() ); + if ( !identifierFetchHandler.handleMember( embeddedMapping ) ) { + attributeFetchBuilders.put( embeddedMapping.name(), new CompleteFetchBuilderEmbeddableValuedModelPart( + rootPath.append( attributeMapping.getPartName() ), + attributeMapping, + extractColumnNames( embeddedMapping ) + ) ); + } + } + } + + this.identifierFetchBuilder = identifierFetchHandler.buildFetchBuilder(); + } + + private static List extractColumnNames(EmbeddedMapping embeddedMapping) { + final List names = new ArrayList<>(); + collectColumnNames( embeddedMapping, names::add ); + return names; + } + + private IdentifierFetchHandler buildIdentifierFetchHandler(EntityPersister entityDescriptor, NavigablePath rootPath) { + if ( entityDescriptor.getIdentifierMapping() instanceof NonAggregatedIdentifierMapping complexId ) { + return new ComplexIdentifierFetchHandler( entityDescriptor, complexId, rootPath ); + } + else { + return new SimpleIdentifierFetchHandler( + entityDescriptor, + (SingleAttributeIdentifierMapping) entityDescriptor.getIdentifierMapping(), + rootPath + ); + } + } + + /// Used to help deal with [MemberMapping] as either an id or attribute. + private interface IdentifierFetchHandler { + boolean handleMember(FieldMapping memberMapping); + boolean handleMember(EmbeddedMapping memberMapping); + FetchBuilder buildFetchBuilder(); + } + + private static class SimpleIdentifierFetchHandler implements IdentifierFetchHandler { + private final EntityMappingType entityDescriptor; + private final SingleAttributeIdentifierMapping idMapping; + private final NavigablePath rootPath; + private MemberMapping memberMapping; + + public SimpleIdentifierFetchHandler( + EntityMappingType entityDescriptor, + SingleAttributeIdentifierMapping idMapping, + NavigablePath rootPath) { + this.entityDescriptor = entityDescriptor; + this.idMapping = idMapping; + this.rootPath = rootPath; + } + + @Override + public boolean handleMember(FieldMapping memberMapping) { + final boolean isId = idMapping.getAttributeName().equals( memberMapping.name() ); + if ( isId ) { + setIdMapping( memberMapping ); + } + return isId; + } + + @Override + public boolean handleMember(EmbeddedMapping memberMapping) { + final boolean isId = idMapping.getAttributeName().equals( memberMapping.name() ); + if ( isId ) { + setIdMapping( memberMapping ); + } + return isId; + } + + private void setIdMapping(MemberMapping memberMapping) { + if ( this.memberMapping != null ) { + throw new IllegalStateException( "Multiple MemberMapping defined for simple identifier mapping : " + entityDescriptor.getEntityName() ); + } + this.memberMapping = memberMapping; + } + + @Override + public FetchBuilder buildFetchBuilder() { + if ( memberMapping instanceof FieldMapping basicMapping ) { + return new CompleteFetchBuilderBasicPart( + rootPath.append( basicMapping.name() ), + idMapping.asBasicValuedModelPart(), + basicMapping.columnName() + ); + } + else { + final var embeddedMapping = (EmbeddedMapping) memberMapping; + return new CompleteFetchBuilderEmbeddableValuedModelPart( + rootPath.append( embeddedMapping.name() ), + idMapping.asEmbeddedAttributeMapping(), + extractColumnNames( embeddedMapping ) + ); + } + } + } + + private static class ComplexIdentifierFetchHandler implements IdentifierFetchHandler { + private final Set idAttributeNames; + private final List columnNames; + private final NonAggregatedIdentifierMapping idMapping; + private final NavigablePath rootPath; + + public ComplexIdentifierFetchHandler( + EntityPersister entityDescriptor, + NonAggregatedIdentifierMapping idMapping, + NavigablePath rootPath) { + this.idMapping = idMapping; + this.rootPath = rootPath; + + idAttributeNames = new HashSet<>(); + idMapping.getVirtualIdEmbeddable().forEachAttributeMapping( (attr) -> idAttributeNames.add( attr.getAttributeName() ) ); + + columnNames = CollectionHelper.arrayList( idMapping.getJdbcTypeCount() ); + } + + @Override + public boolean handleMember(FieldMapping memberMapping) { + final boolean isId = idAttributeNames.contains( memberMapping.name() ); + if ( isId ) { + addId( memberMapping ); + } + return isId; + } + + @Override + public boolean handleMember(EmbeddedMapping memberMapping) { + return false; + } + + private void addId(MemberMapping memberMapping) { + collectColumnNames( memberMapping, columnNames::add ); + } + + @Override + public FetchBuilder buildFetchBuilder() { + return new CompleteFetchBuilderEmbeddableValuedModelPart( + rootPath.append( idMapping.getPartName() ), + idMapping, + columnNames + ); + } + } + + private static void collectColumnNames(MemberMapping memberMapping, Consumer columnNameConsumer) { + if ( memberMapping instanceof FieldMapping basicMapping ) { + columnNameConsumer.accept( basicMapping.columnName() ); + } + else { + var embeddedMapping = (EmbeddedMapping) memberMapping; + for ( MemberMapping embeddedMemberMapping : embeddedMapping.fields() ) { + collectColumnNames( embeddedMemberMapping, columnNameConsumer ); + } + } + } + + @Override + public EntityResult buildResult( + JdbcValuesMetadata jdbcResultsMetadata, + int resultPosition, + DomainResultCreationState creationState) { + applyTableGroup( resultPosition, creationState ); + + return new EntityResultImpl<>( + entityDescriptor, + javaType, + rootPath, + identifierFetchBuilder, + discriminatorFetchBuilder, + attributeFetchBuilders, + jdbcResultsMetadata, + creationState + ); + } + + private void applyTableGroup(int resultPosition, DomainResultCreationState creationState) { + final String implicitAlias = entityDescriptor.getSqlAliasStem() + resultPosition; + final var sqlAliasBase = creationState.getSqlAliasBaseManager().createSqlAliasBase( implicitAlias ); + + // we just want it added to the registry + creationState.getSqlAstCreationState().getFromClauseAccess().resolveTableGroup( + rootPath, + path -> entityDescriptor.createRootTableGroup( + // since this is only used for result set mappings, the canUseInnerJoins value is irrelevant. + true, + rootPath, + implicitAlias, + sqlAliasBase, + null, + creationState.getSqlAstCreationState() + ) + ); + } + + @Override + public ResultBuilder cacheKeyInstance() { + return this; + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/EntityResultImpl.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/EntityResultImpl.java new file mode 100644 index 000000000000..6b63162c48e8 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/EntityResultImpl.java @@ -0,0 +1,175 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.query.results.internal.jpa; + +import org.hibernate.annotations.NotFoundAction; +import org.hibernate.metamodel.mapping.EntityMappingType; +import org.hibernate.metamodel.mapping.EntityValuedModelPart; +import org.hibernate.query.results.spi.FetchBuilder; +import org.hibernate.query.results.spi.FetchBuilderBasicValued; +import org.hibernate.spi.NavigablePath; +import org.hibernate.sql.results.graph.AssemblerCreationState; +import org.hibernate.sql.results.graph.DomainResultAssembler; +import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.Fetch; +import org.hibernate.sql.results.graph.Fetchable; +import org.hibernate.sql.results.graph.FetchableContainer; +import org.hibernate.sql.results.graph.Initializer; +import org.hibernate.sql.results.graph.InitializerParent; +import org.hibernate.sql.results.graph.basic.BasicFetch; +import org.hibernate.sql.results.graph.entity.EntityResult; +import org.hibernate.sql.results.graph.entity.internal.EntityAssembler; +import org.hibernate.sql.results.graph.entity.internal.EntityInitializerImpl; +import org.hibernate.sql.results.graph.internal.ImmutableFetchList; +import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; +import org.hibernate.type.descriptor.java.JavaType; + +import java.util.Map; + +/// [EntityResult] implementation for handling [jakarta.persistence.sql.EntityMapping]. +/// +/// @see EntityBuilder +/// +/// @author Steve Ebersole +class EntityResultImpl implements EntityResult { + private final EntityMappingType entityDescriptor; + + private final JavaType javaType; + private final NavigablePath navigablePath; + + private final Fetch identifierFetch; + private final BasicFetch discriminatorFetch; + private final ImmutableFetchList fetches; + + public EntityResultImpl( + EntityMappingType entityDescriptor, + JavaType javaType, + NavigablePath navigablePath, + FetchBuilder identifierFetchBuilder, + FetchBuilderBasicValued discriminatorFetchBuilder, + Map attributeFetchBuilders, + JdbcValuesMetadata jdbcResultsMetadata, + DomainResultCreationState creationState) { + this.entityDescriptor = entityDescriptor; + this.javaType = javaType; + this.navigablePath = navigablePath; + + this.identifierFetch = identifierFetchBuilder.buildFetch( + this, + navigablePath.append( entityDescriptor.getIdentifierMapping().getPartName() ), + jdbcResultsMetadata, + creationState + ); + + this.discriminatorFetch = discriminatorFetchBuilder == null + ? null + : discriminatorFetchBuilder.buildFetch( + this, + navigablePath.append( entityDescriptor.getDiscriminatorMapping().getPartName() ), + jdbcResultsMetadata, + creationState + ); + + final ImmutableFetchList.Builder fetchCollector = new ImmutableFetchList.Builder( entityDescriptor ); + entityDescriptor.forEachAttributeMapping( (position, attribute) -> { + final FetchBuilder fetchBuilder = attributeFetchBuilders.get( attribute.getAttributeName() ); + if ( fetchBuilder != null ) { + fetchCollector.add( fetchBuilder.buildFetch( + this, + navigablePath.append( attribute.getPartName() ), + jdbcResultsMetadata, + creationState + ) ); + } + else { + fetchCollector.add( attribute.generateFetch( + this, + navigablePath.append( attribute.getPartName() ), + attribute.getMappedFetchOptions().getTiming(), + false, + null, + creationState + ) ); + } + } ); + this.fetches = fetchCollector.build(); + } + + @Override + public DomainResultAssembler createResultAssembler( + InitializerParent parent, + AssemblerCreationState creationState) { + return new EntityAssembler<>( + getResultJavaType(), + creationState.resolveInitializer( navigablePath, entityDescriptor, + () -> createInitializer( parent, creationState ) ) + .asEntityInitializer() + ); + } + + @Override + public Initializer createInitializer( + InitializerParent parent, + AssemblerCreationState creationState) { + return new EntityInitializerImpl( + this, + getResultVariable(), + identifierFetch, + discriminatorFetch, + null, + null, + NotFoundAction.EXCEPTION, + false, + null, + true, + creationState + ); + } + + @Override + public JavaType getResultJavaType() { + return javaType; + } + + @Override + public String getResultVariable() { + return ""; + } + + @Override + public FetchableContainer getReferencedMappingType() { + return entityDescriptor; + } + + @Override + public NavigablePath getNavigablePath() { + return navigablePath; + } + + @Override + public ImmutableFetchList getFetches() { + return fetches; + } + + @Override + public Fetch findFetch(Fetchable fetchable) { + return fetches.get( fetchable ); + } + + @Override + public boolean hasJoinFetches() { + return fetches.hasJoinFetches(); + } + + @Override + public boolean containsCollectionFetches() { + return fetches.containsCollectionFetches(); + } + + @Override + public EntityValuedModelPart getEntityValuedModelPart() { + return entityDescriptor; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/JpaMappingHelper.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/JpaMappingHelper.java new file mode 100644 index 000000000000..a5fd97f1c07a --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/JpaMappingHelper.java @@ -0,0 +1,76 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.query.results.internal.jpa; + +import jakarta.persistence.sql.ColumnMapping; +import jakarta.persistence.sql.CompoundMapping; +import jakarta.persistence.sql.ConstructorMapping; +import jakarta.persistence.sql.EntityMapping; +import jakarta.persistence.sql.MappingElement; +import jakarta.persistence.sql.TupleMapping; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.query.results.spi.ResultSetMapping; + +/// Support for dealing with Jakarta Persistence [jakarta.persistence.sql.ResultSetMapping], both +/// in terms of - +/// +/// * converting one to the Hibernate [form][ResultSetMapping] +/// * creating one from Hibernate's [memento][org.hibernate.query.named.NamedResultSetMappingMemento] +/// +/// @author Steve Ebersole +public class JpaMappingHelper { + public static ResultSetMapping toHibernateMapping( + jakarta.persistence.sql.ResultSetMapping jpaMapping, + SessionFactoryImplementor sessionFactory) { + var resultMapping = sessionFactory.getJdbcValuesMappingProducerProvider() + .buildResultSetMapping( null, true, sessionFactory ); + apply( jpaMapping, resultMapping, sessionFactory ); + return resultMapping; + } + + private static void apply( + jakarta.persistence.sql.ResultSetMapping jpaMapping, + ResultSetMapping resultMapping, + SessionFactoryImplementor sessionFactory) { + if ( jpaMapping instanceof ColumnMapping columnMapping ) { + resultMapping.addResultBuilder( new ColumnBuilder<>( columnMapping, sessionFactory ) ); + } + else if ( jpaMapping instanceof ConstructorMapping constructorMapping ) { + resultMapping.addResultBuilder( new ConstructorBuilder<>( constructorMapping, sessionFactory ) ); + } + else if ( jpaMapping instanceof EntityMapping entityMapping ) { + resultMapping.addResultBuilder( new EntityBuilder<>( entityMapping, sessionFactory ) ); + } + else if ( jpaMapping instanceof TupleMapping tupleMapping ) { + resultMapping.addResultBuilder( new TupleBuilder( tupleMapping, sessionFactory ) ); + } + else if ( jpaMapping instanceof CompoundMapping compoundMapping ) { + for ( int i = 0; i < compoundMapping.elements().length; i++ ) { + final MappingElement mappingElement = compoundMapping.elements()[i]; + resultMapping.addResultBuilder( toHibernateBuilder( mappingElement, sessionFactory ) ); + } + } + else { + throw new IllegalArgumentException( "Unsupported jakarta.persistence.sql.ResultSetMapping type : " + jpaMapping.getClass().getName() ); + } + } + + public static MappingElementBuilder toHibernateBuilder( + jakarta.persistence.sql.MappingElement jpaMapping, + SessionFactoryImplementor sessionFactory) { + if ( jpaMapping instanceof ColumnMapping columnMapping ) { + return new ColumnBuilder<>( columnMapping, sessionFactory ); + } + else if ( jpaMapping instanceof ConstructorMapping constructorMapping ) { + return new ConstructorBuilder<>( constructorMapping, sessionFactory ); + } + else if ( jpaMapping instanceof EntityMapping entityMapping ) { + return new EntityBuilder<>( entityMapping, sessionFactory ); + } + else { + throw new IllegalArgumentException( "Unsupported jakarta.persistence.sql.MappingElement type : " + jpaMapping.getClass().getName() ); + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/MappingElementBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/MappingElementBuilder.java new file mode 100644 index 000000000000..21e5e01664f3 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/MappingElementBuilder.java @@ -0,0 +1,19 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.query.results.internal.jpa; + +import org.hibernate.query.results.spi.ResultBuilder; + +/// Adapter for [jakarta.persistence.sql.MappingElement] as a +/// [org.hibernate.query.results.spi.ResultBuilder]. +/// +/// @author Steve Ebersole +public interface MappingElementBuilder extends ResultBuilder { + /// @see jakarta.persistence.sql.MappingElement#getAlias() + String getAlias(); + + /// @see jakarta.persistence.sql.MappingElement#getJavaType() + Class getJavaType(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/TupleBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/TupleBuilder.java new file mode 100644 index 000000000000..36926966b935 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/TupleBuilder.java @@ -0,0 +1,78 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.query.results.internal.jpa; + +import jakarta.persistence.Tuple; +import jakarta.persistence.TupleElement; +import jakarta.persistence.sql.TupleMapping; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.internal.util.StringHelper; +import org.hibernate.query.results.spi.ResultBuilder; +import org.hibernate.sql.results.graph.DomainResult; +import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.internal.TupleMetadata; +import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; + +/** + * @author Steve Ebersole + */ +public class TupleBuilder extends AbstractMappingElementBuilder implements ResultBuilder { + private final TupleMetadata tupleMetadata; + private final ResultBuilder[] elementBuilders; + + public TupleBuilder(TupleMapping tupleMapping, SessionFactoryImplementor sessionFactory) { + super( null, sessionFactory.getTypeConfiguration().getJavaTypeRegistry().resolveDescriptor( Tuple.class ), sessionFactory ); + + this.elementBuilders = new ResultBuilder[ tupleMapping.elements().length ]; + final TupleMetadataBuilder metadataBuilder = new TupleMetadataBuilder( tupleMapping.elements().length ); + for ( int i = 0; i < tupleMapping.elements().length; i++ ) { + metadataBuilder.add( tupleMapping.elements()[i] ); + elementBuilders[i] = JpaMappingHelper.toHibernateBuilder( + tupleMapping.elements()[i], + sessionFactory + ); + } + this.tupleMetadata = metadataBuilder.buildMetadata(); + } + + @Override + public DomainResult buildResult( + JdbcValuesMetadata jdbcResultsMetadata, + int resultPosition, + DomainResultCreationState creationState) { + final DomainResult[] elementResults = new DomainResult[elementBuilders.length]; + for ( int i = 0; i < elementBuilders.length; i++ ) { + elementResults[i] = elementBuilders[i].buildResult( jdbcResultsMetadata, resultPosition, creationState ); + } + return new TupleResultImpl( javaType, tupleMetadata, elementResults ); + } + + @Override + public ResultBuilder cacheKeyInstance() { + return this; + } + + private static class TupleMetadataBuilder { + private final TupleElement[] elements; + private final String[] aliases; + + private int collectionPosition; + + public TupleMetadataBuilder(int elementCount) { + elements = new TupleElement[elementCount]; + aliases = new String[elementCount]; + } + + public void add(TupleElement element) { + elements[collectionPosition] = element; + aliases[collectionPosition] = StringHelper.nullIfBlank( element.getAlias() ); + collectionPosition++; + } + + public TupleMetadata buildMetadata() { + return new TupleMetadata( elements, aliases ); + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/TupleResultImpl.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/TupleResultImpl.java new file mode 100644 index 000000000000..07d9895dd8b4 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/TupleResultImpl.java @@ -0,0 +1,72 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.query.results.internal.jpa; + +import jakarta.persistence.Tuple; +import org.hibernate.sql.results.graph.AssemblerCreationState; +import org.hibernate.sql.results.graph.DomainResult; +import org.hibernate.sql.results.graph.DomainResultAssembler; +import org.hibernate.sql.results.graph.InitializerParent; +import org.hibernate.sql.results.internal.TupleImpl; +import org.hibernate.sql.results.internal.TupleMetadata; +import org.hibernate.sql.results.jdbc.spi.RowProcessingState; +import org.hibernate.type.descriptor.java.JavaType; + +import java.util.BitSet; + +/** + * @author Steve Ebersole + */ +public record TupleResultImpl( + JavaType resultType, + TupleMetadata tupleMetadata, + DomainResult[] elementResults) implements DomainResult { + + @Override + public JavaType getResultJavaType() { + return resultType; + } + + @Override + public String getResultVariable() { + return ""; + } + + @Override + public TupleAssembler createResultAssembler( + InitializerParent parent, + AssemblerCreationState creationState) { + final DomainResultAssembler[] elementAssemblers = new DomainResultAssembler[elementResults.length]; + for ( int i = 0; i < elementResults.length; i++ ) { + elementAssemblers[i] = elementResults[i].createResultAssembler( parent, creationState ); + } + return new TupleAssembler( resultType, tupleMetadata, elementAssemblers ); + } + + @Override + public void collectValueIndexesToCache(BitSet valueIndexes) { + + } + + public record TupleAssembler( + JavaType resultType, + TupleMetadata tupleMetadata, + DomainResultAssembler[] elementAssemblers) implements DomainResultAssembler { + + @Override + public JavaType getAssembledJavaType() { + return resultType; + } + + @Override + public Tuple assemble(RowProcessingState rowProcessingState) { + final Object[] row = new Object[elementAssemblers.length]; + for ( int i = 0; i < elementAssemblers.length; i++ ) { + row[i] = elementAssemblers[i].assemble( rowProcessingState ); + } + return new TupleImpl( tupleMetadata, row ); + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/package-info.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/package-info.java new file mode 100644 index 000000000000..54843a79952c --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/jpa/package-info.java @@ -0,0 +1,9 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ + +/// Support for Jakarta Persistence [jakarta.persistence.sql.ResultSetMapping]. +/// +/// @author Steve Ebersole +package org.hibernate.query.results.internal.jpa; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/package-info.java b/hibernate-core/src/main/java/org/hibernate/query/results/package-info.java index 3a5f49fbf786..dc216018d0f1 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/package-info.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/package-info.java @@ -4,12 +4,12 @@ */ /** - * Support for defining {@linkplain org.hibernate.query.results.ResultSetMapping result set mappings} + * Support for defining {@linkplain org.hibernate.query.results.spi.ResultSetMapping result set mappings} * used in {@link org.hibernate.query.NativeQuery}, {@link org.hibernate.procedure.ProcedureCall}, * and {@link jakarta.persistence.StoredProcedureQuery}. These result set mappings are used to map * the values in the JDBC {@link java.sql.ResultSet} into the query result graph. * - * @see org.hibernate.query.results.ResultSetMapping + * @see org.hibernate.query.results.spi.ResultSetMapping * * @author Steve Ebersole */ diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/FetchBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/results/spi/FetchBuilder.java similarity index 96% rename from hibernate-core/src/main/java/org/hibernate/query/results/FetchBuilder.java rename to hibernate-core/src/main/java/org/hibernate/query/results/spi/FetchBuilder.java index eb3809f26659..8919c628bd34 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/FetchBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/spi/FetchBuilder.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.query.results; +package org.hibernate.query.results.spi; import org.hibernate.Incubating; import org.hibernate.spi.NavigablePath; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/FetchBuilderBasicValued.java b/hibernate-core/src/main/java/org/hibernate/query/results/spi/FetchBuilderBasicValued.java similarity index 94% rename from hibernate-core/src/main/java/org/hibernate/query/results/FetchBuilderBasicValued.java rename to hibernate-core/src/main/java/org/hibernate/query/results/spi/FetchBuilderBasicValued.java index 6e1b89be760c..533481903ab5 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/FetchBuilderBasicValued.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/spi/FetchBuilderBasicValued.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.query.results; +package org.hibernate.query.results.spi; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.results.graph.DomainResultCreationState; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/GraphNodeBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/results/spi/GraphNodeBuilder.java similarity index 87% rename from hibernate-core/src/main/java/org/hibernate/query/results/GraphNodeBuilder.java rename to hibernate-core/src/main/java/org/hibernate/query/results/spi/GraphNodeBuilder.java index a06b56e04fa9..2b14e437d9a6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/GraphNodeBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/spi/GraphNodeBuilder.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.query.results; +package org.hibernate.query.results.spi; /** * Commonality between the builders for results and fetches. diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/LegacyFetchBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/results/spi/LegacyFetchBuilder.java similarity index 95% rename from hibernate-core/src/main/java/org/hibernate/query/results/LegacyFetchBuilder.java rename to hibernate-core/src/main/java/org/hibernate/query/results/spi/LegacyFetchBuilder.java index 22daec6a503f..8cbb7b0114e6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/LegacyFetchBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/spi/LegacyFetchBuilder.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.query.results; +package org.hibernate.query.results.spi; import org.hibernate.sql.results.graph.Fetchable; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/results/spi/ResultBuilder.java similarity index 97% rename from hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilder.java rename to hibernate-core/src/main/java/org/hibernate/query/results/spi/ResultBuilder.java index 537197ea518c..49cb5a1ec13a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/spi/ResultBuilder.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.query.results; +package org.hibernate.query.results.spi; import org.hibernate.Incubating; import org.hibernate.sql.results.graph.DomainResult; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilderBasicValued.java b/hibernate-core/src/main/java/org/hibernate/query/results/spi/ResultBuilderBasicValued.java similarity index 94% rename from hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilderBasicValued.java rename to hibernate-core/src/main/java/org/hibernate/query/results/spi/ResultBuilderBasicValued.java index f016faba26d2..63589d7fd364 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilderBasicValued.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/spi/ResultBuilderBasicValued.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.query.results; +package org.hibernate.query.results.spi; import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.basic.BasicResult; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilderEmbeddable.java b/hibernate-core/src/main/java/org/hibernate/query/results/spi/ResultBuilderEmbeddable.java similarity index 93% rename from hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilderEmbeddable.java rename to hibernate-core/src/main/java/org/hibernate/query/results/spi/ResultBuilderEmbeddable.java index a6347fca0971..c486fa1736ac 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilderEmbeddable.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/spi/ResultBuilderEmbeddable.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.query.results; +package org.hibernate.query.results.spi; import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.embeddable.EmbeddableResult; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilderEntityValued.java b/hibernate-core/src/main/java/org/hibernate/query/results/spi/ResultBuilderEntityValued.java similarity index 94% rename from hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilderEntityValued.java rename to hibernate-core/src/main/java/org/hibernate/query/results/spi/ResultBuilderEntityValued.java index d22eb84dbbe9..ad2109a50195 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilderEntityValued.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/spi/ResultBuilderEntityValued.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.query.results; +package org.hibernate.query.results.spi; import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.entity.EntityResult; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilderInstantiationValued.java b/hibernate-core/src/main/java/org/hibernate/query/results/spi/ResultBuilderInstantiationValued.java similarity index 89% rename from hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilderInstantiationValued.java rename to hibernate-core/src/main/java/org/hibernate/query/results/spi/ResultBuilderInstantiationValued.java index fe950b28ff7e..affbddcb88d8 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilderInstantiationValued.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/spi/ResultBuilderInstantiationValued.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.query.results; +package org.hibernate.query.results.spi; /** * ResultBuilder specialization for cases involving dynamic-instantiation results. diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/ResultSetMapping.java b/hibernate-core/src/main/java/org/hibernate/query/results/spi/ResultSetMapping.java similarity index 98% rename from hibernate-core/src/main/java/org/hibernate/query/results/ResultSetMapping.java rename to hibernate-core/src/main/java/org/hibernate/query/results/spi/ResultSetMapping.java index 3564169f3288..016762efaba6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/ResultSetMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/spi/ResultSetMapping.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.query.results; +package org.hibernate.query.results.spi; import org.hibernate.Incubating; import org.hibernate.engine.spi.SessionFactoryImplementor; diff --git a/hibernate-core/src/main/java/org/hibernate/query/specification/internal/MutationSpecificationImpl.java b/hibernate-core/src/main/java/org/hibernate/query/specification/internal/MutationSpecificationImpl.java index eff42d7b4c02..a2b7bcf98df7 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/specification/internal/MutationSpecificationImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/specification/internal/MutationSpecificationImpl.java @@ -4,7 +4,12 @@ */ package org.hibernate.query.specification.internal; +import jakarta.persistence.CacheRetrieveMode; +import jakarta.persistence.CacheStoreMode; import jakarta.persistence.EntityManager; +import jakarta.persistence.LockModeType; +import jakarta.persistence.PessimisticLockScope; +import jakarta.persistence.Timeout; import jakarta.persistence.TypedQueryReference; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaDelete; @@ -20,6 +25,7 @@ import org.hibernate.query.IllegalMutationQueryException; import org.hibernate.query.MutationQuery; import org.hibernate.query.restriction.Restriction; +import org.hibernate.query.spi.JpaTypedQueryReference; import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SqmQuerySource; @@ -47,7 +53,7 @@ * * @author Steve Ebersole */ -public class MutationSpecificationImpl implements MutationSpecification, TypedQueryReference { +public class MutationSpecificationImpl implements MutationSpecification, JpaTypedQueryReference { public enum MutationType { // INSERT, @@ -105,6 +111,36 @@ public Map getHints() { return Collections.emptyMap(); } + @Override + public CacheRetrieveMode getCacheRetrieveMode() { + return null; + } + + @Override + public CacheStoreMode getCacheStoreMode() { + return null; + } + + @Override + public LockModeType getLockMode() { + return null; + } + + @Override + public PessimisticLockScope getPessimisticLockScope() { + return null; + } + + @Override + public Timeout getTimeout() { + return null; + } + + @Override + public String getEntityGraphName() { + return ""; + } + @Override public TypedQueryReference reference() { return this; diff --git a/hibernate-core/src/main/java/org/hibernate/query/specification/internal/ProjectionSpecificationImpl.java b/hibernate-core/src/main/java/org/hibernate/query/specification/internal/ProjectionSpecificationImpl.java index e97c3e821e31..934f444571ae 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/specification/internal/ProjectionSpecificationImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/specification/internal/ProjectionSpecificationImpl.java @@ -4,7 +4,12 @@ */ package org.hibernate.query.specification.internal; +import jakarta.persistence.CacheRetrieveMode; +import jakarta.persistence.CacheStoreMode; import jakarta.persistence.EntityManager; +import jakarta.persistence.LockModeType; +import jakarta.persistence.PessimisticLockScope; +import jakarta.persistence.Timeout; import jakarta.persistence.TypedQueryReference; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; @@ -18,6 +23,7 @@ import org.hibernate.query.specification.ProjectionSpecification; import org.hibernate.query.specification.QuerySpecification; import org.hibernate.query.specification.SelectionSpecification; +import org.hibernate.query.spi.JpaTypedQueryReference; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.tree.domain.SqmPath; import org.hibernate.query.sqm.tree.from.SqmRoot; @@ -36,7 +42,7 @@ /** * @author Gavin King */ -public class ProjectionSpecificationImpl implements ProjectionSpecification, TypedQueryReference { +public class ProjectionSpecificationImpl implements ProjectionSpecification, JpaTypedQueryReference { private final SelectionSpecification selectionSpecification; private final List, SqmRoot, SqmSelectableNode>> specifications = new ArrayList<>(); @@ -126,4 +132,34 @@ public Class getResultType() { public Map getHints() { return Collections.emptyMap(); } + + @Override + public CacheRetrieveMode getCacheRetrieveMode() { + return null; + } + + @Override + public CacheStoreMode getCacheStoreMode() { + return null; + } + + @Override + public LockModeType getLockMode() { + return null; + } + + @Override + public PessimisticLockScope getPessimisticLockScope() { + return null; + } + + @Override + public Timeout getTimeout() { + return null; + } + + @Override + public String getEntityGraphName() { + return ""; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/specification/internal/SelectionSpecificationImpl.java b/hibernate-core/src/main/java/org/hibernate/query/specification/internal/SelectionSpecificationImpl.java index 1b767674def7..e6cc5570844d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/specification/internal/SelectionSpecificationImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/specification/internal/SelectionSpecificationImpl.java @@ -4,7 +4,12 @@ */ package org.hibernate.query.specification.internal; +import jakarta.persistence.CacheRetrieveMode; +import jakarta.persistence.CacheStoreMode; import jakarta.persistence.EntityManager; +import jakarta.persistence.LockModeType; +import jakarta.persistence.PessimisticLockScope; +import jakarta.persistence.Timeout; import jakarta.persistence.TypedQueryReference; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.CriteriaBuilder; @@ -20,6 +25,7 @@ import org.hibernate.query.specification.SelectionSpecification; import org.hibernate.query.restriction.Path; import org.hibernate.query.restriction.Restriction; +import org.hibernate.query.spi.JpaTypedQueryReference; import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SqmQuerySource; @@ -47,7 +53,7 @@ * * @author Steve Ebersole */ -public class SelectionSpecificationImpl implements SelectionSpecification, TypedQueryReference { +public class SelectionSpecificationImpl implements SelectionSpecification, JpaTypedQueryReference { private final Class resultType; private final String hql; private final CriteriaQuery criteriaQuery; @@ -333,4 +339,34 @@ else if ( resultType.isAssignableFrom( nodeJavaType.getJavaTypeClass() ) ) { hql ); } + + @Override + public CacheRetrieveMode getCacheRetrieveMode() { + return null; + } + + @Override + public CacheStoreMode getCacheStoreMode() { + return null; + } + + @Override + public LockModeType getLockMode() { + return null; + } + + @Override + public PessimisticLockScope getPessimisticLockScope() { + return null; + } + + @Override + public Timeout getTimeout() { + return null; + } + + @Override + public String getEntityGraphName() { + return ""; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/specification/internal/SimpleProjectionSpecificationImpl.java b/hibernate-core/src/main/java/org/hibernate/query/specification/internal/SimpleProjectionSpecificationImpl.java index b1680fc74861..688bd36775ea 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/specification/internal/SimpleProjectionSpecificationImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/specification/internal/SimpleProjectionSpecificationImpl.java @@ -4,7 +4,12 @@ */ package org.hibernate.query.specification.internal; +import jakarta.persistence.CacheRetrieveMode; +import jakarta.persistence.CacheStoreMode; import jakarta.persistence.EntityManager; +import jakarta.persistence.LockModeType; +import jakarta.persistence.PessimisticLockScope; +import jakarta.persistence.Timeout; import jakarta.persistence.TypedQueryReference; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; @@ -21,6 +26,7 @@ import org.hibernate.query.sqm.tree.select.SqmSelectStatement; import java.util.Collections; +import java.util.List; import java.util.Map; /** @@ -119,4 +125,49 @@ else if ( attribute != null ) { public Map getHints() { return Collections.emptyMap(); } + + @Override + public CacheRetrieveMode getCacheRetrieveMode() { + return null; + } + + @Override + public CacheStoreMode getCacheStoreMode() { + return null; + } + + @Override + public LockModeType getLockMode() { + return null; + } + + @Override + public PessimisticLockScope getPessimisticLockScope() { + return null; + } + + @Override + public Timeout getTimeout() { + return null; + } + + @Override + public String getEntityGraphName() { + return ""; + } + + @Override + public List> getParameterTypes() { + return null; + } + + @Override + public List getParameterNames() { + return null; + } + + @Override + public List getArguments() { + return null; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractCommonQueryContract.java b/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractCommonQueryContract.java index 8fa86412f56e..4f5744bc618c 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractCommonQueryContract.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractCommonQueryContract.java @@ -4,6 +4,7 @@ */ package org.hibernate.query.spi; +import jakarta.persistence.AttributeConverter; import jakarta.persistence.CacheRetrieveMode; import jakarta.persistence.CacheStoreMode; import jakarta.persistence.EntityGraph; @@ -43,6 +44,8 @@ import org.hibernate.query.sqm.tree.expression.SqmParameter; import org.hibernate.query.sqm.tree.select.SqmSelectStatement; import org.hibernate.type.BindableType; +import org.hibernate.type.descriptor.converter.internal.ConverterHelper; +import org.hibernate.type.descriptor.converter.spi.JpaAttributeConverter; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.spi.TypeConfiguration; @@ -202,9 +205,9 @@ public Map getHints() { protected void collectHints(Map hints) { final var queryOptions = getQueryOptions(); - if ( queryOptions.getTimeout() != null ) { - hints.put( HINT_TIMEOUT, queryOptions.getTimeout() ); - hints.put( HINT_SPEC_QUERY_TIMEOUT, queryOptions.getTimeout() * 1000 ); + if ( Timeouts.isRealTimeout( queryOptions.getTimeout() ) ) { + hints.put( HINT_TIMEOUT, Timeouts.getTimeoutInSeconds( queryOptions.getTimeout() ) ); + hints.put( HINT_SPEC_QUERY_TIMEOUT, queryOptions.getTimeout().milliseconds() ); } putIfNotNull( hints, HINT_COMMENT, getComment() ); @@ -434,6 +437,7 @@ protected void applyGraph(String graphString, GraphSemantic graphSemantic) { applyGraph( rootGraph, graphSemantic ); } + protected void applyGraph(RootGraphImplementor entityGraph, GraphSemantic graphSemantic) { getQueryOptions().applyGraph( entityGraph, graphSemantic ); } @@ -592,7 +596,7 @@ public MutableQueryOptions getQueryOptions() { @Override public Integer getTimeout() { - return getQueryOptions().getTimeout(); + return Timeouts.getEffectiveTimeoutInSeconds( getQueryOptions().getTimeout() ); } @@ -910,6 +914,48 @@ public

CommonQueryContract setParameter(int position, P value, Type

type) return this; } + @Override + public

CommonQueryContract setConvertedParameter(String name, P value, Class> converterClass) { + //noinspection unchecked,rawtypes + final JpaAttributeConverter converter = ConverterHelper.createJpaAttributeConverter( + (Class) converterClass, + session.getFactory().getServiceRegistry(), + session.getFactory().getTypeConfiguration() + ); + + var bindValue = converter.getConverterBean().getBeanInstance().convertToDatabaseColumn( value ); + + var bindValueJavaType = converter.getRelationalJavaType(); + var bindValueClass = bindValueJavaType.getJavaTypeClass(); + var bindValueModelType = getParamType( bindValueClass ); + + //noinspection unchecked,rawtypes + locateBinding( name ).setBindValue( bindValue, (BindableType) bindValueModelType ); + + return this; + } + + @Override + public

CommonQueryContract setConvertedParameter(int position, P value, Class> converterClass) { + //noinspection unchecked,rawtypes + final JpaAttributeConverter converter = ConverterHelper.createJpaAttributeConverter( + (Class) converterClass, + session.getFactory().getServiceRegistry(), + session.getFactory().getTypeConfiguration() + ); + + var bindValue = converter.getConverterBean().getBeanInstance().convertToDatabaseColumn( value ); + + var bindValueJavaType = converter.getRelationalJavaType(); + var bindValueClass = bindValueJavaType.getJavaTypeClass(); + var bindValueModelType = getParamType( bindValueClass ); + + //noinspection unchecked,rawtypes + locateBinding( position ).setBindValue( bindValue, (BindableType) bindValueModelType ); + + return this; + } + @Override @Deprecated(since = "7") public CommonQueryContract setParameter(int position, Instant value, TemporalType temporalType) { locateBinding( position ).setBindValue( value, temporalType ); @@ -940,7 +986,6 @@ public

CommonQueryContract setParameter(QueryParameter

parameter, P value return this; } - @Override public

CommonQueryContract setParameter(Parameter

parameter, P value) { if ( value instanceof TypedParameterValue typedParameterValue ) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractQuery.java b/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractQuery.java index 0ad0de8552f0..edcb13ce3510 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractQuery.java @@ -11,6 +11,7 @@ import java.util.Map; import java.util.Set; +import jakarta.persistence.AttributeConverter; import jakarta.persistence.CacheRetrieveMode; import jakarta.persistence.CacheStoreMode; import jakarta.persistence.EntityGraph; @@ -20,6 +21,7 @@ import jakarta.persistence.PessimisticLockScope; import jakarta.persistence.TemporalType; import jakarta.persistence.Timeout; +import jakarta.persistence.TypedQuery; import jakarta.persistence.metamodel.Type; import org.hibernate.CacheMode; import org.hibernate.FlushMode; @@ -126,6 +128,24 @@ public QueryImplementor setHint(String hintName, Object value) { return this; } + @Override + public TypedQuery setTimeout(Integer integer) { + getQueryOptions().setTimeout( integer ); + return this; + } + + @Override + public PessimisticLockScope getLockScope() { + var options = getLockOptions(); + return options == null ? null : options.getScope().getCorrespondingJpaScope(); + } + + @Override + public EntityGraph getEntityGraph() { + //noinspection unchecked + return (EntityGraph) getQueryOptions().getAppliedGraph().getGraph(); + } + @Override public QueryImplementor setEntityGraph(EntityGraph graph, GraphSemantic semantic) { super.setEntityGraph( graph, semantic ); @@ -340,13 +360,14 @@ protected void collectHints(Map hints) { final var queryOptions = getQueryOptions(); final var lockOptions = getLockOptions(); - if ( queryOptions.getTimeout() != null ) { - hints.put( HINT_TIMEOUT, queryOptions.getTimeout() ); - hints.put( HINT_SPEC_QUERY_TIMEOUT, queryOptions.getTimeout() * 1000 ); - hints.put( HINT_JAVAEE_QUERY_TIMEOUT, queryOptions.getTimeout() * 1000 ); + if ( Timeouts.isRealTimeout( queryOptions.getTimeout() ) ) { + final Timeout timeout = queryOptions.getTimeout(); + hints.put( HINT_TIMEOUT, Timeouts.getTimeoutInSeconds( timeout) ); + hints.put( HINT_SPEC_QUERY_TIMEOUT, timeout.milliseconds() ); + hints.put( HINT_JAVAEE_QUERY_TIMEOUT, timeout.milliseconds() ); } - if ( lockOptions.getTimeout().milliseconds() != Timeouts.WAIT_FOREVER_MILLI ) { + if ( Timeouts.isRealTimeout( lockOptions.getTimeout() ) ) { hints.put( HINT_SPEC_LOCK_TIMEOUT, lockOptions.getTimeOut() ); hints.put( HINT_JAVAEE_LOCK_TIMEOUT, lockOptions.getTimeOut() ); } @@ -410,6 +431,18 @@ public

QueryImplementor setParameter(String name, P value, Type

type) return this; } + @Override + public

QueryImplementor setConvertedParameter(String name, P value, Class> converter) { + super.setConvertedParameter( name, value, converter ); + return this; + } + + @Override + public

QueryImplementor setConvertedParameter(int position, P value, Class> converter) { + super.setConvertedParameter( position, value, converter ); + return this; + } + @Override @Deprecated public QueryImplementor setParameter(String name, Instant value, TemporalType temporalType) { super.setParameter( name, value, temporalType ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractSelectionQuery.java b/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractSelectionQuery.java index 40e58b50435d..6ad423b4bda0 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractSelectionQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractSelectionQuery.java @@ -15,6 +15,7 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; +import jakarta.persistence.AttributeConverter; import jakarta.persistence.PessimisticLockScope; import jakarta.persistence.Timeout; import org.hibernate.CacheMode; @@ -654,6 +655,18 @@ public

SelectionQuery setParameter(String name, P value, Type

type) { return this; } + @Override + public

SelectionQuery setConvertedParameter(String name, P value, Class> converter) { + super.setConvertedParameter( name, value, converter ); + return this; + } + + @Override + public

SelectionQuery setConvertedParameter(int position, P value, Class> converter) { + super.setConvertedParameter( position, value, converter ); + return this; + } + @Override @Deprecated public SelectionQuery setParameter(String name, Instant value, TemporalType temporalType) { super.setParameter( name, value, temporalType ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/DelegatingQueryOptions.java b/hibernate-core/src/main/java/org/hibernate/query/spi/DelegatingQueryOptions.java index b49ae586ddbd..23800c577ce2 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/DelegatingQueryOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/DelegatingQueryOptions.java @@ -10,6 +10,7 @@ import jakarta.persistence.CacheRetrieveMode; import jakarta.persistence.CacheStoreMode; +import jakarta.persistence.Timeout; import org.hibernate.CacheMode; import org.hibernate.FlushMode; import org.hibernate.LockOptions; @@ -30,7 +31,7 @@ public DelegatingQueryOptions(QueryOptions queryOptions) { } @Override - public Integer getTimeout() { + public Timeout getTimeout() { return queryOptions.getTimeout(); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/JpaTypedQueryReference.java b/hibernate-core/src/main/java/org/hibernate/query/spi/JpaTypedQueryReference.java new file mode 100644 index 000000000000..1ea9022f9568 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/JpaTypedQueryReference.java @@ -0,0 +1,33 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.query.spi; + +import jakarta.persistence.TypedQueryReference; + +import java.util.List; + +/** + * Extension to {@linkplain TypedQueryReference} to handle the fact + * that every concrete implementation of this contract in Hibernate + * will return null for a number of the defined methods. + * + * @author Steve Ebersole + */ +public interface JpaTypedQueryReference extends TypedQueryReference { + @Override + default List> getParameterTypes() { + return null; + } + + @Override + default List getParameterNames() { + return null; + } + + @Override + default List getArguments() { + return null; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/MutableQueryOptions.java b/hibernate-core/src/main/java/org/hibernate/query/spi/MutableQueryOptions.java index 3087326425c9..286a7b2df810 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/MutableQueryOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/MutableQueryOptions.java @@ -7,6 +7,7 @@ import jakarta.persistence.CacheRetrieveMode; import jakarta.persistence.CacheStoreMode; +import jakarta.persistence.Timeout; import org.hibernate.CacheMode; import org.hibernate.FlushMode; import org.hibernate.graph.GraphSemantic; @@ -63,6 +64,11 @@ default void setCacheMode(CacheMode cacheMode) { */ void setQueryPlanCachingEnabled(Boolean queryPlanCachingEnabled); + /** + * Corollary to {@link #getTimeout()} + */ + void setTimeout(Timeout timeout); + /** * Corollary to {@link #getTimeout()} */ diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/QueryImplementor.java b/hibernate-core/src/main/java/org/hibernate/query/spi/QueryImplementor.java index 278e7cbac844..e90937a51f31 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/QueryImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/QueryImplementor.java @@ -10,6 +10,7 @@ import java.util.Date; import java.util.Map; +import jakarta.persistence.AttributeConverter; import org.hibernate.Incubating; import org.hibernate.ScrollMode; import org.hibernate.engine.spi.SharedSessionContractImplementor; @@ -53,6 +54,12 @@ default QueryImplementor setResultTransformer(ResultTransformer transf return (QueryImplementor) this; } + @Override +

QueryImplementor setConvertedParameter(String name, P value, Class> converter); + + @Override +

QueryImplementor setConvertedParameter(int position, P value, Class> converter); + @Override QueryImplementor setParameter(String name, Object value); diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/QueryOptions.java b/hibernate-core/src/main/java/org/hibernate/query/spi/QueryOptions.java index dab48fa15bec..143e1341835d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/QueryOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/QueryOptions.java @@ -10,6 +10,7 @@ import jakarta.persistence.CacheRetrieveMode; import jakarta.persistence.CacheStoreMode; +import jakarta.persistence.Timeout; import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.CacheMode; @@ -34,7 +35,7 @@ public interface QueryOptions { * The timeout to apply to the query. May also be defined at the transaction * level using {@link org.hibernate.Transaction#getTimeout} */ - Integer getTimeout(); + Timeout getTimeout(); /** * The flush mode to use for the query execution diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/QueryOptionsAdapter.java b/hibernate-core/src/main/java/org/hibernate/query/spi/QueryOptionsAdapter.java index 293cace292c6..75f5ccd7b5db 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/QueryOptionsAdapter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/QueryOptionsAdapter.java @@ -10,6 +10,7 @@ import jakarta.persistence.CacheRetrieveMode; import jakarta.persistence.CacheStoreMode; +import jakarta.persistence.Timeout; import org.hibernate.CacheMode; import org.hibernate.FlushMode; import org.hibernate.LockOptions; @@ -48,7 +49,7 @@ public List getDatabaseHints() { } @Override - public Integer getTimeout() { + public Timeout getTimeout() { return null; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/QueryParameterBinding.java b/hibernate-core/src/main/java/org/hibernate/query/spi/QueryParameterBinding.java index 0b1b0a6a2c67..054bab0e7eb4 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/QueryParameterBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/QueryParameterBinding.java @@ -5,6 +5,7 @@ package org.hibernate.query.spi; import java.util.Collection; + import jakarta.persistence.TemporalType; import org.checkerframework.checker.nullness.qual.Nullable; diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/QueryProducerImplementor.java b/hibernate-core/src/main/java/org/hibernate/query/spi/QueryProducerImplementor.java deleted file mode 100644 index c24fe9f0a734..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/QueryProducerImplementor.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.query.spi; - -import org.hibernate.CacheMode; -import org.hibernate.FlushMode; -import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.query.MutationQuery; -import org.hibernate.query.QueryProducer; -import org.hibernate.query.sql.spi.NativeQueryImplementor; - -import jakarta.persistence.TypedQueryReference; -import jakarta.persistence.criteria.CriteriaDelete; -import jakarta.persistence.criteria.CriteriaQuery; -import jakarta.persistence.criteria.CriteriaUpdate; - -/** - * The internal contract for {@link QueryProducer} implementations. - * - * @deprecated This interface is no longer needed and will be removed. - * - * @author Steve Ebersole - */ -@Deprecated(since = "7.0", forRemoval = true) -public interface QueryProducerImplementor extends QueryProducer { - SessionFactoryImplementor getFactory(); - - FlushMode getHibernateFlushMode(); - CacheMode getCacheMode(); - - @Override @SuppressWarnings("rawtypes") - QueryImplementor getNamedQuery(String queryName); - - @Override @Deprecated @SuppressWarnings("rawtypes") - QueryImplementor createQuery(String queryString); - - @Override - QueryImplementor createQuery(String queryString, Class resultClass); - - @Override - QueryImplementor createQuery(TypedQueryReference typedQueryReference); - - @Override @Deprecated @SuppressWarnings("rawtypes") - QueryImplementor createNamedQuery(String name); - - @Override - QueryImplementor createNamedQuery(String name, Class resultClass); - - @Override @Deprecated @SuppressWarnings("rawtypes") - NativeQueryImplementor createNativeQuery(String sqlString); - - @Override - NativeQueryImplementor createNativeQuery(String sqlString, Class resultClass); - - @Override - NativeQueryImplementor createNativeQuery(String sqlString, Class resultClass, String tableAlias); - - @Override @Deprecated @SuppressWarnings("rawtypes") - NativeQueryImplementor createNativeQuery(String sqlString, String resultSetMappingName); - - @Override - NativeQueryImplementor createNativeQuery(String sqlString, String resultSetMappingName, Class resultClass); - - @Override @Deprecated @SuppressWarnings("rawtypes") - NativeQueryImplementor getNamedNativeQuery(String name); - - @Override @Deprecated @SuppressWarnings("rawtypes") - NativeQueryImplementor getNamedNativeQuery(String name, String resultSetMapping); - - @Override - MutationQuery createMutationQuery(String statementString); - - @Override - MutationQuery createNamedMutationQuery(String name); - - @Override - MutationQuery createNativeMutationQuery(String sqlString); - - @Override - MutationQuery createMutationQuery(@SuppressWarnings("rawtypes") CriteriaUpdate updateQuery); - - @Override - MutationQuery createMutationQuery(@SuppressWarnings("rawtypes") CriteriaDelete deleteQuery); - - @Override - QueryImplementor createQuery(CriteriaQuery criteriaQuery); - - @Override @Deprecated @SuppressWarnings("rawtypes") - QueryImplementor createQuery(CriteriaUpdate updateQuery); - - @Override @Deprecated @SuppressWarnings("rawtypes") - QueryImplementor createQuery(CriteriaDelete deleteQuery); -} diff --git a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NamedNativeQueryMementoImpl.java b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NamedNativeQueryMementoImpl.java index 41e98e5f0723..cbb9e6024bc0 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NamedNativeQueryMementoImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NamedNativeQueryMementoImpl.java @@ -7,6 +7,7 @@ import java.util.Map; import java.util.Set; +import jakarta.persistence.Timeout; import org.hibernate.CacheMode; import org.hibernate.FlushMode; import org.hibernate.engine.spi.SharedSessionContractImplementor; @@ -45,7 +46,7 @@ public NamedNativeQueryMementoImpl( CacheMode cacheMode, FlushMode flushMode, Boolean readOnly, - Integer timeout, + Timeout timeout, Integer fetchSize, String comment, Integer firstResult, diff --git a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java index 6fae0b5323e3..332cbb883dfa 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java @@ -4,39 +4,27 @@ */ package org.hibernate.query.sql.internal; -import java.io.Serializable; -import java.time.Instant; -import java.util.Calendar; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.function.Consumer; -import java.util.function.Supplier; - +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.CacheRetrieveMode; +import jakarta.persistence.CacheStoreMode; +import jakarta.persistence.FlushModeType; +import jakarta.persistence.LockModeType; +import jakarta.persistence.Parameter; +import jakarta.persistence.PersistenceException; import jakarta.persistence.PessimisticLockScope; +import jakarta.persistence.TemporalType; import jakarta.persistence.Timeout; +import jakarta.persistence.Tuple; +import jakarta.persistence.TypedQuery; +import jakarta.persistence.metamodel.SingularAttribute; +import jakarta.persistence.metamodel.Type; import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.CacheMode; import org.hibernate.FlushMode; -import org.hibernate.Locking; -import org.hibernate.jpa.spi.NativeQueryArrayTransformer; -import org.hibernate.jpa.spi.NativeQueryConstructorTransformer; -import org.hibernate.jpa.spi.NativeQueryListTransformer; -import org.hibernate.jpa.spi.NativeQueryMapTransformer; -import org.hibernate.metamodel.mapping.EntityAssociationMapping; -import org.hibernate.metamodel.mapping.EntityMappingType; -import org.hibernate.metamodel.mapping.ModelPart; -import org.hibernate.metamodel.mapping.PluralAttributeMapping; -import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping; -import org.hibernate.query.QueryFlushMode; import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.LockOptions; +import org.hibernate.Locking; import org.hibernate.ScrollMode; import org.hibernate.dialect.Dialect; import org.hibernate.engine.query.spi.NativeQueryInterpreter; @@ -45,13 +33,23 @@ import org.hibernate.graph.RootGraph; import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.internal.util.MathHelper; +import org.hibernate.jpa.spi.NativeQueryArrayTransformer; +import org.hibernate.jpa.spi.NativeQueryConstructorTransformer; +import org.hibernate.jpa.spi.NativeQueryListTransformer; +import org.hibernate.jpa.spi.NativeQueryMapTransformer; import org.hibernate.jpa.spi.NativeQueryTupleTransformer; +import org.hibernate.metamodel.mapping.EntityAssociationMapping; +import org.hibernate.metamodel.mapping.EntityMappingType; +import org.hibernate.metamodel.mapping.ModelPart; +import org.hibernate.metamodel.mapping.PluralAttributeMapping; +import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping; import org.hibernate.metamodel.model.domain.BasicDomainType; import org.hibernate.query.KeyedPage; import org.hibernate.query.KeyedResultList; import org.hibernate.query.NativeQuery; import org.hibernate.query.PathException; import org.hibernate.query.Query; +import org.hibernate.query.QueryFlushMode; import org.hibernate.query.QueryParameter; import org.hibernate.query.ResultListTransformer; import org.hibernate.query.TupleTransformer; @@ -62,8 +60,6 @@ import org.hibernate.query.named.NamedObjectRepository; import org.hibernate.query.named.NamedResultSetMappingMemento; import org.hibernate.query.results.internal.Builders; -import org.hibernate.query.results.ResultBuilder; -import org.hibernate.query.results.ResultSetMapping; import org.hibernate.query.results.internal.ResultSetMappingImpl; import org.hibernate.query.results.internal.dynamic.DynamicResultBuilderBasicStandard; import org.hibernate.query.results.internal.dynamic.DynamicResultBuilderEntityCalculated; @@ -71,6 +67,9 @@ import org.hibernate.query.results.internal.dynamic.DynamicResultBuilderInstantiation; import org.hibernate.query.results.internal.implicit.ImplicitModelPartResultBuilderEntity; import org.hibernate.query.results.internal.implicit.ImplicitResultClassBuilder; +import org.hibernate.query.results.internal.jpa.JpaMappingHelper; +import org.hibernate.query.results.spi.ResultBuilder; +import org.hibernate.query.results.spi.ResultSetMapping; import org.hibernate.query.spi.AbstractQuery; import org.hibernate.query.spi.DomainQueryExecutionContext; import org.hibernate.query.spi.Limit; @@ -104,18 +103,19 @@ import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.spi.UnknownBasicJavaType; -import jakarta.persistence.AttributeConverter; -import jakarta.persistence.CacheRetrieveMode; -import jakarta.persistence.CacheStoreMode; -import jakarta.persistence.FlushModeType; -import jakarta.persistence.LockModeType; -import jakarta.persistence.Parameter; -import jakarta.persistence.PersistenceException; -import jakarta.persistence.TemporalType; -import jakarta.persistence.Tuple; -import jakarta.persistence.TypedQuery; -import jakarta.persistence.metamodel.SingularAttribute; -import jakarta.persistence.metamodel.Type; +import java.io.Serializable; +import java.time.Instant; +import java.util.Calendar; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Supplier; import static java.lang.Character.isWhitespace; import static java.util.Collections.addAll; @@ -130,7 +130,7 @@ import static org.hibernate.internal.util.type.PrimitiveWrappers.canonicalize; import static org.hibernate.jpa.HibernateHints.HINT_NATIVE_LOCK_MODE; import static org.hibernate.query.results.internal.Builders.resultClassBuilder; -import static org.hibernate.query.results.ResultSetMapping.resolveResultSetMapping; +import static org.hibernate.query.results.spi.ResultSetMapping.resolveResultSetMapping; import static org.hibernate.query.sqm.internal.SqmUtil.isResultTypeAlwaysAllowed; import static org.hibernate.sql.ast.internal.ParameterMarkerStrategyStandard.isStandardRenderer; @@ -278,6 +278,28 @@ private NativeQueryImpl( applyOptions( memento ); } + /** + * @see jakarta.persistence.EntityHandler#createNativeQuery(String, jakarta.persistence.sql.ResultSetMapping) + */ + public NativeQueryImpl( + String sql, + jakarta.persistence.sql.ResultSetMapping resultSetMapping, + SharedSessionContractImplementor session) { + super( session ); + originalSqlString = sql; + querySpaces = new HashSet<>(); + + final var parameterInterpretation = resolveParameterInterpretation( sql, session ); + sqlString = parameterInterpretation.getAdjustedSqlString(); + parameterMetadata = parameterInterpretation.toParameterMetadata( session ); + parameterOccurrences = parameterInterpretation.getOrderedParameterOccurrences(); + parameterBindings = parameterMetadata.createBindings( session.getFactory() ); + + this.resultSetMapping = JpaMappingHelper.toHibernateMapping( resultSetMapping, session.getSessionFactory() ); + resultMappingSuppliedToCtor = true; + resultType = resultSetMapping.type(); + } + public NativeQueryImpl( String sql, NamedResultSetMappingMemento resultSetMappingMemento, @@ -590,7 +612,7 @@ public NamedNativeQueryMemento toMemento(String name) { getCacheMode(), options.getFlushMode(), isReadOnly(), - getTimeout(), + getQueryOptions().getTimeout(), getFetchSize(), getComment(), options.getLimit().getFirstRow(), diff --git a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeSelectQueryPlanImpl.java b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeSelectQueryPlanImpl.java index 39c143e382ae..bd44f58aaa57 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeSelectQueryPlanImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeSelectQueryPlanImpl.java @@ -12,7 +12,7 @@ import org.hibernate.ScrollMode; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.internal.scrollable.EmptyScrollableResults; -import org.hibernate.query.results.ResultSetMapping; +import org.hibernate.query.results.spi.ResultSetMapping; import org.hibernate.query.spi.DomainQueryExecutionContext; import org.hibernate.query.spi.QueryOptions; import org.hibernate.query.spi.QueryParameterBindings; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/ResultSetMappingProcessor.java b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/ResultSetMappingProcessor.java index 0780ce1cd8d3..4b41a31258dc 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/ResultSetMappingProcessor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/ResultSetMappingProcessor.java @@ -24,10 +24,10 @@ import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.SingleTableEntityPersister; import org.hibernate.query.NativeQuery; -import org.hibernate.query.results.FetchBuilder; -import org.hibernate.query.results.LegacyFetchBuilder; -import org.hibernate.query.results.ResultBuilder; -import org.hibernate.query.results.ResultSetMapping; +import org.hibernate.query.results.spi.FetchBuilder; +import org.hibernate.query.results.spi.LegacyFetchBuilder; +import org.hibernate.query.results.spi.ResultBuilder; +import org.hibernate.query.results.spi.ResultSetMapping; import org.hibernate.query.results.internal.complete.CompleteResultBuilderCollectionStandard; import org.hibernate.query.results.internal.dynamic.DynamicFetchBuilderContainer; import org.hibernate.query.results.internal.dynamic.DynamicFetchBuilderLegacy; @@ -45,7 +45,7 @@ import static java.util.Collections.emptyMap; import static org.hibernate.internal.util.collections.ArrayHelper.slice; import static org.hibernate.internal.util.collections.ArrayHelper.toStringArray; -import static org.hibernate.query.results.ResultSetMapping.resolveResultSetMapping; +import static org.hibernate.query.results.spi.ResultSetMapping.resolveResultSetMapping; /** diff --git a/hibernate-core/src/main/java/org/hibernate/query/sql/spi/NativeSelectQueryDefinition.java b/hibernate-core/src/main/java/org/hibernate/query/sql/spi/NativeSelectQueryDefinition.java index 736fdd7d6b25..8c20c9042417 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sql/spi/NativeSelectQueryDefinition.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sql/spi/NativeSelectQueryDefinition.java @@ -7,7 +7,7 @@ import java.util.List; import java.util.Set; -import org.hibernate.query.results.ResultSetMapping; +import org.hibernate.query.results.spi.ResultSetMapping; /** * Access the values defining a native select query diff --git a/hibernate-core/src/main/java/org/hibernate/query/sql/spi/SelectInterpretationsKey.java b/hibernate-core/src/main/java/org/hibernate/query/sql/spi/SelectInterpretationsKey.java index e742f26893a6..0899d89172b9 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sql/spi/SelectInterpretationsKey.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sql/spi/SelectInterpretationsKey.java @@ -10,7 +10,7 @@ import org.hibernate.query.ResultListTransformer; import org.hibernate.query.TupleTransformer; -import org.hibernate.query.results.ResultSetMapping; +import org.hibernate.query.results.spi.ResultSetMapping; import org.hibernate.query.spi.QueryInterpretationCache; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AbstractSqmSelectionQuery.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AbstractSqmSelectionQuery.java index 1a9bfa01965d..eecaf5574b21 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AbstractSqmSelectionQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AbstractSqmSelectionQuery.java @@ -312,7 +312,7 @@ protected void applySqmOptions(NamedSqmQueryMemento memento) { if ( memento.getParameterTypes() != null ) { final var basicTypeRegistry = getTypeConfiguration().getBasicTypeRegistry(); final var parameterMetadata = getParameterMetadata(); - memento.getParameterTypes().forEach( (key, value) -> + memento.getAnticipatedParameterTypes().forEach( (key, value) -> parameterMetadata.getQueryParameter( key ) .applyAnticipatedType( basicTypeRegistry.getRegisteredType( value ) ) ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java index 9836a47b589c..bbf35b1cd225 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java @@ -33,6 +33,8 @@ import java.util.ServiceLoader; import java.util.Set; +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.criteria.ParameterExpression; import org.hibernate.SessionFactory; import org.hibernate.dialect.function.AvgFunction; import org.hibernate.dialect.function.SumReturnTypeResolver; @@ -1732,6 +1734,11 @@ public JpaCriteriaParameter parameter(Class paramClass, @Nullable Stri return new JpaCriteriaParameter<>( name, parameterType, notBasic, this ); } + @Override + public ParameterExpression convertedParameter(Class> converter) { + throw new UnsupportedOperationException( "Not implemented yet" ); + } + @Override public JpaParameterExpression> listParameter(Class paramClass) { return listParameter( paramClass, null ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmQueryImpl.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmQueryImpl.java index 80751516bee5..6c559a76b676 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmQueryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmQueryImpl.java @@ -4,6 +4,7 @@ */ package org.hibernate.query.sqm.internal; +import jakarta.persistence.AttributeConverter; import jakarta.persistence.CacheRetrieveMode; import jakarta.persistence.CacheStoreMode; import jakarta.persistence.EntityGraph; @@ -15,7 +16,6 @@ import jakarta.persistence.TemporalType; import jakarta.persistence.Timeout; import jakarta.persistence.metamodel.Type; - import org.hibernate.CacheMode; import org.hibernate.FlushMode; import org.hibernate.HibernateException; @@ -704,6 +704,12 @@ public SqmQueryImplementor setFirstResult(int startPosition) { return this; } + @Override + public EntityGraph getEntityGraph() { + //noinspection unchecked + return (EntityGraph) getQueryOptions().getAppliedGraph().getGraph(); + } + @Override public SqmQueryImplementor setHibernateFlushMode(FlushMode flushMode) { super.setHibernateFlushMode( flushMode ); @@ -747,10 +753,18 @@ public SqmQueryImplementor setLockScope(PessimisticLockScope lockScope) { return this; } + @Override + public PessimisticLockScope getLockScope() { + verifySelect(); + getSession().checkOpen( false ); + return getLockOptions().getScope().getCorrespondingJpaScope(); + } + @Override public SqmQueryImplementor setTimeout(Timeout timeout) { + assert timeout != null; getSession().checkOpen( false ); - getQueryOptions().getLockOptions().setTimeOut( timeout.milliseconds() ); + getQueryOptions().setTimeout( timeout ); return this; } @@ -892,7 +906,7 @@ public NamedSqmQueryMemento toMemento(String name) { getQueryOptions().getFlushMode(), isReadOnly(), getLockOptions(), - getTimeout(), + getQueryOptions().getTimeout(), getFetchSize(), getComment(), emptyMap(), @@ -912,7 +926,7 @@ public NamedSqmQueryMemento toMemento(String name) { getQueryOptions().getFlushMode(), isReadOnly(), getLockOptions(), - getTimeout(), + getQueryOptions().getTimeout(), getFetchSize(), getComment(), emptyMap(), @@ -1061,6 +1075,12 @@ public

SqmQueryImplementor setParameter(String name, P value, Type

typ return this; } + @Override + public

SqmQueryImplementor setConvertedParameter(String name, P value, Class> converter) { + super.setConvertedParameter( name, value, converter ); + return this; + } + @Override @Deprecated public SqmQueryImplementor setParameter(String name, Instant value, TemporalType temporalType) { super.setParameter( name, value, temporalType ); @@ -1085,6 +1105,12 @@ public

SqmQueryImplementor setParameter(int position, P value, Type

ty return this; } + @Override + public

SqmQueryImplementor setConvertedParameter(int position, P value, Class> converter) { + super.setConvertedParameter( position, value, converter ); + return this; + } + @Override @Deprecated public SqmQueryImplementor setParameter(int position, Instant value, TemporalType temporalType) { super.setParameter( position, value, temporalType ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/DelegatingSqmSelectionQueryImplementor.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/DelegatingSqmSelectionQueryImplementor.java index 226af8014963..df4a02f4f514 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/DelegatingSqmSelectionQueryImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/DelegatingSqmSelectionQueryImplementor.java @@ -13,6 +13,7 @@ import java.util.Optional; import java.util.stream.Stream; +import jakarta.persistence.AttributeConverter; import org.hibernate.CacheMode; import org.hibernate.FlushMode; import org.hibernate.Incubating; @@ -348,6 +349,16 @@ public QueryOptions getQueryOptions() { return getDelegate().getQueryOptions(); } + @Override + public

SelectionQuery setConvertedParameter(String name, P value, Class> converter) { + return getDelegate().setConvertedParameter( name, value, converter ); + } + + @Override + public

SelectionQuery setConvertedParameter(int position, P value, Class> converter) { + return getDelegate().setConvertedParameter( position, value, converter ); + } + @Override public SqmSelectionQueryImplementor setParameter(String name, Object value) { getDelegate().setParameter( name, value ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/NamedSqmQueryMemento.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/NamedSqmQueryMemento.java index 1f4d699160fb..edd945d117c6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/NamedSqmQueryMemento.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/NamedSqmQueryMemento.java @@ -33,7 +33,7 @@ public interface NamedSqmQueryMemento extends NamedQueryMemento { LockOptions getLockOptions(); - Map getParameterTypes(); + Map getAnticipatedParameterTypes(); @Override NamedSqmQueryMemento makeCopy(String name); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmFrom.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmFrom.java index 243382d20741..1ff513629ac6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmFrom.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmFrom.java @@ -438,26 +438,26 @@ public SqmMapJoin join(MapAttribute attribute, } @Override - public SqmAttributeJoin join(String attributeName) { + public SqmAttributeJoin join(String attributeName) { return join( attributeName, JoinType.INNER ); } @Override @SuppressWarnings("unchecked") - public SqmAttributeJoin join(String attributeName, JoinType jt) { + public SqmAttributeJoin join(String attributeName, JoinType jt) { final var subPathSource = (SqmPathSource) getReferencedPathSource().getSubPathSource( attributeName ); - return (SqmAttributeJoin) buildJoin( subPathSource, SqmJoinType.from( jt ), false ); + return buildJoin( subPathSource, SqmJoinType.from( jt ), false ); } @Override - public SqmBagJoin joinCollection(String attributeName) { + public SqmBagJoin joinCollection(String attributeName) { return joinCollection( attributeName, JoinType.INNER ); } @Override @SuppressWarnings("unchecked") - public SqmBagJoin joinCollection(String attributeName, JoinType jt) { + public SqmBagJoin joinCollection(String attributeName, JoinType jt) { final var joinedPathSource = getReferencedPathSource().getSubPathSource( attributeName ); if ( joinedPathSource instanceof BagPersistentAttribute ) { final var join = buildBagJoin( @@ -466,7 +466,7 @@ public SqmBagJoin joinCollection(String attributeName, JoinType jt) false ); addSqmJoin( join ); - return (SqmBagJoin) join; + return join; } throw new IllegalArgumentException( @@ -481,13 +481,13 @@ public SqmBagJoin joinCollection(String attributeName, JoinType jt) } @Override - public SqmSetJoin joinSet(String attributeName) { + public SqmSetJoin joinSet(String attributeName) { return joinSet( attributeName, JoinType.INNER ); } @Override @SuppressWarnings("unchecked") - public SqmSetJoin joinSet(String attributeName, JoinType jt) { + public SqmSetJoin joinSet(String attributeName, JoinType jt) { final var joinedPathSource = getReferencedPathSource().getSubPathSource( attributeName ); if ( joinedPathSource instanceof SetPersistentAttribute ) { final var join = buildSetJoin( @@ -496,7 +496,7 @@ public SqmSetJoin joinSet(String attributeName, JoinType jt) { false ); addSqmJoin( join ); - return (SqmSetJoin) join; + return join; } throw new IllegalArgumentException( @@ -511,13 +511,13 @@ public SqmSetJoin joinSet(String attributeName, JoinType jt) { } @Override - public SqmListJoin joinList(String attributeName) { + public SqmListJoin joinList(String attributeName) { return joinList( attributeName, JoinType.INNER ); } @Override @SuppressWarnings("unchecked") - public SqmListJoin joinList(String attributeName, JoinType jt) { + public SqmListJoin joinList(String attributeName, JoinType jt) { final var joinedPathSource = getReferencedPathSource().getSubPathSource( attributeName ); if ( joinedPathSource instanceof ListPersistentAttribute ) { @@ -527,7 +527,7 @@ public SqmListJoin joinList(String attributeName, JoinType jt) { false ); addSqmJoin( join ); - return (SqmListJoin) join; + return join; } throw new IllegalArgumentException( @@ -542,13 +542,13 @@ public SqmListJoin joinList(String attributeName, JoinType jt) { } @Override - public SqmMapJoin joinMap(String attributeName) { + public SqmMapJoin joinMap(String attributeName) { return joinMap( attributeName, JoinType.INNER ); } @Override @SuppressWarnings("unchecked") - public SqmMapJoin joinMap(String attributeName, JoinType jt) { + public SqmMapJoin joinMap(String attributeName, JoinType jt) { final var joinedPathSource = getReferencedPathSource().getSubPathSource( attributeName ); if ( joinedPathSource instanceof MapPersistentAttribute ) { @@ -558,7 +558,7 @@ public SqmMapJoin joinMap(String attributeName, JoinType jt) false ); addSqmJoin( join ); - return (SqmMapJoin) join; + return join; } throw new IllegalArgumentException( @@ -802,17 +802,15 @@ public SqmAttributeJoin fetch(PluralAttribute attribu } @Override - public SqmAttributeJoin fetch(String attributeName) { + public SqmAttributeJoin fetch(String attributeName) { return fetch( attributeName, JoinType.INNER ); } @Override @SuppressWarnings("unchecked") - public SqmAttributeJoin fetch(String attributeName, JoinType jt) { - return (SqmAttributeJoin) buildJoin( - (SqmPathSource) - getReferencedPathSource() - .getSubPathSource( attributeName ), + public SqmAttributeJoin fetch(String attributeName, JoinType jt) { + return buildJoin( + (SqmPathSource) getReferencedPathSource().getSubPathSource( attributeName ), SqmJoinType.from( jt ), true ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPolymorphicRootDescriptor.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPolymorphicRootDescriptor.java index f2d6550b89d2..bdf5fff67a13 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPolymorphicRootDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPolymorphicRootDescriptor.java @@ -4,6 +4,7 @@ */ package org.hibernate.query.sqm.tree.domain; +import jakarta.persistence.EntityGraph; import jakarta.persistence.metamodel.Attribute; import jakarta.persistence.metamodel.CollectionAttribute; import jakarta.persistence.metamodel.ListAttribute; @@ -139,6 +140,16 @@ public String getName() { return polymorphicJavaType.getTypeName(); } + @Override + public EntityGraph createEntityGraph() { + throw new UnsupportedOperationException(); + } + + @Override + public Map> getNamedEntityGraphs() { + throw new UnsupportedOperationException(); + } + @Override public String getHibernateEntityName() { return getName(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFrom.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFrom.java index 942919da2955..ae5914c77a04 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFrom.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFrom.java @@ -180,34 +180,34 @@ static boolean areDeepCompatible(List> theseFroms, List< SqmMapJoin join(MapAttribute map, JoinType jt); @Override - SqmAttributeJoin join(String attributeName); + SqmAttributeJoin join(String attributeName); @Override - SqmAttributeJoin join(String attributeName, JoinType jt); + SqmAttributeJoin join(String attributeName, JoinType jt); @Override - SqmBagJoin joinCollection(String attributeName); + SqmBagJoin joinCollection(String attributeName); @Override - SqmBagJoin joinCollection(String attributeName, JoinType jt); + SqmBagJoin joinCollection(String attributeName, JoinType jt); @Override - SqmSetJoin joinSet(String attributeName); + SqmSetJoin joinSet(String attributeName); @Override - SqmSetJoin joinSet(String attributeName, JoinType jt); + SqmSetJoin joinSet(String attributeName, JoinType jt); @Override - SqmListJoin joinList(String attributeName); + SqmListJoin joinList(String attributeName); @Override - SqmListJoin joinList(String attributeName, JoinType jt); + SqmListJoin joinList(String attributeName, JoinType jt); @Override - SqmMapJoin joinMap(String attributeName); + SqmMapJoin joinMap(String attributeName); @Override - SqmMapJoin joinMap(String attributeName, JoinType jt); + SqmMapJoin joinMap(String attributeName, JoinType jt); @Override SqmFrom copy(SqmCopyContext context); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmJoin.java index 4603c198796d..2bec9a319f9c 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmJoin.java @@ -64,10 +64,10 @@ public interface SqmJoin extends SqmFrom, JpaJoin { void setJoinPredicate(@Nullable SqmPredicate predicate); @Override - SqmAttributeJoin join(String attributeName); + SqmAttributeJoin join(String attributeName); @Override - SqmAttributeJoin join(String attributeName, JoinType jt); + SqmAttributeJoin join(String attributeName, JoinType jt); @Override SqmJoin copy(SqmCopyContext context); @@ -188,26 +188,26 @@ default JpaEntityJoin join(Class entityJavaType, SqmJoinType joinTy SqmMapJoin join(MapAttribute map, JoinType jt); @Override - SqmBagJoin joinCollection(String attributeName); + SqmBagJoin joinCollection(String attributeName); @Override - SqmBagJoin joinCollection(String attributeName, JoinType jt); + SqmBagJoin joinCollection(String attributeName, JoinType jt); @Override - SqmSetJoin joinSet(String attributeName); + SqmSetJoin joinSet(String attributeName); @Override - SqmSetJoin joinSet(String attributeName, JoinType jt); + SqmSetJoin joinSet(String attributeName, JoinType jt); @Override - SqmListJoin joinList(String attributeName); + SqmListJoin joinList(String attributeName); @Override - SqmListJoin joinList(String attributeName, JoinType jt); + SqmListJoin joinList(String attributeName, JoinType jt); @Override - SqmMapJoin joinMap(String attributeName); + SqmMapJoin joinMap(String attributeName); @Override - SqmMapJoin joinMap(String attributeName, JoinType jt); + SqmMapJoin joinMap(String attributeName, JoinType jt); } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/StandardJdbcMutationExecutor.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/StandardJdbcMutationExecutor.java index fd77dc72b41f..0677539a6b30 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/StandardJdbcMutationExecutor.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/StandardJdbcMutationExecutor.java @@ -9,6 +9,8 @@ import java.util.function.BiConsumer; import java.util.function.Function; +import jakarta.persistence.Timeout; +import org.hibernate.Timeouts; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.exception.ConstraintViolationException; import org.hibernate.sql.exec.spi.ExecutionContext; @@ -17,6 +19,8 @@ import org.hibernate.sql.exec.spi.JdbcOperationQueryMutation; import org.hibernate.sql.exec.spi.JdbcParameterBindings; +import static org.hibernate.engine.jdbc.JdbcLogging.JDBC_LOGGER; + /** * @author Steve Ebersole */ @@ -46,9 +50,12 @@ public int execute( // prepare the query final var preparedStatement = statementCreator.apply( finalSql ); try { - final Integer timeout = queryOptions.getTimeout(); - if ( timeout != null ) { - preparedStatement.setQueryTimeout( timeout ); + final Timeout timeout = queryOptions.getTimeout(); + if ( Timeouts.isRealTimeout( timeout ) ) { + // JDBC expects timeout in seconds + final int timeoutInSeconds = Timeouts.getTimeoutInSeconds( timeout ); + JDBC_LOGGER.settingQueryTimeout( timeoutInSeconds ); + preparedStatement.setQueryTimeout( timeoutInSeconds ); } // bind parameters diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcSelectExecutor.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcSelectExecutor.java index 1372aa0c59ef..6eceba173dca 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcSelectExecutor.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcSelectExecutor.java @@ -6,6 +6,7 @@ import jakarta.persistence.CacheRetrieveMode; import jakarta.persistence.CacheStoreMode; +import jakarta.persistence.Timeout; import org.hibernate.FlushMode; import org.hibernate.Incubating; import org.hibernate.LockOptions; @@ -192,7 +193,7 @@ interface StatementCreator { private ExecutionContext getScrollContext(ExecutionContext context) { class ScrollableExecutionContext extends BaseExecutionContext implements QueryOptions { - private final Integer timeout; + private final Timeout timeout; private final FlushMode flushMode; private final Boolean readOnly; private final AppliedGraph appliedGraph; @@ -210,7 +211,7 @@ class ScrollableExecutionContext extends BaseExecutionContext implements QueryOp private final ExecutionContext context; public ScrollableExecutionContext( - Integer timeout, + Timeout timeout, FlushMode flushMode, Boolean readOnly, AppliedGraph appliedGraph, @@ -256,7 +257,7 @@ public QueryOptions getQueryOptions() { } @Override - public Integer getTimeout() { + public Timeout getTimeout() { return timeout; } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/DeferredResultSetAccess.java b/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/DeferredResultSetAccess.java index 4a2060226842..25c5ec8adca2 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/DeferredResultSetAccess.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/DeferredResultSetAccess.java @@ -4,8 +4,10 @@ */ package org.hibernate.sql.results.jdbc.internal; +import jakarta.persistence.Timeout; import org.hibernate.LockMode; import org.hibernate.LockOptions; +import org.hibernate.Timeouts; import org.hibernate.dialect.Dialect; import org.hibernate.dialect.pagination.LimitHandler; import org.hibernate.dialect.pagination.NoopLimitHandler; @@ -238,10 +240,12 @@ private void setQueryOptions(PreparedStatement preparedStatement) throws SQLExce JDBC_LOGGER.settingFetchSize( fetchSize ); preparedStatement.setFetchSize( fetchSize ); } - final Integer timeout = queryOptions.getTimeout(); - if ( timeout != null ) { - JDBC_LOGGER.settingQueryTimeout( timeout ); - preparedStatement.setQueryTimeout( timeout ); + final Timeout timeout = queryOptions.getTimeout(); + if ( Timeouts.isRealTimeout( timeout ) ) { + // JDBC expects timeout in seconds + final int timeoutInSeconds = Timeouts.getTimeoutInSeconds( timeout ); + JDBC_LOGGER.settingQueryTimeout( timeoutInSeconds ); + preparedStatement.setQueryTimeout( timeoutInSeconds ); } } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/JdbcValuesMappingProducerProviderStandard.java b/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/JdbcValuesMappingProducerProviderStandard.java index 8b33f7ff81cb..efdd1bd1316d 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/JdbcValuesMappingProducerProviderStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/JdbcValuesMappingProducerProviderStandard.java @@ -5,7 +5,7 @@ package org.hibernate.sql.results.jdbc.internal; import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.query.results.ResultSetMapping; +import org.hibernate.query.results.spi.ResultSetMapping; import org.hibernate.query.results.internal.ResultSetMappingImpl; import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.ast.tree.select.QueryGroup; diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/spi/JdbcValuesMappingProducer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/spi/JdbcValuesMappingProducer.java index 629aa329e323..a8c38cdd13d8 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/spi/JdbcValuesMappingProducer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/spi/JdbcValuesMappingProducer.java @@ -9,7 +9,7 @@ import org.hibernate.Incubating; import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.query.results.ResultSetMapping; +import org.hibernate.query.results.spi.ResultSetMapping; /** * Producer for JdbcValuesMapping references. diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/spi/JdbcValuesMappingProducerProvider.java b/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/spi/JdbcValuesMappingProducerProvider.java index b1088acb4b27..cbf4fc4a35f8 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/spi/JdbcValuesMappingProducerProvider.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/spi/JdbcValuesMappingProducerProvider.java @@ -6,7 +6,7 @@ import org.hibernate.Incubating; import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.query.results.ResultSetMapping; +import org.hibernate.query.results.spi.ResultSetMapping; import org.hibernate.service.Service; import org.hibernate.sql.ast.tree.select.SelectStatement; diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/internal/ConverterHelper.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/internal/ConverterHelper.java index 9b8622d8ba84..9a60f43fd797 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/internal/ConverterHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/internal/ConverterHelper.java @@ -6,9 +6,12 @@ import jakarta.persistence.AttributeConverter; import org.hibernate.resource.beans.spi.ManagedBean; +import org.hibernate.resource.beans.spi.ManagedBeanRegistry; +import org.hibernate.service.ServiceRegistry; import org.hibernate.type.descriptor.converter.spi.BasicValueConverter; import org.hibernate.type.descriptor.converter.spi.JpaAttributeConverter; import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry; +import org.hibernate.type.spi.TypeConfiguration; import static org.hibernate.internal.util.GenericsHelper.erasedType; @@ -51,4 +54,12 @@ public static JpaAttributeConverter createJpaAttributeConverter( registry.resolveDescriptor( relationalJavaClass ) ); } + + public static JpaAttributeConverter createJpaAttributeConverter( + Class> converterClass, + ServiceRegistry serviceRegistry, + TypeConfiguration typeConfiguration) { + var converterBean = serviceRegistry.requireService( ManagedBeanRegistry.class ).getBean( converterClass ); + return createJpaAttributeConverter( converterBean, typeConfiguration.getJavaTypeRegistry() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CalendarDateJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CalendarDateJavaType.java index 757345cb9875..4c35c0e25f21 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CalendarDateJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CalendarDateJavaType.java @@ -101,7 +101,12 @@ public Calendar cast(Object value) { @Override public Calendar coerce(Object value) { - return wrap( value, null ); + try { + return wrap( value, null ); + } + catch (Exception e) { + throw CoercionHelper.coercionException( e ); + } } public X unwrap(Calendar value, Class type, WrapperOptions options) { diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CalendarJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CalendarJavaType.java index 9d69570a57b9..e11d69e1d5a0 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CalendarJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CalendarJavaType.java @@ -117,7 +117,12 @@ public Calendar cast(Object value) { @Override public Calendar coerce(Object value) { - return wrap( value, null ); + try { + return wrap( value, null ); + } + catch (Exception e) { + throw CoercionHelper.coercionException( e ); + } } public X unwrap(Calendar value, Class type, WrapperOptions options) { diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CoercionHelper.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CoercionHelper.java index 311b234483a6..9b2b769237e9 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CoercionHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CoercionHelper.java @@ -381,6 +381,12 @@ public static boolean isWholeNumber(float floatValue) { return floatValue == ( (float) (long) floatValue ); } + public static CoercionException coercionException(Exception e) { + var ce = new CoercionException( e.getMessage() ); + ce.addSuppressed( e ); + return ce; + } + @FunctionalInterface public interface Coercer { T doCoercion(); diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/DateJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/DateJavaType.java index f6680becfc12..9bc3e11aad59 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/DateJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/DateJavaType.java @@ -193,7 +193,12 @@ public Date wrap(X value, WrapperOptions options) { @Override public Object coerce(Object value) { - return wrap( value, null ); + try { + return wrap( value, null ); + } + catch (Exception e) { + throw CoercionHelper.coercionException( e ); + } } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JdbcDateJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JdbcDateJavaType.java index ebad46f62753..677e389ca804 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JdbcDateJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JdbcDateJavaType.java @@ -114,7 +114,12 @@ public int extractHashCode(Date value) { @Override public Date coerce(Object value) { - return wrap( value, null ); + try { + return wrap( value, null ); + } + catch (Exception e) { + throw CoercionHelper.coercionException( e ); + } } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JdbcTimeJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JdbcTimeJavaType.java index 1d868df7fc70..8e94aa5f9328 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JdbcTimeJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JdbcTimeJavaType.java @@ -116,7 +116,12 @@ public boolean areEqual(Time one, Time another) { @Override public Time coerce(Object value) { - return wrap( value, null ); + try { + return wrap( value, null ); + } + catch (Exception e) { + throw CoercionHelper.coercionException( e ); + } } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JdbcTimestampJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JdbcTimestampJavaType.java index b9c63cfca8b7..18606dbe2b3f 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JdbcTimestampJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JdbcTimestampJavaType.java @@ -107,7 +107,12 @@ public int extractHashCode(Timestamp value) { @Override public Timestamp coerce(Object value) { - return wrap( value, null ); + try { + return wrap( value, null ); + } + catch (Exception e) { + throw CoercionHelper.coercionException( e ); + } } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/PrimitiveByteArrayJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/PrimitiveByteArrayJavaType.java index bfaedc9b68dc..be85e73eb441 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/PrimitiveByteArrayJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/PrimitiveByteArrayJavaType.java @@ -166,7 +166,12 @@ else if ( value instanceof Byte[] array ) { @Override public byte[] coerce(Object value) { - return wrap( value, null ); + try { + return wrap( value, null ); + } + catch (Exception e) { + throw CoercionHelper.coercionException( e ); + } } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/PrimitiveCharacterArrayJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/PrimitiveCharacterArrayJavaType.java index 7bcb1fca2908..03936a93b1a2 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/PrimitiveCharacterArrayJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/PrimitiveCharacterArrayJavaType.java @@ -110,7 +110,12 @@ else if ( value instanceof Character character ) { @Override public char[] coerce(Object value) { - return wrap( value, null ); + try { + return wrap( value, null ); + } + catch (Exception e) { + throw CoercionHelper.coercionException( e ); + } } private static class ArrayMutabilityPlan extends MutableMutabilityPlan { diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/StringJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/StringJavaType.java index a10b9fc29ac4..614124404a90 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/StringJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/StringJavaType.java @@ -148,6 +148,11 @@ public boolean isWider(JavaType javaType) { @Override public String coerce(Object value) { - return wrap( value, null ); + try { + return wrap( value, null ); + } + catch (Exception e) { + throw CoercionHelper.coercionException( e ); + } } } diff --git a/hibernate-core/src/main/resources/org/hibernate/xsd/cfg/configuration-8.0.xsd b/hibernate-core/src/main/resources/org/hibernate/xsd/cfg/configuration-8.0.xsd new file mode 100644 index 000000000000..35515d03fade --- /dev/null +++ b/hibernate-core/src/main/resources/org/hibernate/xsd/cfg/configuration-8.0.xsd @@ -0,0 +1,418 @@ + + + + + + + + + ... + + + ]]> + + + + + + + + + + + + + + + + + + + + + + Configuration of a persistence unit. + + + + + + + + + + + + Description of this persistence unit. + + + + + + + + + + + + Provider class that supplies EntityManagers for this + persistence unit. + + + + + + + + + + + + Qualifier annotation class used for dependency injection. + + + + + + + + + + + + Scope annotation class used for dependency injection. + + + + + + + + + + + + The container-specific name of the JTA datasource to use. + + + + + + + + + + + + The container-specific name of a non-JTA datasource to use. + + + + + + + + + + + + File containing mapping information. Loaded as a resource + by the persistence provider. + + + + + + + + + + + + Jar file that is to be scanned for managed classes. + + + + + + + + + + + + Managed class to be included in the persistence unit and + to scan for annotations. It should be annotated + with either @Entity, @Embeddable or @MappedSuperclass. + + + + + + + + + + + + When set to true then only listed classes and jars will + be scanned for persistent classes, otherwise the + enclosing jar or directory will also be scanned. + Not applicable to Java SE persistence units. + + + + + + + + + + + + + The default fetch type for one-to-one and many-to-one associations. + + + + + + + + + + + + + Defines whether caching is enabled for the + persistence unit if caching is supported by the + persistence provider. When set to ALL, all entities + will be cached. When set to NONE, no entities will + be cached. When set to ENABLE_SELECTIVE, only entities + specified as cacheable will be cached. When set to + DISABLE_SELECTIVE, entities specified as not cacheable + will not be cached. When not specified or when set to + UNSPECIFIED, provider defaults may apply. + + + + + + + + + + + + The validation mode to be used for the persistence unit. + + + + + + + + + + + + + A list of standard and vendor-specific properties + and hints. + + + + + + + + + A name-value pair. + + + + + + + + + + + + + + + An extension point for integration related configuration, e.g. cdi: + + + + + + + + + + + + + Name used in code to reference this persistence unit. + + + + + + + + + + + + Type of transactions used by EntityManagers from this + persistence unit. + + + + + + + + + + + + + + + + + + + public enum PersistenceUnitTransactionType {JTA, RESOURCE_LOCAL}; + + + + + + + + + + + + + + + + public enum FetchType { LAZY, EAGER, DEFAULT }; + + + + + + + + + + + + + + + + + public enum SharedCacheMode { ALL, NONE, ENABLE_SELECTIVE, DISABLE_SELECTIVE, UNSPECIFIED}; + + + + + + + + + + + + + + + + + + + public enum ValidationMode { AUTO, CALLBACK, NONE }; + + + + + + + + + + + diff --git a/hibernate-core/src/main/resources/org/hibernate/xsd/mapping/legacy-mapping-4.0.xsd b/hibernate-core/src/main/resources/org/hibernate/xsd/mapping/legacy-mapping-4.0.xsd index 7a67b1098900..5a38c1606073 100644 --- a/hibernate-core/src/main/resources/org/hibernate/xsd/mapping/legacy-mapping-4.0.xsd +++ b/hibernate-core/src/main/resources/org/hibernate/xsd/mapping/legacy-mapping-4.0.xsd @@ -202,7 +202,7 @@ - + @@ -224,7 +224,7 @@ - + @@ -2080,4 +2080,8 @@ + + + + diff --git a/hibernate-core/src/main/resources/org/hibernate/xsd/mapping/mapping-8.0.xsd b/hibernate-core/src/main/resources/org/hibernate/xsd/mapping/mapping-8.0.xsd new file mode 100644 index 000000000000..767cb4f8d3e0 --- /dev/null +++ b/hibernate-core/src/main/resources/org/hibernate/xsd/mapping/mapping-8.0.xsd @@ -0,0 +1,3576 @@ + + + + + + + + ... + + ]]> + + + + + + + + + + + The entity-mappings element is the root element of a mapping + file. It contains the following four types of elements: + + 1. The persistence-unit-metadata element contains metadata + for the entire persistence unit. It is undefined if this element + occurs in multiple mapping files within the same persistence unit. + + 2. The package, schema, catalog and access elements apply to all of + the entity, mapped-superclass and embeddable elements defined in + the same file in which they occur. + + 3. The sequence-generator, table-generator, converter, named-query, + named-native-query, named-stored-procedure-query, and + sql-result-set-mapping elements are global to the persistence + unit. It is undefined to have more than one sequence-generator + or table-generator of the same name in the same or different + mapping files in a persistence unit. It is undefined to have + more than one named-query, named-native-query, sql-result-set-mapping, + or named-stored-procedure-query of the same name in the same + or different mapping files in a persistence unit. It is also + undefined to have more than one converter for the same target + type in the same or different mapping files in a persistence unit. + + 4. The entity, mapped-superclass and embeddable elements each define + the mapping information for a managed persistent class. The mapping + information contained in these elements may be complete or it may + be partial. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Metadata that applies to the persistence unit and not just to + the mapping file in which it is contained. + + If the xml-mapping-metadata-complete element is specified, + the complete set of mapping metadata for the persistence unit + is contained in the XML mapping files for the persistence unit. + + + + + + + + + + + + + + + + + These defaults are applied to the persistence unit as a whole + unless they are overridden by local annotation or XML + element settings. + + schema - Used as the schema for all tables, secondary tables, join + tables, collection tables, sequence generators, and table + generators that apply to the persistence unit + catalog - Used as the catalog for all tables, secondary tables, join + tables, collection tables, sequence generators, and table + generators that apply to the persistence unit + delimited-identifiers - Used to treat database identifiers as + delimited identifiers. + access - Used as the access type for all managed classes in + the persistence unit + cascade-persist - Adds cascade-persist to the set of cascade options + in all entity relationships of the persistence unit + entity-listeners - List of default entity listeners to be invoked + on each entity in the persistence unit. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Defines the settings and mappings for an entity. Is allowed to be + sparsely populated and used in conjunction with the annotations. + Alternatively, the metadata-complete attribute can be used to + indicate that no annotations on the entity class (and its fields + or properties) are to be processed. If this is the case then + the defaulting rules for the entity and its subelements will + be recursively applied. + + @Target(TYPE) @Retention(RUNTIME) + public @interface Entity { + String name() default ""; + } + + + + + + + + + + + See `@org.hibernate.boot.internal.Abstract` + + + + + + + See `@org.hibernate.boot.internal.Extends` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This element determines how the persistence provider accesses the + state of an entity or embedded object. + + + + + + + + + + + + + + + + + @Repeatable(AssociationOverrides.class) + @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME) + public @interface AssociationOverride { + String name(); + JoinColumn[] joinColumns() default{}; + ForeignKey foreignKey() default @ForeignKey(PROVIDER_DEFAULT); + JoinTable joinTable() default @JoinTable; + } + + + + + + + + + + + + + + + + + + + + + + + + @Repeatable(AttributeOverrides.class) + @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME) + public @interface AttributeOverride { + String name(); + Column column(); + } + + + + + + + + + + + + + + + + + This element contains the entity field or property mappings. + It may be sparsely populated to include only a subset of the + fields or properties. If metadata-complete for the entity is true + then the remainder of the attributes will be defaulted according + to the default rules. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + See `@jakarta.persistence.Basic` + See `@jakarta.persistence.Lob` + See `@jakarta.persistence.Temporal` + See `@jakarta.persistence.Enumerated` + See `@jakarta.persistence.Convert` + See `@org.hibernate.annotations.Nationalized` + See `@org.hibernate.annotations.OptimisticLock` + See `@org.hibernate.annotations.AttributeAccessor` + See `@org.hibernate.annotations.Type` + See `@org.hibernate.annotations.JavaType` + See `@org.hibernate.annotations.JdbcType` + See `@org.hibernate.annotations.JdbcTypeCode` + See `@org.hibernate.annotations.Mutability` + See `@org.hibernate.annotations.Immutable` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + See @org.hibernate.annotations.Target + + Generally only useful for dynamic-models - specifies the attribute's Java type + + + + + + + @org.hibernate.annotations.JavaType + + + + + + + + + @org.hibernate.annotations.JdbcType + + + + + + + @org.hibernate.annotations.JdbcTypeCode + + + + + + + Name from org.hibernate.type.SqlTypes + + + + + + + + + + + + + + + + public enum CascadeType { ALL, PERSIST, MERGE, REMOVE, REFRESH, DETACH } + + + + + + + + + + + + + + + + + + + + + + + @Target({}) @Retention(RUNTIME) + public @interface CheckConstraint { + String name() default ""; + String constraint(); + String options() default ""; + } + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface CollectionTable { + String name() default ""; + String catalog() default ""; + String schema() default ""; + JoinColumn[] joinColumns() default {}; + ForeignKey foreignKey() default @ForeignKey(ConstraintMode.PROVIDER_DEFAULT); + UniqueConstraint[] uniqueConstraints() default {}; + Index[] indexes() default {}; + String options() default ""; + } + + + + + + + + + + + + + + + + + + + + + + + + + + See `@jakarta.persistence.Column` + See `@org.hibernate.annotations.Comment` + See `@org.hibernate.annotations.Check` + See `@org.hibernate.annotations.ColumnDefault` + See `@org.hibernate.annotations.ColumnTransformer` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + type() default void.class; + } + + ]]> + + + + + + + + + + + + public enum ConstraintMode { CONSTRAINT, NO_CONSTRAINT, PROVIDER_DEFAULT } + + + + + + + + + + + + + + + + targetClass(); + ColumnResult[] columns(); + EntityResult[] entities(); + } + + ]]> + + + + + + + + + + + + + converter() default AttributeConverter.class; + String attributeName() default ""; + boolean disableConversion() default false; + } + + ]]> + + + + + + + + + + + + + + + + @Target({TYPE}) @Retention(RUNTIME) + public @interface Converter { + boolean autoApply() default false; + } + + + + + + + + + + + + + + + + + @Target({TYPE}) @Retention(RUNTIME) + public @interface DiscriminatorColumn { + String name() default "DTYPE"; + DiscriminatorType discriminatorType() default STRING; + String columnDefinition() default ""; + String options() default ""; + int length() default 31; + } + + + + + + + + + + + + + + + + + + + @interface DiscriminatorFormula { + /** The fragment */ + String value(); + DiscriminatorType discriminatorType() default STRING; + } + + @interface DiscriminatorOptions { + boolean force() default false; + ... + } + + + + + + + + + + + + + + + + + public enum DiscriminatorType { STRING, CHAR, INTEGER } + + + + + + + + + + + + + + + + + + @Target({TYPE}) @Retention(RUNTIME) + public @interface DiscriminatorValue { + String value(); + } + + + + + + + + + + + + targetClass() default void.class; + FetchType fetch() default FetchType.LAZY; + } + + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + See `@jakarta.persistence.Embeddable` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface Embedded {} + + + + + + + + See `@org.hibernate.boot.internal.Target` + + + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface EmbeddedId {} + + + + + + + + See `@org.hibernate.boot.internal.Target` + + + + + + + + + + + + + + + + + Defines an entity listener to be invoked at lifecycle events + for the entities that list this listener. + + + + + + + + + + + + + + + + + + + + + [] value(); + } + + ]]> + + + + + + + + + + + entityClass(); + LockModeType lockMode() default LockModeType.OPTIMISTIC; + FieldResult[] fields() default {}; + String discriminatorColumn() default ""; + } + + ]]> + + + + + + + + + + + + + + + + + public enum EnumType { ORDINAL, STRING } + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface Enumerated { + EnumType value() default ORDINAL; + } + + + + + + + + + + + + + public enum FetchType { LAZY, EAGER } + + + + + + + + + + + + + + + + @Target({}) @Retention(RUNTIME) + public @interface FieldResult { + String name(); + String column(); + } + + + + + + + + + + + + + + @Target({}) @Retention(RUNTIME) + public @interface ForeignKey { + String name() default ""; + ConstraintMode value() default CONSTRAINT; + String foreign-key-definition() default ""; + String options() default ""; + } + + Note that the elements that embed the use of the annotation + default this use as @ForeignKey(PROVIDER_DEFAULT). + + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface GeneratedValue { + GenerationType strategy() default AUTO; + String generator() default ""; + } + + + + + + + + + + + + + + public enum GenerationType { TABLE, SEQUENCE, IDENTITY, UUID, AUTO } + + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface Id {} + + + + + + + + + + + + + + + + + + + + + + + + + + + value(); + } + + ]]> + + + + + + + + + + + @Target({}) @Retention(RUNTIME) + public @interface Index { + String name() default ""; + String columnList(); + boolean unique() default false; + String options() default ""; + } + + + + + + + + + + + + + + + + + + + @Target({TYPE}) @Retention(RUNTIME) + public @interface Inheritance { + InheritanceType strategy() default InheritanceType.SINGLE_TABLE; + } + + + + + + + + + + + + + public enum InheritanceType { SINGLE_TABLE, TABLE_PER_CLASS, JOINED } + + + + + + + + + + + + + + + + + @Repeatable(JoinColumns.class) + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface JoinColumn { + String name() default ""; + String referencedColumnName() default ""; + boolean unique() default false; + boolean nullable() default true; + boolean insertable() default true; + boolean updatable() default true; + String columnDefinition() default ""; + String options() default ""; + String table() default ""; + ForeignKey foreignKey() default @ForeignKey(); + CheckConstraint[] check() default {}; + String comment() default ""; + } + + + + + + + + + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface JoinTable { + String name() default ""; + String catalog() default ""; + String schema() default ""; + JoinColumn[] joinColumns() default {}; + JoinColumn[] inverseJoinColumns() default {}; + ForeignKey foreignKey() default @ForeignKey(ConstraintMode.PROVIDER_DEFAULT); + ForeignKey inverseForeignKey() default @ForeignKey(ConstraintMode.PROVIDER_DEFAULT); + UniqueConstraint[] uniqueConstraints() default {}; + Index[] indexes() default {}; + CheckConstraint[] check() default {}; + String comment() default ""; + String options() default ""; + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface Lob {} + + + + + + + + + + + + public enum LockModeType implements FindOption, RefreshOption { READ, WRITE, OPTIMISTIC, OPTIMISTIC_FORCE_INCREMENT, PESSIMISTIC_READ, PESSIMISTIC_WRITE, PESSIMISTIC_FORCE_INCREMENT, NONE} + + + + + + + + + + + + + + + + + + + + + + + public enum PessimisticLockScope implements FindOption, RefreshOption, LockOption { NORMAL, EXTENDED, FETCHED } + + + + + + + + + + + + + + + + targetEntity() default void.class; + CascadeType[] cascade() default {}; + FetchType fetch() default FetchType.LAZY; + String mappedBy() default ""; + } + + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + targetEntity() default void.class; + CascadeType[] cascade() default {}; + FetchType fetch() default FetchType.EAGER; + boolean optional() default true; + } + + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + public @interface PropertyRef { + String value(); + } + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface MapKey { + String name() default ""; + } + + + + + + + + + + + value(); + } + + ]]> + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface MapKeyColumn { + String name() default ""; + boolean unique() default false; + boolean nullable() default false; + boolean insertable() default true; + boolean updatable() default true; + String columnDefinition() default ""; + String options() default ""; + String table() default ""; + int length() default 255; + int precision() default 0; // decimal precision + int scale() default 0; // decimal scale + } + + + + + + + + + + + + + + + + + + + + + + + @Repeatable(MapKeyJoinColumns.class) + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface MapKeyJoinColumn { + String name() default ""; + String referencedColumnName() default ""; + boolean unique() default false; + boolean nullable() default false; + boolean insertable() default true; + boolean updatable() default true; + String comment() default ""; + String columnDefinition() default ""; + String options() default ""; + String table() default ""; + ForeignKey foreignKey() default @ForeignKey(ConstraintMode.PROVIDER_DEFAULT); + CheckConstraint[] check() default {} + } + + + + + + + + + + + + + + + + + + + + + + + + + + + Defines the settings and mappings for a mapped superclass. Is + allowed to be sparsely populated and used in conjunction with + the annotations. Alternatively, the metadata-complete attribute + can be used to indicate that no annotations are to be processed + If this is the case then the defaulting rules will be recursively + applied. + + @Target(TYPE) @Retention(RUNTIME) + public @interface MappedSuperclass {} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @Target({}) @Retention(RUNTIME) + public @interface NamedAttributeNode { + String value(); + String subgraph() default ""; + String keySubgraph() default ""; + } + + + + + + + + + + + + + + + @Repeatable(NamedEntityGraphs.class) + @Target({TYPE}) @Retention(RUNTIME) + public @interface NamedEntityGraph { + String name() default ""; + NamedAttributeNode[] attributeNodes() default {}; + boolean includeAllAttributes() default false; + NamedSubgraph[] subgraphs() default {}; + NamedSubGraph[] subclassSubgraphs() default {}; + } + + + + + + + + + + + + + + + + + + resultClass() default void.class; + String resultSetMapping() default ""; //named SqlResultSetMapping + EntityResult[] entities() default {}; + ConstructorResult[] classes() default {}; + ColumnResult[] columns() default {}; + } + + ]]> + + + + + + + + + + + + + + + + + + + + + + + @Repeatable(NamedQueries.class) + @Target({TYPE}) @Retention(RUNTIME) + public @interface NamedQuery { + String name(); + String query(); + Class resultClass(); + String entityGraph(); + LockModeType lockMode() default LockModeType.NONE; + PessimisticLockScope lockScope() default NORMAL; + QueryHint[] hints() default {}; + } + + + + + + + + + + + + + + + + + + + + + + + @Repeatable(NamedStoredProcedureQueries.class) + @Target({TYPE}) @Retention(RUNTIME) + public @interface NamedStoredProcedureQuery { + String name(); + String procedureName(); + StoredProcedureParameter[] parameters() default {}; + Class[] resultClasses() default {}; + String[] resultSetMappings() default{}; + QueryHint[] hints() default {}; + } + + + + + + + + + + + + + + + + + + + type() default void.class; + NamedAttributeNode[] attributeNodes(); + } + + ]]> + + + + + + + + + + + + + targetEntity() default void.class; + CascadeType[] cascade() default {}; + FetchType fetch() default FetchType.LAZY; + String mappedBy() default ""; + boolean orphanRemoval() default false; + } + + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + targetEntity() default void.class; + CascadeType[] cascade() default {}; + FetchType fetch() default FetchType.EAGER; + boolean optional() default true; + String mappedBy() default ""; + boolean orphanRemoval() default false; + } + + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface OrderBy { + String value() default ""; + } + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface OrderColumn { + String name() default ""; + boolean nullable() default true; + boolean insertable() default true; + boolean updatable() default true; + String comment() default ""; + String columnDefinition() default ""; + String options() default ""; + } + + + + + + + + + + + + + + + + + + + + + public enum ParameterMode { IN, INOUT, OUT, REF_CURSOR } + + + + + + + + + + + + + + + + + + @Target({METHOD}) @Retention(RUNTIME) + public @interface PostLoad {} + + + + + + + + + + + + + + + + @Target({METHOD}) @Retention(RUNTIME) + public @interface PostPersist {} + + + + + + + + + + + + + + + + @Target({METHOD}) @Retention(RUNTIME) + public @interface PostRemove {} + + + + + + + + + + + + + + + + @Target({METHOD}) @Retention(RUNTIME) + public @interface PostUpdate {} + + + + + + + + + + + + + + + + @Target({METHOD}) @Retention(RUNTIME) + public @interface PrePersist {} + + + + + + + + + + + + + + + + @Target({METHOD}) @Retention(RUNTIME) + public @interface PreRemove {} + + + + + + + + + + + + + + + + @Target({METHOD}) @Retention(RUNTIME) + public @interface PreUpdate {} + + + + + + + + + + + + + + + + @Repeatable(PrimaryKeyJoinColumns.class) + @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME) + public @interface PrimaryKeyJoinColumn { + String name() default ""; + String referencedColumnName() default ""; + String columnDefinition() default ""; + String options() default ""; + ForeignKey foreignKey() default @ForeignKey(PROVIDER_DEFAULT); + } + + + + + + + + + + + + + + + + + + + @Target({}) @Retention(RUNTIME) + public @interface QueryHint { + String name(); + String value(); + } + + + + + + + + + + + + + + + + See `@jakarta.persistence.SecondaryTable` + See `@org.hibernate.annotations.SecondaryRow` + + + + + + + + + + + + + + + + + + + + + + + + + + + + @Repeatable(SequenceGenerators.class) + @Target({TYPE, METHOD, FIELD, PACKAGE}) @Retention(RUNTIME) + public @interface SequenceGenerator { + String name() default ""; + String sequenceName() default ""; + String catalog() default ""; + String schema() default ""; + int initialValue() default 1; + int allocationSize() default 50; + String options() default ""; + } + + + + + + + + + + + + + + + + + + + + + + + @Repeatable(SqlResultSetMappings.class) + @Target({TYPE}) @Retention(RUNTIME) + public @interface SqlResultSetMapping { + String name(); + EntityResult[] entities() default {}; + ConstructorResult[] classes() default{}; + ColumnResult[] columns() default {}; + } + + + + + + + + + + + + + + + + + type(); + } + + ]]> + + + + + + + + + + + + + + + + @Target({TYPE}) @Retention(RUNTIME) + public @interface Table { + String name() default ""; + String catalog() default ""; + String schema() default ""; + UniqueConstraint[] uniqueConstraints() default {}; + Index[] indexes() default {}; + CheckConstraint[] check() default {}; + String comment() default ""; + String options() default ""; + } + + + + + + + + + + + + + + + + + + + + + @Repeatable(TableGenerators.class) + @Target({TYPE, METHOD, FIELD, PACKAGE}) @Retention(RUNTIME) + public @interface TableGenerator { + String name() default ""; + String table() default ""; + String catalog() default ""; + String schema() default ""; + String pkColumnName() default ""; + String valueColumnName() default ""; + String pkColumnValue() default ""; + int initialValue() default 0; + int allocationSize() default 50; + UniqueConstraint[] uniqueConstraints() default {}; + Indexes[] indexes() default {}; + String options() default ""; + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface Temporal { + TemporalType value(); + } + + + + + + + + + + + + + @Deprecated(since = "3.2") + public enum TemporalType { + DATE, // java.sql.Date + TIME, // java.sql.Time + TIMESTAMP // java.sql.Timestamp + } + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface Transient {} + + + + + + + + + + + + + @Target({}) @Retention(RUNTIME) + public @interface UniqueConstraint { + String name() default ""; + String[] columnNames(); + String options() default ""; + } + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface Version {} + + + + + + + + + + + + + + + + + + + + + + + + See @JavaTypeRegistration + + + + + + + + + + See @JdbcTypeRegistration + + + + + + + + + See @TypeRegistration + + + + + + + + + + See @CompositeTypeRegistration + + + + + + + + + + See @CollectionTypeRegistration + + + + + + + + + + + + + Configuration parameter user-types + + + + + + + + + + See `@org.hibernate.metamodel.CollectionClassification` + + + + + + + + + + + + + + + + + + + + See @ConverterRegistration + + + + + + + + + + + See @EmbeddableInstantiatorRegistration + + + + + + + + + + + + + Specifies a filter definition. After definition, a filter + can be applied to entity or collection by name. + + @interface FilterDef { + String name(); + String defaultCondition() default ""; + ParamDef[] parameters() default {}; + boolean autoEnabled() default false; + } + + + + + + + + + + Used to identify all bind parameters in the condition element + + type(); + Class resolver() default Supplier.class; + } + ]]> + + + + + + + + + + + + + + + + + + Applies a filter defined by hbm-filter-def usage + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + element defines a single path to which the fetch + refers, as well as the style of fetch to apply. The 'root' of the + path is different depending upon the context in which the + containing occurs; within a element, + the entity-name of the containing class mapping is assumed... + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + Names a org.hibernate.id.IdentifierGenerator implementation (class attribute) + as well as any configuration information need by the implementation (Hibernate + will pass it the parameters after instantiation). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + See `@org.hibernate.annotations.TenantId` + + + + + + + + + + + + + + + + + + + @org.hibernate.annotations.SQLSelect + + + + + + + + + + + + + + + + org.hibernate.annotations.SQLInsert + org.hibernate.annotations.SQLUpdate + org.hibernate.annotations.SQLDelete + org.hibernate.annotations.SQLDeleteAll + + + + + + + + + + + + + + + org.hibernate.annotations.ResultCheckStyle enum values + + + + + + + + + + + + + + + See @org.hibernate.annotations.Cache + + Used to specify Hibernate-specific extra control over the caching + of entity and collection state. + + + + + + + + + + + org.hibernate.cache.spi.access.AccessType enum values + + + + + + + + + + + + + + org.hibernate.CacheMode enum values + + + + + + + + + + + + + + + + + + + + + + + + + + + See `@org.hibernate.annotations.OptimisticLockType` + See `@org.hibernate.annotations.OptimisticLocking` + + + + + + + + + + + + + + + + + See `@org.hibernate.annotations.PolymorphismType` + See `@org.hibernate.annotations.Polymorphism` + + + + + + + + + + + + + + + See `@org.hibernate.annotations.TenantId` + + + + + + + + + + + + + + + + See `@org.hibernate.annotations.NaturalId` + + + + + + + + + + + + + + + + + + + + + + See `@org.hibernate.annotations.Any` + + + + + + + + + + + + + + + + + + + + + Describes the discriminator of a discriminated association (any, many-to-any), + including the mapping of discriminator values to matching entity name + + + + + + + + + + + + + Describes the "foreign key" of a discriminated association (any, many-to-any). + + + + + + + + + + + + + + com.acme.Employee + ]]> + + + + + + + + + + + + See `@org.hibernate.annotations.ManyToAny` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + See `@org.hibernate.annotations.Nationalized` + + + + + + + + + + + See `org.hibernate.annotations.GenerationTime` + See `org.hibernate.tuple.GenerationTiming` + See `@org.hibernate.annotations.Generated` + + + + + + + + + + + + + + + + See `@org.hibernate.annotations.Type` + + + + + + + + + + + + + + + See `@org.hibernate.annotations.Comment` + See `@org.hibernate.annotations.Check` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + See `@org.hibernate.annotations.CollectionId` + See `@org.hibernate.annotations.CollectionIdType` + See `@org.hibernate.annotations.CollectionIdJavaType` + See `@org.hibernate.annotations.CollectionIdJdbcType` + See `@org.hibernate.annotations.CollectionIdJdbcTypeCode` + + + + + + + + + + + + + + + + See `@org.hibernate.annotations.CollectionType` + + + + + + + + + + + + + + + See `@org.hibernate.boot.internal.CollectionClassification`. + + Defines a limited set of `org.hibernate.metamodel.CollectionClassification`. + + We leave off the following enumerated values, since we can distinguish those already + via presence of , , and - + * ID_BAG + * SORTED_SET + * ORDERED_SET + * SORTED_MAP + * ORDERED_MAP + + ARRAY is also missing, as handling the element type is tricky. + + + + + + + + + + + + + + + + + org.hibernate.FetchMode enum values + + + + + + + + + + + + + + + + See `@org.hibernate.annotations.UuidGenerator` + + + + + + + + + org.hibernate.annotations.UuidGenerator.Style enum values + + + + + + + + + + + + + + + + + + + + + + + + + + See `org.hibernate.annotations.OnDeleteAction` enum + + + + + + + + + + + + + + + + + + org.hibernate.FetchMode enum values + + + + + + + + + + + + + + + Common Hibernate specific extensions available for named query definitions. + + todo : a lot of these extensions could be handled by JPA QueryHint scheme + + + + + + + + + + + + + + + + + + + + + + + + + + + org.hibernate.FlushMode enum values + + + + + + + + + + + + + Used only by tools to generate finder methods for named queries + + + + + + + diff --git a/hibernate-core/src/main/xjb/configuration-bindings.xjb b/hibernate-core/src/main/xjb/configuration-bindings.xjb index 06698867b7f4..1bb865dff5e3 100644 --- a/hibernate-core/src/main/xjb/configuration-bindings.xjb +++ b/hibernate-core/src/main/xjb/configuration-bindings.xjb @@ -8,7 +8,7 @@ xmlns:xsd="http://www.w3.org/2001/XMLSchema" version="3.0"> - + @@ -45,11 +45,17 @@ --> - + + + + + + + + diff --git a/hibernate-core/src/main/xjb/mapping-bindings.xjb b/hibernate-core/src/main/xjb/mapping-bindings.xjb index cfbbfabfa0c3..41955192430a 100644 --- a/hibernate-core/src/main/xjb/mapping-bindings.xjb +++ b/hibernate-core/src/main/xjb/mapping-bindings.xjb @@ -8,7 +8,7 @@ xmlns:simplify="http://jvnet.org/basicjaxb/xjc/simplify" version="3.0"> - + @@ -692,6 +692,19 @@ printMethod="org.hibernate.boot.jaxb.mapping.internal.LockModeTypeMarshalling.toXml" /> + + + + + + + + + listenerGroup = new EventListenerGroupImpl( EventType.CLEAR, null, false ); + EventListenerGroup listenerGroup = new EventListenerGroupImpl( EventType.CLEAR, false ); @Test public void testListenersIterator() { diff --git a/hibernate-core/src/test/java/org/hibernate/event/service/internal/EventListenerGroupAppendListenerTest.java b/hibernate-core/src/test/java/org/hibernate/event/service/internal/EventListenerGroupAppendListenerTest.java deleted file mode 100644 index bf35f2517802..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/event/service/internal/EventListenerGroupAppendListenerTest.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.event.service.internal; - -import java.lang.reflect.Field; - -import org.hibernate.event.internal.DefaultMergeEventListener; -import org.hibernate.event.service.spi.DuplicationStrategy; -import org.hibernate.event.service.spi.EventListenerGroup; -import org.hibernate.event.spi.EventType; -import org.hibernate.event.spi.MergeEventListener; -import org.hibernate.jpa.event.spi.CallbackRegistry; - -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.orm.junit.BaseSessionFactoryFunctionalTest; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - -/** - * @author Frank Doherty - */ -@JiraKey(value = "HHH-13070") -public class EventListenerGroupAppendListenerTest extends BaseSessionFactoryFunctionalTest { - - private static final DuplicationStrategy DUPLICATION_STRATEGY_REPLACE_ORIGINAL = new DuplicationStrategy() { - - @Override - public boolean areMatch( - Object added, Object existing) { - return true; - } - - @Override - public Action getAction() { - return Action.REPLACE_ORIGINAL; - } - }; - - @Test - public void testAppendListenerWithNoStrategy() { - SpecificMergeEventListener1 mergeEventListener = new SpecificMergeEventListener1(); - - runAppendListenerTest( null, mergeEventListener ); - } - - @Test - public void testAppendListenerWithReplaceOriginalStrategy() { - SpecificMergeEventListener2 mergeEventListener = new SpecificMergeEventListener2(); - - runAppendListenerTest( DUPLICATION_STRATEGY_REPLACE_ORIGINAL, mergeEventListener ); - } - - private void runAppendListenerTest( - DuplicationStrategy duplicationStrategy, - DefaultMergeEventListener mergeEventListener) { - inTransaction( session -> { - - EventListenerGroup group = - sessionFactory().getEventListenerRegistry() - .getEventListenerGroup( EventType.MERGE ); - if ( duplicationStrategy != null ) { - group.addDuplicationStrategy( duplicationStrategy ); - } - group.appendListener( mergeEventListener ); - - Iterable listeners = group.listeners(); - assertTrue( listeners.iterator().hasNext(), "Should have at least one listener" ); - listeners.forEach( this::assertCallbackRegistry ); - } ); - } - - private void assertCallbackRegistry( - MergeEventListener listener) { - try { - assertNotNull( getCallbackRegistry( listener ), "callbackRegistry should not be null" ); - } - catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) { - fail( "Unable to get callbackRegistry field on listener" ); - } - } - - private static CallbackRegistry getCallbackRegistry( - MergeEventListener listener) - throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { - Class clazz = Class.forName( "org.hibernate.event.internal.AbstractSaveEventListener" ); - Field field = clazz.getDeclaredField( "callbackRegistry" ); - field.setAccessible( true ); - return (CallbackRegistry) field.get( listener ); - } - - private static class SpecificMergeEventListener1 extends DefaultMergeEventListener { - - // we need a specific class, otherwise the default duplication strategy avoiding listeners from the same classes - // will be triggered. - } - - private static class SpecificMergeEventListener2 extends DefaultMergeEventListener { - - // we need a specific class, otherwise the default duplication strategy avoiding listeners from the same classes - // will be triggered. - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/cascade/CascadeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/cascade/CascadeTest.java index f970d04f41df..6ad1dc8d8f5e 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/cascade/CascadeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/cascade/CascadeTest.java @@ -111,12 +111,9 @@ public void testRemove(SessionFactoryScope scope) { session.remove( t.mouth ); } ); - scope.inTransaction( - session -> { - Tooth t = session.get( Tooth.class, tooth.id ); - assertNull( t ); - } - ); + scope.inTransaction( session -> { + assertNull( session.find( Tooth.class, tooth.id ) ); + } ); } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/derivedidentities/bidirectional/OneToOneWithDerivedIdentityTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/derivedidentities/bidirectional/OneToOneWithDerivedIdentityTest.java index fe0690363354..60971f7c5f02 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/derivedidentities/bidirectional/OneToOneWithDerivedIdentityTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/derivedidentities/bidirectional/OneToOneWithDerivedIdentityTest.java @@ -231,7 +231,7 @@ public void testCase(SessionFactoryScope scope) { session.getTransaction().begin(); - Query q = session.getNamedQuery( "PersonQuery" ); + Query q = session.createNamedQuery( "PersonQuery" ); List persons = q.list(); assertEquals( persons.size(), 1 ); assertEquals( persons.get( 0 ).getName(), "Alfio" ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/derivedidentities/e4/a/DerivedIdentitySimpleParentSimpleDepTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/derivedidentities/e4/a/DerivedIdentitySimpleParentSimpleDepTest.java index 6bea5d476a59..8c0b36ae5b77 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/derivedidentities/e4/a/DerivedIdentitySimpleParentSimpleDepTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/derivedidentities/e4/a/DerivedIdentitySimpleParentSimpleDepTest.java @@ -105,7 +105,7 @@ public void testSimplePkValueLoading(SessionFactoryScope scope) { public void tearDown(SessionFactoryScope scope) { scope.inTransaction( session -> { - FinancialHistory history = session.get( FinancialHistory.class, "aaa" ); + FinancialHistory history = session.find( FinancialHistory.class, "aaa" ); if ( history != null ) { session.remove( history ); session.remove( history.patient ); @@ -115,7 +115,7 @@ public void tearDown(SessionFactoryScope scope) { scope.inTransaction( session -> { - MedicalHistory history = session.get( MedicalHistory.class, "aaa" ); + MedicalHistory history = session.find( MedicalHistory.class, "aaa" ); if ( history != null ) { session.remove( history ); session.remove( history.patient ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/entitynonentity/EntityNonEntityTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/entitynonentity/EntityNonEntityTest.java index 7cc37ba460fa..228d6bec145c 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/entitynonentity/EntityNonEntityTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/entitynonentity/EntityNonEntityTest.java @@ -88,12 +88,12 @@ public void testGetAndFindNonEntityThrowsIllegalArgumentException(SessionFactory .getEntityDescriptor( Cellular.class.getName() ) ); - assertThrows( UnknownEntityTypeException.class, () -> scope.inTransaction( + assertThrows( IllegalArgumentException.class, () -> scope.inTransaction( session -> session.get( Cellular.class, 1 ) ) ); - assertThrows( UnknownEntityTypeException.class, () -> scope.inTransaction( + assertThrows( IllegalArgumentException.class, () -> scope.inTransaction( session -> session.get( Cellular.class.getName(), 1 ) ) ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/generics/GenericMappedSuperclassNestedJoinTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/generics/GenericMappedSuperclassNestedJoinTest.java index 4a2934d81016..2b9c9579d282 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/generics/GenericMappedSuperclassNestedJoinTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/generics/GenericMappedSuperclassNestedJoinTest.java @@ -112,7 +112,7 @@ public void testNestedGenericJoinCriteria(SessionFactoryScope scope) { final CriteriaBuilder cb = session.getCriteriaBuilder(); final CriteriaQuery cq = cb.createQuery( String.class ); final Root root = cq.from( SelectionProductRuleProductLink.class ); - final Join p1 = root.join( "parent" ); + final Join p1 = root.join( "parent" ); assertThat( p1.getJavaType() ).isEqualTo( SeqOrderLinkObjectWithUserContext.class ); assertThat( p1.getModel() ).isSameAs( root.getModel().getAttribute( "parent" ) ); assertThat( ( (SqmPath) p1 ).getResolvedModel().getBindableJavaType() ) diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/id/EnumIdTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/id/EnumIdTest.java index e50385001264..e59da2fddd8f 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/id/EnumIdTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/id/EnumIdTest.java @@ -51,7 +51,7 @@ public void testEnumAsId(SessionFactoryScope scope) { scope.inTransaction( session -> { - PlanetCheatSheet mercuryFromDb = session.get( + PlanetCheatSheet mercuryFromDb = session.find( PlanetCheatSheet.class, Planet.MERCURY ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/id/IdTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/id/IdTest.java index 7608eff8db0b..7351bf8cef71 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/id/IdTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/id/IdTest.java @@ -69,7 +69,7 @@ public void testNoGenerator(SessionFactoryScope scope) { Hotel hotel = session.get( Hotel.class, 12L ); assertNotNull( hotel ); assertEquals( "California", hotel.getName() ); - assertNull( session.get( Hotel.class, 13L ) ); + assertNull( session.find( Hotel.class, 13L ) ); return hotel; } ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/id/sequences/EnumIdTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/id/sequences/EnumIdTest.java index 467b42ed0b2c..2e68f55c2d0d 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/id/sequences/EnumIdTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/id/sequences/EnumIdTest.java @@ -53,7 +53,7 @@ public void testEnumAsId(SessionFactoryScope scope) { scope.inTransaction( session -> { - PlanetCheatSheet mercuryFromDb = session.get( PlanetCheatSheet.class, Planet.MERCURY ); + PlanetCheatSheet mercuryFromDb = session.find( PlanetCheatSheet.class, Planet.MERCURY ); assertNull( mercuryFromDb ); } ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/idclass/IdClassCompositePKTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/idclass/IdClassCompositePKTest.java index 2bbc2602fbb7..5cc98b479c31 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/idclass/IdClassCompositePKTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/idclass/IdClassCompositePKTest.java @@ -31,7 +31,7 @@ public void testEntityMappningPropertiesAreNotIgnored(SessionFactoryScope scope) da.setDomainName( "org" ); session.persist( da ); - Query q = session.getNamedQuery( "DomainAdmin.testQuery" ); + Query q = session.createNamedQuery( "DomainAdmin.testQuery" ); assertEquals( 1, q.list().size() ); } ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/idclass/xml/IdClassXmlTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/idclass/xml/IdClassXmlTest.java index fe6f71f2c3b8..fbd56d7edbcd 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/idclass/xml/IdClassXmlTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/idclass/xml/IdClassXmlTest.java @@ -40,7 +40,7 @@ public void testEntityMappingPropertiesAreNotIgnored(SessionFactoryScope scope) link.setSpeciesId( 1L ); session.persist( link ); - Query q = session.getNamedQuery( "testQuery" ); + Query q = session.createNamedQuery( "testQuery" ); final List list = q.list(); assertEquals( 1, list.size() ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/idmanytoone/IdManyToOneTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/idmanytoone/IdManyToOneTest.java index c21f9201277a..be07be2515ae 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/idmanytoone/IdManyToOneTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/idmanytoone/IdManyToOneTest.java @@ -100,7 +100,7 @@ public void testCriteriaRestrictionOnIdManyToOne(SessionFactoryScope scope) { CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder(); CriteriaQuery criteria = criteriaBuilder.createQuery( Course.class ); Root root = criteria.from( Course.class ); - Join students = root.join( "students", JoinType.INNER ); + Join students = root.join( "students", JoinType.INNER ); Join student = students.join( "student", JoinType.INNER ); criteria.where( criteriaBuilder.equal( student.get( "name" ), "Foo" ) ); s.createQuery( criteria ).list(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/AddressBook.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/AddressBook.java index 9fc065f9199b..39e3918e37d1 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/AddressBook.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/AddressBook.java @@ -51,7 +51,7 @@ public void setEntries(Map entries) { this.entries = entries; } - @MapKey(name = "person.lastname") + @MapKey("person.lastname") @OneToMany(mappedBy = "book") public Map getLastNameEntries() { return lastNameEntries; @@ -61,7 +61,7 @@ public void setLastNameEntries(Map lastNameEntries) { this.lastNameEntries = lastNameEntries; } - @MapKey(name = "directory") + @MapKey("directory") @OneToMany(mappedBy = "book") public Map getDirectoryEntries() { return directoryEntries; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/ExchangeOffice.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/ExchangeOffice.java index 34ec1c6a0609..0e5de22ff6ad 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/ExchangeOffice.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/ExchangeOffice.java @@ -33,7 +33,7 @@ public Integer getId() { } @jakarta.persistence.OneToMany(mappedBy = "parent") - @jakarta.persistence.MapKey(name="key") + @jakarta.persistence.MapKey("key") private Map exchangeRates = new java.util.HashMap(); public Map getExchangeRates() { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/GenerationUser.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/GenerationUser.java index bbc179de8ec2..87be4c3e8998 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/GenerationUser.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/GenerationUser.java @@ -23,7 +23,7 @@ public class GenerationUser { private int id; @OneToMany - @MapKey(name="generation") + @MapKey("generation") private Map ref = new HashMap<>(); public int getId() { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/Newspaper.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/Newspaper.java index 2e5c3086d0b3..ed74acabf6a3 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/Newspaper.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/Newspaper.java @@ -39,7 +39,7 @@ public void setName(String name) { } @ManyToMany - @MapKey(name = "title") + @MapKey("title") public Map getNews() { return news; } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/Painter.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/Painter.java index 5896b8f3cb7e..c8a400af2396 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/Painter.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/Painter.java @@ -32,7 +32,7 @@ public void setId(Integer id) { } @OneToMany(cascade = {CascadeType.ALL}) - @MapKey(name = "name") + @MapKey("name") @JoinColumn public Map getPaintings() { return paintings; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/Software.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/Software.java index 212c520affcb..955e38cb12d9 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/Software.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/Software.java @@ -28,7 +28,7 @@ public void setName(String name) { } @OneToMany(mappedBy = "software") - @MapKey(name = "codeName") + @MapKey("codeName") public Map getVersions() { return versions; } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/Training.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/Training.java index c2b0922446dd..e7585f9c803b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/Training.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/indexcoll/Training.java @@ -20,7 +20,7 @@ public class Training { @Id @GeneratedValue private Long id; @SortNatural - @MapKey(name="name") @ManyToMany SortedMap trainees = new TreeMap(); + @MapKey("name") @ManyToMany SortedMap trainees = new TreeMap<>(); public Long getId() { return id; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/inheritance/joined/JoinedSubclassTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/inheritance/joined/JoinedSubclassTest.java index 5a6395eb3c05..07f507deae15 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/inheritance/joined/JoinedSubclassTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/inheritance/joined/JoinedSubclassTest.java @@ -122,14 +122,14 @@ public void testInheritance(SessionFactoryScope scope) { scope.inTransaction( session -> { String eventPK = "event1"; - EventInformation event = session.get( EventInformation.class, eventPK ); + EventInformation event = session.find( EventInformation.class, eventPK ); if ( event == null ) { event = new EventInformation(); event.setNotificationId( eventPK ); session.persist( event ); } String alarmPK = "alarm1"; - Alarm alarm = session.get( Alarm.class, alarmPK ); + Alarm alarm = session.find( Alarm.class, alarmPK ); if ( alarm == null ) { alarm = new Alarm(); alarm.setNotificationId( alarmPK ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/join/JoinTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/join/JoinTest.java index 0658ccb1eaa6..67bbaa65db05 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/join/JoinTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/join/JoinTest.java @@ -157,7 +157,7 @@ public void testManyToOne(SessionFactoryScope scope) { CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder(); CriteriaQuery criteria = criteriaBuilder.createQuery( Life.class ); Root root = criteria.from( Life.class ); - jakarta.persistence.criteria.Join owner = root.join( "owner", JoinType.INNER ); + jakarta.persistence.criteria.Join owner = root.join( "owner", JoinType.INNER ); criteria.where( criteriaBuilder.equal( owner.get( "name" ), "kitty" ) ); Life life = session.createQuery( criteria ).uniqueResult(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/manytomany/ManyToManyTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/manytomany/ManyToManyTest.java index 813bf17df6fe..9003aa09e19c 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/manytomany/ManyToManyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/manytomany/ManyToManyTest.java @@ -165,7 +165,7 @@ public void testCanUseCriteriaQuery(SessionFactoryScope scope) { CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder(); CriteriaQuery criteria = criteriaBuilder.createQuery( Supplier.class ); Root root = criteria.from( Supplier.class ); - Join suppStores = root.join( "suppStores", JoinType.INNER ); + Join suppStores = root.join( "suppStores", JoinType.INNER ); criteria.where( criteriaBuilder.equal( suppStores.get( "name" ), "Fnac" ) ); List result = s.createQuery( criteria ).list(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/query/NamedQueryTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/query/NamedQueryTest.java index cebfaec4a9d0..3693fe8afbe6 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/query/NamedQueryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/query/NamedQueryTest.java @@ -60,7 +60,7 @@ public void tearDown(SessionFactoryScope scope) { public void testNamedQueriesOrdinalParametersAreOneBased(SessionFactoryScope scope) { scope.inTransaction( session -> { - Query query = session.getNamedQuery( "NamedQuery" ); + Query query = session.createNamedQuery( "NamedQuery", Game.class ); query.setParameter( 1, GAME_TITLES[0] ); List list = query.getResultList(); assertEquals( 1, list.size() ); @@ -73,7 +73,7 @@ public void testNamedQueriesOrdinalParametersAreOneBased(SessionFactoryScope sco public void testNoExceptionThrownForNamedUpdate(SessionFactoryScope scope) { scope.inTransaction( session -> { - Query query = session.getNamedQuery( "NamedUpdate" ); + Query query = session.createNamedQuery( "NamedUpdate" ); query.setParameter( 1, GAME_TITLES[0] + " 2" ); query.setParameter( 2, GAME_TITLES[0] ); assertDoesNotThrow( () -> query.executeUpdate(), "without fixing, 'java.lang.IllegalStateException: Expecting a SELECT query' exception would be thrown" ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/query/QueryAndSQLTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/query/QueryAndSQLTest.java index 6902becac8cb..4b2e3d073195 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/query/QueryAndSQLTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/query/QueryAndSQLTest.java @@ -313,7 +313,7 @@ public void testPackageQueries(SessionFactoryScope scope) { session -> { Plane p = new Plane(); session.persist( p ); - Query q = session.getNamedQuery( "plane.getAll" ); + Query q = session.createNamedQuery( "plane.getAll" ); assertEquals( 1, q.list().size() ); session.remove( q.list().get( 0 ) ); } @@ -340,20 +340,20 @@ public void testClassQueries(SessionFactoryScope scope) { scope.inTransaction( session -> { - Query q = session.getNamedQuery( "night.moreRecentThan" ); + Query q = session.createNamedQuery( "night.moreRecentThan" ); q.setParameter( "date", aMonthAgo, StandardBasicTypes.DATE ); assertEquals( 1, q.list().size() ); - q = session.getNamedQuery( "night.moreRecentThan" ); + q = session.createNamedQuery( "night.moreRecentThan" ); q.setParameter( "date", inAMonth, StandardBasicTypes.DATE ); assertEquals( 0, q.list().size() ); Statistics stats = scope.getSessionFactory().getStatistics(); stats.setStatisticsEnabled( true ); stats.clear(); - q = session.getNamedQuery( "night.duration" ); + q = session.createNamedQuery( "night.duration" ); q.setParameter( "duration", 14l ); assertEquals( 1, q.list().size() ); assertEquals( 1, stats.getQueryCachePutCount() ); - q = session.getNamedQuery( "night.duration" ); + q = session.createNamedQuery( "night.duration" ); q.setParameter( "duration", 14l ); session.remove( q.list().get( 0 ) ); assertEquals( 1, stats.getQueryCacheHitCount() ); @@ -386,13 +386,13 @@ public void testSQLQuery(SessionFactoryScope scope) { tx.commit(); session.clear(); tx = session.beginTransaction(); - Query q = session.getNamedQuery( "night.getAll.bySQL" ); + Query q = session.createNamedQuery( "night.getAll.bySQL" ); q.setParameter( 1, 9990 ); List result = q.list(); assertEquals( 1, result.size() ); Night n2 = (Night) result.get( 0 ); assertEquals( n2.getDuration(), n.getDuration() ); - List areas = session.getNamedQuery( "getAreaByNative" ).list(); + List areas = session.createNamedQuery( "getAreaByNative" ).list(); assertTrue( 1 == areas.size() ); assertEquals( area.getName(), ( (Area) areas.get( 0 ) ).getName() ); session.remove( areas.get( 0 ) ); @@ -422,7 +422,7 @@ public void testImportQueryFromMappedSuperclass(SessionFactoryScope scope) { scope.inSession( session -> { try { - session.getNamedQuery( "night.olderThan" ); + session.createNamedQuery( "night.olderThan" ); } catch (MappingException ex) { fail( "Query imported from MappedSuperclass" ); @@ -460,7 +460,7 @@ public void testSQLQueryWithManyToOne(SessionFactoryScope scope) { Statistics stats = scope.getSessionFactory().getStatistics(); stats.setStatisticsEnabled( true ); stats.clear(); - Query q = session.getNamedQuery( "night&areaCached" ); + Query q = session.createNamedQuery( "night&areaCached" ); q.setCacheable( true ); List result = q.list(); assertEquals( 1, result.size() ); @@ -493,7 +493,7 @@ public void testImplicitNativeQuery(SessionFactoryScope scope) { tx.commit(); session.clear(); tx = session.beginTransaction(); - Query q = session.getNamedQuery( "implicitSample" ); + Query q = session.createNamedQuery( "implicitSample" ); List result = q.list(); assertEquals( 1, result.size() ); assertEquals( ship.getModel(), ( (SpaceShip) result.get( 0 ) ).getModel() ); @@ -531,7 +531,7 @@ public void testNativeQueryAndCompositePKAndComponents(SessionFactoryScope scope tx.commit(); session.clear(); tx = session.beginTransaction(); - Query q = session.getNamedQuery( "compositekey" ); + Query q = session.createNamedQuery( "compositekey" ); List result = q.list(); assertEquals( 1, result.size() ); Object[] row = (Object[]) result.get( 0 ); @@ -575,7 +575,7 @@ public void testDiscriminator(SessionFactoryScope scope) { tx.commit(); session.clear(); tx = session.beginTransaction(); - List results = session.getNamedQuery( "all.dictionaries" ).list(); + List results = session.createNamedQuery( "all.dictionaries" ).list(); assertEquals( 2, results.size() ); assertTrue( results.get( 0 ) instanceof SynonymousDictionary @@ -610,10 +610,10 @@ public void testCache(SessionFactoryScope scope) { scope.inTransaction( session -> { - Query query = session.getNamedQuery( "plane.byId" ).setParameter( "id", plane.getId() ); + Query query = session.createNamedQuery( "plane.byId" ).setParameter( "id", plane.getId() ); query.uniqueResult(); assertEquals( 1, sessionFactory.getStatistics().getQueryCachePutCount() ); - session.getNamedQuery( "plane.byId" ).setParameter( "id", plane.getId() ).uniqueResult(); + session.createNamedQuery( "plane.byId" ).setParameter( "id", plane.getId() ).uniqueResult(); assertEquals( 1, sessionFactory.getStatistics().getQueryCacheHitCount() ); } ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/xml/ejb3/Ejb3XmlElementCollectionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/xml/ejb3/Ejb3XmlElementCollectionTest.java index 3e67269b3258..af192754d8be 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/xml/ejb3/Ejb3XmlElementCollectionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/xml/ejb3/Ejb3XmlElementCollectionTest.java @@ -130,6 +130,7 @@ public void testMapKeyNoAttributes() { final MapKey mapKeyUsage = memberDetails.getDirectAnnotationUsage( MapKey.class ); assertThat( mapKeyUsage.name() ).isEmpty(); + assertThat( mapKeyUsage.value() ).isEmpty(); } @Test @@ -146,7 +147,7 @@ public void testMapKeyAllAttributes() { assertThat( memberDetails.hasDirectAnnotationUsage( MapKeyJoinColumn.class ) ).isFalse(); final MapKey mapKeyUsage = memberDetails.getDirectAnnotationUsage( MapKey.class ); - assertThat( mapKeyUsage.name() ).isEqualTo( "field2" ); + assertThat( mapKeyUsage.value() ).isEqualTo( "field2" ); } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/xml/ejb3/Ejb3XmlTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/xml/ejb3/Ejb3XmlTest.java index a28cde47d26e..5e97a4920745 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/xml/ejb3/Ejb3XmlTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/xml/ejb3/Ejb3XmlTest.java @@ -59,9 +59,9 @@ public void testEjb3Xml(SessionFactoryScope scope) { s.clear(); model.setYear( new Date() ); - manufacturer = s.get( Manufacturer.class, manufacturer.getId() ); + manufacturer = s.find( Manufacturer.class, manufacturer.getId() ); @SuppressWarnings("unchecked") - List cars = s.getNamedQuery( "allModelsPerManufacturer" ) + List cars = s.createNamedQuery( "allModelsPerManufacturer" ) .setParameter( "manufacturer", manufacturer ) .list(); assertEquals( 1, cars.size() ); @@ -97,7 +97,7 @@ public void testXmlDefaultOverriding(SessionFactoryScope scope) { s.flush(); s.clear(); - assertEquals( 1, s.getNamedQuery( "manufacturer.findAll" ).list().size() ); + assertEquals( 1, s.createNamedQuery( "manufacturer.findAll" ).list().size() ); tx.rollback(); } ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/xml/ejb3/OrmVersion1SupportedTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/xml/ejb3/OrmVersion1SupportedTest.java index 1707e01790f6..a0347564a903 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/xml/ejb3/OrmVersion1SupportedTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/xml/ejb3/OrmVersion1SupportedTest.java @@ -33,7 +33,7 @@ public void testOrm1Support(SessionFactoryScope scope) { session.flush(); session.clear(); - assertThat( session.getNamedQuery( "find.the.light" ).list().size() ).isEqualTo( 1 ); + assertThat( session.createNamedQuery( "find.the.light" ).list().size() ).isEqualTo( 1 ); } ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/BootstrapTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/BootstrapTest.java index 4e7de7a2205e..561088c3501a 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/BootstrapTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/BootstrapTest.java @@ -13,6 +13,7 @@ import java.util.Properties; import javax.sql.DataSource; +import jakarta.persistence.FetchType; import org.hibernate.Interceptor; import org.hibernate.SessionFactory; import org.hibernate.SessionFactoryObserver; @@ -64,7 +65,7 @@ import jakarta.persistence.ValidationMode; import jakarta.persistence.spi.ClassTransformer; import jakarta.persistence.spi.PersistenceUnitInfo; -import jakarta.persistence.spi.PersistenceUnitTransactionType; +import jakarta.persistence.PersistenceUnitTransactionType; /** * @author Vlad Mihalcea @@ -634,7 +635,7 @@ public List getQualifierAnnotationNames() { } @Override - public jakarta.persistence.spi.PersistenceUnitTransactionType getTransactionType() { + public jakarta.persistence.PersistenceUnitTransactionType getTransactionType() { return transactionType; } @@ -682,6 +683,11 @@ public List getManagedClassNames() { return managedClassNames; } + @Override + public List getAllManagedClassNames() { + return managedClassNames; + } + @Override public boolean excludeUnlistedClasses() { return false; @@ -697,6 +703,11 @@ public ValidationMode getValidationMode() { return ValidationMode.AUTO; } + @Override + public FetchType getDefaultToOneFetchType() { + return FetchType.EAGER; + } + public Properties getProperties() { return properties; } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/cascade/CascadeOnUninitializedTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/cascade/CascadeOnUninitializedTest.java index 8f374b8b31d4..5a522ee75f75 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/cascade/CascadeOnUninitializedTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/cascade/CascadeOnUninitializedTest.java @@ -151,8 +151,8 @@ public void testDeleteEnhancedEntityWithUninitializedManyToOne(SessionFactorySco // both the Person and its Address should be deleted scope.inTransaction( session -> { - assertNull( session.get( Person.class, person.getId() ) ); - assertNull( session.get( Person.class, person.getPrimaryAddress().getId() ) ); + assertNull( session.find( Person.class, person.getId() ) ); + assertNull( session.find( Person.class, person.getPrimaryAddress().getId() ) ); } ); } @@ -192,8 +192,8 @@ public void testDeleteEnhancedEntityWithUninitializedOneToMany(SessionFactorySco // both the Person and its Address should be deleted scope.inTransaction( session -> { - assertNull( session.get( Person.class, person.getId() ) ); - assertNull( session.get( Person.class, person.getAddresses().iterator().next().getId() ) ); + assertNull( session.find( Person.class, person.getId() ) ); + assertNull( session.find( Person.class, person.getAddresses().iterator().next().getId() ) ); } ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/cascade/CascadeOnUninitializedWithCollectionInDefaultFetchGroupFalseTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/cascade/CascadeOnUninitializedWithCollectionInDefaultFetchGroupFalseTest.java index 55b044f6d99e..1c45c38e6de8 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/cascade/CascadeOnUninitializedWithCollectionInDefaultFetchGroupFalseTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/cascade/CascadeOnUninitializedWithCollectionInDefaultFetchGroupFalseTest.java @@ -161,8 +161,8 @@ public void testDeleteEnhancedEntityWithUninitializedManyToOne(SessionFactorySco // both the Person and its Address should be deleted scope.inTransaction( session -> { - assertNull( session.get( Person.class, person.getId() ) ); - assertNull( session.get( Person.class, person.getPrimaryAddress().getId() ) ); + assertNull( session.find( Person.class, person.getId() ) ); + assertNull( session.find( Person.class, person.getPrimaryAddress().getId() ) ); } ); } @@ -205,8 +205,8 @@ public void testDeleteEnhancedEntityWithUninitializedOneToMany(SessionFactorySco // both the Person and its Address should be deleted scope.inTransaction( session -> { - assertNull( session.get( Person.class, person.getId() ) ); - assertNull( session.get( Person.class, person.getAddresses().iterator().next().getId() ) ); + assertNull( session.find( Person.class, person.getId() ) ); + assertNull( session.find( Person.class, person.getAddresses().iterator().next().getId() ) ); } ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/detached/RemoveDetachedInstanceTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/detached/RemoveDetachedInstanceTest.java index 07a8942d5f8a..59d0c7837551 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/detached/RemoveDetachedInstanceTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/detached/RemoveDetachedInstanceTest.java @@ -76,12 +76,12 @@ void testRemoveDetachedInstance(SessionFactoryScope scope) { } ); scope.inTransaction( session -> { - ParentChild pc = session.get( ParentChild.class, PARENT_CHILD_ID ); + ParentChild pc = session.find( ParentChild.class, PARENT_CHILD_ID ); assertThat( pc ).isNull(); - Parent parent = session.get( Parent.class, PARENT_ID ); + Parent parent = session.find( Parent.class, PARENT_ID ); assertThat( parent ).isNotNull(); assertThat( parent.getChildren() ).isEmpty(); - Child child = session.get( Child.class, CHILD_ID ); + Child child = session.find( Child.class, CHILD_ID ); assertThat( child ).isNotNull(); assertThat( child.getChildren() ).isEmpty(); @@ -96,23 +96,23 @@ void testRemoveDetachedInstance2(SessionFactoryScope scope) { scope.inTransaction( session -> { session.remove( parentChild ); session.remove( parentChild.getChild() ); - Parent parent = session.get( Parent.class, PARENT_ID ); + Parent parent = session.find( Parent.class, PARENT_ID ); assertThat( parent ).isNotNull(); List pc = parent.getChildren(); assertThat( pc ).isNotNull(); assertThat( pc.size() ).isEqualTo( 1 ); assertThat( pc.get( 0 ) ).isSameAs( parentChild ); - Child child = session.get( Child.class, CHILD_ID ); + Child child = session.find( Child.class, CHILD_ID ); assertThat( child ).isNull(); } ); scope.inTransaction( session -> { - ParentChild pc = session.get( ParentChild.class, PARENT_CHILD_ID ); + ParentChild pc = session.find( ParentChild.class, PARENT_CHILD_ID ); assertThat( pc ).isNull(); - Parent parent = session.get( Parent.class, PARENT_ID ); + Parent parent = session.find( Parent.class, PARENT_ID ); assertThat( parent ).isNotNull(); assertThat( parent.getChildren() ).isEmpty(); - Child child = session.get( Child.class, CHILD_ID ); + Child child = session.find( Child.class, CHILD_ID ); assertThat( child ).isNull(); } ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/orphan/OrphanTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/orphan/OrphanTest.java index 914104f04a27..6b41d3498737 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/orphan/OrphanTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/orphan/OrphanTest.java @@ -74,9 +74,9 @@ public void testOrphanDeleteOnDelete(SessionFactoryScope scope) { scope.inTransaction( session -> { - assertNull( session.get( Part.class, "Widge" ) ); - assertNull( session.get( Part.class, "Get" ) ); - assertNull( session.get( Product.class, "Widget" ) ); + assertNull( session.find( Part.class, "Widge" ) ); + assertNull( session.find( Part.class, "Get" ) ); + assertNull( session.find( Product.class, "Widget" ) ); } ); } @@ -104,8 +104,8 @@ public void testOrphanDeleteAfterPersist(SessionFactoryScope scope) { scope.inTransaction( session -> { - assertNull( session.get( Part.class, "Widge" ) ); - assertNotNull( session.get( Part.class, "Get" ) ); + assertNull( session.find( Part.class, "Widge" ) ); + assertNotNull( session.find( Part.class, "Get" ) ); session.remove( session.get( Product.class, "Widget" ) ); } ); @@ -135,8 +135,8 @@ public void testOrphanDeleteAfterPersistAndFlush(SessionFactoryScope scope) { scope.inTransaction( session -> { - assertNull( session.get( Part.class, "Widge" ) ); - assertNotNull( session.get( Part.class, "Get" ) ); + assertNull( session.find( Part.class, "Widge" ) ); + assertNotNull( session.find( Part.class, "Get" ) ); session.remove( session.get( Product.class, "Widget" ) ); } ); @@ -173,8 +173,8 @@ public void testCannotLockDetachedEntity(SessionFactoryScope scope) { scope.inTransaction( session -> { - assertNotNull( session.get( Part.class, "Widge" ) ); - assertNotNull( session.get( Part.class, "Get" ) ); + assertNotNull( session.find( Part.class, "Widge" ) ); + assertNotNull( session.find( Part.class, "Get" ) ); session.remove( session.get( Product.class, "Widget" ) ); } ); @@ -208,8 +208,8 @@ public void testOrphanDeleteOnSaveOrUpdate(SessionFactoryScope scope) { scope.inTransaction( session -> { - assertNull( session.get( Part.class, "Widge" ) ); - assertNotNull( session.get( Part.class, "Get" ) ); + assertNull( session.find( Part.class, "Widge" ) ); + assertNotNull( session.find( Part.class, "Get" ) ); session.remove( session.get( Product.class, "Widget" ) ); } ); @@ -245,8 +245,8 @@ public void testOrphanDeleteOnSaveOrUpdateAfterSerialization(SessionFactoryScope scope.inTransaction( session -> { - assertNull( session.get( Part.class, "Widge" ) ); - assertNotNull( session.get( Part.class, "Get" ) ); + assertNull( session.find( Part.class, "Widge" ) ); + assertNotNull( session.find( Part.class, "Get" ) ); session.remove( session.get( Product.class, "Widget" ) ); } ); @@ -286,8 +286,8 @@ public void testOrphanDelete(SessionFactoryScope scope) { scope.inTransaction( session -> { - assertNull( session.get( Part.class, "Widge" ) ); - assertNotNull( session.get( Part.class, "Get" ) ); + assertNull( session.find( Part.class, "Widge" ) ); + assertNotNull( session.find( Part.class, "Get" ) ); session.remove( session.get( Product.class, "Widget" ) ); } ); @@ -322,8 +322,8 @@ public void testOrphanDeleteOnMerge(SessionFactoryScope scope) { scope.inTransaction( session -> { - assertNull( session.get( Part.class, "Widge" ) ); - assertNotNull( session.get( Part.class, "Get" ) ); + assertNull( session.find( Part.class, "Widge" ) ); + assertNotNull( session.find( Part.class, "Get" ) ); session.remove( session.get( Product.class, "Widget" ) ); } ); @@ -354,7 +354,7 @@ public void testOrphanDeleteOnMergeRemoveElementMerge(SessionFactoryScope scope) scope.inTransaction( session -> { - assertNull( session.get( Part.class, "Widge" ) ); + assertNull( session.find( Part.class, "Widge" ) ); session.remove( session.get( Product.class, "Widget" ) ); } ); @@ -392,7 +392,7 @@ public void testOrphanDeleteOnAddElementMergeRemoveElementMerge(SessionFactorySc scope.inTransaction( session -> { - assertNotNull( session.get( Part.class, "Widge" ) ); + assertNotNull( session.find( Part.class, "Widge" ) ); session.remove( session.get( Product.class, "Widget" ) ); } ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/cache/InsertedDataTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/cache/InsertedDataTest.java index f0662c1fbf09..2d468246c917 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/cache/InsertedDataTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/cache/InsertedDataTest.java @@ -122,7 +122,7 @@ public void testInsertWithRefreshThenRollback(SessionFactoryScope scope) { assertTrue( scope.getSessionFactory().getCache().containsEntity( CacheableItem.class, item.getId() ) ); - CacheableItem item1 = scope.fromTransaction( s -> s.get( CacheableItem.class, item.getId() ) ); + CacheableItem item1 = scope.fromTransaction( s -> s.find( CacheableItem.class, item.getId() ) ); assertNull( item1, "it should be null" ); } @@ -155,7 +155,7 @@ public void testInsertWithClearThenRollback(SessionFactoryScope scope) { assertFalse( scope.getSessionFactory().getCache().containsEntity( CacheableItem.class, item.getId() ) ); Long id = item.getId(); - item = scope.fromTransaction( s -> s.get( CacheableItem.class, id ) ); + item = scope.fromTransaction( s -> s.find( CacheableItem.class, id ) ); assertNull( item, "it should be null" ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/cache/SharedDomainDataAndQueryResultsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/cache/SharedDomainDataAndQueryResultsTest.java index 96e5f6dbb3a8..7653d3a476ec 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/cache/SharedDomainDataAndQueryResultsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/cache/SharedDomainDataAndQueryResultsTest.java @@ -227,7 +227,7 @@ public void testAllCachedStatistics(SessionFactoryScope scope) { scope.inTransaction( session -> { - List dogs = session.getNamedQuery( "Dog.findAll" ).list(); + List dogs = session.createNamedQuery( "Dog.findAll", Dog.class ).list(); assertEquals( 2, dogs.size() ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/cache/polymorphism/PolymorphicCacheTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/cache/polymorphism/PolymorphicCacheTest.java index 826bebeb3617..5de35cb06f1b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/cache/polymorphism/PolymorphicCacheTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/cache/polymorphism/PolymorphicCacheTest.java @@ -57,7 +57,7 @@ public void testPolymorphismAndCache(SessionFactoryScope scope) { // test accessing the wrong class by id with a cache-hit scope.inTransaction( (session) -> { try { - final CachedItem2 loaded = session.get( CachedItem2.class, 1 ); + final CachedItem2 loaded = session.find( CachedItem2.class, 1 ); assertThat( loaded ).isNull(); } catch (WrongClassException legacyBehavior) { @@ -82,7 +82,7 @@ public void testPolymorphismAndCache(SessionFactoryScope scope) { scope.inTransaction( (session) -> { // the legacy behavior for no cache hit was to return null try { - final CachedItem2 loaded = session.get( CachedItem2.class, 1 ); + final CachedItem2 loaded = session.find( CachedItem2.class, 1 ); assertThat( loaded ).isNull(); } catch (WrongClassException legacyBehavior) { @@ -114,11 +114,11 @@ public void testPolymorphismAndCache(SessionFactoryScope scope) { assertThat( cache.containsEntity( CachedItem2.class, 2 ) ).isTrue(); scope.inTransaction( session, (s) -> { - final CachedItem1 loadedItem1 = s.get( CachedItem1.class, 1 ); + final CachedItem1 loadedItem1 = s.find( CachedItem1.class, 1 ); assertThat( loadedItem1 ).isNotNull(); assertThat( loadedItem1.getName() ).isEqualTo( "updated" ); - final CachedItem2 loadedItem2 = s.get( CachedItem2.class, 2 ); + final CachedItem2 loadedItem2 = s.find( CachedItem2.class, 2 ); assertThat( loadedItem2 ).isNotNull(); } ); @@ -130,10 +130,10 @@ public void testPolymorphismAndCache(SessionFactoryScope scope) { session.remove( session.getReference( CachedItem1.class, 1 ) ); } ); scope.inTransaction( session, (s) -> { - final CachedItem1 cachedItem1 = session.get( CachedItem1.class, 1 ); + final CachedItem1 cachedItem1 = session.find( CachedItem1.class, 1 ); assertThat( cachedItem1 ).isNull(); - final CachedItem2 cachedItem2 = session.get( CachedItem2.class, 2 ); + final CachedItem2 cachedItem2 = session.find( CachedItem2.class, 2 ); assertThat( cachedItem2 ).isNotNull(); } ); } ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/caching/mocked/ReadWriteCacheTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/caching/mocked/ReadWriteCacheTest.java index cca1bb268f24..059c3246250e 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/caching/mocked/ReadWriteCacheTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/caching/mocked/ReadWriteCacheTest.java @@ -243,8 +243,7 @@ public void testUpdateNativeQuery(SessionFactoryScope scope) throws InterruptedE } private void assertBookNotFound(long bookId, Session session) { - Book book = session.get( Book.class, bookId ); - assertNull( book ); + assertNull( session.find( Book.class, bookId ) ); } private void createBook(long bookId, Session session) { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/cdi/type/SimpleTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/cdi/type/SimpleTests.java index b40094c7e1f2..942a61c483c4 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/cdi/type/SimpleTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/cdi/type/SimpleTests.java @@ -68,7 +68,7 @@ void testProperUsage() { try ( final SessionFactory sf = metadata.buildSessionFactory() ) { sf.inSession( (session) -> { - session.createSelectionQuery( "from MappedEntity" ).list(); + session.createSelectionQuery( "from MappedEntity", MappedEntity.class ).list(); } ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/cid/CompositeIdWithGeneratorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/cid/CompositeIdWithGeneratorTest.java index f3e5faf651e7..1e42872f30ba 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/cid/CompositeIdWithGeneratorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/cid/CompositeIdWithGeneratorTest.java @@ -351,7 +351,7 @@ public void testDelete(SessionFactoryScope scope) { // attempt to re-fetch - show it was deleted PurchaseRecord find = scope.fromTransaction( session -> - session.get( PurchaseRecord.class, generatedId ) + session.find( PurchaseRecord.class, generatedId ) ); assertThat( find ).isNull(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/collection/ListAndSetProxyTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/collection/ListAndSetProxyTest.java index 48675ba1a184..0fc5d2fe4e53 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/collection/ListAndSetProxyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/collection/ListAndSetProxyTest.java @@ -104,7 +104,7 @@ public void setId(String id) { } @OneToMany(mappedBy = "theMapKey.theOne") - @MapKey(name = "theMapKey") + @MapKey("theMapKey") public Map getTheManys() { return theManys; } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/collection/map/EmbeddableIndexTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/collection/map/EmbeddableIndexTest.java index dbcf98fb3e7e..fcc58126fc7f 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/collection/map/EmbeddableIndexTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/collection/map/EmbeddableIndexTest.java @@ -91,7 +91,7 @@ public void setId(String id) { } @OneToMany(mappedBy = "theMapKey.theOne") - @MapKey(name = "theMapKey") + @MapKey("theMapKey") public Map getTheManys() { return theManys; } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/collection/mapkey/Book.java b/hibernate-core/src/test/java/org/hibernate/orm/test/collection/mapkey/Book.java index 2191e41e343e..29d01d7e41bd 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/collection/mapkey/Book.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/collection/mapkey/Book.java @@ -24,7 +24,7 @@ class Book { @OneToMany(cascade = PERSIST, mappedBy = "isbn") - @MapKey(name = "name") + @MapKey("name") Map chapters; Book(String isbn) { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/collection/ordered/joinedInheritence/OrderCollectionOfJoinedHierarchyTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/collection/ordered/joinedInheritence/OrderCollectionOfJoinedHierarchyTest.java index 9c8c7232a26d..d3236e11ffbb 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/collection/ordered/joinedInheritence/OrderCollectionOfJoinedHierarchyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/collection/ordered/joinedInheritence/OrderCollectionOfJoinedHierarchyTest.java @@ -30,7 +30,7 @@ public class OrderCollectionOfJoinedHierarchyTest { @Test public void testQuerySyntaxCheck(SessionFactoryScope scope) { scope.inTransaction( - session -> session.get( Zoo.class, 1L ) + session -> session.find( Zoo.class, 1L ) ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/component/basic/ComponentTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/component/basic/ComponentTest.java index baf5c6931e94..885d0ccc36df 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/component/basic/ComponentTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/component/basic/ComponentTest.java @@ -204,7 +204,7 @@ public void testComponentFormulaQuery() { CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder(); CriteriaQuery criteria = criteriaBuilder.createQuery( User.class ); Root root = criteria.from( User.class ); - Join person = root.join( "person", JoinType.INNER ); + Join person = root.join( "person", JoinType.INNER ); criteria.where( criteriaBuilder.between( person.get( "yob" ), new Integer(1999), new Integer(2002) ) ); s.createQuery( criteria ).list(); @@ -247,7 +247,7 @@ public void testCustomColumnReadAndWrite() { CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder(); CriteriaQuery criteria = criteriaBuilder.createQuery( User.class ); Root root = criteria.from( User.class ); - Join person = root.join( "person", JoinType.INNER ); + Join person = root.join( "person", JoinType.INNER ); criteria.where( criteriaBuilder.between( person.get( "heightInches" ), HEIGHT_INCHES - 0.01d, HEIGHT_INCHES + 0.01d) ); u = s.createQuery( criteria ).uniqueResult(); // u = (User)s.createCriteria(User.class) @@ -277,7 +277,7 @@ public void testCustomColumnReadAndWrite() { @Test public void testNamedQuery() { inTransaction( - s -> s.getNamedQuery( "userNameIn") + s -> s.createNamedQuery( "userNameIn") .setParameterList( "nameList", new Object[] {"1ovthafew", "turin", "xam"} ) .list() ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/compositefk/OneToManyEmbeddedIdFKWithOrphanRemovalTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/compositefk/OneToManyEmbeddedIdFKWithOrphanRemovalTest.java index 3ff35f9ad572..b4ce1dd51bdb 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/compositefk/OneToManyEmbeddedIdFKWithOrphanRemovalTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/compositefk/OneToManyEmbeddedIdFKWithOrphanRemovalTest.java @@ -74,12 +74,9 @@ public void testOrphanRemoval(SessionFactoryScope scope) { } ); - scope.inTransaction( - session -> { - SystemUser user = session.get( SystemUser.class, superUserKey ); - assertNull( user ); - } - ); + scope.inTransaction( session -> { + assertNull( session.find( SystemUser.class, superUserKey ) ); + } ); } @AfterEach diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/constraint/ForeignKeyConstraintTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/constraint/ForeignKeyConstraintTest.java index 0864cbebad9f..d756ea01c3fe 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/constraint/ForeignKeyConstraintTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/constraint/ForeignKeyConstraintTest.java @@ -167,9 +167,9 @@ public void testSecondaryTable(DomainModelScope scope) { } @Test - public void testGet(SessionFactoryScope scope) { + public void testFind(SessionFactoryScope scope) { scope.inTransaction( - session -> session.get( Student.class, 1L ) + session -> session.find( Student.class, 1L ) ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/functional/SQLServerDialectTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/functional/SQLServerDialectTest.java index bf4fc4799da4..4a3e82cb231c 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/functional/SQLServerDialectTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/functional/SQLServerDialectTest.java @@ -266,7 +266,7 @@ public void testPaginationWithAggregation(SessionFactoryScope scope) { CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder(); CriteriaQuery criteria = criteriaBuilder.createQuery( Object[].class ); Root root = criteria.from( Category.class ); - Join products = root.join( "products", JoinType.INNER ); + Join products = root.join( "products", JoinType.INNER ); criteria.multiselect( root.get( "id" ), criteriaBuilder.countDistinct( products.get( "id" ) ) ); criteria.groupBy( root.get( "id" ) ); criteria.orderBy( criteriaBuilder.asc( root.get( "id" ) ) ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/parser/EntityGraphParserTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/parser/EntityGraphParserTest.java index 863ebcb4505f..11339dfb2b85 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/parser/EntityGraphParserTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/parser/EntityGraphParserTest.java @@ -58,8 +58,7 @@ public void testLinkParsing(EntityManagerFactoryScope scope) { assertThat( node ).isNotNull(); assertThat( node.getAttributeName() ).isEqualTo( "linkToOne" ); AssertionHelper.assertNullOrEmpty( node.getKeySubgraphs() ); - @SuppressWarnings("rawtypes") - Map sub = node.getSubgraphs(); + Map, Subgraph> sub = node.getSubgraphs(); AssertionHelper.assertBasicAttributes( sub.get( GraphParsingTestEntity.class ), "name", "description" ); } @@ -74,8 +73,7 @@ public void testMapKeyParsing(EntityManagerFactoryScope scope) { assertThat( node ).isNotNull(); assertThat( node.getAttributeName() ).isEqualTo( "map" ); AssertionHelper.assertNullOrEmpty( node.getSubgraphs() ); - @SuppressWarnings("rawtypes") - Map sub = node.getKeySubgraphs(); + Map, Subgraph> sub = node.getKeySubgraphs(); AssertionHelper.assertBasicAttributes( sub.get( GraphParsingTestEntity.class ), "name", "description" ); } @@ -90,8 +88,7 @@ public void testMapValueParsing(EntityManagerFactoryScope scope) { assertThat( node ).isNotNull(); assertThat( node.getAttributeName() ).isEqualTo( "map" ); AssertionHelper.assertNullOrEmpty( node.getKeySubgraphs() ); - @SuppressWarnings("rawtypes") - Map sub = node.getSubgraphs(); + Map, Subgraph> sub = node.getSubgraphs(); AssertionHelper.assertBasicAttributes( sub.get( GraphParsingTestEntity.class ), "name", "description" ); } @@ -105,34 +102,24 @@ public void testMixParsingWithMaps(EntityManagerFactoryScope scope) { AttributeNode linkToOne = AssertionHelper.getAttributeNodeByName( graph, "linkToOne", true ); AssertionHelper.assertNullOrEmpty( linkToOne.getKeySubgraphs() ); - @SuppressWarnings("rawtypes") - Map linkToOneSubgraphs = linkToOne.getSubgraphs(); - @SuppressWarnings("rawtypes") - Subgraph linkToOneRoot = linkToOneSubgraphs.get( GraphParsingTestEntity.class ); + Map, Subgraph> linkToOneSubgraphs = linkToOne.getSubgraphs(); + Subgraph linkToOneRoot = linkToOneSubgraphs.get( GraphParsingTestEntity.class ); AssertionHelper.assertBasicAttributes( linkToOneRoot, "name", "description" ); AttributeNode linkToOneMap = AssertionHelper.getAttributeNodeByName( linkToOneRoot, "map", true ); - @SuppressWarnings("rawtypes") - Map linkToOneMapKeySubgraphs = linkToOneMap.getKeySubgraphs(); - @SuppressWarnings("rawtypes") - Subgraph linkToOneMapKeyRoot = linkToOneMapKeySubgraphs.get( GraphParsingTestEntity.class ); + Map, Subgraph> linkToOneMapKeySubgraphs = linkToOneMap.getKeySubgraphs(); + Subgraph linkToOneMapKeyRoot = linkToOneMapKeySubgraphs.get( GraphParsingTestEntity.class ); AssertionHelper.assertBasicAttributes( linkToOneMapKeyRoot, "name" ); - @SuppressWarnings("rawtypes") - Map linkToOneMapSubgraphs = linkToOneMap.getSubgraphs(); - @SuppressWarnings("rawtypes") - Subgraph linkToOneMapRoot = linkToOneMapSubgraphs.get( GraphParsingTestEntity.class ); + Map, Subgraph> linkToOneMapSubgraphs = linkToOneMap.getSubgraphs(); + Subgraph linkToOneMapRoot = linkToOneMapSubgraphs.get( GraphParsingTestEntity.class ); AssertionHelper.assertBasicAttributes( linkToOneMapRoot, "description" ); AttributeNode map = AssertionHelper.getAttributeNodeByName( graph, "map", true ); - @SuppressWarnings("rawtypes") - Map mapKeySubgraphs = map.getKeySubgraphs(); - @SuppressWarnings("rawtypes") - Subgraph mapKeyRoot = mapKeySubgraphs.get( GraphParsingTestEntity.class ); + Map, Subgraph> mapKeySubgraphs = map.getKeySubgraphs(); + Subgraph mapKeyRoot = mapKeySubgraphs.get( GraphParsingTestEntity.class ); AssertionHelper.assertBasicAttributes( mapKeyRoot, "name", "description" ); - @SuppressWarnings("rawtypes") - Map mapSubgraphs = map.getSubgraphs(); - @SuppressWarnings("rawtypes") - Subgraph mapRoot = mapSubgraphs.get( GraphParsingTestEntity.class ); + Map, Subgraph> mapSubgraphs = map.getSubgraphs(); + Subgraph mapRoot = mapSubgraphs.get( GraphParsingTestEntity.class ); AssertionHelper.assertBasicAttributes( mapRoot, "description" ); } } @@ -147,24 +134,18 @@ public void testMixParsingWithSimplifiedMaps(EntityManagerFactoryScope scope) { AttributeNode linkToOne = AssertionHelper.getAttributeNodeByName( graph, "linkToOne", true ); AssertionHelper.assertNullOrEmpty( linkToOne.getKeySubgraphs() ); - @SuppressWarnings("rawtypes") - Map linkToOneSubgraphs = linkToOne.getSubgraphs(); - @SuppressWarnings("rawtypes") - Subgraph linkToOneRoot = linkToOneSubgraphs.get( GraphParsingTestEntity.class ); + Map, Subgraph> linkToOneSubgraphs = linkToOne.getSubgraphs(); + Subgraph linkToOneRoot = linkToOneSubgraphs.get( GraphParsingTestEntity.class ); AssertionHelper.assertBasicAttributes( linkToOneRoot, "name", "description" ); AttributeNode linkToOneMap = AssertionHelper.getAttributeNodeByName( linkToOneRoot, "map", true ); - @SuppressWarnings("rawtypes") - Map linkToOneMapKeySubgraphs = linkToOneMap.getKeySubgraphs(); - @SuppressWarnings("rawtypes") - Subgraph linkToOneMapKeyRoot = linkToOneMapKeySubgraphs.get( GraphParsingTestEntity.class ); + Map, Subgraph> linkToOneMapKeySubgraphs = linkToOneMap.getKeySubgraphs(); + Subgraph linkToOneMapKeyRoot = linkToOneMapKeySubgraphs.get( GraphParsingTestEntity.class ); AssertionHelper.assertBasicAttributes( linkToOneMapKeyRoot, "name" ); AttributeNode map = AssertionHelper.getAttributeNodeByName( graph, "map", true ); - @SuppressWarnings("rawtypes") - Map mapSubgraphs = map.getSubgraphs(); - @SuppressWarnings("rawtypes") - Subgraph mapRoot = mapSubgraphs.get( GraphParsingTestEntity.class ); + Map, Subgraph> mapSubgraphs = map.getSubgraphs(); + Subgraph mapRoot = mapSubgraphs.get( GraphParsingTestEntity.class ); AssertionHelper.assertBasicAttributes( mapRoot, "description", "name" ); } } @@ -237,15 +218,13 @@ private void checkMapKeyAndValueSubgraphs( for ( AttributeNode node : graph.getAttributeNodes() ) { if ( mapAttributeName.equals( node.getAttributeName() ) ) { count++; - @SuppressWarnings("rawtypes") - Map keySubgraphs = node.getKeySubgraphs(); + Map, Subgraph> keySubgraphs = node.getKeySubgraphs(); assertThat( !keySubgraphs.isEmpty() ) .describedAs( "Missing the key subgraph" ) .isTrue(); assertThat( keySubgraphs.get( GraphParsingTestEntity.class ) ).isSameAs( keySubgraph ); - @SuppressWarnings("rawtypes") - Map valueSubgraphs = node.getSubgraphs(); + Map, Subgraph> valueSubgraphs = node.getSubgraphs(); assertThat( !valueSubgraphs.isEmpty() ) .describedAs( "Missing the value subgraph" ) .isTrue(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/parser/EntityGraphParserTypedTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/parser/EntityGraphParserTypedTest.java index fa33ad650c19..29d6229b90e7 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/parser/EntityGraphParserTypedTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/parser/EntityGraphParserTypedTest.java @@ -65,8 +65,7 @@ public void testLinkParsing(SessionFactoryScope factoryScope) { assertNotNull( node ); assertEquals( "linkToOne", node.getAttributeName() ); assertNullOrEmpty( node.getKeySubgraphs() ); - @SuppressWarnings("rawtypes") - Map sub = node.getSubgraphs(); + Map, Subgraph> sub = node.getSubgraphs(); assertBasicAttributes( sub.get( GraphParsingTestEntity.class ), "name", "description" ); } @@ -84,8 +83,7 @@ public void testMapKeyParsing(SessionFactoryScope factoryScope) { assertNotNull( node ); assertEquals( "map", node.getAttributeName() ); assertNullOrEmpty( node.getSubgraphs() ); - @SuppressWarnings("rawtypes") - Map sub = node.getKeySubgraphs(); + Map, Subgraph> sub = node.getKeySubgraphs(); assertBasicAttributes( sub.get( GraphParsingTestEntity.class ), "name", "description" ); } @@ -103,8 +101,7 @@ public void testMapValueParsing(SessionFactoryScope factoryScope) { assertNotNull( node ); assertEquals( "map", node.getAttributeName() ); assertNullOrEmpty( node.getKeySubgraphs() ); - @SuppressWarnings("rawtypes") - Map sub = node.getSubgraphs(); + Map, Subgraph> sub = node.getSubgraphs(); assertBasicAttributes( sub.get( GraphParsingTestEntity.class ), "name", "description" ); } @@ -121,34 +118,24 @@ public void testMixParsingWithMaps(SessionFactoryScope factoryScope) { AttributeNode linkToOne = getAttributeNodeByName( graph, "linkToOne", true ); assertNullOrEmpty( linkToOne.getKeySubgraphs() ); - @SuppressWarnings("rawtypes") - Map linkToOneSubgraphs = linkToOne.getSubgraphs(); - @SuppressWarnings("rawtypes") - Subgraph linkToOneRoot = linkToOneSubgraphs.get( GraphParsingTestEntity.class ); + Map, Subgraph> linkToOneSubgraphs = linkToOne.getSubgraphs(); + Subgraph linkToOneRoot = linkToOneSubgraphs.get( GraphParsingTestEntity.class ); assertBasicAttributes( linkToOneRoot, "name", "description" ); AttributeNode linkToOneMap = getAttributeNodeByName( linkToOneRoot, "map", true ); - @SuppressWarnings("rawtypes") - Map linkToOneMapKeySubgraphs = linkToOneMap.getKeySubgraphs(); - @SuppressWarnings("rawtypes") - Subgraph linkToOneMapKeyRoot = linkToOneMapKeySubgraphs.get( GraphParsingTestEntity.class ); + Map, Subgraph> linkToOneMapKeySubgraphs = linkToOneMap.getKeySubgraphs(); + Subgraph linkToOneMapKeyRoot = linkToOneMapKeySubgraphs.get( GraphParsingTestEntity.class ); assertBasicAttributes( linkToOneMapKeyRoot, "name" ); - @SuppressWarnings("rawtypes") - Map linkToOneMapSubgraphs = linkToOneMap.getSubgraphs(); - @SuppressWarnings("rawtypes") - Subgraph linkToOneMapRoot = linkToOneMapSubgraphs.get( GraphParsingTestEntity.class ); + Map, Subgraph> linkToOneMapSubgraphs = linkToOneMap.getSubgraphs(); + Subgraph linkToOneMapRoot = linkToOneMapSubgraphs.get( GraphParsingTestEntity.class ); assertBasicAttributes( linkToOneMapRoot, "description" ); AttributeNode map = getAttributeNodeByName( graph, "map", true ); - @SuppressWarnings("rawtypes") - Map mapKeySubgraphs = map.getKeySubgraphs(); - @SuppressWarnings("rawtypes") - Subgraph mapKeyRoot = mapKeySubgraphs.get( GraphParsingTestEntity.class ); + Map, Subgraph> mapKeySubgraphs = map.getKeySubgraphs(); + Subgraph mapKeyRoot = mapKeySubgraphs.get( GraphParsingTestEntity.class ); assertBasicAttributes( mapKeyRoot, "name", "description" ); - @SuppressWarnings("rawtypes") - Map mapSubgraphs = map.getSubgraphs(); - @SuppressWarnings("rawtypes") - Subgraph mapRoot = mapSubgraphs.get( GraphParsingTestEntity.class ); + Map, Subgraph> mapSubgraphs = map.getSubgraphs(); + Subgraph mapRoot = mapSubgraphs.get( GraphParsingTestEntity.class ); assertBasicAttributes( mapRoot, "description" ); } } @@ -166,24 +153,18 @@ public void testMixParsingWithSimplifiedMaps(SessionFactoryScope factoryScope) { AttributeNode linkToOne = getAttributeNodeByName( graph, "linkToOne", true ); assertNullOrEmpty( linkToOne.getKeySubgraphs() ); - @SuppressWarnings("rawtypes") - Map linkToOneSubgraphs = linkToOne.getSubgraphs(); - @SuppressWarnings("rawtypes") - Subgraph linkToOneRoot = linkToOneSubgraphs.get( GraphParsingTestEntity.class ); + Map, Subgraph> linkToOneSubgraphs = linkToOne.getSubgraphs(); + Subgraph linkToOneRoot = linkToOneSubgraphs.get( GraphParsingTestEntity.class ); assertBasicAttributes( linkToOneRoot, "name", "description" ); AttributeNode linkToOneMap = getAttributeNodeByName( linkToOneRoot, "map", true ); - @SuppressWarnings("rawtypes") - Map linkToOneMapKeySubgraphs = linkToOneMap.getKeySubgraphs(); - @SuppressWarnings("rawtypes") - Subgraph linkToOneMapKeyRoot = linkToOneMapKeySubgraphs.get( GraphParsingTestEntity.class ); + Map, Subgraph> linkToOneMapKeySubgraphs = linkToOneMap.getKeySubgraphs(); + Subgraph linkToOneMapKeyRoot = linkToOneMapKeySubgraphs.get( GraphParsingTestEntity.class ); assertBasicAttributes( linkToOneMapKeyRoot, "name" ); AttributeNode map = getAttributeNodeByName( graph, "map", true ); - @SuppressWarnings("rawtypes") - Map mapSubgraphs = map.getSubgraphs(); - @SuppressWarnings("rawtypes") - Subgraph mapRoot = mapSubgraphs.get( GraphParsingTestEntity.class ); + Map, Subgraph> mapSubgraphs = map.getSubgraphs(); + Subgraph mapRoot = mapSubgraphs.get( GraphParsingTestEntity.class ); assertBasicAttributes( mapRoot, "description", "name" ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/event/AddListenerTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/event/AddListenerTests.java new file mode 100644 index 000000000000..e05915009b84 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/event/AddListenerTests.java @@ -0,0 +1,144 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.event; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.PostLoad; +import jakarta.persistence.PostRemove; +import jakarta.persistence.PostUpdate; +import jakarta.persistence.PrePersist; +import jakarta.persistence.Table; +import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; +import org.hibernate.testing.orm.junit.Jpa; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/// Tests for the JPA 4 [jakarta.persistence.EntityManagerFactory#addListener] feature +/// +/// @author Steve Ebersole +@Jpa( annotatedClasses = AddListenerTests.Stuff.class) +public class AddListenerTests { + @BeforeEach + void testPersist(EntityManagerFactoryScope factoryScope) { + var listener = new StuffListener(); + + factoryScope.inTransaction( (em) -> { + final var prePersistReg = em.getEntityManagerFactory().addListener( + Stuff.class, + PrePersist.class, + listener::capture + ); + + em.persist( new Stuff( 1, "th!ngs" ) ); + assertThat( listener.callCount ).isEqualTo( 1 ); + + prePersistReg.cancel(); + + em.persist( new Stuff( 2, "irrelevant" ) ); + assertThat( listener.callCount ).isEqualTo( 1 ); + } ); + } + + @Test + void testLoadAndUpdate(EntityManagerFactoryScope factoryScope) { + var listener = new StuffListener(); + + factoryScope.inTransaction( (em) -> { + var postLoadReg = em.getEntityManagerFactory().addListener( + Stuff.class, + PostLoad.class, + listener::capture + ); + + var first = em.get( Stuff.class, 1 ); + assertThat( listener.callCount ).isEqualTo( 1 ); + + postLoadReg.cancel(); + + var second = em.get( Stuff.class, 2 ); + assertThat( listener.callCount ).isEqualTo( 1 ); + + listener.reset(); + + var postUpdateReg = em.getEntityManagerFactory().addListener( + Stuff.class, + PostUpdate.class, + listener::capture + ); + first.name = "fixed"; + em.flush(); + assertThat( listener.callCount ).isEqualTo( 1 ); + + postUpdateReg.cancel(); + + second.name = "altered"; + em.flush(); + assertThat( listener.callCount ).isEqualTo( 1 ); + } ); + } + + @Test + void testRemoval(EntityManagerFactoryScope factoryScope) { + var listener = new StuffListener(); + + factoryScope.inTransaction( (em) -> { + var first = em.get( Stuff.class, 1 ); + var second = em.get( Stuff.class, 2 ); + + var postRemoveReg = em.getEntityManagerFactory().addListener( + Stuff.class, + PostRemove.class, + listener::capture + ); + + em.remove( first ); + em.flush(); + assertThat( listener.callCount ).isEqualTo( 1 ); + + postRemoveReg.cancel(); + + em.remove( second ); + em.flush(); + assertThat( listener.callCount ).isEqualTo( 1 ); + } ); + } + + @AfterEach + void dropTestData(EntityManagerFactoryScope factoryScope) { + factoryScope.dropData(); + } + + @Entity(name="Stuff") + @Table(name="stuffs") + public static class Stuff { + @Id + private Integer id; + private String name; + + public Stuff() { + } + + public Stuff(Integer id, String name) { + this.id = id; + this.name = name; + } + } + + public static class StuffListener { + public int callCount; + + public void capture(Stuff stuff) { + callCount++; + } + + public void reset() { + callCount = 0; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/event/EmbeddableCallbackTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/event/EmbeddableCallbackTest.java deleted file mode 100644 index 123a1f9f1e60..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/event/EmbeddableCallbackTest.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.test.event; - -import jakarta.persistence.Embeddable; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.PrePersist; - -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; -import org.hibernate.testing.orm.junit.Jpa; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertNull; - -/** - * @author Vlad Mihalcea - */ -@Jpa( - annotatedClasses = EmbeddableCallbackTest.Employee.class -) -public class EmbeddableCallbackTest { - - @AfterEach - public void tearDown(EntityManagerFactoryScope scope) { - scope.getEntityManagerFactory().getSchemaManager().truncate(); - } - - @Test - @JiraKey(value = "HHH-12326") - public void test(EntityManagerFactoryScope scope) { - scope.inTransaction( entityManager -> { - Employee employee = new Employee(); - employee.details = new EmployeeDetails(); - employee.id = 1; - - entityManager.persist( employee ); - } ); - - scope.inTransaction( entityManager -> { - Employee employee = entityManager.find( Employee.class, 1 ); - - assertThat( employee.name, is( "Vlad" ) ); - assertThat( employee.details.jobTitle, is( "Developer Advocate" ) ); - } ); - } - - @Test - @JiraKey(value = "HHH-13110") - public void testNullEmbeddable(EntityManagerFactoryScope scope) { - scope.inTransaction( entityManager -> { - Employee employee = new Employee(); - employee.id = 1; - - entityManager.persist( employee ); - } ); - - scope.inTransaction( entityManager -> { - Employee employee = entityManager.find( Employee.class, 1 ); - - assertThat( employee.name, is( "Vlad" ) ); - assertNull( employee.details ); - } ); - } - - @Entity(name = "Employee") - public static class Employee { - - @Id - private Integer id; - - private String name; - - private EmployeeDetails details; - - @PrePersist - public void setUp() { - name = "Vlad"; - } - } - - @Embeddable - public static class EmployeeDetails { - - private String jobTitle; - - @PrePersist - public void setUp() { - jobTitle = "Developer Advocate"; - } - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/filter/subclass/joined2/JoinedInheritanceFilterTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/filter/subclass/joined2/JoinedInheritanceFilterTest.java index ecac04cf55e7..d0eb7b95bed9 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/filter/subclass/joined2/JoinedInheritanceFilterTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/filter/subclass/joined2/JoinedInheritanceFilterTest.java @@ -67,7 +67,7 @@ List transactionKind() { BiConsumer> kind1 = SessionFactoryScope::inTransaction; TriFunction, Object, Object> find1 = Session::find; BiConsumer> kind2 = SessionFactoryScope::inStatelessTransaction; - TriFunction, Object, Object> find2 = StatelessSession::get; + TriFunction, Object, Object> find2 = StatelessSession::find; return List.of( Arguments.of( kind1, find1 ), Arguments.of( kind2, find2 ) diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/flush/NativeCriteriaSyncTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/flush/NativeCriteriaSyncTest.java index 71a9b0597433..4944ec6fad0d 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/flush/NativeCriteriaSyncTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/flush/NativeCriteriaSyncTest.java @@ -49,7 +49,7 @@ public void test(SessionFactoryScope factoryScope) { CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder(); CriteriaQuery criteria = criteriaBuilder.createQuery( SimpleEntityWithAssociation.class ); Root root = criteria.from( SimpleEntityWithAssociation.class ); - Join join = root.join( + Join join = root.join( "manyToManyAssociatedEntities", JoinType.INNER ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/hbm/query/QueryReturnTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/hbm/query/QueryReturnTest.java index d10af14ab6e0..1de9bbf6fcf4 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/hbm/query/QueryReturnTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/hbm/query/QueryReturnTest.java @@ -10,7 +10,7 @@ import org.hibernate.internal.util.ReaderInputStream; import org.hibernate.query.internal.ResultSetMappingResolutionContext; import org.hibernate.query.named.NamedResultSetMappingMemento; -import org.hibernate.query.results.ResultSetMapping; +import org.hibernate.query.results.spi.ResultSetMapping; import org.hibernate.query.results.internal.ResultSetMappingImpl; import org.hibernate.query.results.internal.complete.CompleteResultBuilderEntityValued; import org.hibernate.testing.orm.junit.BaseUnitTest; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/BooleanPredicateTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/BooleanPredicateTest.java index a85e4bd78c22..181320c238b3 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/BooleanPredicateTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/BooleanPredicateTest.java @@ -18,34 +18,34 @@ public class BooleanPredicateTest { @Test void test(SessionFactoryScope scope) { scope.inSession(session -> { - assertEquals(1, session.createSelectionQuery("select 1 where true is true").getResultList().size()); - assertEquals(0, session.createSelectionQuery("select 1 where false is true").getResultList().size()); - assertEquals(0, session.createSelectionQuery("select 1 where true is not true").getResultList().size()); - assertEquals(1, session.createSelectionQuery("select 1 where false is not true").getResultList().size()); + assertEquals(1, session.createSelectionQuery("select 1 where true is true", Integer.class).getResultList().size()); + assertEquals(0, session.createSelectionQuery("select 1 where false is true", Integer.class).getResultList().size()); + assertEquals(0, session.createSelectionQuery("select 1 where true is not true", Integer.class).getResultList().size()); + assertEquals(1, session.createSelectionQuery("select 1 where false is not true", Integer.class).getResultList().size()); - assertEquals(0, session.createSelectionQuery("select 1 where true is false").getResultList().size()); - assertEquals(1, session.createSelectionQuery("select 1 where false is false").getResultList().size()); - assertEquals(1, session.createSelectionQuery("select 1 where true is not false").getResultList().size()); - assertEquals(0, session.createSelectionQuery("select 1 where false is not false").getResultList().size()); + assertEquals(0, session.createSelectionQuery("select 1 where true is false", Integer.class).getResultList().size()); + assertEquals(1, session.createSelectionQuery("select 1 where false is false", Integer.class).getResultList().size()); + assertEquals(1, session.createSelectionQuery("select 1 where true is not false", Integer.class).getResultList().size()); + assertEquals(0, session.createSelectionQuery("select 1 where false is not false", Integer.class).getResultList().size()); }); } @SkipForDialect(dialectClass = DerbyDialect.class, reason = "Derby doesn't accept literal null in case") @Test void testNulls(SessionFactoryScope scope) { scope.inSession(session -> { - assertEquals(1, session.createSelectionQuery("select 1 where true is true").getResultList().size()); - assertEquals(0, session.createSelectionQuery("select 1 where false is true").getResultList().size()); - assertEquals(0, session.createSelectionQuery("select 1 where null is true").getResultList().size()); - assertEquals(0, session.createSelectionQuery("select 1 where true is not true").getResultList().size()); - assertEquals(1, session.createSelectionQuery("select 1 where false is not true").getResultList().size()); - assertEquals(1, session.createSelectionQuery("select 1 where null is not true").getResultList().size()); + assertEquals(1, session.createSelectionQuery("select 1 where true is true", Integer.class).getResultList().size()); + assertEquals(0, session.createSelectionQuery("select 1 where false is true", Integer.class).getResultList().size()); + assertEquals(0, session.createSelectionQuery("select 1 where null is true", Integer.class).getResultList().size()); + assertEquals(0, session.createSelectionQuery("select 1 where true is not true", Integer.class).getResultList().size()); + assertEquals(1, session.createSelectionQuery("select 1 where false is not true", Integer.class).getResultList().size()); + assertEquals(1, session.createSelectionQuery("select 1 where null is not true", Integer.class).getResultList().size()); - assertEquals(0, session.createSelectionQuery("select 1 where true is false").getResultList().size()); - assertEquals(1, session.createSelectionQuery("select 1 where false is false").getResultList().size()); - assertEquals(0, session.createSelectionQuery("select 1 where null is false").getResultList().size()); - assertEquals(1, session.createSelectionQuery("select 1 where true is not false").getResultList().size()); - assertEquals(0, session.createSelectionQuery("select 1 where false is not false").getResultList().size()); - assertEquals(1, session.createSelectionQuery("select 1 where null is not false").getResultList().size()); + assertEquals(0, session.createSelectionQuery("select 1 where true is false", Integer.class).getResultList().size()); + assertEquals(1, session.createSelectionQuery("select 1 where false is false", Integer.class).getResultList().size()); + assertEquals(0, session.createSelectionQuery("select 1 where null is false", Integer.class).getResultList().size()); + assertEquals(1, session.createSelectionQuery("select 1 where true is not false", Integer.class).getResultList().size()); + assertEquals(0, session.createSelectionQuery("select 1 where false is not false", Integer.class).getResultList().size()); + assertEquals(1, session.createSelectionQuery("select 1 where null is not false", Integer.class).getResultList().size()); }); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/BulkManipulationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/BulkManipulationTest.java index 3921a8886613..c39b15acf79b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/BulkManipulationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/BulkManipulationTest.java @@ -367,9 +367,9 @@ public void testSimpleNativeQueryManipulations(SessionFactoryScope factoryScope) Car c = (Car) session.createQuery( "from Car where owner = 'Kirsten'" ).uniqueResult(); c.setOwner( "NotKirsten" ); assertEquals( 0, - session.getNamedQuery( "native-delete-car" ).setParameter( 1, "Kirsten" ).executeUpdate() ); + session.createNamedQuery( "native-delete-car" ).setParameter( 1, "Kirsten" ).executeUpdate() ); assertEquals( 1, - session.getNamedQuery( "native-delete-car" ).setParameter( 1, "NotKirsten" ).executeUpdate() ); + session.createNamedQuery( "native-delete-car" ).setParameter( 1, "NotKirsten" ).executeUpdate() ); assertEquals( 0, session.createNativeQuery( "delete from SUV where owner = :owner" ) .setParameter( "owner", "NotThere" ) diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/HQLTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/HQLTest.java index 7994df88d6e8..3575e3e95890 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/HQLTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/HQLTest.java @@ -21,7 +21,6 @@ import org.hibernate.dialect.PostgreSQLDialect; import org.hibernate.dialect.SQLServerDialect; import org.hibernate.dialect.SybaseASEDialect; -import org.hibernate.query.QueryProducer; import org.hibernate.testing.orm.domain.userguide.Account; import org.hibernate.testing.orm.domain.userguide.AddressType; import org.hibernate.testing.orm.domain.userguide.Call; @@ -979,7 +978,7 @@ public void test_jpql_api_single_result_example(SessionFactoryScope factoryScope @Test public void test_hql_api_example(SessionFactoryScope factoryScope) { factoryScope.inTransaction( entityManager -> { - QueryProducer session = entityManager.unwrap(Session.class); + Session session = entityManager.unwrap(Session.class); //tag::hql-api-example[] org.hibernate.query.Query query = session.createQuery( "select p " + @@ -993,7 +992,7 @@ public void test_hql_api_example(SessionFactoryScope factoryScope) { @Test public void test_hql_api_named_query_example(SessionFactoryScope factoryScope) { factoryScope.inTransaction( entityManager -> { - QueryProducer session = entityManager.unwrap(Session.class); + Session session = entityManager.unwrap(Session.class); //tag::hql-api-named-query-example[] org.hibernate.query.Query query = session.createNamedQuery( "get_person_by_name", @@ -1005,7 +1004,7 @@ public void test_hql_api_named_query_example(SessionFactoryScope factoryScope) { @Test public void test_hql_api_basic_usage_example(SessionFactoryScope factoryScope) { factoryScope.inTransaction( entityManager -> { - QueryProducer session = entityManager.unwrap(Session.class); + Session session = entityManager.unwrap(Session.class); //tag::hql-api-basic-usage-example[] org.hibernate.query.Query query = session.createQuery( "select p " + @@ -1027,7 +1026,7 @@ public void test_hql_api_basic_usage_example(SessionFactoryScope factoryScope) { @Test public void test_hql_api_parameter_example(SessionFactoryScope factoryScope) { factoryScope.inTransaction( entityManager -> { - QueryProducer session = entityManager.unwrap(Session.class); + Session session = entityManager.unwrap(Session.class); //tag::hql-api-parameter-example[] org.hibernate.query.Query query = session.createQuery( "select p " + @@ -1042,7 +1041,7 @@ public void test_hql_api_parameter_example(SessionFactoryScope factoryScope) { @Test public void test_hql_api_parameter_inferred_type_example(SessionFactoryScope factoryScope) { factoryScope.inTransaction( entityManager -> { - QueryProducer session = entityManager.unwrap(Session.class); + Session session = entityManager.unwrap(Session.class); //tag::hql-api-parameter-inferred-type-example[] org.hibernate.query.Query query = session.createQuery( "select p " + @@ -1058,7 +1057,7 @@ public void test_hql_api_parameter_inferred_type_example(SessionFactoryScope fac public void test_hql_api_parameter_short_form_example(SessionFactoryScope factoryScope) { factoryScope.inTransaction( entityManager -> { LocalDateTime timestamp = LocalDateTime.now(); - QueryProducer session = entityManager.unwrap(Session.class); + Session session = entityManager.unwrap(Session.class); //tag::hql-api-parameter-short-form-example[] org.hibernate.query.Query query = session.createQuery( "select p " + @@ -1077,7 +1076,7 @@ public void test_hql_api_parameter_short_form_example(SessionFactoryScope factor public void test_hql_api_positional_parameter_example(SessionFactoryScope factoryScope) { factoryScope.inTransaction( entityManager -> { Date timestamp = new Date(); - QueryProducer session = entityManager.unwrap(Session.class); + Session session = entityManager.unwrap(Session.class); //tag::hql-api-ordinal-parameter-example[] org.hibernate.query.Query query = session.createQuery( "select p " + @@ -1092,7 +1091,7 @@ public void test_hql_api_positional_parameter_example(SessionFactoryScope factor @Test public void test_hql_api_list_example(SessionFactoryScope factoryScope) { factoryScope.inTransaction( entityManager -> { - QueryProducer session = entityManager.unwrap(Session.class); + Session session = entityManager.unwrap(Session.class); //tag::hql-api-list-example[] List persons = session.createQuery( "select p " + @@ -1108,7 +1107,7 @@ public void test_hql_api_list_example(SessionFactoryScope factoryScope) { @Test public void test_hql_api_stream_example(SessionFactoryScope factoryScope) { factoryScope.inTransaction( entityManager -> { - QueryProducer session = entityManager.unwrap(Session.class); + Session session = entityManager.unwrap(Session.class); //tag::hql-api-stream-example[] try(Stream persons = session.createQuery( "select p " + @@ -1135,7 +1134,7 @@ private void process(Map> callRegistry) { @Test public void test_hql_api_stream_projection_example(SessionFactoryScope factoryScope) { factoryScope.inTransaction( entityManager -> { - QueryProducer session = entityManager.unwrap(Session.class); + Session session = entityManager.unwrap(Session.class); //tag::hql-api-stream-projection-example[] try (Stream persons = session.createQuery( "select p.name, p.nickName " + @@ -1154,7 +1153,7 @@ public void test_hql_api_stream_projection_example(SessionFactoryScope factorySc @Test public void test_hql_api_scroll_projection_example(SessionFactoryScope factoryScope) { factoryScope.inTransaction( entityManager -> { - QueryProducer session = entityManager.unwrap(Session.class); + Session session = entityManager.unwrap(Session.class); //tag::hql-api-scroll-example[] try (ScrollableResults scrollableResults = session.createQuery( "select p " + @@ -1177,7 +1176,7 @@ public void test_hql_api_scroll_projection_example(SessionFactoryScope factorySc public void test_hql_api_scroll_open_example(SessionFactoryScope factoryScope) { //noinspection resource ScrollableResults scrollableResults = factoryScope.fromTransaction( entityManager -> { - QueryProducer session = entityManager.unwrap(Session.class); + Session session = entityManager.unwrap(Session.class); return session.createQuery( "select p " + "from Person p " + diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/HqlOperatorTypesafetyTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/HqlOperatorTypesafetyTest.java index 89b8191f88c9..112fbfd94640 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/HqlOperatorTypesafetyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/HqlOperatorTypesafetyTest.java @@ -20,22 +20,22 @@ public class HqlOperatorTypesafetyTest { @Test void testOperatorTyping(SessionFactoryScope scope) { scope.inSession( s -> { // these should succeed - s.createSelectionQuery("from Book where title = 'Hibernate'").getResultList(); - s.createSelectionQuery("from Book where title > ''").getResultList(); - s.createSelectionQuery("select edition + 1 from Book").getResultList(); - s.createSelectionQuery("select title || '!' from Book").getResultList(); + s.createSelectionQuery("from Book where title = 'Hibernate'", Book.class).getResultList(); + s.createSelectionQuery("from Book where title > ''", Book.class).getResultList(); + s.createSelectionQuery("select edition + 1 from Book", Integer.class).getResultList(); + s.createSelectionQuery("select title || '!' from Book", String.class).getResultList(); try { - s.createSelectionQuery("from Book where title = 1").getResultList(); + s.createSelectionQuery("from Book where title = 1", Book.class).getResultList(); fail(); } catch (SemanticException se) {} try { - s.createSelectionQuery("from Book where title > 1").getResultList(); + s.createSelectionQuery("from Book where title > 1", Book.class).getResultList(); fail(); } catch (SemanticException se) {} try { - s.createSelectionQuery("select title + 1 from Book").getResultList(); + s.createSelectionQuery("select title + 1 from Book", Book.class).getResultList(); fail(); } catch (SemanticException se) {} @@ -45,39 +45,39 @@ public class HqlOperatorTypesafetyTest { @Test void testSubselectTyping(SessionFactoryScope scope) { scope.inSession( s -> { // these should succeed - s.createSelectionQuery("from Book where title in (select title from Book)").getResultList(); - s.createSelectionQuery("from Book where title = any (select title from Book)").getResultList(); + s.createSelectionQuery("from Book where title in (select title from Book)", Book.class).getResultList(); + s.createSelectionQuery("from Book where title = any (select title from Book)", Book.class).getResultList(); // test tuple length errors try { - s.createSelectionQuery("from Book where title = any (select title, isbn from Book)").getResultList(); + s.createSelectionQuery("from Book where title = any (select title, isbn from Book)", Book.class).getResultList(); fail(); } catch (SemanticException se) {} try { - s.createSelectionQuery("from Book where title = every (select title, isbn from Book)").getResultList(); + s.createSelectionQuery("from Book where title = every (select title, isbn from Book)", Book.class).getResultList(); fail(); } catch (SemanticException se) {} try { - s.createSelectionQuery("from Book where title in (select title, isbn from Book)").getResultList(); + s.createSelectionQuery("from Book where title in (select title, isbn from Book)", Book.class).getResultList(); fail(); } catch (SemanticException se) {} // test typing errors try { - s.createSelectionQuery("from Book where 1 = any (select title from Book)").getResultList(); + s.createSelectionQuery("from Book where 1 = any (select title from Book)", Book.class).getResultList(); fail(); } catch (SemanticException se) {} try { - s.createSelectionQuery("from Book where 1 = every (select title from Book)").getResultList(); + s.createSelectionQuery("from Book where 1 = every (select title from Book)", Book.class).getResultList(); fail(); } catch (SemanticException se) {} try { - s.createSelectionQuery("from Book where 1 in (select title from Book)").getResultList(); + s.createSelectionQuery("from Book where 1 in (select title from Book)", Book.class).getResultList(); fail(); } catch (SemanticException se) {} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/ManyToOneJoinReuseTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/ManyToOneJoinReuseTest.java index ac534ce516cf..03052d4701e5 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/ManyToOneJoinReuseTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/ManyToOneJoinReuseTest.java @@ -71,7 +71,7 @@ public void joinAndImplicitPath(SessionFactoryScope scope) { JpaCriteriaQuery query = cb.createQuery( BookList.class ); JpaRoot root = query.from( BookList.class ); - Join join = root.join( "book", JoinType.INNER ); + Join join = root.join( "book", JoinType.INNER ); query.where( cb.and( root.get( "book" ).isNotNull(), diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/ScrollableCollectionFetchingTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/ScrollableCollectionFetchingTest.java index e564699e6eec..f30c200bd1a4 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/ScrollableCollectionFetchingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/ScrollableCollectionFetchingTest.java @@ -51,7 +51,7 @@ public void testTupleReturnWithFetch(SessionFactoryScope scope) { scope.inTransaction( session -> { session.createMutationQuery("insert Mammal (description, bodyWeight, pregnant) values ('Human', 80.0, false)").executeUpdate(); - assertEquals( 1L, session.createSelectionQuery("select count(*) from Mammal").getSingleResult() ); + assertEquals( 1L, session.createSelectionQuery("select count(*) from Mammal", Long.class).getSingleResult() ); try (ScrollableResults results = session.createQuery("select a, a.bodyWeight from Animal a left join fetch a.offspring").scroll()) { assertTrue( results.next() ); Object[] result = (Object[]) results.get(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/SelectionQueryExampleTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/SelectionQueryExampleTests.java index 9920a2f068db..b7c11e4e927e 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/SelectionQueryExampleTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/SelectionQueryExampleTests.java @@ -41,7 +41,7 @@ public void selectionQueryTest(SessionFactoryScope scope) { scope.inTransaction( (session) -> { //tag::example-hql-selection-query[] // can be validated while creating the SelectionQuery - SelectionQuery badQuery = session.createSelectionQuery( "delete Person" ); + SelectionQuery badQuery = session.createSelectionQuery( "delete Person", Person.class ); //end::example-hql-selection-query[] } ); } @@ -64,7 +64,7 @@ public void namedSelectionQueryTest(SessionFactoryScope scope) { scope.inTransaction( (session) -> { //tag::example-hql-named-selection-query[] // can be validated while creating the SelectionQuery - SelectionQuery badQuery = session.getNamedQuery( "delete_Person" ); + SelectionQuery badQuery = session.createNamedQuery( "delete_Person" ); //end::example-hql-named-selection-query[] } ); } @@ -75,7 +75,7 @@ public void namedQueryTest(SessionFactoryScope scope) { scope.inTransaction( (session) -> { //tag::example-hql-named-selection-query-query[] // cannot be validated until execution - Query query = session.getNamedQuery( "delete_Person" ); + Query query = session.createNamedQuery( "delete_Person" ); query.getResultList(); //end::example-hql-named-selection-query-query[] } ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/nofrom/NoFromTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/nofrom/NoFromTest.java index dade2b1068af..6743ac954a0b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/nofrom/NoFromTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/nofrom/NoFromTest.java @@ -49,14 +49,14 @@ public void test(SessionFactoryScope scope) { public void testError(SessionFactoryScope scope) { scope.inSession( s -> { try { - s.createSelectionQuery("where id = 1").getResultList(); + s.createSelectionQuery("where id = 1", Object.class).getResultList(); fail(); } catch (SemanticException se) {} }); scope.inSession( s -> { try { - s.createSelectionQuery("order by id desc").getResultList(); + s.createSelectionQuery("order by id desc", Object.class).getResultList(); fail(); } catch (SemanticException se) {} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/OneToManyAbstractTablePerClassTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/OneToManyAbstractTablePerClassTest.java index 9bef1e934f8a..0ddbc62c46fc 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/OneToManyAbstractTablePerClassTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/OneToManyAbstractTablePerClassTest.java @@ -118,7 +118,7 @@ public static abstract class TablePerClassBase { @OrderColumn(name = "listIndex") @JoinColumn(name = "listParent") List childrenList = new ArrayList<>(); - @MapKey(name = "id") + @MapKey("id") @OneToMany(mappedBy = "parent") Map childrenMap = new HashMap<>(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/discriminator/joinedsubclass/JoinedSubclassTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/discriminator/joinedsubclass/JoinedSubclassTest.java index 0b793b93bf1f..d583809d603b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/discriminator/joinedsubclass/JoinedSubclassTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/discriminator/joinedsubclass/JoinedSubclassTest.java @@ -65,7 +65,7 @@ public void shouldRetrieveSubEntity(SessionFactoryScope scope) { public void shouldNotRetrieveSubSubSubEntity(SessionFactoryScope scope) { scope.inSession( session -> { - SubSubSubEntity loaded = session.get( SubSubSubEntity.class, subSubEntityId ); + SubSubSubEntity loaded = session.find( SubSubSubEntity.class, subSubEntityId ); assertNull( loaded ); } ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/intg/AdditionalMappingContributorTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/intg/AdditionalMappingContributorTests.java index 0b8b7f339163..39cb8bbf1e92 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/intg/AdditionalMappingContributorTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/intg/AdditionalMappingContributorTests.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.List; +import java.util.Map; import org.hibernate.boot.ResourceStreamLocator; import org.hibernate.boot.models.HibernateAnnotations; @@ -66,7 +67,7 @@ void verifyClassContribution(DomainModelScope domainModelScope, SessionFactorySc sessionFactoryScope.inTransaction( (session) -> { //noinspection deprecation - final List results = session.createSelectionQuery( "from Entity2" ).list(); + final List results = session.createSelectionQuery( "from Entity2", Entity2.class ).list(); assertThat( results ).hasSize( 0 ); } ); } @@ -89,7 +90,7 @@ void verifyOrmXmlContribution(DomainModelScope domainModelScope, SessionFactoryS sessionFactoryScope.inTransaction( (session) -> { //noinspection deprecation - final List results = session.createSelectionQuery( "from Entity3" ).list(); + final List results = session.createSelectionQuery( "from Entity3", Entity3.class ).list(); assertThat( results ).hasSize( 0 ); } ); } @@ -121,11 +122,11 @@ void verifyJdkClassDetailsContributions( sessionFactoryScope.inTransaction( (session) -> { //noinspection deprecation - final List results4 = session.createSelectionQuery( "from Entity4" ).list(); + final List results4 = session.createSelectionQuery( "from Entity4", Entity4.class ).list(); assertThat( results4 ).hasSize( 0 ); //noinspection deprecation - final List results5 = session.createSelectionQuery( "from ___Entity5___" ).list(); + final List results5 = session.createSelectionQuery( "from ___Entity5___", Entity5.class ).list(); assertThat( results5 ).hasSize( 0 ); } ); } @@ -150,7 +151,7 @@ void verifyDynamicClassDetailsContributions( sessionFactoryScope.inTransaction( (session) -> { //noinspection deprecation - final List results6 = session.createSelectionQuery( "from Entity6" ).list(); + final List results6 = session.createSelectionQuery( "from Entity6", Map.class ).list(); assertThat( results6 ).hasSize( 0 ); } ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/intg/reactive/JdbcValuesMappingProducerProviderTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/intg/reactive/JdbcValuesMappingProducerProviderTests.java index 9830ee4ef0db..3f7792809c5d 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/intg/reactive/JdbcValuesMappingProducerProviderTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/intg/reactive/JdbcValuesMappingProducerProviderTests.java @@ -6,7 +6,7 @@ import org.hibernate.SessionFactory; import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.query.results.ResultSetMapping; +import org.hibernate.query.results.spi.ResultSetMapping; import org.hibernate.sql.ast.tree.select.SelectStatement; import org.hibernate.sql.results.jdbc.internal.JdbcValuesMappingProducerProviderStandard; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/iterate/ScrollTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/iterate/ScrollTest.java index 0adcc66043a5..cdc2fc83612a 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/iterate/ScrollTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/iterate/ScrollTest.java @@ -49,7 +49,7 @@ public void testScroll(SessionFactoryScope scope) { scope.inTransaction( s -> { - try (ScrollableResults sr = s.getNamedQuery( "Item.nameDesc" ).scroll()) { + try (ScrollableResults sr = s.createNamedQuery( "Item.nameDesc", Item.class ).scroll()) { assertTrue( sr.next() ); Item i1 = (Item) sr.get(); assertTrue( sr.next() ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jdbc/internal/AggressiveReleaseTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jdbc/internal/AggressiveReleaseTest.java index 2ec6f226f402..825599f35e8f 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jdbc/internal/AggressiveReleaseTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jdbc/internal/AggressiveReleaseTest.java @@ -282,7 +282,7 @@ public void testHql() { JdbcCoordinatorImpl jdbcCoord = (JdbcCoordinatorImpl) session.getJdbcCoordinator(); ResourceRegistry resourceRegistry = jdbcCoord.getLogicalConnection().getResourceRegistry(); - session.createSelectionQuery( "select 1" ).uniqueResult(); + session.createSelectionQuery( "select 1", Integer.class ).uniqueResult(); assertFalse( resourceRegistry.hasRegisteredResources() ); assertEquals( 0, connectionProvider.getAcquiredConnections().size() ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/join/JoinAndFetchWithCriteriaSelectionQueryTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/join/JoinAndFetchWithCriteriaSelectionQueryTest.java index 582b1df3ee63..a46f4352a03b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/join/JoinAndFetchWithCriteriaSelectionQueryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/join/JoinAndFetchWithCriteriaSelectionQueryTest.java @@ -73,8 +73,8 @@ void fetchBeforeJoinWithWhereClauseTest(SessionFactoryScope scope) { Root from = query.from( Book.class ); // The fetch MUST BE created before the join for this test - Fetch fetch = from.fetch( "authors" ); - Join join = from.join( "authors" ); + Fetch fetch = from.fetch( "authors" ); + Join join = from.join( "authors" ); query.where( cb.equal( join.get( "id" ), 2L ) ); // Because there's a filter on the association, they need to be two distinct joins @@ -100,8 +100,8 @@ void fetchAfterJoinWithWhereClauseTest(SessionFactoryScope scope) { Root from = query.from( Book.class ); // The join MUST BE created before the fetch for this test - Join join = from.join( "authors" ); - Fetch fetch = from.fetch( "authors" ); + Join join = from.join( "authors" ); + Fetch fetch = from.fetch( "authors" ); query.where( cb.equal( join.get( "id" ), 2L ) ); // Because there's a filter on the association, they need to be two distinct joins @@ -126,8 +126,8 @@ void fetchAfterJoinWithoutWhereClauseTest(SessionFactoryScope scope) { Root from = query.from( Book.class ); // The join MUST BE created before the fetch for this test - Join join = from.join( "authors" ); - Fetch fetch = from.fetch( "authors" ); + Join join = from.join( "authors" ); + Fetch fetch = from.fetch( "authors" ); // The current behaviour, but we could reuse the same join in this case assertThat( join ).isNotEqualTo( fetch ); @@ -160,8 +160,8 @@ void fetchBeforeJoinWithoutWhereClauseTest(SessionFactoryScope scope) { Root from = query.from( Book.class ); // The fetch MUST BE created before the join for this test - Fetch fetch = from.fetch( "authors" ); - Join join = from.join( "authors" ); + Fetch fetch = from.fetch( "authors" ); + Join join = from.join( "authors" ); // The current behaviour, but we could reuse the same join in this case assertThat( join ).isNotEqualTo( fetch ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/joinedsubclass/JoinedSubclassTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/joinedsubclass/JoinedSubclassTest.java index c1eb8e305344..ac8083466cb9 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/joinedsubclass/JoinedSubclassTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/joinedsubclass/JoinedSubclassTest.java @@ -52,15 +52,15 @@ public void testAccessAsIncorrectSubclass(SessionFactoryScope scope) { Customer c = scope.fromTransaction( session -> - session.get( Customer.class, e.getId() ) + session.find( Customer.class, e.getId() ) ); assertNull( c ); scope.inTransaction( session -> { - Employee employee = session.get( Employee.class, e.getId() ); - Customer customer = session.get( Customer.class, e.getId() ); + Employee employee = session.find( Employee.class, e.getId() ); + Customer customer = session.find( Customer.class, e.getId() ); assertNotNull( employee ); assertNull( customer ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/BaseEntityManagerFunctionalTestCase.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/BaseEntityManagerFunctionalTestCase.java index e883d9cf2035..a12db8c34010 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/BaseEntityManagerFunctionalTestCase.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/BaseEntityManagerFunctionalTestCase.java @@ -13,6 +13,7 @@ import java.util.Properties; import jakarta.persistence.EntityManager; +import jakarta.persistence.FetchType; import jakarta.persistence.SharedCacheMode; import jakarta.persistence.ValidationMode; import jakarta.persistence.PersistenceUnitTransactionType; @@ -128,12 +129,12 @@ public boolean isExcludeUnlistedClasses() { } @Override - public PersistenceUnitTransactionType getPersistenceUnitTransactionType() { - return null; + public FetchType getDefaultToOneFetchType() { + return FetchType.EAGER; } - @Override @SuppressWarnings("removal") - public jakarta.persistence.spi.PersistenceUnitTransactionType getTransactionType() { + @Override + public PersistenceUnitTransactionType getPersistenceUnitTransactionType() { return null; } @@ -188,11 +189,12 @@ public ClassLoader getTempClassLoader() { } @Override - public void pushClassTransformer(EnhancementContext enhancementContext) { + public boolean isClassTransformerRegistrationDisabled() { + return true; } @Override - public ClassTransformer getClassTransformer() { + public ClassTransformer pushClassTransformer(EnhancementContext enhancementContext) { return null; } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/compliance/CriteriaWrongResultClassTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/compliance/CriteriaWrongResultClassTest.java index 0aacacb4e603..0dada8d402c4 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/compliance/CriteriaWrongResultClassTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/compliance/CriteriaWrongResultClassTest.java @@ -59,7 +59,7 @@ public static class Department { @OneToMany @JoinTable(name = "DEPARTMENT_EMPLOYEE_TABLE") - @MapKey(name = "nickname") + @MapKey("nickname") private Map people = new HashMap<>(); public Department() { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/compliance/EntityManagerFindTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/compliance/EntityManagerFindTest.java index 3f7dc57b1b03..2810c1a3b9e0 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/compliance/EntityManagerFindTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/compliance/EntityManagerFindTest.java @@ -30,14 +30,11 @@ public class EntityManagerFindTest { @Test public void testFindWrongTypeAsId(EntityManagerFactoryScope scope) { - scope.inEntityManager( - entityManager -> - Assertions.assertThrows( - IllegalArgumentException.class, - () -> - entityManager.find( TestEntity.class, "ID" ) - ) - ); + scope.inEntityManager(entityManager -> + Assertions.assertThrows( + IllegalArgumentException.class, + () -> entityManager.find( TestEntity.class, "ID" ) + ) ); } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/CriteriaToOneIdJoinTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/CriteriaToOneIdJoinTest.java index 5bd772e00af6..7107674f4a3b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/CriteriaToOneIdJoinTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/CriteriaToOneIdJoinTest.java @@ -52,7 +52,7 @@ public void testIdJoin(EntityManagerFactoryScope scope) { final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); final CriteriaQuery query = cb.createQuery( ParentEntity.class ); final Root root = query.from( ParentEntity.class ); - final Join secondaryJoin = root.join( "child" ); + final Join secondaryJoin = root.join( "child" ); query.select( root ).orderBy( cb.asc( secondaryJoin.get( "name" ) ) ); final ParentEntity result = entityManager.createQuery( query ).getSingleResult(); assertThat( result.getChild().getName() ).isEqualTo( "child_entity" ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/TreatJoinTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/TreatJoinTest.java index 50e1cb974a0b..4d723f0af70c 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/TreatJoinTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/TreatJoinTest.java @@ -94,7 +94,7 @@ public void testTreatJoin2(EntityManagerFactoryScope scope) { CriteriaQuery query = cb.createQuery( Bid.class ); Root bid = query.from( Bid.class ); - Join item = bid.join( "item" ); + Join item = bid.join( "item" ); cb.treat( item, Book.class ); cb.treat( item, Car.class ); @@ -114,7 +114,7 @@ public void testJoinMethodOnATreatedJoin(EntityManagerFactoryScope scope) { Root bid = query.from( Bid.class ); final Join item = bid.join( "item" ); - final Join price = item.join( "price" ); + final Join price = item.join( "price" ); Join book = cb.treat( item, Book.class ); Join owner = book.join( "author" ); @@ -154,7 +154,7 @@ public void testJoinOnTreatedRoot(EntityManagerFactoryScope scope) { Root treatedRoot = cb.treat(root, Book.class); criteria.where( cb.equal( - treatedRoot.join("author").get("name"), + treatedRoot.join("author").get("name"), "Andrea Camilleri")); final List resultList = entityManager.createQuery( criteria.select( treatedRoot ) ).getResultList(); final Item item = resultList.get( 0 ); @@ -174,7 +174,7 @@ public void testJoinOnTreatedRootWithJoin(EntityManagerFactoryScope scope) { Root treatedRoot = cb.treat(root, Book.class); criteria.where( cb.equal( - treatedRoot.join("author").get("name"), + treatedRoot.join("author").get("name"), "Andrea Camilleri")); entityManager.createQuery(criteria.select(treatedRoot)).getResultList(); } ); @@ -187,8 +187,7 @@ public void testJoinOnTreatedJoin(EntityManagerFactoryScope scope) { CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery criteria = cb.createQuery(Bid.class); Root root = criteria.from(Bid.class); - Join join = cb.treat( - root. join("item"), Book.class) + Join join = cb.treat(root.join("item"), Book.class) .join("author"); criteria.where(cb.equal(join. get("name"), "Andrea Camilleri")); entityManager.createQuery(criteria.select(root)).getResultList(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/TreatKeywordTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/TreatKeywordTest.java index 15bf889274f7..938d226ab267 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/TreatKeywordTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/TreatKeywordTest.java @@ -251,7 +251,7 @@ public void testTypeFilterInSubquery(EntityManagerFactoryScope scope) { query.orderBy( cb.asc( root.get( "id" ) ) ); Subquery subquery = query.subquery( String.class ); Root subqueryRoot = subquery.correlate( root ); - Join other = subqueryRoot.join( "other" ); + Join other = subqueryRoot.join( "other" ); subquery.select( other.get( "name" ) ); subquery.where( cb.equal( root.type(), cb.literal( JoinedEntitySubclass.class ) ) ); query.select( subquery ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/model/MapOwner.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/model/MapOwner.java index e5d7f686aa30..39ce028ce3e3 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/model/MapOwner.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/model/MapOwner.java @@ -20,7 +20,7 @@ public class MapOwner { private Long id; @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) - @MapKey(name = "relationship") + @MapKey("relationship") private Map contents; public Long getId() { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/ops/GetLoadTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/ops/GetLoadTest.java index a2325db9f854..a3b93a314c4b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/ops/GetLoadTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/ops/GetLoadTest.java @@ -78,7 +78,7 @@ public void testGet(EntityManagerFactoryScope scope) { assertTrue( Hibernate.isInitialized( node ) ); assertFalse( Hibernate.isInitialized( node.getChildren() ) ); assertFalse( Hibernate.isInitialized( node.getParent() ) ); - assertNull( s.get( Node.class, "xyz" ) ); + assertNull( s.find( Node.class, "xyz" ) ); } ); @@ -207,7 +207,7 @@ public void testLoadIdNotFound_FieldBasedAccess(EntityManagerFactoryScope scope) entityManager.getTransaction().begin(); Session s = (Session) entityManager.getDelegate(); - assertNull( s.get( Workload.class, 999 ) ); + assertNull( s.find( Workload.class, 999 ) ); Workload proxy = s.getReference( Workload.class, 999 ); assertFalse( Hibernate.isInitialized( proxy ) ); @@ -252,7 +252,7 @@ public void testLoadIdNotFound_PropertyBasedAccess(EntityManagerFactoryScope sco entityManager.getTransaction().begin(); Session s = (Session) entityManager.getDelegate(); - assertNull( s.get( Employee.class, 999 ) ); + assertNull( s.find( Employee.class, 999 ) ); Employee proxy = s.getReference( Employee.class, 999 ); assertFalse( Hibernate.isInitialized( proxy ) ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/proxy/JPAProxyTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/proxy/JPAProxyTest.java index 0787e79faea2..0110eaffdfe8 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/proxy/JPAProxyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/proxy/JPAProxyTest.java @@ -13,8 +13,8 @@ import jakarta.persistence.EntityNotFoundException; import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.fail; /** * Test relation between proxies and get()/load() processing @@ -58,8 +58,12 @@ public void testGetSemantics() { Long nonExistentId = -1L; inTransaction( session -> { - Item item = session.get( Item.class, nonExistentId ); - assertNull( item , "get() of non-existent entity did not return null"); + try { + session.get( Item.class, nonExistentId ); + fail(); + } + catch (EntityNotFoundException expected) { + } } ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/ql/NamedNativeQueryTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/ql/NamedNativeQueryTest.java index 21cded380ad3..a1c6328a93cd 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/ql/NamedNativeQueryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/ql/NamedNativeQueryTest.java @@ -66,7 +66,7 @@ public void testSingleSelect(SessionFactoryScope scope) { final DestinationEntity destination = createDestination( scope, createFrom( scope, name, lastName ), fullName ); scope.inSession( session -> { - Query select = session.getNamedQuery( "DestinationEntity.selectIds" ); + Query select = session.createNamedQuery( "DestinationEntity.selectIds" ); select.setParameterList( "ids", Collections.singletonList( destination.id ) ); Object[] unique = (Object[]) select.uniqueResult(); // Compare the Strings, not the actual IDs. Can come back as, for ex, @@ -92,7 +92,7 @@ public void testMultipleSelect(SessionFactoryScope scope) { } scope.inSession( session -> { - Query select = session.getNamedQuery( "DestinationEntity.selectIds" ); + Query select = session.createNamedQuery( "DestinationEntity.selectIds" ); select.setParameterList( "ids", ids ); List list = select.list(); @@ -118,7 +118,7 @@ public void testInsertSingleValue(SessionFactoryScope scope) { final int id = 10000;// id fake scope.inTransaction( session -> { - Query insert = session.getNamedQuery( "DestinationEntity.insert" ); + Query insert = session.createNamedQuery( "DestinationEntity.insert" ); insert.setParameter( "generatedId", id ); insert.setParameter( "fromId", fromEntity.id ); insert.setParameter( "fullName", fullName ); @@ -150,7 +150,7 @@ public void testInsertMultipleValues(SessionFactoryScope scope) { } scope.inTransaction( session -> { - Query insertSelect = session.getNamedQuery( "DestinationEntity.insertSelect" ); + Query insertSelect = session.createNamedQuery( "DestinationEntity.insertSelect" ); insertSelect.setParameterList( "ids", ids ); int executeUpdate = insertSelect.executeUpdate(); assertEquals( quantity, executeUpdate ); @@ -180,7 +180,7 @@ public void testUpdateSingleValue(SessionFactoryScope scope) { final FromEntity anotherFrom = createFrom( scope, lastName, name ); scope.inTransaction( session -> { - Query update = session.getNamedQuery( "DestinationEntity.update" ); + Query update = session.createNamedQuery( "DestinationEntity.update" ); update.setParameter( "idFrom", anotherFrom.id ); update.setParameter( "fullName", inverseFullName ); update.setParameterList( "ids", Collections.singletonList( destinationEntity.id ) ); @@ -213,7 +213,7 @@ public void testUpdateMultipleValues(SessionFactoryScope scope) { final FromEntity anotherFrom = createFrom( scope, lastName, name ); scope.inTransaction( session -> { - Query update = session.getNamedQuery( "DestinationEntity.update" ); + Query update = session.createNamedQuery( "DestinationEntity.update" ); update.setParameter( "idFrom", anotherFrom.id ); update.setParameter( "fullName", inverseFullName ); update.setParameterList( "ids", ids ); @@ -243,7 +243,7 @@ public void testDeleteSingleValue(SessionFactoryScope scope) { final DestinationEntity destinationEntity = createDestination( scope, fromEntity, fullName ); scope.inTransaction( session -> { - Query delete = session.getNamedQuery( "DestinationEntity.delete" ); + Query delete = session.createNamedQuery( "DestinationEntity.delete" ); delete.setParameterList( "ids", Collections.singletonList( destinationEntity.id ) ); int executeUpdate = delete.executeUpdate(); @@ -269,7 +269,7 @@ public void testDeleteMultipleValues(SessionFactoryScope scope) { } scope.inTransaction( session -> { - Query delete = session.getNamedQuery( "DestinationEntity.delete" ); + Query delete = session.createNamedQuery( "DestinationEntity.delete" ); delete.setParameterList( "ids", ids ); int executeUpdate = delete.executeUpdate(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/ql/NamedNativeQueryWithGenericsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/ql/NamedNativeQueryWithGenericsTest.java index 7314db90549c..dd7b9a7bec88 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/ql/NamedNativeQueryWithGenericsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/ql/NamedNativeQueryWithGenericsTest.java @@ -56,7 +56,8 @@ public void testNamedNativeQuery(SessionFactoryScope scope) { name = "MyEntity.findMyEntity", query = "WITH all_my_entities AS " + "(SELECT me.* FROM my_entity me) " + - "SELECT {ame.*} FROM all_my_entities ame") + "SELECT {ame.*} FROM all_my_entities ame" + ) }) @Entity(name = "my_entity") @Table(name = "my_entity") diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NamedQueryFlushModeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NamedQueryFlushModeTest.java index 77427af166f1..3b33dd5549cf 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NamedQueryFlushModeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NamedQueryFlushModeTest.java @@ -39,7 +39,7 @@ public void testNamedQueryWithFlushModeManual(EntityManagerFactoryScope scope) { scope.inEntityManager( entityManager -> { Session s = entityManager.unwrap( Session.class ); - Query query = s.getNamedQuery( queryName ); + Query query = s.createNamedQuery( queryName ); assertEquals( FlushMode.MANUAL, query.getHibernateFlushMode() ); // JPA flush mode is an approximation assertEquals( jakarta.persistence.FlushModeType.COMMIT, query.getFlushMode() ); @@ -53,7 +53,7 @@ public void testNamedQueryWithFlushModeCommit(EntityManagerFactoryScope scope) { scope.inEntityManager( entityManager -> { Session s = entityManager.unwrap( Session.class ); - Query query = s.getNamedQuery( queryName ); + Query query = s.createNamedQuery( queryName ); assertEquals( FlushMode.COMMIT, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.COMMIT, query.getFlushMode() ); } @@ -66,7 +66,7 @@ public void testNamedQueryWithFlushModeAuto(EntityManagerFactoryScope scope) { scope.inEntityManager( entityManager -> { Session s = entityManager.unwrap( Session.class ); - Query query = s.getNamedQuery( queryName ); + Query query = s.createNamedQuery( queryName ); assertEquals( FlushMode.AUTO, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.AUTO, query.getFlushMode() ); } @@ -79,7 +79,7 @@ public void testNamedQueryWithFlushModeAlways(EntityManagerFactoryScope scope) { scope.inEntityManager( entityManager -> { Session s = entityManager.unwrap( Session.class ); - Query query = s.getNamedQuery( queryName ); + Query query = s.createNamedQuery( queryName ); assertEquals( FlushMode.ALWAYS, query.getHibernateFlushMode() ); // JPA flush mode is an approximation assertEquals( jakarta.persistence.FlushModeType.AUTO, query.getFlushMode() ); @@ -99,22 +99,22 @@ public void testNamedQueryWithFlushModePersistenceContext(EntityManagerFactorySc // JPA doesn't allow null flush modes, so we expect some approximation of the flush mode to be returned s.setHibernateFlushMode( FlushMode.MANUAL ); - query = s.getNamedQuery( queryName ); + query = s.createNamedQuery( queryName ); assertEquals( FlushMode.MANUAL, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.COMMIT, query.getFlushMode() ); s.setHibernateFlushMode( FlushMode.COMMIT ); - query = s.getNamedQuery( queryName ); + query = s.createNamedQuery( queryName ); assertEquals( FlushMode.COMMIT, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.COMMIT, query.getFlushMode() ); s.setHibernateFlushMode( FlushMode.AUTO ); - query = s.getNamedQuery( queryName ); + query = s.createNamedQuery( queryName ); assertEquals( FlushMode.AUTO, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.AUTO, query.getFlushMode() ); s.setHibernateFlushMode( FlushMode.ALWAYS ); - query = s.getNamedQuery( queryName ); + query = s.createNamedQuery( queryName ); assertEquals( FlushMode.ALWAYS, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.AUTO, query.getFlushMode() ); } @@ -127,7 +127,7 @@ public void testNamedNativeQueryWithFlushModeManual(EntityManagerFactoryScope sc scope.inEntityManager( entityManager -> { Session s = entityManager.unwrap( Session.class ); - NativeQuery query = s.getNamedNativeQuery( queryName ); + NativeQuery query = (NativeQuery) s.createNamedQuery( queryName ); assertEquals( FlushMode.MANUAL, query.getHibernateFlushMode() ); } ); @@ -139,7 +139,7 @@ public void testNamedNativeQueryWithFlushModeCommit(EntityManagerFactoryScope sc scope.inEntityManager( entityManager -> { Session s = entityManager.unwrap( Session.class ); - NativeQuery query = s.getNamedNativeQuery( queryName ); + NativeQuery query = (NativeQuery) s.createNamedQuery( queryName ); assertEquals( FlushMode.COMMIT, query.getHibernateFlushMode() ); } ); @@ -151,7 +151,7 @@ public void testNamedNativeQueryWithFlushModeAuto(EntityManagerFactoryScope scop scope.inEntityManager( entityManager -> { Session s = entityManager.unwrap( Session.class ); - NativeQuery query = s.getNamedNativeQuery( queryName ); + NativeQuery query = (NativeQuery) s.createNamedQuery( queryName ); assertEquals( FlushMode.AUTO, query.getHibernateFlushMode() ); } ); @@ -163,7 +163,7 @@ public void testNamedNativeQueryWithFlushModeAlways(EntityManagerFactoryScope sc scope.inEntityManager( entityManager -> { Session s = entityManager.unwrap( Session.class ); - NativeQuery query = s.getNamedNativeQuery( queryName ); + NativeQuery query = (NativeQuery) s.createNamedQuery( queryName ); assertEquals( FlushMode.ALWAYS, query.getHibernateFlushMode() ); } ); @@ -181,22 +181,22 @@ public void testNamedNativeQueryWithFlushModePersistenceContext(EntityManagerFac // JPA doesn't allow null flush modes, so we expect some approximation of the flush mode to be returned s.setHibernateFlushMode( FlushMode.MANUAL ); - query = s.getNamedNativeQuery( queryName ); + query = (NativeQuery) s.createNamedQuery( queryName ); assertEquals( FlushMode.MANUAL, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.COMMIT, query.getFlushMode() ); s.setHibernateFlushMode( FlushMode.COMMIT ); - query = s.getNamedNativeQuery( queryName ); + query = (NativeQuery) s.createNamedQuery( queryName ); assertEquals( FlushMode.COMMIT, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.COMMIT, query.getFlushMode() ); s.setHibernateFlushMode( FlushMode.AUTO ); - query = s.getNamedNativeQuery( queryName ); + query = (NativeQuery) s.createNamedQuery( queryName ); assertEquals( FlushMode.AUTO, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.AUTO, query.getFlushMode() ); s.setHibernateFlushMode( FlushMode.ALWAYS ); - query = s.getNamedNativeQuery( queryName ); + query = (NativeQuery) s.createNamedQuery( queryName ); assertEquals( FlushMode.ALWAYS, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.AUTO, query.getFlushMode() ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NamedQueryQueryFlushModeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NamedQueryQueryFlushModeTest.java index 9ad7b8e8b09f..2b3288fd016e 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NamedQueryQueryFlushModeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NamedQueryQueryFlushModeTest.java @@ -12,7 +12,6 @@ import org.hibernate.Session; import org.hibernate.annotations.NamedNativeQuery; import org.hibernate.annotations.NamedQuery; -import org.hibernate.query.NativeQuery; import org.hibernate.query.Query; import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; import org.hibernate.testing.orm.junit.JiraKey; @@ -36,7 +35,7 @@ public void testNamedQueryWithFlushModeManual(EntityManagerFactoryScope scope) { scope.inEntityManager( entityManager -> { Session s = entityManager.unwrap( Session.class ); - Query query = s.getNamedQuery( queryName ); + Query query = s.createNamedQuery( queryName ); assertEquals( FlushMode.MANUAL, query.getHibernateFlushMode() ); // JPA flush mode is an approximation assertEquals( jakarta.persistence.FlushModeType.COMMIT, query.getFlushMode() ); @@ -50,7 +49,7 @@ public void testNamedQueryWithFlushModeCommit(EntityManagerFactoryScope scope) { scope.inEntityManager( entityManager -> { Session s = entityManager.unwrap( Session.class ); - Query query = s.getNamedQuery( queryName ); + Query query = s.createNamedQuery( queryName ); assertEquals( FlushMode.MANUAL, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.COMMIT, query.getFlushMode() ); } @@ -63,7 +62,7 @@ public void testNamedQueryWithFlushModeAuto(EntityManagerFactoryScope scope) { scope.inEntityManager( entityManager -> { Session s = entityManager.unwrap( Session.class ); - Query query = s.getNamedQuery( queryName ); + Query query = s.createNamedQuery( queryName ); assertEquals( FlushMode.AUTO, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.AUTO, query.getFlushMode() ); } @@ -76,7 +75,7 @@ public void testNamedQueryWithFlushModeAlways(EntityManagerFactoryScope scope) { scope.inEntityManager( entityManager -> { Session s = entityManager.unwrap( Session.class ); - Query query = s.getNamedQuery( queryName ); + Query query = s.createNamedQuery( queryName ); assertEquals( FlushMode.ALWAYS, query.getHibernateFlushMode() ); // JPA flush mode is an approximation assertEquals( jakarta.persistence.FlushModeType.AUTO, query.getFlushMode() ); @@ -96,25 +95,25 @@ public void testNamedQueryWithFlushModePersistenceContext(EntityManagerFactorySc // JPA doesn't allow null flush modes, so we expect some approximation of the flush mode to be returned s.setHibernateFlushMode( FlushMode.MANUAL ); - query = s.getNamedQuery( queryName ); + query = s.createNamedQuery( queryName ); assertEquals( FlushMode.MANUAL, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.COMMIT, query.getFlushMode() ); assertEquals( QueryFlushMode.DEFAULT, query.getQueryFlushMode() ); s.setHibernateFlushMode( FlushMode.COMMIT ); - query = s.getNamedQuery( queryName ); + query = s.createNamedQuery( queryName ); assertEquals( FlushMode.COMMIT, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.COMMIT, query.getFlushMode() ); assertEquals( QueryFlushMode.DEFAULT, query.getQueryFlushMode() ); s.setHibernateFlushMode( FlushMode.AUTO ); - query = s.getNamedQuery( queryName ); + query = s.createNamedQuery( queryName ); assertEquals( FlushMode.AUTO, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.AUTO, query.getFlushMode() ); assertEquals( QueryFlushMode.DEFAULT, query.getQueryFlushMode() ); s.setHibernateFlushMode( FlushMode.ALWAYS ); - query = s.getNamedQuery( queryName ); + query = s.createNamedQuery( queryName ); assertEquals( FlushMode.ALWAYS, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.AUTO, query.getFlushMode() ); assertEquals( QueryFlushMode.DEFAULT, query.getQueryFlushMode() ); @@ -128,7 +127,7 @@ public void testNamedNativeQueryWithFlushModeManual(EntityManagerFactoryScope sc scope.inEntityManager( entityManager -> { Session s = entityManager.unwrap( Session.class ); - NativeQuery query = s.getNamedNativeQuery( queryName ); + Query query = s.createNamedQuery( queryName ); assertEquals( FlushMode.MANUAL, query.getHibernateFlushMode() ); assertEquals( QueryFlushMode.NO_FLUSH, query.getQueryFlushMode() ); } @@ -141,7 +140,7 @@ public void testNamedNativeQueryWithFlushModeCommit(EntityManagerFactoryScope sc scope.inEntityManager( entityManager -> { Session s = entityManager.unwrap( Session.class ); - NativeQuery query = s.getNamedNativeQuery( queryName ); + Query query = s.createNamedQuery( queryName ); assertEquals( FlushMode.MANUAL, query.getHibernateFlushMode() ); assertEquals( QueryFlushMode.NO_FLUSH, query.getQueryFlushMode() ); } @@ -154,7 +153,7 @@ public void testNamedNativeQueryWithFlushModeAuto(EntityManagerFactoryScope scop scope.inEntityManager( entityManager -> { Session s = entityManager.unwrap( Session.class ); - NativeQuery query = s.getNamedNativeQuery( queryName ); + Query query = s.createNamedQuery( queryName ); assertEquals( FlushMode.AUTO, query.getHibernateFlushMode() ); assertEquals( QueryFlushMode.DEFAULT, query.getQueryFlushMode() ); } @@ -167,7 +166,7 @@ public void testNamedNativeQueryWithFlushModeAlways(EntityManagerFactoryScope sc scope.inEntityManager( entityManager -> { Session s = entityManager.unwrap( Session.class ); - NativeQuery query = s.getNamedNativeQuery( queryName ); + Query query = s.createNamedQuery( queryName ); assertEquals( FlushMode.ALWAYS, query.getHibernateFlushMode() ); assertEquals( QueryFlushMode.FLUSH, query.getQueryFlushMode() ); } @@ -180,28 +179,28 @@ public void testNamedNativeQueryWithFlushModePersistenceContext(EntityManagerFac scope.inEntityManager( entityManager -> { Session s = entityManager.unwrap( Session.class ); - NativeQuery query; + Query query; // A null Hibernate flush mode means we will use whatever mode is set on the session // JPA doesn't allow null flush modes, so we expect some approximation of the flush mode to be returned s.setHibernateFlushMode( FlushMode.MANUAL ); - query = s.getNamedNativeQuery( queryName ); + query = s.createNamedQuery( queryName ); assertEquals( FlushMode.MANUAL, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.COMMIT, query.getFlushMode() ); s.setHibernateFlushMode( FlushMode.COMMIT ); - query = s.getNamedNativeQuery( queryName ); + query = s.createNamedQuery( queryName ); assertEquals( FlushMode.COMMIT, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.COMMIT, query.getFlushMode() ); s.setHibernateFlushMode( FlushMode.AUTO ); - query = s.getNamedNativeQuery( queryName ); + query = s.createNamedQuery( queryName ); assertEquals( FlushMode.AUTO, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.AUTO, query.getFlushMode() ); s.setHibernateFlushMode( FlushMode.ALWAYS ); - query = s.getNamedNativeQuery( queryName ); + query = s.createNamedQuery( queryName ); assertEquals( FlushMode.ALWAYS, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.AUTO, query.getFlushMode() ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NamedQueryTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NamedQueryTest.java index 5cde6135946a..b65b5c2c5eb3 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NamedQueryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NamedQueryTest.java @@ -96,7 +96,7 @@ public void testNamedQueryOrdinalParametersConflict2(EntityManagerFactoryScope s assertEquals( 1, list.size() ); final Session session = entityManager.unwrap( Session.class ); - final org.hibernate.query.Query sessionQuery = session.getNamedQuery( "NamedQuery" ); + final org.hibernate.query.Query sessionQuery = session.createNamedQuery( "NamedQuery" ); sessionQuery.setParameter( 1, GAME_TITLES[0] ); list = sessionQuery.getResultList(); @@ -146,8 +146,9 @@ public void testNativeNamedQueriesOrdinalParametersConflict2(EntityManagerFactor assertEquals( 1, list.size() ); final Session session = entityManager.unwrap( Session.class ); - final org.hibernate.query.Query sessionQuery = session.getNamedNativeQuery( - "NamedNativeQuery" ); + final org.hibernate.query.Query sessionQuery = session.createNamedQuery( + "NamedNativeQuery" + ); sessionQuery.setParameter( 1, GAME_TITLES[0] ); list = sessionQuery.getResultList(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/xml/versions/JpaXsdVersionsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/xml/versions/JpaXsdVersionsTest.java index 576ba3d89b43..fb155689b464 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/xml/versions/JpaXsdVersionsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/xml/versions/JpaXsdVersionsTest.java @@ -5,12 +5,13 @@ package org.hibernate.orm.test.jpa.xml.versions; import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.FetchType; import jakarta.persistence.PersistenceException; import jakarta.persistence.SharedCacheMode; import jakarta.persistence.ValidationMode; import jakarta.persistence.spi.ClassTransformer; import jakarta.persistence.spi.PersistenceUnitInfo; -import jakarta.persistence.spi.PersistenceUnitTransactionType; +import jakarta.persistence.PersistenceUnitTransactionType; import org.hibernate.AnnotationException; import org.hibernate.InvalidMappingException; @@ -146,6 +147,11 @@ public List getManagedClassNames() { return managedClassNames; } + @Override + public List getAllManagedClassNames() { + return managedClassNames; + } + public String getPersistenceProviderClassName() { return null; } @@ -184,6 +190,11 @@ public ValidationMode getValidationMode() { return null; } + @Override + public FetchType getDefaultToOneFetchType() { + return FetchType.EAGER; + } + private final Properties properties = new Properties(); public Properties getProperties() { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/keymanytoone/bidir/embedded/KeyManyToOneTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/keymanytoone/bidir/embedded/KeyManyToOneTest.java index 5747f7ef3dfb..c879b22ddc59 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/keymanytoone/bidir/embedded/KeyManyToOneTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/keymanytoone/bidir/embedded/KeyManyToOneTest.java @@ -48,7 +48,7 @@ public void testCriteriaRestrictionOnKeyManyToOne(SessionFactoryScope scope) { CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder(); CriteriaQuery criteria = criteriaBuilder.createQuery( Order.class ); Root root = criteria.from( Order.class ); - Join customer = root.join( "customer", JoinType.INNER ); + Join customer = root.join( "customer", JoinType.INNER ); criteria.where( criteriaBuilder.equal( customer.get( "name" ), "Acme" ) ); s.createQuery( criteria ).list(); } ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/legacy/ABCTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/legacy/ABCTest.java index 3e500ac39457..ccd25dab5481 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/legacy/ABCTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/legacy/ABCTest.java @@ -160,15 +160,15 @@ public void testSubclassing(SessionFactoryScope scope) { } @Test - public void testGetSave(SessionFactoryScope scope) { + public void testFindSave(SessionFactoryScope scope) { scope.inTransaction( session -> { - assertNull( session.get( D.class, 1L ) ); + assertNull( session.find( D.class, 1L ) ); D d = new D(); d.setId( 1L ); session.persist( d ); session.flush(); - assertNotNull( session.get( D.class, 1L ) ); + assertNotNull( session.find( D.class, 1L ) ); session.remove( d ); session.flush(); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/loaders/HqlSelectTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/loaders/HqlSelectTest.java index d8c45f2561c3..2bb84d30b10b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/loaders/HqlSelectTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/loaders/HqlSelectTest.java @@ -59,7 +59,7 @@ void test(SessionFactoryScope scope) { }); scope.inTransaction( s -> { - WithHqlSelect wss = s.get( WithHqlSelect.class, withHqlSelect.id ); + WithHqlSelect wss = s.find( WithHqlSelect.class, withHqlSelect.id ); assertNull( wss ); }); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/loading/LoadingSmokeTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/LoadingSmokeTests.java deleted file mode 100644 index b08bdfbb1d5e..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/loading/LoadingSmokeTests.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.test.loading; - -import org.hibernate.Hibernate; -import org.hibernate.loader.ast.internal.SingleIdEntityLoaderStandardImpl; -import org.hibernate.loader.ast.spi.SingleIdEntityLoader; -import org.hibernate.persister.entity.AbstractEntityPersister; - -import org.hibernate.testing.orm.domain.StandardDomainModel; -import org.hibernate.testing.orm.domain.gambit.BasicEntity; -import org.hibernate.testing.orm.junit.DomainModel; -import org.hibernate.testing.orm.junit.SessionFactory; -import org.hibernate.testing.orm.junit.SessionFactoryFunctionalTesting; -import org.hibernate.testing.orm.junit.SessionFactoryScope; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * @author Steve Ebersole - */ -@DomainModel( - standardModels = StandardDomainModel.GAMBIT -) -@SessionFactory -@SessionFactoryFunctionalTesting -public class LoadingSmokeTests { - @Test - public void testBasicLoad(SessionFactoryScope scope) { - scope.inTransaction( - session -> { - final BasicEntity loaded = session.byId( BasicEntity.class ).getReference( 1 ); - assertThat( loaded, notNullValue() ); - assertThat( Hibernate.isInitialized( loaded ), is( false ) ); - } - ); - } - - @Test - public void testBasicGet(SessionFactoryScope scope) { - scope.inTransaction( - session -> { - final BasicEntity gotten = session.byId( BasicEntity.class ).load( 1 ); - assertThat( gotten, notNullValue() ); - assertThat( Hibernate.isInitialized( gotten ), is( true ) ); - assertThat( gotten.getId(), is( 1 ) ); - assertThat( gotten.getData(), is( "first" ) ); - - final AbstractEntityPersister entityDescriptor = (AbstractEntityPersister) session.getSessionFactory() - .getRuntimeMetamodels().getMappingMetamodel() - .getEntityDescriptor( BasicEntity.class ); - - final SingleIdEntityLoader singleIdEntityLoader = entityDescriptor.getSingleIdLoader(); - assertThat( singleIdEntityLoader, instanceOf( SingleIdEntityLoaderStandardImpl.class ) ); - } - ); - } - - @BeforeAll - public void createTestData(SessionFactoryScope scope) { - scope.inTransaction( - session -> { - session.persist( new BasicEntity( 1, "first" ) ); - session.persist( new BasicEntity( 2, "second" ) ); - } - ); - } - - @AfterAll - public void deleteTestData(SessionFactoryScope scope) { - scope.inTransaction( - session -> { - session.doWork( - connection -> { - connection.prepareStatement( "delete from BasicEntity" ).execute(); - } - ); - } - ); - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/loading/multiLoad/FindMutipleTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/multiLoad/FindMutipleTest.java index 9c758697a571..b2cc26118a44 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/loading/multiLoad/FindMutipleTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/multiLoad/FindMutipleTest.java @@ -46,6 +46,7 @@ public class FindMutipleTest { assertSame(record, all.get(0)); }); } + @Entity static class Record { @Id Long id; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/loading/semantics/Base.java b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/semantics/Base.java new file mode 100644 index 000000000000..866521735d7e --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/semantics/Base.java @@ -0,0 +1,45 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.loading.semantics; + +import org.hibernate.testing.orm.domain.StandardDomainModel; +import org.hibernate.testing.orm.domain.library.Book; +import org.hibernate.testing.orm.domain.library.Person; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; + +/** + * @author Steve Ebersole + */ +@DomainModel(standardModels = StandardDomainModel.LIBRARY) +@SessionFactory +public abstract class Base { + @BeforeEach + void createTestData(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + var mistborn = new Book( 1, "Mistborn", "123" ); + var mistborn2 = new Book( 2, "The Well of Ascension", "456" ); + var mistborn3 = new Book( 3, "The Hero of Ages", "789" ); + + var sanderson = new Person( 1, "Brandon Sanderson" ); + mistborn.addAuthor( sanderson ); + mistborn2.addAuthor( sanderson ); + mistborn3.addAuthor( sanderson ); + + session.persist( mistborn ); + session.persist( mistborn2 ); + session.persist( mistborn3 ); + session.persist( sanderson ); + } ); + } + + @AfterEach + void dropTestData(SessionFactoryScope factoryScope) { + factoryScope.dropData(); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/loading/semantics/EntityGraphLoadSemanticTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/semantics/EntityGraphLoadSemanticTests.java new file mode 100644 index 000000000000..b1454f21ae32 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/semantics/EntityGraphLoadSemanticTests.java @@ -0,0 +1,181 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.loading.semantics; + +import jakarta.persistence.EntityGraph; +import jakarta.persistence.EntityNotFoundException; +import jakarta.persistence.LockModeType; +import org.hibernate.Hibernate; +import org.hibernate.graph.RootGraph; +import org.hibernate.testing.orm.domain.library.Book; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; + +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +/** + * Tests the semantics of the loading based on {@linkplain EntityGraph} using get/find methods. + * + * @see jakarta.persistence.EntityHandler#find(EntityGraph, Object, jakarta.persistence.FindOption...) + * @see jakarta.persistence.EntityHandler#get(EntityGraph, Object, jakarta.persistence.FindOption...) + * + * @author Steve Ebersole + */ +public class EntityGraphLoadSemanticTests extends Base { + @Test + void testTransactionalLoadingStateful(SessionFactoryScope factoryScope) { + final RootGraph graph = factoryScope.getSessionFactory().parseEntityGraph( Book.class, "authors" ); + + factoryScope.inTransaction( (session) -> { + final Book book = session.find( graph, 1 ); + assertThat( book ).isNotNull(); + assertThat( Hibernate.isInitialized( book.getAuthors() ) ).isTrue(); + assertThat( Hibernate.isInitialized( book.getEditors() ) ).isFalse(); + } ); + + factoryScope.inTransaction( (session) -> { + final Book book = session.get( graph, 1 ); + assertThat( book ).isNotNull(); + assertThat( Hibernate.isInitialized( book.getAuthors() ) ).isTrue(); + assertThat( Hibernate.isInitialized( book.getEditors() ) ).isFalse(); + } ); + } + + @Test + void testTransactionalLoadingStateless(SessionFactoryScope factoryScope) { + final RootGraph graph = factoryScope.getSessionFactory().parseEntityGraph( Book.class, "authors" ); + + factoryScope.inStatelessTransaction( (session) -> { + final Book book = session.find( graph, 1 ); + assertThat( book ).isNotNull(); + assertThat( Hibernate.isInitialized( book.getAuthors() ) ).isTrue(); + assertThat( Hibernate.isInitialized( book.getEditors() ) ).isFalse(); + } ); + + factoryScope.inStatelessTransaction( (session) -> { + final Book book = session.get( graph, 1 ); + assertThat( book ).isNotNull(); + assertThat( Hibernate.isInitialized( book.getAuthors() ) ).isTrue(); + assertThat( Hibernate.isInitialized( book.getEditors() ) ).isFalse(); + } ); + } + + @Test + void testNonTransactionalLoadingStateful(SessionFactoryScope factoryScope) { + final RootGraph graph = factoryScope.getSessionFactory().parseEntityGraph( Book.class, "authors" ); + + factoryScope.inSession( (session) -> { + final Book book = session.find( graph, 1 ); + assertThat( book ).isNotNull(); + assertThat( Hibernate.isInitialized( book.getAuthors() ) ).isTrue(); + assertThat( Hibernate.isInitialized( book.getEditors() ) ).isFalse(); + } ); + + factoryScope.inSession( (session) -> { + final Book book = session.get( graph, 1 ); + assertThat( book ).isNotNull(); + assertThat( Hibernate.isInitialized( book.getAuthors() ) ).isTrue(); + assertThat( Hibernate.isInitialized( book.getEditors() ) ).isFalse(); + } ); + } + + @Test + void testNonTransactionalLoadingStateless(SessionFactoryScope factoryScope) { + final RootGraph graph = factoryScope.getSessionFactory().parseEntityGraph( Book.class, "authors" ); + + factoryScope.inStatelessSession( (session) -> { + final Book book = session.find( graph, 1 ); + assertThat( book ).isNotNull(); + assertThat( Hibernate.isInitialized( book.getAuthors() ) ).isTrue(); + assertThat( Hibernate.isInitialized( book.getEditors() ) ).isFalse(); + } ); + + factoryScope.inStatelessSession( (session) -> { + final Book book = session.get( graph, 1 ); + assertThat( book ).isNotNull(); + assertThat( Hibernate.isInitialized( book.getAuthors() ) ).isTrue(); + assertThat( Hibernate.isInitialized( book.getEditors() ) ).isFalse(); + } ); + } + + @Test + void testNoMatchStateful(SessionFactoryScope factoryScope) { + final RootGraph graph = factoryScope.getSessionFactory().parseEntityGraph( Book.class, "authors" ); + + factoryScope.inTransaction( (session) -> { + final Book book = session.find( graph, 5, LockModeType.PESSIMISTIC_READ ); + assertThat( book ).isNull(); + } ); + factoryScope.inTransaction( (session) -> { + try { + session.get( graph, 5, LockModeType.PESSIMISTIC_READ ); + fail( "Expecting failure" ); + } + catch (EntityNotFoundException expected) {} + } ); + } + + @Test + void testNoMatchStateless(SessionFactoryScope factoryScope) { + final RootGraph graph = factoryScope.getSessionFactory().parseEntityGraph( Book.class, "authors" ); + + factoryScope.inStatelessTransaction( (session) -> { + final Book book = session.find( graph, 5, LockModeType.PESSIMISTIC_READ ); + assertThat( book ).isNull(); + } ); + factoryScope.inStatelessTransaction( (session) -> { + try { + session.get( graph, 5, LockModeType.PESSIMISTIC_READ ); + fail( "Expecting failure" ); + } + catch (EntityNotFoundException expected) {} + } ); + } + + @Test + void testBadKeyTypeStateful(SessionFactoryScope factoryScope) { + var uuid = UUID.randomUUID(); + final RootGraph graph = factoryScope.getSessionFactory().parseEntityGraph( Book.class, "authors" ); + + factoryScope.inTransaction( (session) -> { + try { + session.find( graph, uuid, LockModeType.PESSIMISTIC_READ ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + factoryScope.inTransaction( (session) -> { + try { + session.get( graph, uuid, LockModeType.PESSIMISTIC_READ ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + } + + @Test + void testBadKeyTypeStateless(SessionFactoryScope factoryScope) { + var uuid = UUID.randomUUID(); + final RootGraph graph = factoryScope.getSessionFactory().parseEntityGraph( Book.class, "authors" ); + + factoryScope.inStatelessTransaction( (session) -> { + try { + session.find( graph, uuid, LockModeType.PESSIMISTIC_READ ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + factoryScope.inStatelessTransaction( (session) -> { + try { + session.get( graph, uuid, LockModeType.PESSIMISTIC_READ ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/loading/semantics/LockingLoadSemanticTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/semantics/LockingLoadSemanticTests.java new file mode 100644 index 000000000000..e406c46c8015 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/semantics/LockingLoadSemanticTests.java @@ -0,0 +1,197 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.loading.semantics; + +import jakarta.persistence.EntityNotFoundException; +import jakarta.persistence.LockModeType; +import jakarta.persistence.TransactionRequiredException; +import org.hibernate.testing.orm.domain.library.Book; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; + +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +/** + * Tests the semantics of the loading with locks using get/find methods. + * + * @see jakarta.persistence.EntityHandler#find(Class, Object, jakarta.persistence.FindOption...) + * @see jakarta.persistence.EntityHandler#get(Class, Object, jakarta.persistence.FindOption...) + * + * @author Steve Ebersole + */ +public class LockingLoadSemanticTests extends Base { + @Test + void testTransactionalLoadingStateful(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + var book = session.find( Book.class, 1, LockModeType.PESSIMISTIC_WRITE ); + assertThat( book ).isNotNull(); + } ); + + factoryScope.inTransaction( (session) -> { + var book = session.get( Book.class, 1, LockModeType.PESSIMISTIC_WRITE ); + assertThat( book ).isNotNull(); + } ); + } + + @Test + void testTransactionalLoadingStateless(SessionFactoryScope factoryScope) { + factoryScope.inStatelessTransaction( (session) -> { + var book = session.find( Book.class, 1, LockModeType.PESSIMISTIC_WRITE ); + assertThat( book ).isNotNull(); + } ); + + factoryScope.inStatelessTransaction( (session) -> { + var book = session.get( Book.class, 1, LockModeType.PESSIMISTIC_WRITE ); + assertThat( book ).isNotNull(); + } ); + } + + @Test + void testNonTransactionalLoadingStateful(SessionFactoryScope factoryScope) { + factoryScope.inSession( (session) -> { + try { + session.find( Book.class, 1, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (TransactionRequiredException expected) {} + } ); + + factoryScope.inSession( (session) -> { + try { + session.get( Book.class, 1, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (TransactionRequiredException expected) {} + } ); + } + + @Test + void testNonTransactionalLoadingStateless(SessionFactoryScope factoryScope) { + factoryScope.inStatelessSession( (session) -> { + try { + session.find( Book.class, 1, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (TransactionRequiredException expected) {} + } ); + + factoryScope.inStatelessSession( (session) -> { + try { + session.get( Book.class, 1, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (TransactionRequiredException expected) {} + } ); + } + + @Test + void testNoMatchStateful(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + var book = session.find( Book.class, 9, LockModeType.PESSIMISTIC_WRITE ); + assertThat( book ).isNull(); + } ); + factoryScope.inTransaction( (session) -> { + try { + session.get( Book.class, 9, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (EntityNotFoundException expected) {} + } ); + } + + @Test + void testNoMatchStateless(SessionFactoryScope factoryScope) { + factoryScope.inStatelessTransaction( (session) -> { + var book = session.find( Book.class, 9, LockModeType.PESSIMISTIC_WRITE ); + assertThat( book ).isNull(); + } ); + factoryScope.inStatelessTransaction( (session) -> { + try { + session.get( Book.class, 9, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (EntityNotFoundException expected) {} + } ); + } + + @Test + void testBadKeyTypeStateful(SessionFactoryScope factoryScope) { + var uuid = UUID.randomUUID(); + + factoryScope.inTransaction( (session) -> { + try { + session.find( Book.class, uuid, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + factoryScope.inTransaction( (session) -> { + try { + session.get( Book.class, uuid, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + } + + @Test + void testBadKeyTypeStateless(SessionFactoryScope factoryScope) { + var uuid = UUID.randomUUID(); + + factoryScope.inTransaction( (session) -> { + try { + session.find( Book.class, uuid, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + factoryScope.inTransaction( (session) -> { + try { + session.get( Book.class, uuid, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + } + + @Test + void testBadEntityTypeStateful(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + try { + session.find( Long.class, 1, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + factoryScope.inTransaction( (session) -> { + try { + session.get( Long.class, 1, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + } + + @Test + void testBadEntityTypeStateless(SessionFactoryScope factoryScope) { + factoryScope.inStatelessTransaction( (session) -> { + try { + session.find( Long.class, 1, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + factoryScope.inStatelessTransaction( (session) -> { + try { + session.get( Long.class, 1, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/loading/semantics/NaturalIdLoadSemanticTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/semantics/NaturalIdLoadSemanticTests.java new file mode 100644 index 000000000000..4bf8276cc53d --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/semantics/NaturalIdLoadSemanticTests.java @@ -0,0 +1,184 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.loading.semantics; + +import jakarta.persistence.EntityNotFoundException; +import org.hibernate.KeyType; +import org.hibernate.testing.orm.domain.library.Book; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; + +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +/** + * Tests the semantics of the loading based on natural id using get/find methods. + * + * @see jakarta.persistence.EntityHandler#find(Class, Object, jakarta.persistence.FindOption...) + * @see jakarta.persistence.EntityHandler#get(Class, Object, jakarta.persistence.FindOption...) + * + * @author Steve Ebersole + */ +public class NaturalIdLoadSemanticTests extends Base { + @Test + void testTransactionalLoadingStateful(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + var book = session.find( Book.class, "123", KeyType.NATURAL ); + assertThat( book ).isNotNull(); + } ); + + factoryScope.inTransaction( (session) -> { + var book = session.get( Book.class, "123", KeyType.NATURAL ); + assertThat( book ).isNotNull(); + } ); + } + + @Test + void testTransactionalLoadingStateless(SessionFactoryScope factoryScope) { + factoryScope.inStatelessTransaction( (session) -> { + var book = session.find( Book.class, "123", KeyType.NATURAL ); + assertThat( book ).isNotNull(); + } ); + + factoryScope.inStatelessTransaction( (session) -> { + var book = session.get( Book.class, "123", KeyType.NATURAL ); + assertThat( book ).isNotNull(); + } ); + } + + @Test + void testNonTransactionalLoadingStateful(SessionFactoryScope factoryScope) { + factoryScope.inSession( (session) -> { + var book = session.find( Book.class, "123", KeyType.NATURAL ); + assertThat( book ).isNotNull(); + } ); + + factoryScope.inSession( (session) -> { + var book = session.get( Book.class, "123", KeyType.NATURAL ); + assertThat( book ).isNotNull(); + } ); + } + + @Test + void testNonTransactionalLoadingStateless(SessionFactoryScope factoryScope) { + factoryScope.inStatelessSession( (session) -> { + var book = session.find( Book.class, "123", KeyType.NATURAL ); + assertThat( book ).isNotNull(); + } ); + + factoryScope.inStatelessSession( (session) -> { + var book = session.get( Book.class, "123", KeyType.NATURAL ); + assertThat( book ).isNotNull(); + } ); + } + + @Test + void testNoMatchStateful(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + var book = session.find( Book.class, "987", KeyType.NATURAL ); + assertThat( book ).isNull(); + } ); + factoryScope.inTransaction( (session) -> { + try { + session.get( Book.class, "987", KeyType.NATURAL ); + fail( "Expecting failure" ); + } + catch (EntityNotFoundException expected) {} + } ); + } + + @Test + void testNoMatchStateless(SessionFactoryScope factoryScope) { + factoryScope.inStatelessTransaction( (session) -> { + var book = session.find( Book.class, "987", KeyType.NATURAL ); + assertThat( book ).isNull(); + } ); + factoryScope.inStatelessTransaction( (session) -> { + try { + session.get( Book.class, "987", KeyType.NATURAL ); + fail( "Expecting failure" ); + } + catch (EntityNotFoundException expected) {} + } ); + } + + @Test + void testBadKeyTypeStateful(SessionFactoryScope factoryScope) { + var uuid = UUID.randomUUID(); + + factoryScope.inTransaction( (session) -> { + try { + session.find( Book.class, uuid, KeyType.NATURAL ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + factoryScope.inTransaction( (session) -> { + try { + session.get( Book.class, uuid, KeyType.NATURAL ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + } + + @Test + void testBadKeyTypeStateless(SessionFactoryScope factoryScope) { + var uuid = UUID.randomUUID(); + + factoryScope.inTransaction( (session) -> { + try { + session.find( Book.class, uuid, KeyType.NATURAL ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + factoryScope.inTransaction( (session) -> { + try { + session.get( Book.class, uuid, KeyType.NATURAL ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + } + + @Test + void testBadEntityTypeStateful(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + try { + session.find( Long.class, "123", KeyType.NATURAL ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + factoryScope.inTransaction( (session) -> { + try { + session.get( Long.class, "123", KeyType.NATURAL ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + } + + @Test + void testBadEntityTypeStateless(SessionFactoryScope factoryScope) { + factoryScope.inStatelessTransaction( (session) -> { + try { + session.find( Long.class, "123", KeyType.NATURAL ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + factoryScope.inStatelessTransaction( (session) -> { + try { + session.get( Long.class, "123", KeyType.NATURAL ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/loading/semantics/NaturalIdLockingLoadSemanticTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/semantics/NaturalIdLockingLoadSemanticTests.java new file mode 100644 index 000000000000..de8b5bfdc7dd --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/semantics/NaturalIdLockingLoadSemanticTests.java @@ -0,0 +1,198 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.loading.semantics; + +import jakarta.persistence.EntityNotFoundException; +import jakarta.persistence.LockModeType; +import jakarta.persistence.TransactionRequiredException; +import org.hibernate.KeyType; +import org.hibernate.testing.orm.domain.library.Book; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; + +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +/** + * Tests the semantics of the loading based on natural id with locks using get/find methods. + * + * @see jakarta.persistence.EntityHandler#find(Class, Object, jakarta.persistence.FindOption...) + * @see jakarta.persistence.EntityHandler#get(Class, Object, jakarta.persistence.FindOption...) + * + * @author Steve Ebersole + */ +public class NaturalIdLockingLoadSemanticTests extends Base { + @Test + void testTransactionalLoadingStateful(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + var book = session.find( Book.class, "123", KeyType.NATURAL, LockModeType.PESSIMISTIC_WRITE ); + assertThat( book ).isNotNull(); + } ); + + factoryScope.inTransaction( (session) -> { + var book = session.get( Book.class, "123", KeyType.NATURAL, LockModeType.PESSIMISTIC_WRITE ); + assertThat( book ).isNotNull(); + } ); + } + + @Test + void testTransactionalLoadingStateless(SessionFactoryScope factoryScope) { + factoryScope.inStatelessTransaction( (session) -> { + var book = session.find( Book.class, "123", KeyType.NATURAL, LockModeType.PESSIMISTIC_WRITE ); + assertThat( book ).isNotNull(); + } ); + + factoryScope.inStatelessTransaction( (session) -> { + var book = session.get( Book.class, "123", KeyType.NATURAL, LockModeType.PESSIMISTIC_WRITE ); + assertThat( book ).isNotNull(); + } ); + } + + @Test + void testNonTransactionalLoadingStateful(SessionFactoryScope factoryScope) { + factoryScope.inSession( (session) -> { + try { + session.find( Book.class, "123", KeyType.NATURAL, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (TransactionRequiredException expected) {} + } ); + + factoryScope.inSession( (session) -> { + try { + session.get( Book.class, "123", KeyType.NATURAL, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (TransactionRequiredException expected) {} + } ); + } + + @Test + void testNonTransactionalLoadingStateless(SessionFactoryScope factoryScope) { + factoryScope.inStatelessSession( (session) -> { + try { + session.find( Book.class, "123", KeyType.NATURAL, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (TransactionRequiredException expected) {} + } ); + + factoryScope.inStatelessSession( (session) -> { + try { + session.get( Book.class, "123", KeyType.NATURAL, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (TransactionRequiredException expected) {} + } ); + } + + @Test + void testNoMatchStateful(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + var book = session.find( Book.class, "987", KeyType.NATURAL, LockModeType.PESSIMISTIC_WRITE ); + assertThat( book ).isNull(); + } ); + factoryScope.inTransaction( (session) -> { + try { + session.get( Book.class, "987", KeyType.NATURAL, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (EntityNotFoundException expected) {} + } ); + } + + @Test + void testNoMatchStateless(SessionFactoryScope factoryScope) { + factoryScope.inStatelessTransaction( (session) -> { + var book = session.find( Book.class, "987", KeyType.NATURAL, LockModeType.PESSIMISTIC_WRITE ); + assertThat( book ).isNull(); + } ); + factoryScope.inStatelessTransaction( (session) -> { + try { + session.get( Book.class, "987", KeyType.NATURAL, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (EntityNotFoundException expected) {} + } ); + } + + @Test + void testBadKeyTypeStateful(SessionFactoryScope factoryScope) { + var uuid = UUID.randomUUID(); + + factoryScope.inTransaction( (session) -> { + try { + session.find( Book.class, uuid, KeyType.NATURAL, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + factoryScope.inTransaction( (session) -> { + try { + session.get( Book.class, uuid, KeyType.NATURAL, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + } + + @Test + void testBadKeyTypeStateless(SessionFactoryScope factoryScope) { + var uuid = UUID.randomUUID(); + + factoryScope.inTransaction( (session) -> { + try { + session.find( Book.class, uuid, KeyType.NATURAL, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + factoryScope.inTransaction( (session) -> { + try { + session.get( Book.class, uuid, KeyType.NATURAL, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + } + + @Test + void testBadEntityTypeStateful(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + try { + session.find( Long.class, "123", KeyType.NATURAL, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + factoryScope.inTransaction( (session) -> { + try { + session.get( Long.class, "123", KeyType.NATURAL, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + } + + @Test + void testBadEntityTypeStateless(SessionFactoryScope factoryScope) { + factoryScope.inStatelessTransaction( (session) -> { + try { + session.find( Long.class, "123", KeyType.NATURAL, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + factoryScope.inStatelessTransaction( (session) -> { + try { + session.get( Long.class, "123", KeyType.NATURAL, LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/loading/semantics/SimpleLoadSemanticTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/semantics/SimpleLoadSemanticTests.java new file mode 100644 index 000000000000..42c752d19907 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/semantics/SimpleLoadSemanticTests.java @@ -0,0 +1,183 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.loading.semantics; + +import jakarta.persistence.EntityNotFoundException; +import org.hibernate.testing.orm.domain.library.Book; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; + +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +/** + * Tests the semantics of the simplest of the get/find methods. + * + * @see jakarta.persistence.EntityHandler#find(Class, Object) + * @see jakarta.persistence.EntityHandler#get(Class, Object) + * + * @author Steve Ebersole + */ +public class SimpleLoadSemanticTests extends Base { + @Test + void testTransactionalLoadingStateful(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + var book = session.find( Book.class, 1 ); + assertThat( book ).isNotNull(); + } ); + + factoryScope.inTransaction( (session) -> { + var book = session.get( Book.class, 1 ); + assertThat( book ).isNotNull(); + } ); + } + + @Test + void testTransactionalLoadingStateless(SessionFactoryScope factoryScope) { + factoryScope.inStatelessTransaction( (session) -> { + var book = session.find( Book.class, 1 ); + assertThat( book ).isNotNull(); + } ); + + factoryScope.inStatelessTransaction( (session) -> { + var book = session.get( Book.class, 1 ); + assertThat( book ).isNotNull(); + } ); + } + + @Test + void testNonTransactionalLoadingStateful(SessionFactoryScope factoryScope) { + factoryScope.inSession( (session) -> { + var book = session.find( Book.class, 1 ); + assertThat( book ).isNotNull(); + } ); + + factoryScope.inSession( (session) -> { + var book = session.get( Book.class, 1 ); + assertThat( book ).isNotNull(); + } ); + } + + @Test + void testNonTransactionalLoadingStateless(SessionFactoryScope factoryScope) { + factoryScope.inStatelessSession( (session) -> { + var book = session.find( Book.class, 1 ); + assertThat( book ).isNotNull(); + } ); + + factoryScope.inStatelessSession( (session) -> { + var book = session.get( Book.class, 1 ); + assertThat( book ).isNotNull(); + } ); + } + + @Test + void testNoMatchStateful(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + var book = session.find( Book.class, 5 ); + assertThat( book ).isNull(); + } ); + factoryScope.inTransaction( (session) -> { + try { + session.get( Book.class, 5 ); + fail( "Expecting failure" ); + } + catch (EntityNotFoundException expected) {} + } ); + } + + @Test + void testNoMatchStateless(SessionFactoryScope factoryScope) { + factoryScope.inStatelessTransaction( (session) -> { + var book = session.find( Book.class, 5 ); + assertThat( book ).isNull(); + } ); + factoryScope.inStatelessTransaction( (session) -> { + try { + session.get( Book.class, 5 ); + fail( "Expecting failure" ); + } + catch (EntityNotFoundException expected) {} + } ); + } + + @Test + void testBadKeyTypeStateful(SessionFactoryScope factoryScope) { + var uuid = UUID.randomUUID(); + + factoryScope.inTransaction( (session) -> { + try { + session.find( Book.class, uuid ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + factoryScope.inTransaction( (session) -> { + try { + session.get( Book.class, uuid ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + } + + @Test + void testBadKeyTypeStateless(SessionFactoryScope factoryScope) { + var uuid = UUID.randomUUID(); + + factoryScope.inStatelessTransaction( (session) -> { + try { + session.find( Book.class, uuid ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + factoryScope.inStatelessTransaction( (session) -> { + try { + session.get( Book.class, uuid ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + } + + @Test + void testBadEntityTypeStateful(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + try { + session.find( Long.class, 1 ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + factoryScope.inTransaction( (session) -> { + try { + session.get( Long.class, 1 ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + } + + @Test + void testBadEntityTypeStateless(SessionFactoryScope factoryScope) { + factoryScope.inStatelessTransaction( (session) -> { + try { + session.find( Long.class, 1 ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + factoryScope.inStatelessTransaction( (session) -> { + try { + session.get( Long.class, 1 ); + fail( "Expecting failure" ); + } + catch (IllegalArgumentException expected) {} + } ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/loading/semantics/package-info.java b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/semantics/package-info.java new file mode 100644 index 000000000000..f70a3e9f68ac --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/semantics/package-info.java @@ -0,0 +1,13 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ + +/** + * Tests the semantics of the various {@linkplain jakarta.persistence.EntityHandler#find} + * and {@linkplain jakarta.persistence.EntityHandler#get} methods in terms of defined + * expectations. + * + * @author Steve Ebersole + */ +package org.hibernate.orm.test.loading.semantics; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/locking/options/LockedRowsTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/options/LockedRowsTests.java index 09936208ff1c..efd09372a89f 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/locking/options/LockedRowsTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/options/LockedRowsTests.java @@ -5,6 +5,7 @@ package org.hibernate.orm.test.locking.options; import jakarta.persistence.LockModeType; +import jakarta.persistence.LockTimeoutException; import jakarta.persistence.Timeout; import org.hibernate.PessimisticLockException; import org.hibernate.community.dialect.InformixDialect; @@ -78,7 +79,8 @@ void testFindNoWait(SessionFactoryScope factoryScope) { session2.find(Book.class,1, PESSIMISTIC_WRITE, NO_WAIT); fail("Expecting a failure due to locked rows and no-wait"); } - catch (PessimisticLockException expected) { + catch (LockTimeoutException expected) { + System.out.println( "Caught expected exception - " + expected ); } } ); } ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/manytomany/mapkey/ManyToManyMapKeyTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomany/mapkey/ManyToManyMapKeyTest.java index abca704d3340..6dae343808e5 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/manytomany/mapkey/ManyToManyMapKeyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomany/mapkey/ManyToManyMapKeyTest.java @@ -150,7 +150,7 @@ public static class MapContainer { private String name; @ManyToMany(cascade = CascadeType.REMOVE) - @MapKey(name = "mapKey") + @MapKey("mapKey") private Map map = new HashMap<>(); public MapContainer() { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/manytomany/mapkey/ManyToManyWithMaykeyAndSchemaDefinitionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomany/mapkey/ManyToManyWithMaykeyAndSchemaDefinitionTest.java index e7170f8a8cc7..1e413e83a8fd 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/manytomany/mapkey/ManyToManyWithMaykeyAndSchemaDefinitionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomany/mapkey/ManyToManyWithMaykeyAndSchemaDefinitionTest.java @@ -93,7 +93,7 @@ public static class EntityA { private String name; @ManyToMany - @MapKey(name = "id") + @MapKey("id") @JoinTable(name = "entitya_entityb", schema = "myschema", joinColumns = @JoinColumn(name = "entitya_pk"), inverseJoinColumns = @JoinColumn(name = "entityb_pk")) private Map entityBMap = new HashMap<>(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/AbstractManyToManyAssociationClassTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/AbstractManyToManyAssociationClassTest.java index fd12906efc12..7ea72af79575 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/AbstractManyToManyAssociationClassTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/AbstractManyToManyAssociationClassTest.java @@ -65,27 +65,22 @@ public void testRemoveAndAddSameElement(SessionFactoryScope scope) { deleteMembership( user, group, membership ); addMembership( user, group, membership ); - scope.inTransaction( - session -> - session.merge( user ) - ); - - scope.inTransaction( - session -> { - user = session.get( User.class, user.getId() ); - group = session.get( Group.class, group.getId() ); - membership = session.get( membership.getClass(), membership.getId() ); - assertEquals( "user", user.getName() ); - assertEquals( "group", group.getName() ); - assertEquals( "membership", membership.getName() ); - assertEquals( 1, user.getMemberships().size() ); - assertEquals( 1, group.getMemberships().size() ); - assertSame( membership, user.getMemberships().iterator().next() ); - assertSame( membership, group.getMemberships().iterator().next() ); - assertSame( user, membership.getUser() ); - assertSame( group, membership.getGroup() ); - } - ); + scope.inTransaction( session -> session.merge( user ) ); + + scope.inTransaction( session -> { + user = session.get( User.class, user.getId() ); + group = session.get( Group.class, group.getId() ); + membership = session.get( membership.getClass(), membership.getId() ); + assertEquals( "user", user.getName() ); + assertEquals( "group", group.getName() ); + assertEquals( "membership", membership.getName() ); + assertEquals( 1, user.getMemberships().size() ); + assertEquals( 1, group.getMemberships().size() ); + assertSame( membership, user.getMemberships().iterator().next() ); + assertSame( membership, group.getMemberships().iterator().next() ); + assertSame( user, membership.getUser() ); + assertSame( group, membership.getGroup() ); + } ); } @Test @@ -94,27 +89,22 @@ public void testRemoveAndAddEqualElement(SessionFactoryScope scope) { membership = createMembership( "membership" ); addMembership( user, group, membership ); - scope.inTransaction( - session -> - session.merge( user ) - ); - - scope.inTransaction( - session -> { - user = session.get( User.class, user.getId() ); - group = session.get( Group.class, group.getId() ); - membership = session.get( membership.getClass(), membership.getId() ); - assertEquals( "user", user.getName() ); - assertEquals( "group", group.getName() ); - assertEquals( "membership", membership.getName() ); - assertEquals( 1, user.getMemberships().size() ); - assertEquals( 1, group.getMemberships().size() ); - assertSame( membership, user.getMemberships().iterator().next() ); - assertSame( membership, group.getMemberships().iterator().next() ); - assertSame( user, membership.getUser() ); - assertSame( group, membership.getGroup() ); - } - ); + scope.inTransaction( session -> session.merge( user ) ); + + scope.inTransaction( session -> { + user = session.get( User.class, user.getId() ); + group = session.get( Group.class, group.getId() ); + membership = session.get( membership.getClass(), membership.getId() ); + assertEquals( "user", user.getName() ); + assertEquals( "group", group.getName() ); + assertEquals( "membership", membership.getName() ); + assertEquals( 1, user.getMemberships().size() ); + assertEquals( 1, group.getMemberships().size() ); + assertSame( membership, user.getMemberships().iterator().next() ); + assertSame( membership, group.getMemberships().iterator().next() ); + assertSame( user, membership.getUser() ); + assertSame( group, membership.getGroup() ); + } ); } @Test @@ -125,27 +115,22 @@ public void testRemoveAndAddEqualCollection(SessionFactoryScope scope) { group.setMemberships( new HashSet<>() ); addMembership( user, group, membership ); - scope.inTransaction( - session -> - session.merge( user ) - ); - - scope.inTransaction( - session -> { - user = session.get( User.class, user.getId() ); - group = session.get( Group.class, group.getId() ); - membership = session.get( membership.getClass(), membership.getId() ); - assertEquals( "user", user.getName() ); - assertEquals( "group", group.getName() ); - assertEquals( "membership", membership.getName() ); - assertEquals( 1, user.getMemberships().size() ); - assertEquals( 1, group.getMemberships().size() ); - assertSame( membership, user.getMemberships().iterator().next() ); - assertSame( membership, group.getMemberships().iterator().next() ); - assertSame( user, membership.getUser() ); - assertSame( group, membership.getGroup() ); - } - ); + scope.inTransaction( session -> session.merge( user ) ); + + scope.inTransaction( session -> { + user = session.get( User.class, user.getId() ); + group = session.get( Group.class, group.getId() ); + membership = session.get( membership.getClass(), membership.getId() ); + assertEquals( "user", user.getName() ); + assertEquals( "group", group.getName() ); + assertEquals( "membership", membership.getName() ); + assertEquals( 1, user.getMemberships().size() ); + assertEquals( 1, group.getMemberships().size() ); + assertSame( membership, user.getMemberships().iterator().next() ); + assertSame( membership, group.getMemberships().iterator().next() ); + assertSame( user, membership.getUser() ); + assertSame( group, membership.getGroup() ); + } ); } @Test @@ -154,27 +139,22 @@ public void testRemoveAndAddSameElementNonKeyModified(SessionFactoryScope scope) addMembership( user, group, membership ); membership.setName( "membership1" ); - scope.inTransaction( - session -> - session.merge( user ) - ); - - scope.inTransaction( - session -> { - user = session.get( User.class, user.getId() ); - group = session.get( Group.class, group.getId() ); - membership = session.get( membership.getClass(), membership.getId() ); - assertEquals( "user", user.getName() ); - assertEquals( "group", group.getName() ); - assertEquals( "membership1", membership.getName() ); - assertEquals( 1, user.getMemberships().size() ); - assertEquals( 1, group.getMemberships().size() ); - assertSame( membership, user.getMemberships().iterator().next() ); - assertSame( membership, group.getMemberships().iterator().next() ); - assertSame( user, membership.getUser() ); - assertSame( group, membership.getGroup() ); - } - ); + scope.inTransaction( session -> session.merge( user ) ); + + scope.inTransaction( session -> { + user = session.get( User.class, user.getId() ); + group = session.get( Group.class, group.getId() ); + membership = session.get( membership.getClass(), membership.getId() ); + assertEquals( "user", user.getName() ); + assertEquals( "group", group.getName() ); + assertEquals( "membership1", membership.getName() ); + assertEquals( 1, user.getMemberships().size() ); + assertEquals( 1, group.getMemberships().size() ); + assertSame( membership, user.getMemberships().iterator().next() ); + assertSame( membership, group.getMemberships().iterator().next() ); + assertSame( user, membership.getUser() ); + assertSame( group, membership.getGroup() ); + } ); } @Test @@ -184,45 +164,36 @@ public void testRemoveAndAddEqualElementNonKeyModified(SessionFactoryScope scope addMembership( user, group, membership ); membership.setName( "membership1" ); - scope.inTransaction( - session -> - session.merge( user ) - ); - - scope.inTransaction( - session -> { - user = session.get( User.class, user.getId() ); - group = session.get( Group.class, group.getId() ); - membership = session.get( membership.getClass(), membership.getId() ); - assertEquals( "user", user.getName() ); - assertEquals( "group", group.getName() ); - assertEquals( "membership1", membership.getName() ); - assertEquals( 1, user.getMemberships().size() ); - assertEquals( 1, group.getMemberships().size() ); - assertSame( membership, user.getMemberships().iterator().next() ); - assertSame( membership, group.getMemberships().iterator().next() ); - assertSame( user, membership.getUser() ); - assertSame( group, membership.getGroup() ); - } - ); + scope.inTransaction( session -> session.merge( user ) ); + + scope.inTransaction( session -> { + user = session.get( User.class, user.getId() ); + group = session.get( Group.class, group.getId() ); + membership = session.get( membership.getClass(), membership.getId() ); + assertEquals( "user", user.getName() ); + assertEquals( "group", group.getName() ); + assertEquals( "membership1", membership.getName() ); + assertEquals( 1, user.getMemberships().size() ); + assertEquals( 1, group.getMemberships().size() ); + assertSame( membership, user.getMemberships().iterator().next() ); + assertSame( membership, group.getMemberships().iterator().next() ); + assertSame( user, membership.getUser() ); + assertSame( group, membership.getGroup() ); + } ); } @Test public void testDeleteDetached(SessionFactoryScope scope) { - scope.inTransaction( - session -> { - session.remove( user ); - session.remove( group ); - } - ); - - scope.inTransaction( - session -> { - assertNull( session.get( User.class, user.getId() ) ); - assertNull( session.get( Group.class, group.getId() ) ); - assertNull( session.get( membership.getClass(), membership.getId() ) ); - } - ); + scope.inTransaction( session -> { + session.remove( user ); + session.remove( group ); + } ); + + scope.inTransaction( session -> { + assertNull( session.find( User.class, user.getId() ) ); + assertNull( session.find( Group.class, group.getId() ) ); + assertNull( session.find( membership.getClass(), membership.getId() ) ); + } ); } public void deleteMembership(User u, Group g, Membership ug) { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/map/MapIndexFormulaTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/map/MapIndexFormulaTest.java index f640d02c0e1d..5717eb435d48 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/map/MapIndexFormulaTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/map/MapIndexFormulaTest.java @@ -4,7 +4,6 @@ */ package org.hibernate.orm.test.map; -import java.util.List; import java.util.Map; import org.hibernate.dialect.MariaDBDialect; @@ -81,7 +80,7 @@ public void testIndexFormulaMap(SessionFactoryScope scope) { scope.inTransaction( session -> { - Group g = session.get( Group.class, "developers" ); + Group g = session.find( Group.class, "developers" ); assertEquals( 1, g.getUsers().size() ); Map smap = ( (User) g.getUsers().get( "gavin" ) ).getSession(); assertEquals( 1, smap.size() ); @@ -97,13 +96,13 @@ public void testIndexFormulaMap(SessionFactoryScope scope) { scope.inTransaction( session -> { - Group g = session.get( Group.class, "developers" ); - assertEquals( g.getUsers().size(), 1 ); + Group g = session.find( Group.class, "developers" ); + assertEquals( 1, g.getUsers().size() ); User t = (User) g.getUsers().get( "turin" ); Map smap = t.getSession(); - assertEquals( smap.size(), 0 ); + assertEquals( 0, smap.size() ); assertEquals( - 1l, + 1L, session.createQuery( "select count(*) from User" ).uniqueResult() ); session.remove( g ); @@ -133,9 +132,11 @@ public void testSQLQuery(SessionFactoryScope scope) { session.flush(); session.clear(); - List results = session.getNamedQuery( "userSessionData" ).setParameter( "uname", "%in" ).list(); - assertEquals( results.size(), 2 ); - gavin = (User) results.get( 0 ); + var results = session.createNamedQuery( "userSessionData", User.class ) + .setParameter( "uname", "%in" ) + .list(); + assertEquals( 2, results.size() ); + gavin = results.get( 0 ); assertEquals( "gavin", gavin.getName() ); assertEquals( 2, gavin.getSession().size() ); session.createMutationQuery( "delete SessionAttribute" ).executeUpdate(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/basic/BlobAttributeQueryUpdateTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/basic/BlobAttributeQueryUpdateTest.java index 8a95a8a90e47..50fad9c520ca 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/basic/BlobAttributeQueryUpdateTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/basic/BlobAttributeQueryUpdateTest.java @@ -8,6 +8,7 @@ import java.sql.Blob; import java.sql.SQLException; +import jakarta.persistence.Query; import org.hibernate.engine.jdbc.proxy.BlobProxy; import org.hibernate.testing.orm.junit.DomainModel; @@ -20,7 +21,6 @@ import jakarta.persistence.Entity; import jakarta.persistence.Id; -import jakarta.persistence.TypedQuery; import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; import static org.hibernate.Hibernate.getLobHelper; @@ -72,9 +72,8 @@ public void testUpdateUsingBlobProxy(SessionFactoryScope scope) { scope.inTransaction( session -> { - TypedQuery query = session.createQuery( - "UPDATE TestEntity b SET b.blobValue = :blobValue WHERE b.id = :id", - null + Query query = session.createQuery( + "UPDATE TestEntity b SET b.blobValue = :blobValue WHERE b.id = :id" ); query.setParameter( "id", 1 ); Blob value = BlobProxy.generateProxy( UPDATED_BYTES_2 ); @@ -107,9 +106,8 @@ public void testUpdateUsingLobHelper(SessionFactoryScope scope) { scope.inTransaction( session -> { - TypedQuery query = session.createQuery( - "UPDATE TestEntity b SET b.blobValue = :blobValue WHERE b.id = :id", - null + Query query = session.createQuery( + "UPDATE TestEntity b SET b.blobValue = :blobValue WHERE b.id = :id" ); query.setParameter( "id", 1 ); Blob value = getLobHelper().createBlob( UPDATED_BYTES_2 ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/basic/BooleanMappingTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/basic/BooleanMappingTests.java index 27f731099b58..8875cd5dcf2c 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/basic/BooleanMappingTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/basic/BooleanMappingTests.java @@ -146,45 +146,45 @@ public void dropTestData(SessionFactoryScope scope) { public void testComparisonLiteralHandling(SessionFactoryScope scope) { scope.inTransaction( (session) -> { assertThat( - session.createSelectionQuery( "from EntityOfBooleans where convertedYesNo = true" ).list(), + session.createSelectionQuery( "from EntityOfBooleans where convertedYesNo = true", EntityOfBooleans.class ).list(), hasSize( 0 ) ); assertThat( - session.createSelectionQuery( "from EntityOfBooleans where convertedTrueFalse = true" ).list(), + session.createSelectionQuery( "from EntityOfBooleans where convertedTrueFalse = true", EntityOfBooleans.class ).list(), hasSize( 0 ) ); assertThat( - session.createSelectionQuery( "from EntityOfBooleans where convertedNumeric = true" ).list(), + session.createSelectionQuery( "from EntityOfBooleans where convertedNumeric = true", EntityOfBooleans.class ).list(), hasSize( 0 ) ); } ); scope.inTransaction( (session) -> { assertThat( - session.createSelectionQuery( "from EntityOfBooleans where convertedYesNo = false" ).list(), + session.createSelectionQuery( "from EntityOfBooleans where convertedYesNo = false", EntityOfBooleans.class ).list(), hasSize( 1 ) ); assertThat( - session.createSelectionQuery( "from EntityOfBooleans where convertedTrueFalse = false" ).list(), + session.createSelectionQuery( "from EntityOfBooleans where convertedTrueFalse = false", EntityOfBooleans.class ).list(), hasSize( 1 ) ); assertThat( - session.createSelectionQuery( "from EntityOfBooleans where convertedNumeric = false" ).list(), + session.createSelectionQuery( "from EntityOfBooleans where convertedNumeric = false", EntityOfBooleans.class ).list(), hasSize( 1 ) ); } ); scope.inTransaction( (session) -> { assertThat( - session.createSelectionQuery( "from EntityOfBooleans where convertedYesNo != true" ).list(), + session.createSelectionQuery( "from EntityOfBooleans where convertedYesNo != true", EntityOfBooleans.class ).list(), hasSize( 1 ) ); assertThat( - session.createSelectionQuery( "from EntityOfBooleans where convertedTrueFalse != true" ).list(), + session.createSelectionQuery( "from EntityOfBooleans where convertedTrueFalse != true", EntityOfBooleans.class ).list(), hasSize( 1 ) ); assertThat( - session.createSelectionQuery( "from EntityOfBooleans where convertedNumeric != true" ).list(), + session.createSelectionQuery( "from EntityOfBooleans where convertedNumeric != true", EntityOfBooleans.class ).list(), hasSize( 1 ) ); } ); @@ -195,30 +195,30 @@ public void testComparisonLiteralHandling(SessionFactoryScope scope) { public void testExpressionAsPredicateUsage(SessionFactoryScope scope) { scope.inTransaction( (session) -> { assertThat( - session.createSelectionQuery( "from EntityOfBooleans where convertedYesNo" ).list(), + session.createSelectionQuery( "from EntityOfBooleans where convertedYesNo", EntityOfBooleans.class ).list(), hasSize( 0 ) ); assertThat( - session.createSelectionQuery( "from EntityOfBooleans where convertedTrueFalse" ).list(), + session.createSelectionQuery( "from EntityOfBooleans where convertedTrueFalse", EntityOfBooleans.class ).list(), hasSize( 0 ) ); assertThat( - session.createSelectionQuery( "from EntityOfBooleans where convertedNumeric" ).list(), + session.createSelectionQuery( "from EntityOfBooleans where convertedNumeric", EntityOfBooleans.class ).list(), hasSize( 0 ) ); } ); scope.inTransaction( (session) -> { assertThat( - session.createSelectionQuery( "from EntityOfBooleans where (convertedYesNo)" ).list(), + session.createSelectionQuery( "from EntityOfBooleans where (convertedYesNo)", EntityOfBooleans.class ).list(), hasSize( 0 ) ); assertThat( - session.createSelectionQuery( "from EntityOfBooleans where (convertedTrueFalse)" ).list(), + session.createSelectionQuery( "from EntityOfBooleans where (convertedTrueFalse)", EntityOfBooleans.class ).list(), hasSize( 0 ) ); assertThat( - session.createSelectionQuery( "from EntityOfBooleans where (convertedNumeric)" ).list(), + session.createSelectionQuery( "from EntityOfBooleans where (convertedNumeric)", EntityOfBooleans.class ).list(), hasSize( 0 ) ); } ); @@ -230,29 +230,29 @@ public void testExpressionAsPredicateUsage(SessionFactoryScope scope) { public void testNegatedExpressionAsPredicateUsage(SessionFactoryScope scope) { scope.inTransaction( (session) -> { assertThat( - session.createSelectionQuery( "from EntityOfBooleans where not convertedYesNo" ).list(), + session.createSelectionQuery( "from EntityOfBooleans where not convertedYesNo", EntityOfBooleans.class ).list(), hasSize( 1 ) ); assertThat( - session.createSelectionQuery( "from EntityOfBooleans where not convertedTrueFalse" ).list(), + session.createSelectionQuery( "from EntityOfBooleans where not convertedTrueFalse", EntityOfBooleans.class ).list(), hasSize( 1 ) ); assertThat( - session.createSelectionQuery( "from EntityOfBooleans where not convertedNumeric" ).list(), + session.createSelectionQuery( "from EntityOfBooleans where not convertedNumeric", EntityOfBooleans.class ).list(), hasSize( 1 ) ); } ); scope.inTransaction( (session) -> { assertThat( - session.createSelectionQuery( "from EntityOfBooleans where not (convertedYesNo)" ).list(), + session.createSelectionQuery( "from EntityOfBooleans where not (convertedYesNo)", EntityOfBooleans.class ).list(), hasSize( 1 ) ); assertThat( - session.createSelectionQuery( "from EntityOfBooleans where not (convertedTrueFalse)" ).list(), + session.createSelectionQuery( "from EntityOfBooleans where not (convertedTrueFalse)", EntityOfBooleans.class ).list(), hasSize( 1 ) ); assertThat( - session.createSelectionQuery( "from EntityOfBooleans where not (convertedNumeric)" ).list(), + session.createSelectionQuery( "from EntityOfBooleans where not (convertedNumeric)", EntityOfBooleans.class ).list(), hasSize( 1 ) ); } ); @@ -278,15 +278,15 @@ public void testSetClauseUsage(SessionFactoryScope scope) { scope.inTransaction( (session) -> { assertThat( - session.createSelectionQuery( "from EntityOfBooleans where convertedYesNo" ).list(), + session.createSelectionQuery( "from EntityOfBooleans where convertedYesNo", EntityOfBooleans.class ).list(), hasSize( 1 ) ); assertThat( - session.createSelectionQuery( "from EntityOfBooleans where convertedTrueFalse" ).list(), + session.createSelectionQuery( "from EntityOfBooleans where convertedTrueFalse", EntityOfBooleans.class ).list(), hasSize( 1 ) ); assertThat( - session.createSelectionQuery( "from EntityOfBooleans where convertedNumeric" ).list(), + session.createSelectionQuery( "from EntityOfBooleans where convertedNumeric", EntityOfBooleans.class ).list(), hasSize( 1 ) ); } ); @@ -337,7 +337,7 @@ public void testBooleanFunctionAsPredicate(SessionFactoryScope scope) { statementInspector.clear(); scope.inTransaction( (session) -> { - session.createSelectionQuery( "from EntityOfBooleans where boolean_func1 or boolean_func2" ).list(); + session.createSelectionQuery( "from EntityOfBooleans where boolean_func1 or boolean_func2", EntityOfBooleans.class ).list(); } ); assertThat( statementInspector.getSqlQueries().size(), equalTo( 1 ) ); @@ -364,7 +364,7 @@ public void testBooleanFunctionInPredicate(SessionFactoryScope scope) { statementInspector.clear(); scope.inTransaction( (session) -> { - session.createSelectionQuery( "from EntityOfBooleans where boolean_func1 = true or boolean_func2 = false" ).list(); + session.createSelectionQuery( "from EntityOfBooleans where boolean_func1 = true or boolean_func2 = false", EntityOfBooleans.class ).list(); } ); assertThat( statementInspector.getSqlQueries().size(), equalTo( 1 ) ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/BidirectionalMapTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/BidirectionalMapTest.java index 11399173576b..0a4b6fe5f8d8 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/BidirectionalMapTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/BidirectionalMapTest.java @@ -59,7 +59,7 @@ public static class Person { private Long id; @OneToMany(mappedBy = "person", cascade = CascadeType.ALL, orphanRemoval = true) - @MapKey(name = "type") + @MapKey("type") @MapKeyEnumerated private Map phoneRegister = new HashMap<>(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/MapKeyToOneInEmbeddedIdTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/MapKeyToOneInEmbeddedIdTest.java index 205de95e9680..6a4e046d3c29 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/MapKeyToOneInEmbeddedIdTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/MapKeyToOneInEmbeddedIdTest.java @@ -79,7 +79,7 @@ public static class EntityA { private Integer id; @ManyToMany - @MapKey( name = "id.entity" ) + @MapKey( "id.entity" ) private Map bEntities = new HashMap<>(); public EntityA() { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/UnidirectionalMapTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/UnidirectionalMapTest.java index ea4ef2dbecf0..3ba96a9a8f2c 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/UnidirectionalMapTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/UnidirectionalMapTest.java @@ -69,7 +69,7 @@ public static class Person { name = "phone_register", joinColumns = @JoinColumn(name = "phone_id"), inverseJoinColumns = @JoinColumn(name = "person_id")) - @MapKey(name = "since") + @MapKey("since") @MapKeyTemporal(TemporalType.TIMESTAMP) private Map phoneRegister = new HashMap<>(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/converted/converter/map/MapKeyAttributeConverterTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/converted/converter/map/MapKeyAttributeConverterTest.java index 61a52e3eaf24..019822319685 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/converted/converter/map/MapKeyAttributeConverterTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/converted/converter/map/MapKeyAttributeConverterTest.java @@ -267,37 +267,37 @@ public static class MapEntity { private Integer id; @OneToMany(mappedBy = "mapEntity", cascade = CascadeType.ALL, fetch = FetchType.EAGER) - @MapKey(name = "implicitType") + @MapKey("implicitType") private Map implicitType = new HashMap<>(); @OneToMany(mappedBy = "mapEntity", cascade = CascadeType.ALL) - @MapKey(name = "explicitType") + @MapKey("explicitType") private Map explicitType = new HashMap<>(); @OneToMany(mappedBy = "mapEntity", cascade = CascadeType.ALL) - @MapKey(name = "enumDefault") + @MapKey("enumDefault") private Map enumDefaultType = new HashMap<>(); @OneToMany(mappedBy = "mapEntity", cascade = CascadeType.ALL) - @MapKey(name = "enumExplicitOrdinal") + @MapKey("enumExplicitOrdinal") private Map enumExplicitOrdinalType = new HashMap<>(); @OneToMany(mappedBy = "mapEntity", cascade = CascadeType.ALL) - @MapKey(name = "enumExplicitString") + @MapKey("enumExplicitString") private Map enumExplicitStringType = new HashMap<>(); @OneToMany(mappedBy = "mapEntity", cascade = CascadeType.ALL) - @MapKey(name = "enumExplicit") + @MapKey("enumExplicit") private Map enumExplicitType = new HashMap<>(); @OneToMany(mappedBy = "mapEntity", cascade = CascadeType.ALL) - @MapKey(name = "enumImplicit") + @MapKey("enumImplicit") private Map enumImplicitType = new HashMap<>(); @OneToMany(mappedBy = "mapEntity", cascade = CascadeType.ALL) - @MapKey(name = "enumImplicitOverrideOrdinal") + @MapKey("enumImplicitOverrideOrdinal") private Map enumImplicitOverrideOrdinalType = new HashMap<>(); @OneToMany(mappedBy = "mapEntity", cascade = CascadeType.ALL) - @MapKey(name = "enumImplicitOverrideString") + @MapKey("enumImplicitOverrideString") private Map enumImplicitOverrideStringType = new HashMap<>(); @OneToMany(mappedBy = "mapEntity", cascade = CascadeType.ALL) - @MapKey(name = "enumImplicitOverridden") + @MapKey("enumImplicitOverridden") private Map enumImplicitOverriddenType = new HashMap<>(); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/fetch/depth/NoDepthTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/fetch/depth/NoDepthTests.java index 68aeb5e03ea8..37b11034f9fe 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/fetch/depth/NoDepthTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/fetch/depth/NoDepthTests.java @@ -49,8 +49,8 @@ public void testNoMax() { private void testIt(boolean configureMaxDepth) { try ( final SessionFactoryImplementor sf = buildSessionFactory( configureMaxDepth ) ) { inTransaction( sf, (session) -> { - session.createSelectionQuery( "from SysModule" ).getResultList(); - session.createSelectionQuery( "from SysModule2" ).getResultList(); + session.createSelectionQuery( "from SysModule", SysModule.class ).getResultList(); + session.createSelectionQuery( "from SysModule2", SysModule2.class ).getResultList(); } ); } } @@ -97,8 +97,8 @@ private void testItJpa(boolean configureMax) { try ( final SessionFactoryImplementor sf = emf.unwrap( SessionFactoryImplementor.class ) ) { // play around with the SF and make sure it is operable inTransaction( sf, (s) -> { - s.createSelectionQuery( "from SysModule" ).list(); - s.createSelectionQuery( "from SysModule2" ).list(); + s.createSelectionQuery( "from SysModule", SysModule.class ).list(); + s.createSelectionQuery( "from SysModule2", SysModule2.class ).list(); }); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/inheritance/discriminator/DiscriminatorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/inheritance/discriminator/DiscriminatorTest.java index f6c228afe18c..a387298fe7b3 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/inheritance/discriminator/DiscriminatorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/inheritance/discriminator/DiscriminatorTest.java @@ -35,7 +35,6 @@ xmlMappings = "org/hibernate/orm/test/mapping/inheritance/discriminator/Person.hbm.xml" ) @SessionFactory -@SuppressWarnings("deprecation") public class DiscriminatorTest { @AfterEach @@ -104,8 +103,8 @@ public void testDiscriminatorSubclass(SessionFactoryScope scope) { s.clear(); - mark = s.get( Employee.class, mark.getId() ); - joe = s.get( Customer.class, joe.getId() ); + mark = s.find( Employee.class, mark.getId() ); + joe = s.find( Customer.class, joe.getId() ); mark.setZip( "30306" ); assertThat( s.createQuery( "from Person p where p.address.zip = '30306'" ).list().size(), is( 1 ) ); @@ -131,14 +130,14 @@ public void testAccessAsIncorrectSubclass(SessionFactoryScope scope) { Customer c = null; scope.fromTransaction( - s -> s.get( Customer.class, employee.getId() ) + s -> s.find( Customer.class, employee.getId() ) ); assertNull( c ); scope.inTransaction( s -> { - Employee e = s.get( Employee.class, employee.getId() ); - Customer customer = s.get( Customer.class, employee.getId() ); + Employee e = s.find( Employee.class, employee.getId() ); + Customer customer = s.find( Customer.class, employee.getId() ); assertNotNull( e ); assertNull( customer ); } @@ -211,7 +210,7 @@ public void testLoadSuperclassProxyPolymorphicAccess(SessionFactoryScope scope) // load the superclass proxy. Person pLoad = s.getReference( Person.class, e.getId() ); assertInstanceOf( HibernateProxy.class, pLoad ); - Person pGet = s.get( Person.class, e.getId() ); + Person pGet = s.find( Person.class, e.getId() ); Person pQuery = (Person) s.createQuery( "from Person where id = :id" ) .setParameter( "id", e.getId() ) .uniqueResult(); @@ -238,7 +237,7 @@ public void testLoadSuperclassProxyPolymorphicAccess(SessionFactoryScope scope) // load the superclass proxy. Person pLoad = s.getReference( Person.class, e.getId() ); assertInstanceOf( HibernateProxy.class, pLoad ); - Person pGet = s.get( Person.class, e.getId() ); + Person pGet = s.find( Person.class, e.getId() ); Person pQuery = (Person) s.createQuery( "from Person where id = :id" ) .setParameter( "id", e.getId() ) .uniqueResult(); @@ -284,7 +283,7 @@ public void testLoadSuperclassProxyEvictPolymorphicAccess(SessionFactoryScope sc assertInstanceOf( HibernateProxy.class, pLoad ); // evict the proxy s.evict( pLoad ); - Employee pGet = (Employee) s.get( Person.class, e.getId() ); + Employee pGet = (Employee) s.find( Person.class, e.getId() ); Employee pQuery = (Employee) s.createQuery( "from Person where id = :id" ) .setParameter( "id", e.getId() ) .uniqueResult(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/inheritance/discriminator/SimpleInheritanceTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/inheritance/discriminator/SimpleInheritanceTest.java index e395d551bd52..23c75030ff6b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/inheritance/discriminator/SimpleInheritanceTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/inheritance/discriminator/SimpleInheritanceTest.java @@ -127,26 +127,20 @@ public void testAccessAsIncorrectSubclass(SessionFactoryScope scope) { } ); - Customer c = scope.fromTransaction( - s -> - s.get( Customer.class, employee.getId() ) - - ); + Customer c = scope.fromTransaction( s -> s.find( Customer.class, employee.getId() ) ); assertNull( c ); scope.inTransaction( s -> { - Employee e = s.get( Employee.class, employee.getId() ); - Customer c1 = s.get( Customer.class, e.getId() ); + Employee e = s.find( Employee.class, employee.getId() ); + Customer c1 = s.find( Customer.class, e.getId() ); assertNotNull( e ); assertNull( c1 ); } ); - scope.inTransaction( - session -> session.remove( employee ) - ); + scope.inTransaction(session -> session.remove( employee ) ); } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/multitenancy/schema/AbstractSchemaBasedMultiTenancyTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/multitenancy/schema/AbstractSchemaBasedMultiTenancyTest.java index 58aca31fface..46ba0934cbc2 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/multitenancy/schema/AbstractSchemaBasedMultiTenancyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/multitenancy/schema/AbstractSchemaBasedMultiTenancyTest.java @@ -159,7 +159,7 @@ public void testBasicExpectedBehavior() { } ); doInHibernateSessionBuilder( this::acme, session -> { - Customer check = session.get( Customer.class, steve.getId() ); + Customer check = session.find( Customer.class, steve.getId() ); assertThat( check ) .describedAs( "tenancy not properly isolated" ) .isNull(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/nationalized/StringNationalizedTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/nationalized/StringNationalizedTest.java index e08678fbd09c..b38e10560e11 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/nationalized/StringNationalizedTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/nationalized/StringNationalizedTest.java @@ -4,19 +4,15 @@ */ package org.hibernate.orm.test.nationalized; -import java.util.List; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.Table; - import org.hibernate.annotations.Nationalized; import org.hibernate.dialect.OracleDialect; import org.hibernate.dialect.PostgreSQLDialect; -import org.hibernate.query.Query; - -import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.testing.orm.junit.RequiresDialect; import org.hibernate.testing.orm.junit.RequiresDialects; import org.hibernate.testing.orm.junit.SessionFactory; @@ -59,9 +55,9 @@ public void testSaveEntityWithNationalizedProperty(SessionFactoryScope scope) { scope.inSession( session -> { - final Query query = session.createQuery( "from NationalizedEntity where name = :name", null ); + var query = session.createQuery( "from NationalizedEntity where name = :name", NationalizedEntity.class ); query.setParameter( "name", "Hello" ); - final List list = query.list(); + var list = query.list(); assertThat( list.size(), is( 1 ) ); } ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/toone/ToOneOnDeleteSetNullTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/toone/ToOneOnDeleteSetNullTest.java index 3126e5aab44e..0702d5c51254 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/toone/ToOneOnDeleteSetNullTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/toone/ToOneOnDeleteSetNullTest.java @@ -40,62 +40,56 @@ public void tearDown(SessionFactoryScope scope) { @Test @RequiresDialectFeature(feature = DialectFeatureChecks.SupportsCascadeDeleteCheck.class) public void testManyToOne(SessionFactoryScope scope) { - scope.inTransaction( - session -> { - Parent parent = new Parent(); - parent.id = 1L; - session.persist( parent ); - - Child child1 = new Child(); - child1.id = 1L; - child1.parent = parent; - session.persist( child1 ); - - GrandChild grandChild11 = new GrandChild(); - grandChild11.id = 1L; - grandChild11.parent = child1; - session.persist( grandChild11 ); - - Child child2 = new Child(); - child2.id = 2L; - child2.parent = parent; - session.persist( child2 ); - - GrandChild grandChild21 = new GrandChild(); - grandChild21.id = 2L; - grandChild21.parent = child2; - session.persist( grandChild21 ); - - GrandChild grandChild22 = new GrandChild(); - grandChild22.id = 3L; - grandChild22.parent = child2; - session.persist( grandChild22 ); - } - ); - - scope.inTransaction( - session -> { - assertNotNull( session.get(Child.class, 1L).parent ); - assertNotNull( session.get(Child.class, 2L).parent ); - assertNotNull( session.get(GrandChild.class, 2L).parent ); - assertNotNull( session.get(GrandChild.class, 3L).parent ); - } - ); - scope.inTransaction( - session -> { - Parent parent = session.get( Parent.class, 1L ); - session.remove( parent ); - } - ); - scope.inTransaction( - session -> { - assertNull( session.get(Child.class, 1L).parent ); - assertNull( session.get(Child.class, 2L).parent ); - assertNotNull( session.get(GrandChild.class, 2L).parent ); - assertNotNull( session.get(GrandChild.class, 3L).parent ); - assertNull( session.get( Parent.class, 1L ) ); - } - ); + scope.inTransaction( session -> { + Parent parent = new Parent(); + parent.id = 1L; + session.persist( parent ); + + Child child1 = new Child(); + child1.id = 1L; + child1.parent = parent; + session.persist( child1 ); + + GrandChild grandChild11 = new GrandChild(); + grandChild11.id = 1L; + grandChild11.parent = child1; + session.persist( grandChild11 ); + + Child child2 = new Child(); + child2.id = 2L; + child2.parent = parent; + session.persist( child2 ); + + GrandChild grandChild21 = new GrandChild(); + grandChild21.id = 2L; + grandChild21.parent = child2; + session.persist( grandChild21 ); + + GrandChild grandChild22 = new GrandChild(); + grandChild22.id = 3L; + grandChild22.parent = child2; + session.persist( grandChild22 ); + } ); + + scope.inTransaction( session -> { + assertNotNull( session.find(Child.class, 1L).parent ); + assertNotNull( session.find(Child.class, 2L).parent ); + assertNotNull( session.find(GrandChild.class, 2L).parent ); + assertNotNull( session.find(GrandChild.class, 3L).parent ); + } ); + + scope.inTransaction( session -> { + Parent parent = session.get( Parent.class, 1L ); + session.remove( parent ); + } ); + + scope.inTransaction( session -> { + assertNull( session.find(Child.class, 1L).parent ); + assertNull( session.find(Child.class, 2L).parent ); + assertNotNull( session.find(GrandChild.class, 2L).parent ); + assertNotNull( session.find(GrandChild.class, 3L).parent ); + assertNull( session.find( Parent.class, 1L ) ); + } ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/toone/ToOneOnDeleteTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/toone/ToOneOnDeleteTest.java index 904cc3faa980..7aa97e5de727 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/toone/ToOneOnDeleteTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/toone/ToOneOnDeleteTest.java @@ -42,62 +42,57 @@ public void tearDown(SessionFactoryScope scope) { @Test @RequiresDialectFeature(feature = DialectFeatureChecks.SupportsCascadeDeleteCheck.class) public void testManyToOne(SessionFactoryScope scope) { - scope.inTransaction( - session -> { - Parent parent = new Parent(); - parent.id = 1L; - session.persist( parent ); - - Child child1 = new Child(); - child1.id = 1L; - child1.parent = parent; - session.persist( child1 ); - - GrandChild grandChild11 = new GrandChild(); - grandChild11.id = 1L; - grandChild11.parent = child1; - session.persist( grandChild11 ); - - Child child2 = new Child(); - child2.id = 2L; - child2.parent = parent; - session.persist( child2 ); - - GrandChild grandChild21 = new GrandChild(); - grandChild21.id = 2L; - grandChild21.parent = child2; - session.persist( grandChild21 ); - - GrandChild grandChild22 = new GrandChild(); - grandChild22.id = 3L; - grandChild22.parent = child2; - session.persist( grandChild22 ); - } - ); - - scope.inTransaction( - session -> { - assertNotNull( session.get(Child.class, 1L) ); - assertNotNull( session.get(Child.class, 2L) ); - assertNotNull( session.get(GrandChild.class, 2L) ); - assertNotNull( session.get(GrandChild.class, 3L) ); - } - ); - scope.inTransaction( - session -> { - Parent parent = session.get( Parent.class, 1L ); - session.remove( parent ); - } - ); - scope.inTransaction( - session -> { - assertNull( session.get(Child.class, 1L) ); - assertNull( session.get(Child.class, 2L) ); - assertNull( session.get(GrandChild.class, 2L) ); - assertNull( session.get(GrandChild.class, 3L) ); - assertNull( session.get( Parent.class, 1L ) ); - } - ); } + scope.inTransaction( session -> { + Parent parent = new Parent(); + parent.id = 1L; + session.persist( parent ); + + Child child1 = new Child(); + child1.id = 1L; + child1.parent = parent; + session.persist( child1 ); + + GrandChild grandChild11 = new GrandChild(); + grandChild11.id = 1L; + grandChild11.parent = child1; + session.persist( grandChild11 ); + + Child child2 = new Child(); + child2.id = 2L; + child2.parent = parent; + session.persist( child2 ); + + GrandChild grandChild21 = new GrandChild(); + grandChild21.id = 2L; + grandChild21.parent = child2; + session.persist( grandChild21 ); + + GrandChild grandChild22 = new GrandChild(); + grandChild22.id = 3L; + grandChild22.parent = child2; + session.persist( grandChild22 ); + } ); + + scope.inTransaction( session -> { + assertNotNull( session.find(Child.class, 1L) ); + assertNotNull( session.find(Child.class, 2L) ); + assertNotNull( session.find(GrandChild.class, 2L) ); + assertNotNull( session.find(GrandChild.class, 3L) ); + } ); + + scope.inTransaction( session -> { + Parent parent = session.get( Parent.class, 1L ); + session.remove( parent ); + } ); + + scope.inTransaction( session -> { + assertNull( session.find(Child.class, 1L) ); + assertNull( session.find(Child.class, 2L) ); + assertNull( session.find(GrandChild.class, 2L) ); + assertNull( session.find(GrandChild.class, 3L) ); + assertNull( session.find( Parent.class, 1L ) ); + } ); + } @Entity(name = "Parent") diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/onetomany/inheritance/joined/Library.java b/hibernate-core/src/test/java/org/hibernate/orm/test/onetomany/inheritance/joined/Library.java index e0dc5d783e97..53225d8d7f44 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/onetomany/inheritance/joined/Library.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/onetomany/inheritance/joined/Library.java @@ -23,11 +23,11 @@ public class Library { private int entid; @OneToMany(mappedBy="library", cascade = CascadeType.ALL) - @MapKey(name="inventoryCode") + @MapKey("inventoryCode") private Map booksOnInventory = new HashMap<>(); @OneToMany(mappedBy="library", cascade = CascadeType.ALL) - @MapKey(name="isbn") + @MapKey("isbn") private Map booksOnIsbn = new HashMap<>(); public int getEntid() { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/onetomany/inheritance/perclass/Library.java b/hibernate-core/src/test/java/org/hibernate/orm/test/onetomany/inheritance/perclass/Library.java index 0c2fedef5d1f..25267dfc7550 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/onetomany/inheritance/perclass/Library.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/onetomany/inheritance/perclass/Library.java @@ -23,11 +23,11 @@ public class Library { private int entid; @OneToMany(mappedBy="library", cascade = CascadeType.ALL) - @MapKey(name="inventoryCode") + @MapKey("inventoryCode") private Map booksOnInventory = new HashMap<>(); @OneToMany(mappedBy="library", cascade = CascadeType.ALL) - @MapKey(name="isbn") + @MapKey("isbn") private Map booksOnIsbn = new HashMap<>(); public int getEntid() { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/onetomany/inheritance/single/Library.java b/hibernate-core/src/test/java/org/hibernate/orm/test/onetomany/inheritance/single/Library.java index c0ed11779c7f..b6be3f7c1e5e 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/onetomany/inheritance/single/Library.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/onetomany/inheritance/single/Library.java @@ -24,11 +24,11 @@ public class Library { private int entid; @OneToMany(mappedBy="library", cascade = CascadeType.ALL) - @MapKey(name="inventoryCode") + @MapKey("inventoryCode") private Map booksOnInventory = new HashMap<>(); @OneToMany(mappedBy="library", cascade = CascadeType.ALL) - @MapKey(name="isbn") + @MapKey("isbn") private Map booksOnIsbn = new HashMap<>(); public int getEntid() { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/onetoone/formula/OneToOneFormulaTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/onetoone/formula/OneToOneFormulaTest.java index 50b72b5381d1..e528487ac13c 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/onetoone/formula/OneToOneFormulaTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/onetoone/formula/OneToOneFormulaTest.java @@ -130,7 +130,7 @@ public void testOneToOneFormula() { CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder(); CriteriaQuery criteria = criteriaBuilder.createQuery( Person.class ); Root root = criteria.from( Person.class ); - Join address = root.join( "address", JoinType.INNER ); + Join address = root.join( "address", JoinType.INNER ); criteria.where( criteriaBuilder.equal( address.get( "zip" ), "3181" ) ); Person p = session.createQuery( criteria ).uniqueResult(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/ops/GetLoadTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/GetLoadTest.java index bc45eedef349..97fcde49e793 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/ops/GetLoadTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/GetLoadTest.java @@ -67,7 +67,7 @@ public void testGetLoad(SessionFactoryScope scope) { assertTrue( Hibernate.isInitialized( n ) ); assertFalse( Hibernate.isInitialized( n.getChildren() ) ); assertFalse( Hibernate.isInitialized( n.getParent() ) ); - assertNull( session.get( Node.class, "xyz" ) ); + assertNull( session.find( Node.class, "xyz" ) ); } ); @@ -119,7 +119,7 @@ public void testGetAfterDelete(SessionFactoryScope scope) { Employer e = scope.fromTransaction( session -> { session.remove( emp ); - return session.get( Employer.class, emp.getId() ); + return session.find( Employer.class, emp.getId() ); } ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeMultipleEntityCopiesAllowedOrphanDeleteTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeMultipleEntityCopiesAllowedOrphanDeleteTest.java index 0f4cda312173..a6e16b7249c0 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeMultipleEntityCopiesAllowedOrphanDeleteTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeMultipleEntityCopiesAllowedOrphanDeleteTest.java @@ -194,7 +194,7 @@ public void testTopLevelUnidirOneToManyBackrefWithRemovedElement(SessionFactoryS Item item = session.get( Item.class, item1.getId() ); assertThat( item.getSubItemsBackref().size(), is( 1 ) ); // because cascade includes "delete-orphan" the removed SubItem should have been deleted. - SubItem subItem = session.get( SubItem.class, subItem1.getId() ); + SubItem subItem = session.find( SubItem.class, subItem1.getId() ); assertNull( subItem ); } ); @@ -402,7 +402,7 @@ public void testTopLevelUnidirOneToManyNoBackrefWithRemovedElement(SessionFactor Category category = session.get( Category.class, category1.getId() ); assertThat( category.getSubCategories().size(), is( 1 ) ); assertTrue( category.getSubCategories().contains( subCategory2 ) ); - SubCategory subCategory = session.get( SubCategory.class, subCategory1.getId() ); + SubCategory subCategory = session.find( SubCategory.class, subCategory1.getId() ); assertNull( subCategory ); } ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/orphan/OrphanTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/orphan/OrphanTest.java index c371801cacd3..415b7ffdcd38 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/orphan/OrphanTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/orphan/OrphanTest.java @@ -60,9 +60,9 @@ public void testOrphanDeleteOnDelete(SessionFactoryScope scope) { scope.inTransaction( session -> { - assertNull( session.get( Part.class, "Widge" ) ); - assertNull( session.get( Part.class, "Get" ) ); - assertNull( session.get( Product.class, "Widget" ) ); + assertNull( session.find( Part.class, "Widge" ) ); + assertNull( session.find( Part.class, "Get" ) ); + assertNull( session.find( Product.class, "Widget" ) ); } ); } @@ -90,8 +90,8 @@ public void testOrphanDeleteAfterPersist(SessionFactoryScope scope) { scope.inTransaction( session -> { - assertNull( session.get( Part.class, "Widge" ) ); - assertNotNull( session.get( Part.class, "Get" ) ); + assertNull( session.find( Part.class, "Widge" ) ); + assertNotNull( session.find( Part.class, "Get" ) ); session.remove( session.get( Product.class, "Widget" ) ); } ); @@ -121,8 +121,8 @@ public void testOrphanDeleteAfterPersistAndFlush(SessionFactoryScope scope) { scope.inTransaction( session -> { - assertNull( session.get( Part.class, "Widge" ) ); - assertNotNull( session.get( Part.class, "Get" ) ); + assertNull( session.find( Part.class, "Widge" ) ); + assertNotNull( session.find( Part.class, "Get" ) ); session.remove( session.get( Product.class, "Widget" ) ); } ); @@ -200,8 +200,8 @@ public void testOrphanDelete(SessionFactoryScope scope) { scope.inTransaction( session -> { - assertNull( session.get( Part.class, "Widge" ) ); - assertNotNull( session.get( Part.class, "Get" ) ); + assertNull( session.find( Part.class, "Widge" ) ); + assertNotNull( session.find( Part.class, "Get" ) ); session.remove( session.get( Product.class, "Widget" ) ); } ); @@ -236,8 +236,8 @@ public void testOrphanDeleteOnMerge(SessionFactoryScope scope) { scope.inTransaction( session -> { - assertNull( session.get( Part.class, "Widge" ) ); - assertNotNull( session.get( Part.class, "Get" ) ); + assertNull( session.find( Part.class, "Widge" ) ); + assertNotNull( session.find( Part.class, "Get" ) ); session.remove( session.get( Product.class, "Widget" ) ); } ); @@ -268,7 +268,7 @@ public void testOrphanDeleteOnMergeRemoveElementMerge(SessionFactoryScope scope) scope.inTransaction( session -> { - assertNull( session.get( Part.class, "Widge" ) ); + assertNull( session.find( Part.class, "Widge" ) ); session.remove( session.get( Product.class, "Widget" ) ); } ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/pc/FindMultipleDocTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/pc/FindMultipleDocTests.java index f54867f06c51..789108557e2b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/pc/FindMultipleDocTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/pc/FindMultipleDocTests.java @@ -5,11 +5,14 @@ package org.hibernate.orm.test.pc; import jakarta.persistence.Entity; +import jakarta.persistence.EntityNotFoundException; import jakarta.persistence.Id; import jakarta.persistence.Table; +import org.hibernate.KeyType; import org.hibernate.RemovalsMode; import org.hibernate.OrderingMode; import org.hibernate.SessionCheckMode; +import org.hibernate.annotations.NaturalId; import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.FailureExpected; import org.hibernate.testing.orm.junit.SessionFactory; @@ -48,7 +51,7 @@ void dropTestData(SessionFactoryScope factoryScope) { } @Test - void testBasicUsage(SessionFactoryScope factoryScope) { + void testBasicFindMultiple(SessionFactoryScope factoryScope) { factoryScope.inTransaction( (session) -> { //tag::pc-find-multiple-example[] List persons = session.findMultiple( @@ -61,6 +64,40 @@ void testBasicUsage(SessionFactoryScope factoryScope) { } ); } + @Test + void testBasicGetMultiple(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + //tag::pc-get-multiple-example[] + try { + List persons = session.getMultiple( + Person.class, + List.of( 1, 2, 3 ), + PESSIMISTIC_WRITE, + ORDERED + ); + } + catch (EntityNotFoundException e) { + // handle it + } + //end::pc-get-multiple-example[] + } ); + } + + @Test + void testFindMultipleByNaturalId(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + //tag::pc-find-multiple-natural-id-example[] + List persons = session.findMultiple( + Person.class, + List.of(1,2,3), + KeyType.NATURAL, + PESSIMISTIC_WRITE, + ORDERED + ); + //end::pc-find-multiple-natural-id-example[] + } ); + } + @Test void testReplaceRemovals(SessionFactoryScope factoryScope) { factoryScope.inTransaction( (session) -> { @@ -237,6 +274,7 @@ void testOrderedReplacedRemovals(SessionFactoryScope factoryScope) { public static class Person { @Id private Integer id; + @NaturalId private String name; public Person() { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/pc/PersistenceContextTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/pc/PersistenceContextTest.java index 30c1dd3855cc..586ff97661e6 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/pc/PersistenceContextTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/pc/PersistenceContextTest.java @@ -14,6 +14,7 @@ import jakarta.persistence.PersistenceUnitUtil; import jakarta.persistence.PersistenceUtil; import org.hibernate.Hibernate; +import org.hibernate.KeyType; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.annotations.NaturalId; @@ -93,9 +94,21 @@ public void test(EntityManagerFactoryScope scope) { scope.inTransaction( entityManager -> { Long personId = _personId; - //tag::pc-find-jpa-example[] + //tag::pc-find-example[] Person person = entityManager.find( Person.class, personId ); - //end::pc-find-jpa-example[] + //end::pc-find-example[] + } ); + scope.inTransaction( entityManager -> { + Long personId = _personId; + + //tag::pc-get-example[] + try { + Person person = entityManager.get( Person.class, personId ); + } + catch (EntityNotFoundException e) { + // handle it + } + //end::pc-get-example[] } ); scope.inTransaction( entityManager -> { Session session = entityManager.unwrap( Session.class ); @@ -126,32 +139,25 @@ public void test(EntityManagerFactoryScope scope) { //end::pc-get-reference-native-example[] } ); scope.inTransaction( entityManager -> { - Session session = entityManager.unwrap( Session.class ); - Long personId = _personId; + String isbn = "123-456-7890"; - //tag::pc-find-native-example[] - Person person = session.get( Person.class, personId ); - //end::pc-find-native-example[] + //tag::pc-find-by-natural-id-example[] + Book book = entityManager.find( Book.class, isbn, KeyType.NATURAL ); + //end::pc-find-by-simple-natural-id-example[] + assertThat(book).isNotNull(); } ); scope.inTransaction( entityManager -> { - Session session = entityManager.unwrap( Session.class ); - Long personId = _personId; + String isbn = "123-456-7890"; - //tag::pc-find-by-id-native-example[] - Person person = session.byId( Person.class ).load( personId ); - //end::pc-find-by-id-native-example[] + //tag::pc-get-by-natural-id-example[] + Book book = entityManager.find( Book.class, isbn, KeyType.NATURAL ); + //end::pc-get-by-simple-natural-id-example[] + assertThat(book).isNotNull(); + } ); - //tag::pc-find-optional-by-id-native-example[] - Optional optionalPerson = session.byId( Person.class ).loadOptional( personId ); - //end::pc-find-optional-by-id-native-example[] - String isbn = "123-456-7890"; - //tag::pc-find-by-simple-natural-id-example[] - Book book = session.bySimpleNaturalId( Book.class ).getReference( isbn ); - //end::pc-find-by-simple-natural-id-example[] - assertThat(book ).isNotNull(); - } ); + // todo (jpa4) : find references to these tags in the doc and drop scope.inTransaction( entityManager -> { Session session = entityManager.unwrap( Session.class ); String isbn = "123-456-7890"; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/CteTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/CteTests.java index 65e68b9736e9..36b7305bcd0b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/CteTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/CteTests.java @@ -348,7 +348,7 @@ public void testSimpleRecursive(SessionFactoryScope scope) { ); final JpaRoot root = cq.from( alternativeContacts ); - final JpaJoin alt = root.join( "alt" ); + final JpaJoin alt = root.join( "alt" ); cq.multiselect( alt ); cq.orderBy( cb.asc( alt.get( "id" ) ) ); @@ -405,7 +405,7 @@ public void testRecursiveCycleClause(SessionFactoryScope scope) { ); final JpaRoot root = cq.from( alternativeContacts ); - final JpaJoin alt = root.join( "alt" ); + final JpaJoin alt = root.join( "alt" ); cq.multiselect( alt, root.get( "isCycle" ) ); cq.orderBy( cb.asc( alt.get( "id" ) ), cb.asc( root.get( "isCycle" ) ) ); @@ -468,7 +468,7 @@ public void testRecursiveCycleUsingClause(SessionFactoryScope scope) { ); final JpaRoot root = cq.from( alternativeContacts ); - final JpaJoin alt = root.join( "alt" ); + final JpaJoin alt = root.join( "alt" ); cq.multiselect( alt, root.get( "isCycle" ) ); cq.orderBy( cb.asc( alt.get( "id" ) ), cb.asc( root.get( "isCycle" ) ) ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/ImplicitJoinInSubqueryTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/ImplicitJoinInSubqueryTest.java index 6833e7dfe424..59833d964ef4 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/ImplicitJoinInSubqueryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/ImplicitJoinInSubqueryTest.java @@ -32,14 +32,13 @@ public class ImplicitJoinInSubqueryTest { public void testImplicitJoinInSubquery(SessionFactoryScope scope) { SQLStatementInspector statementInspector = scope.getCollectingStatementInspector(); statementInspector.clear(); - scope.inTransaction( - entityManager -> { - entityManager.createSelectionQuery( - "select 1 from A a where exists (select 1 from B b where a.b.c.id = 5)" - ).getResultList(); - assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "b2_0.id=a1_0.b_id" ); - } - ); + scope.inTransaction( entityManager -> { + entityManager.createSelectionQuery( + "select 1 from A a where exists (select 1 from B b where a.b.c.id = 5)", + Integer.class + ).getResultList(); + assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "b2_0.id=a1_0.b_id" ); + } ); } @Test @@ -47,15 +46,14 @@ public void testImplicitJoinInSubquery(SessionFactoryScope scope) { public void testImplicitJoinInSubquery2(SessionFactoryScope scope) { SQLStatementInspector statementInspector = scope.getCollectingStatementInspector(); statementInspector.clear(); - scope.inTransaction( - entityManager -> { - entityManager.createSelectionQuery( - "select a from A a where exists (select 1 from B b where a.b.c is null)" - ).getResultList(); - assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "b1_0.c_id is null" ); - assertThat( statementInspector.getSqlQueries().get( 0 ) ).doesNotContain( ".id=b1_0.c_id" ); - } - ); + scope.inTransaction(entityManager -> { + entityManager.createSelectionQuery( + "select a from A a where exists (select 1 from B b where a.b.c is null)", + A.class + ).getResultList(); + assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "b1_0.c_id is null" ); + assertThat( statementInspector.getSqlQueries().get( 0 ) ).doesNotContain( ".id=b1_0.c_id" ); + } ); } @Entity(name = "A") diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/Jpa4ParameterBindingTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/Jpa4ParameterBindingTests.java new file mode 100644 index 000000000000..dca676c96392 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/Jpa4ParameterBindingTests.java @@ -0,0 +1,76 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.query; + +import jakarta.persistence.AttributeConverter; +import org.hibernate.testing.orm.domain.StandardDomainModel; +import org.hibernate.testing.orm.domain.library.Book; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; + +/** + * @author Steve Ebersole + */ +@DomainModel( standardModels = StandardDomainModel.LIBRARY) +@SessionFactory +public class Jpa4ParameterBindingTests { + + @Test + void testHql(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + session.createQuery( "from Book where id = :id", Book.class ) + .setConvertedParameter( "id", "123", StringToIntConverter.class ) + .list(); + + session.createQuery( "from Book where id = ?1", Book.class ) + .setConvertedParameter( 1, "123", StringToIntConverter.class ) + .list(); + + session.createQuery( "from Book where id = :id", Book.class ) + .setParameter( "id", 1, Integer.class ) + .list(); + + session.createQuery( "from Book where id = ?1", Book.class ) + .setParameter( 1, 1, Integer.class ) + .list(); + } ); + } + + @Test + void testNativeQuery(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + session.createNativeQuery( "select * from books where id = :id", Book.class ) + .setConvertedParameter( "id", "123", StringToIntConverter.class ) + .list(); + + session.createNativeQuery( "select * from books where id = ?1", Book.class ) + .setConvertedParameter( 1, "123", StringToIntConverter.class ) + .list(); + + session.createNativeQuery( "select * from books where id = :id", Book.class ) + .setParameter( "id", 1, Integer.class ) + .list(); + + session.createNativeQuery( "select * from books where id = ?1", Book.class ) + .setParameter( 1, 1, Integer.class ) + .list(); + } ); + + } + + public static class StringToIntConverter implements AttributeConverter { + @Override + public Integer convertToDatabaseColumn(String domainValue) { + return domainValue == null ? null : Integer.parseInt( domainValue ); + } + + @Override + public String convertToEntityAttribute(Integer relationalValue) { + return relationalValue == null ? null : Integer.toString( relationalValue ); + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SQLServerNationalizedScalarQueryTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SQLServerNationalizedScalarQueryTest.java index 17cec931644d..7eae735f251a 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SQLServerNationalizedScalarQueryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SQLServerNationalizedScalarQueryTest.java @@ -38,8 +38,8 @@ public class SQLServerNationalizedScalarQueryTest { @JiraKey(value = "HHH-16857") @Test public void testLiteral(SessionFactoryScope scope) { - scope.inTransaction(session -> session.createSelectionQuery("from User where name = 'Gavin'").getResultList()); - scope.inTransaction(session -> session.createSelectionQuery("from User where role = 'ADMIN'").getResultList()); + scope.inTransaction(session -> session.createSelectionQuery("from User where name = 'Gavin'", User.class).getResultList()); + scope.inTransaction(session -> session.createSelectionQuery("from User where role = 'ADMIN'", User.class).getResultList()); } @JiraKey(value = "HHH-10183") diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromEmbeddedIdTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromEmbeddedIdTests.java index 16353f82b547..e8171a71e10e 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromEmbeddedIdTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromEmbeddedIdTests.java @@ -58,7 +58,7 @@ public void testEntity(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); + final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); subquery.multiselect( alternativeContact.alias( "contact" ) ); subquery.orderBy( cb.asc( alternativeContact.get( "name" ).get( "first" ) ) ); @@ -108,14 +108,14 @@ public void testEntityJoin(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); + final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); subquery.multiselect( alternativeContact.alias( "contact" ) ); subquery.orderBy( cb.desc( alternativeContact.get( "name" ).get( "first" ) ) ); subquery.fetch( 1 ); final JpaDerivedJoin a = root.joinLateral( subquery, JoinType.LEFT ); - final Join alt = a.join( "contact" ); + final Join alt = a.join( "contact" ); cq.multiselect( root.get( "name" ), alt.get( "name" ) ); cq.orderBy( cb.asc( root.get( "id" ) ) ); @@ -156,7 +156,7 @@ public void testEntityImplicit(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); + final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); subquery.multiselect( alternativeContact.alias( "contact" ) ); subquery.orderBy( cb.desc( alternativeContact.get( "name" ).get( "first" ) ) ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromIdClassTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromIdClassTests.java index e2401f348e87..16aa1e623b72 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromIdClassTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromIdClassTests.java @@ -56,7 +56,7 @@ public void testEntity(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); + final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); subquery.multiselect( alternativeContact.alias( "contact" ) ); subquery.orderBy( cb.asc( alternativeContact.get( "name" ).get( "first" ) ) ); @@ -107,14 +107,14 @@ public void testEntityJoin(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); + final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); subquery.multiselect( alternativeContact.alias( "contact" ) ); subquery.orderBy( cb.desc( alternativeContact.get( "name" ).get( "first" ) ) ); subquery.fetch( 1 ); final JpaDerivedJoin a = root.joinLateral( subquery, JoinType.LEFT ); - final Join alt = a.join( "contact" ); + final Join alt = a.join( "contact" ); cq.multiselect( root.get( "name" ), alt.get( "name" ) ); cq.orderBy( cb.asc( root.get( "id1" ) ) ); @@ -155,7 +155,7 @@ public void testEntityImplicit(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); + final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); subquery.multiselect( alternativeContact.alias( "contact" ) ); subquery.orderBy( cb.desc( alternativeContact.get( "name" ).get( "first" ) ) ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromInverseOneEmbeddedIdTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromInverseOneEmbeddedIdTests.java index ebb7efe2fe47..f3d5864206dd 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromInverseOneEmbeddedIdTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromInverseOneEmbeddedIdTests.java @@ -56,7 +56,7 @@ public void testEntity(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); + final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); subquery.multiselect( alternativeContact.alias( "contact" ) ); subquery.orderBy( cb.asc( alternativeContact.get( "name" ).get( "first" ) ) ); @@ -106,14 +106,14 @@ public void testEntityJoin(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); + final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); subquery.multiselect( alternativeContact.alias( "contact" ) ); subquery.orderBy( cb.desc( alternativeContact.get( "name" ).get( "first" ) ) ); subquery.fetch( 1 ); final JpaDerivedJoin a = root.joinLateral( subquery, JoinType.LEFT ); - final Join alt = a.join( "contact" ); + final Join alt = a.join( "contact" ); cq.multiselect( root.get( "name" ), alt.get( "name" ) ); cq.orderBy( cb.asc( root.get( "id" ) ) ); @@ -154,7 +154,7 @@ public void testEntityImplicit(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); + final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); subquery.multiselect( alternativeContact.alias( "contact" ) ); subquery.orderBy( cb.desc( alternativeContact.get( "name" ).get( "first" ) ) ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromInverseOneIdClassTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromInverseOneIdClassTests.java index 94260e98a716..d5e0b717a590 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromInverseOneIdClassTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromInverseOneIdClassTests.java @@ -56,7 +56,7 @@ public void testEntity(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); + final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); subquery.multiselect( alternativeContact.alias( "contact" ) ); subquery.orderBy( cb.asc( alternativeContact.get( "name" ).get( "first" ) ) ); @@ -107,14 +107,14 @@ public void testEntityJoin(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); + final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); subquery.multiselect( alternativeContact.alias( "contact" ) ); subquery.orderBy( cb.desc( alternativeContact.get( "name" ).get( "first" ) ) ); subquery.fetch( 1 ); final JpaDerivedJoin a = root.joinLateral( subquery, JoinType.LEFT ); - final Join alt = a.join( "contact" ); + final Join alt = a.join( "contact" ); cq.multiselect( root.get( "name" ), alt.get( "name" ) ); cq.orderBy( cb.asc( root.get( "id1" ) ) ); @@ -155,7 +155,7 @@ public void testEntityImplicit(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); + final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); subquery.multiselect( alternativeContact.alias( "contact" ) ); subquery.orderBy( cb.desc( alternativeContact.get( "name" ).get( "first" ) ) ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromInverseOneTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromInverseOneTests.java index 3b0b06281b6d..17f1e8eeb5be 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromInverseOneTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromInverseOneTests.java @@ -56,7 +56,7 @@ public void testEntity(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); + final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); subquery.multiselect( alternativeContact.alias( "contact" ) ); subquery.orderBy( cb.asc( alternativeContact.get( "name" ).get( "first" ) ) ); @@ -104,14 +104,14 @@ public void testEntityJoin(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); + final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); subquery.multiselect( alternativeContact.alias( "contact" ) ); subquery.orderBy( cb.desc( alternativeContact.get( "name" ).get( "first" ) ) ); subquery.fetch( 1 ); final JpaDerivedJoin a = root.joinLateral( subquery, JoinType.LEFT ); - final Join alt = a.join( "contact" ); + final Join alt = a.join( "contact" ); cq.multiselect( root.get( "name" ), alt.get( "name" ) ); cq.orderBy( cb.asc( root.get( "id" ) ) ); @@ -152,7 +152,7 @@ public void testEntityImplicit(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); + final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); subquery.multiselect( alternativeContact.alias( "contact" ) ); subquery.orderBy( cb.desc( alternativeContact.get( "name" ).get( "first" ) ) ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromManyToManyEmbeddedIdTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromManyToManyEmbeddedIdTests.java index 9a35513d9877..79c360a3fefb 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromManyToManyEmbeddedIdTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromManyToManyEmbeddedIdTests.java @@ -56,7 +56,7 @@ public void testEntity(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); + final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); subquery.multiselect( alternativeContacts.alias( "contact" ) ); subquery.orderBy( cb.asc( alternativeContacts.get( "name" ).get( "first" ) ) ); @@ -106,14 +106,14 @@ public void testEntityJoin(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); + final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); subquery.multiselect( alternativeContacts.alias( "contact" ) ); subquery.orderBy( cb.desc( alternativeContacts.get( "name" ).get( "first" ) ) ); subquery.fetch( 1 ); final JpaDerivedJoin a = root.joinLateral( subquery, JoinType.LEFT ); - final Join alt = a.join( "contact" ); + final Join alt = a.join( "contact" ); cq.multiselect( root.get( "name" ), alt.get( "name" ) ); cq.orderBy( cb.asc( root.get( "id" ) ) ); @@ -154,7 +154,7 @@ public void testEntityImplicit(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); + final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); subquery.multiselect( alternativeContacts.alias( "contact" ) ); subquery.orderBy( cb.desc( alternativeContacts.get( "name" ).get( "first" ) ) ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromManyToManyIdClassTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromManyToManyIdClassTests.java index 066bc32aec51..c90736d77940 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromManyToManyIdClassTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromManyToManyIdClassTests.java @@ -56,7 +56,7 @@ public void testEntity(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); + final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); subquery.multiselect( alternativeContacts.alias( "contact" ) ); subquery.orderBy( cb.asc( alternativeContacts.get( "name" ).get( "first" ) ) ); @@ -107,14 +107,14 @@ public void testEntityJoin(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); + final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); subquery.multiselect( alternativeContacts.alias( "contact" ) ); subquery.orderBy( cb.desc( alternativeContacts.get( "name" ).get( "first" ) ) ); subquery.fetch( 1 ); final JpaDerivedJoin a = root.joinLateral( subquery, JoinType.LEFT ); - final Join alt = a.join( "contact" ); + final Join alt = a.join( "contact" ); cq.multiselect( root.get( "name" ), alt.get( "name" ) ); cq.orderBy( cb.asc( root.get( "id1" ) ) ); @@ -155,7 +155,7 @@ public void testEntityImplicit(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); + final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); subquery.multiselect( alternativeContacts.alias( "contact" ) ); subquery.orderBy( cb.desc( alternativeContacts.get( "name" ).get( "first" ) ) ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromManyToManyTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromManyToManyTests.java index 07409a0ae126..73c96f8d6afa 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromManyToManyTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromManyToManyTests.java @@ -56,7 +56,7 @@ public void testEntity(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); + final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); subquery.multiselect( alternativeContacts.alias( "contact" ) ); subquery.orderBy( cb.asc( alternativeContacts.get( "name" ).get( "first" ) ) ); @@ -104,14 +104,14 @@ public void testEntityJoin(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); + final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); subquery.multiselect( alternativeContacts.alias( "contact" ) ); subquery.orderBy( cb.desc( alternativeContacts.get( "name" ).get( "first" ) ) ); subquery.fetch( 1 ); final JpaDerivedJoin a = root.joinLateral( subquery, JoinType.LEFT ); - final Join alt = a.join( "contact" ); + final Join alt = a.join( "contact" ); cq.multiselect( root.get( "name" ), alt.get( "name" ) ); cq.orderBy( cb.asc( root.get( "id" ) ) ); @@ -152,7 +152,7 @@ public void testEntityImplicit(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); + final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); subquery.multiselect( alternativeContacts.alias( "contact" ) ); subquery.orderBy( cb.desc( alternativeContacts.get( "name" ).get( "first" ) ) ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromOneToManyEmbeddedIdTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromOneToManyEmbeddedIdTests.java index e530d7bba06e..4c5dec547510 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromOneToManyEmbeddedIdTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromOneToManyEmbeddedIdTests.java @@ -58,7 +58,7 @@ public void testEntity(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); + final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); subquery.multiselect( alternativeContacts.alias( "contact" ) ); subquery.orderBy( cb.asc( alternativeContacts.get( "name" ).get( "first" ) ) ); @@ -108,14 +108,14 @@ public void testEntityJoin(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); + final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); subquery.multiselect( alternativeContacts.alias( "contact" ) ); subquery.orderBy( cb.desc( alternativeContacts.get( "name" ).get( "first" ) ) ); subquery.fetch( 1 ); final JpaDerivedJoin a = root.joinLateral( subquery, JoinType.LEFT ); - final Join alt = a.join( "contact" ); + final Join alt = a.join( "contact" ); cq.multiselect( root.get( "name" ), alt.get( "name" ) ); cq.orderBy( cb.asc( root.get( "id" ) ) ); @@ -156,7 +156,7 @@ public void testEntityImplicit(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); + final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); subquery.multiselect( alternativeContacts.alias( "contact" ) ); subquery.orderBy( cb.desc( alternativeContacts.get( "name" ).get( "first" ) ) ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromOneToManyIdClassTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromOneToManyIdClassTests.java index fcb58b915bbd..0e7a1c2279a3 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromOneToManyIdClassTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromOneToManyIdClassTests.java @@ -58,7 +58,7 @@ public void testEntity(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); + final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); subquery.multiselect( alternativeContacts.alias( "contact" ) ); subquery.orderBy( cb.asc( alternativeContacts.get( "name" ).get( "first" ) ) ); @@ -109,14 +109,14 @@ public void testEntityJoin(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); + final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); subquery.multiselect( alternativeContacts.alias( "contact" ) ); subquery.orderBy( cb.desc( alternativeContacts.get( "name" ).get( "first" ) ) ); subquery.fetch( 1 ); final JpaDerivedJoin a = root.joinLateral( subquery, JoinType.LEFT ); - final Join alt = a.join( "contact" ); + final Join alt = a.join( "contact" ); cq.multiselect( root.get( "name" ), alt.get( "name" ) ); cq.orderBy( cb.asc( root.get( "id1" ) ) ); @@ -157,7 +157,7 @@ public void testEntityImplicit(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); + final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); subquery.multiselect( alternativeContacts.alias( "contact" ) ); subquery.orderBy( cb.desc( alternativeContacts.get( "name" ).get( "first" ) ) ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromOneToManyTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromOneToManyTests.java index 8b6251efcf1d..4105b4af45f6 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromOneToManyTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromOneToManyTests.java @@ -58,7 +58,7 @@ public void testEntity(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); + final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); subquery.multiselect( alternativeContacts.alias( "contact" ) ); subquery.orderBy( cb.asc( alternativeContacts.get( "name" ).get( "first" ) ) ); @@ -106,14 +106,14 @@ public void testEntityJoin(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); + final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); subquery.multiselect( alternativeContacts.alias( "contact" ) ); subquery.orderBy( cb.desc( alternativeContacts.get( "name" ).get( "first" ) ) ); subquery.fetch( 1 ); final JpaDerivedJoin a = root.joinLateral( subquery, JoinType.LEFT ); - final Join alt = a.join( "contact" ); + final Join alt = a.join( "contact" ); cq.multiselect( root.get( "name" ), alt.get( "name" ) ); cq.orderBy( cb.asc( root.get( "id" ) ) ); @@ -154,7 +154,7 @@ public void testEntityImplicit(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); + final Join alternativeContacts = correlatedRoot.join( "alternativeContacts" ); subquery.multiselect( alternativeContacts.alias( "contact" ) ); subquery.orderBy( cb.desc( alternativeContacts.get( "name" ).get( "first" ) ) ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromTests.java index fb6476f3eb9a..549504add292 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubQueryInFromTests.java @@ -137,7 +137,7 @@ public void testBasic(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join address = correlatedRoot.join( "addresses" ); + final Join address = correlatedRoot.join( "addresses" ); subquery.multiselect( address.get( "line1" ).alias( "address" ) ); subquery.orderBy( cb.asc( address.get( "line1" ) ) ); @@ -178,7 +178,7 @@ public void testEmbeddedRoot(SessionFactoryScope scope) { final JpaCriteriaQuery cq = cb.createTupleQuery(); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root subQueryRoot = subquery.from( Contact.class ); - final Join address = subQueryRoot.join( "addresses" ); + final Join address = subQueryRoot.join( "addresses" ); subquery.multiselect( subQueryRoot.get( "name" ).alias( "name" ), address.get( "postalCode" ).alias( "zip" ) ); subquery.where( cb.equal( subQueryRoot.get( "id" ), 1 ) ); @@ -224,7 +224,7 @@ public void testEmbedded(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join address = correlatedRoot.join( "addresses" ); + final Join address = correlatedRoot.join( "addresses" ); subquery.multiselect( address.get( "postalCode" ).alias( "zip" ) ); subquery.orderBy( cb.asc( address.get( "line1" ) ) ); @@ -265,7 +265,7 @@ public void testEntityRoot(SessionFactoryScope scope) { final JpaCriteriaQuery cq = cb.createTupleQuery(); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root subQueryRoot = subquery.from( Contact.class ); - final Join alternativeContact = subQueryRoot.join( "alternativeContact" ); + final Join alternativeContact = subQueryRoot.join( "alternativeContact" ); subquery.multiselect( subQueryRoot.get( "name" ).alias( "name" ), alternativeContact.alias( "contact" ) ); subquery.where( cb.equal( subQueryRoot.get( "id" ), 1 ) ); @@ -307,7 +307,7 @@ public void testEntity(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); + final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); subquery.multiselect( alternativeContact.alias( "contact" ) ); subquery.orderBy( cb.asc( alternativeContact.get( "name" ).get( "first" ) ) ); @@ -353,14 +353,14 @@ public void testEntityJoin(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); + final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); subquery.multiselect( alternativeContact.alias( "contact" ) ); subquery.orderBy( cb.desc( alternativeContact.get( "name" ).get( "first" ) ) ); subquery.fetch( 1 ); final JpaDerivedJoin a = root.joinLateral( subquery, JoinType.LEFT ); - final Join alt = a.join( "contact" ); + final Join alt = a.join( "contact" ); cq.multiselect( root.get( "name" ), alt.get( "name" ) ); cq.where( cb.equal( root.get( "id" ), 1 ) ); @@ -401,7 +401,7 @@ public void testEntityImplicit(SessionFactoryScope scope) { final JpaRoot root = cq.from( Contact.class ); final JpaSubQuery subquery = cq.subquery( Tuple.class ); final Root correlatedRoot = subquery.correlate( root ); - final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); + final Join alternativeContact = correlatedRoot.join( "alternativeContact" ); subquery.multiselect( alternativeContact.alias( "contact" ) ); subquery.orderBy( cb.desc( alternativeContact.get( "name" ).get( "first" ) ) ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubselectFetch2Test.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubselectFetch2Test.java index 204378c07788..101df14c1f5d 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubselectFetch2Test.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/SubselectFetch2Test.java @@ -12,6 +12,7 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import jakarta.persistence.Transient; +import jakarta.persistence.Tuple; import jakarta.persistence.Version; import org.hibernate.annotations.Fetch; import org.hibernate.annotations.FetchMode; @@ -90,7 +91,10 @@ void test2(SessionFactoryScope scope) { @Test void test3(SessionFactoryScope scope) { scope.inTransaction( session -> { - session.createSelectionQuery( "select nh, n1, n2 from NodeHolder nh join nh.node1 n1 join nh.node2 n2" ).getResultList(); + session.createSelectionQuery( + "select nh, n1, n2 from NodeHolder nh join nh.node1 n1 join nh.node2 n2", + Tuple.class + ).getResultList(); } ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/ToHqlStringTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/ToHqlStringTest.java index 355404b89132..fbc3b26659cd 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/ToHqlStringTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/ToHqlStringTest.java @@ -82,7 +82,7 @@ public void testCriteriaWithTreatToHqlString(EntityManagerFactoryScope scope) { CriteriaQuery criteriaQuery = builder.createQuery( Object.class ); Root root = criteriaQuery.from( TestEntity.class ); - Join entity = builder.treat( root, TestEntitySub.class ).join( "entity" ); + Join entity = builder.treat( root, TestEntitySub.class ).join( "entity" ); criteriaQuery = criteriaQuery.select( entity ); TypedQuery query = entityManager.createQuery( criteriaQuery ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/CriteriaInheritanceJoinTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/CriteriaInheritanceJoinTest.java index 27f32d6e7316..93e839586d6c 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/CriteriaInheritanceJoinTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/CriteriaInheritanceJoinTest.java @@ -92,7 +92,7 @@ public void findAddressExplicitJoin(SessionFactoryScope scope) { final CriteriaBuilder cb = session.getCriteriaBuilder(); final CriteriaQuery
cq = cb.createQuery( Address.class ); final Root
addressRoot = cq.from( Address.class ); - final Join join = cb.treat( addressRoot, StreetAddress.class ).join( "street" ); + final Join join = cb.treat( addressRoot, StreetAddress.class ).join( "street" ); cq.select( addressRoot ).where( cb.equal( join.get( "name" ), "Via Roma" ) ); final Address result = session.createQuery( cq ).getSingleResult(); assertThat( result ).isInstanceOf( StreetAddress.class ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/CriteriaMultiselectGroupByAndOrderByTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/CriteriaMultiselectGroupByAndOrderByTest.java index 9b0103fd277d..6abce532e2e2 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/CriteriaMultiselectGroupByAndOrderByTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/CriteriaMultiselectGroupByAndOrderByTest.java @@ -152,7 +152,7 @@ private void executeSubquery(SessionFactoryScope scope, boolean order, boolean h final JpaSubQuery subquery = query.subquery( Tuple.class ); final Root sqRoot = subquery.from( Primary.class ); - final Join secondaryJoin = sqRoot.join( "secondary" ); + final Join secondaryJoin = sqRoot.join( "secondary" ); final Path entityName = secondaryJoin.get( "entityName" ); final Expression sum = cb.sum( sqRoot.get( "amount" ) ); subquery.multiselect( diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/NodeBuilderTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/NodeBuilderTests.java index 4a207cfb44e0..b9736d612ab7 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/NodeBuilderTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/NodeBuilderTests.java @@ -5,6 +5,7 @@ package org.hibernate.orm.test.query.criteria; import org.hibernate.testing.orm.domain.StandardDomainModel; +import org.hibernate.testing.orm.domain.retail.Order; import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.SessionFactory; import org.hibernate.testing.orm.junit.SessionFactoryScope; @@ -22,7 +23,7 @@ public class NodeBuilderTests { public void testFkExpression(SessionFactoryScope scope) { scope.inTransaction( (session) -> { final String hql = "from Order o where fk(o.salesAssociate) = 1"; - session.createSelectionQuery( hql ).getResultList(); + session.createSelectionQuery( hql, Order.class ).getResultList(); } ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/SelectCaseTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/SelectCaseTest.java index 186927d96d62..08afd6c9fc1d 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/SelectCaseTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/SelectCaseTest.java @@ -58,7 +58,7 @@ public void testSelectCaseStringExpressionReturningAnIntegerValues(EntityManager CriteriaQuery criteriaQuery = cb.createTupleQuery(); Root personRoot = criteriaQuery.from( Person.class ); - Join secondaryJoin = personRoot.join( "address" ); + Join secondaryJoin = personRoot.join( "address" ); criteriaQuery.multiselect( cb.selectCase( secondaryJoin.get( "code" ) ) .when( "GR", personRoot.get( "age" ) ) diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/graph/QueryWithGraphTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/graph/QueryWithGraphTests.java new file mode 100644 index 000000000000..34f79435c86c --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/graph/QueryWithGraphTests.java @@ -0,0 +1,90 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.query.graph; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import org.hibernate.Hibernate; +import org.hibernate.annotations.NamedEntityGraph; +import org.hibernate.graph.spi.RootGraphImplementor; +import org.hibernate.orm.test.query.resultmapping.dynamic.Book; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.FailureExpected; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Steve Ebersole + */ +@DomainModel(annotatedClasses = {Book.class, QueryWithGraphTests.Publisher.class}) +@SessionFactory +@FailureExpected(reason = "Need https://github.com/jakartaee/persistence/pull/842") +public class QueryWithGraphTests { + @BeforeEach + void setUp(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + var book = new Book( 1, "The Two Towers", "987-654", LocalDate.now() ); + session.persist( book ); + + var publisher = new Publisher( 1, "Me", List.of(book) ); + session.persist( publisher ); + } ); + } + + @AfterEach + void tearDown(SessionFactoryScope factoryScope) { + factoryScope.dropData(); + } + + @Test + void simpleTest(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + var results = session.createQuery( "from Publisher", Publisher.class ).list(); + assertThat( results ).hasSize( 1 ); + assertThat( Hibernate.isInitialized( results.get( 0 ).books ) ).isFalse(); + } ); + factoryScope.inTransaction( (session) -> { + final RootGraphImplementor entityGraph = (RootGraphImplementor) session.getEntityGraph( "pub-with-books" ); + var results = session.createQuery( "from Publisher", entityGraph ).list(); + assertThat( results ).hasSize( 1 ); + assertThat( Hibernate.isInitialized( results.get( 0 ).books ) ).isTrue(); + } ); + } + + @Entity(name="Publisher") + @Table(name="Publisher") + @NamedEntityGraph( + name = "pub-with-books", + graph = "id, name, books" + ) + public static class Publisher { + @Id + private Integer id; + private String name; + @OneToMany + @JoinColumn(name = "book_fk") + private List books; + + public Publisher() { + } + + public Publisher(Integer id, String name, List books) { + this.id = id; + this.name = name; + this.books = books; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/DistinctFromTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/DistinctFromTest.java index a86ffdf62741..5f94d73c8fa3 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/DistinctFromTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/DistinctFromTest.java @@ -117,19 +117,19 @@ public void testNotDistinctFromStringParam(SessionFactoryScope scope) { @Test void testNulls(SessionFactoryScope scope) { scope.inSession(session -> { - assertEquals(1, session.createSelectionQuery("select 1 where 1 is distinct from 0").getResultList().size()); - assertEquals(0, session.createSelectionQuery("select 1 where 1 is distinct from 1").getResultList().size()); - assertEquals(1, session.createSelectionQuery("select 1 where 1 is distinct from null").getResultList().size()); - assertEquals(1, session.createSelectionQuery("select 1 where null is distinct from 1").getResultList().size()); - assertEquals(1, session.createSelectionQuery("select 1 where null is distinct from 0").getResultList().size()); - assertEquals(0, session.createSelectionQuery("select 1 where null is distinct from null").getResultList().size()); + assertEquals(1, session.createSelectionQuery("select 1 where 1 is distinct from 0", Integer.class).getResultList().size()); + assertEquals(0, session.createSelectionQuery("select 1 where 1 is distinct from 1", Integer.class).getResultList().size()); + assertEquals(1, session.createSelectionQuery("select 1 where 1 is distinct from null", Integer.class).getResultList().size()); + assertEquals(1, session.createSelectionQuery("select 1 where null is distinct from 1", Integer.class).getResultList().size()); + assertEquals(1, session.createSelectionQuery("select 1 where null is distinct from 0", Integer.class).getResultList().size()); + assertEquals(0, session.createSelectionQuery("select 1 where null is distinct from null", Integer.class).getResultList().size()); - assertEquals(0, session.createSelectionQuery("select 1 where 1 is not distinct from 0").getResultList().size()); - assertEquals(1, session.createSelectionQuery("select 1 where 1 is not distinct from 1").getResultList().size()); - assertEquals(0, session.createSelectionQuery("select 1 where 1 is not distinct from null").getResultList().size()); - assertEquals(0, session.createSelectionQuery("select 1 where null is not distinct from 1").getResultList().size()); - assertEquals(0, session.createSelectionQuery("select 1 where null is not distinct from 0").getResultList().size()); - assertEquals(1, session.createSelectionQuery("select 1 where null is not distinct from null").getResultList().size()); + assertEquals(0, session.createSelectionQuery("select 1 where 1 is not distinct from 0", Integer.class).getResultList().size()); + assertEquals(1, session.createSelectionQuery("select 1 where 1 is not distinct from 1", Integer.class).getResultList().size()); + assertEquals(0, session.createSelectionQuery("select 1 where 1 is not distinct from null", Integer.class).getResultList().size()); + assertEquals(0, session.createSelectionQuery("select 1 where null is not distinct from 1", Integer.class).getResultList().size()); + assertEquals(0, session.createSelectionQuery("select 1 where null is not distinct from 0", Integer.class).getResultList().size()); + assertEquals(1, session.createSelectionQuery("select 1 where null is not distinct from null", Integer.class).getResultList().size()); }); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/EnumComparisonTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/EnumComparisonTest.java index 7ad421eaceb6..9d496862e975 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/EnumComparisonTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/EnumComparisonTest.java @@ -27,27 +27,27 @@ void test(SessionFactoryScope scope) { session.createMutationQuery("delete WithEnum").executeUpdate(); session.persist(new WithEnum()); assertEquals(1, - session.createSelectionQuery("from WithEnum where stringEnum > X").getResultList().size()); + session.createSelectionQuery("from WithEnum where stringEnum > X", WithEnum.class).getResultList().size()); assertEquals(1, - session.createSelectionQuery("from WithEnum where ordinalEnum > X").getResultList().size()); + session.createSelectionQuery("from WithEnum where ordinalEnum > X", WithEnum.class).getResultList().size()); assertEquals(1, - session.createSelectionQuery("from WithEnum where stringEnum > 'X'").getResultList().size()); + session.createSelectionQuery("from WithEnum where stringEnum > 'X'", WithEnum.class).getResultList().size()); assertEquals(1, - session.createSelectionQuery("from WithEnum where ordinalEnum > 1").getResultList().size()); + session.createSelectionQuery("from WithEnum where ordinalEnum > 1", WithEnum.class).getResultList().size()); try { - session.createSelectionQuery("from WithEnum where ordinalEnum > 'X'").getResultList(); + session.createSelectionQuery("from WithEnum where ordinalEnum > 'X'", WithEnum.class).getResultList(); fail(); } catch (SemanticException se) { } try { - session.createSelectionQuery("from WithEnum where stringEnum > 1").getResultList(); + session.createSelectionQuery("from WithEnum where stringEnum > 1", WithEnum.class).getResultList(); fail(); } catch (SemanticException se) { } - session.createSelectionQuery("select max(ordinalEnum) from WithEnum").getSingleResult(); - session.createSelectionQuery("select max(stringEnum) from WithEnum").getSingleResult(); + session.createSelectionQuery("select max(ordinalEnum) from WithEnum", Enum.class).getSingleResult(); + session.createSelectionQuery("select max(stringEnum) from WithEnum", Enum.class).getSingleResult(); }); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/FunctionTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/FunctionTests.java index 9b1ee6a76e41..29d2eef6d84b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/FunctionTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/FunctionTests.java @@ -2550,7 +2550,10 @@ public void testMaxOverUnion(SessionFactoryScope scope) { public void testBetweenDates(SessionFactoryScope scope) { scope.inTransaction( session -> { - session.createSelectionQuery("select theDate from EntityOfBasics where theDate between local date and local date + 7 day").getResultList(); + session.createSelectionQuery( + "select theDate from EntityOfBasics where theDate between local date and local date + 7 day", + Date.class + ).getResultList(); } ); } @@ -2559,7 +2562,10 @@ public void testBetweenDates(SessionFactoryScope scope) { public void testMemberOf(SessionFactoryScope scope) { scope.inTransaction( session -> { - session.createSelectionQuery("from EntityOfLists where org.hibernate.testing.orm.domain.gambit.EnumValue.THREE member of listOfEnums").getResultList(); + session.createSelectionQuery( + "from EntityOfLists where org.hibernate.testing.orm.domain.gambit.EnumValue.THREE member of listOfEnums", + EntityOfLists.class + ).getResultList(); } ); } @@ -2568,9 +2574,9 @@ public void testMemberOf(SessionFactoryScope scope) { public void testEnumIsNull(SessionFactoryScope scope) { scope.inTransaction( session -> { - session.createSelectionQuery("from EntityOfBasics where gender is null").getResultList(); - session.createSelectionQuery("from EntityOfBasics e where e.gender is null").getResultList(); - session.createSelectionQuery("from EntityOfBasics where :gender is null").setParameter("gender", EntityOfBasics.Gender.MALE).getResultList(); + session.createSelectionQuery("from EntityOfBasics where gender is null", EntityOfBasics.class).getResultList(); + session.createSelectionQuery("from EntityOfBasics e where e.gender is null", EntityOfBasics.class).getResultList(); + session.createSelectionQuery("from EntityOfBasics where :gender is null", EntityOfBasics.class).setParameter("gender", EntityOfBasics.Gender.MALE).getResultList(); } ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/thisalias/HQLThisTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/thisalias/HQLThisTest.java index 49bc84a1c50e..dfe78be46d5a 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/thisalias/HQLThisTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/thisalias/HQLThisTest.java @@ -20,15 +20,15 @@ public class HQLThisTest { void test(SessionFactoryScope scope) { scope.inTransaction(s -> s.persist(new This("gavin"))); scope.inSession(s -> { - s.createSelectionQuery("select this.name from This this where this.name = 'gavin'").getSingleResult(); - s.createSelectionQuery("from This where this.name = 'gavin'").getSingleResult(); - s.createSelectionQuery("select this.name from This order by this.name").getSingleResult(); - s.createSelectionQuery("select count(this) from This").getSingleResult(); - s.createSelectionQuery("select id(this) from This").getSingleResult(); + s.createSelectionQuery("select this.name from This this where this.name = 'gavin'", String.class).getSingleResult(); + s.createSelectionQuery("from This where this.name = 'gavin'", This.class).getSingleResult(); + s.createSelectionQuery("select this.name from This order by this.name", String.class).getSingleResult(); + s.createSelectionQuery("select count(this) from This", Long.class).getSingleResult(); + s.createSelectionQuery("select id(this) from This", Long.class).getSingleResult(); // testing case insensitivity - s.createSelectionQuery("select THIS.name from This ORDER BY THIS.name").getSingleResult(); - s.createSelectionQuery("select count(THIS) from This").getSingleResult(); - s.createSelectionQuery("select id(ThIs) from This").getSingleResult(); + s.createSelectionQuery("select THIS.name from This ORDER BY THIS.name", String.class).getSingleResult(); + s.createSelectionQuery("select count(THIS) from This", Long.class).getSingleResult(); + s.createSelectionQuery("select id(ThIs) from This", Long.class).getSingleResult(); }); } @Entity(name="This") diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/joinfetch/JoinFetchTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/joinfetch/JoinFetchTest.java index 46808216ea87..76fe5e15df3d 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/joinfetch/JoinFetchTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/joinfetch/JoinFetchTest.java @@ -119,7 +119,7 @@ public void testJoinFetch(SessionFactoryScope scope) { scope.inTransaction( (s) -> { - Item i1 = (Item) s.getNamedQuery( Item.class.getName() + ".all" ).list().get( 0 ); + Item i1 = (Item) s.createNamedQuery( Item.class.getName() + ".all" ).list().get( 0 ); assertTrue( Hibernate.isInitialized( i1.getBids() ) ); assertTrue( Hibernate.isInitialized( i1.getComments() ) ); assertEquals( 3, i1.getComments().size() ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/EntityResultTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/EntityResultTests.java index f3109088c03c..cac640a3129b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/EntityResultTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/EntityResultTests.java @@ -260,7 +260,7 @@ public void testImplicitEmbeddedMapping(SessionFactoryScope scope) { scope.inTransaction( session -> { final EntityWithEmbedded result = (EntityWithEmbedded) session - .getNamedNativeQuery( EntityWithEmbedded.IMPLICIT ) + .createNamedQuery( EntityWithEmbedded.IMPLICIT ) .getSingleResult(); assertThat( result, notNullValue() ); assertThat( result.getId(), is( 1 ) ); @@ -276,7 +276,7 @@ public void testExplicitEmbeddedMapping(SessionFactoryScope scope) { scope.inTransaction( session -> { final EntityWithEmbedded result = (EntityWithEmbedded) session - .getNamedNativeQuery( EntityWithEmbedded.EXPLICIT ) + .createNamedQuery( EntityWithEmbedded.EXPLICIT ) .getSingleResult(); assertThat( result, notNullValue() ); assertThat( result.getId(), is( 1 ) ); @@ -356,7 +356,7 @@ public void testImplicitHbmMappingEntityComplete(SessionFactoryScope scope) { scope.inTransaction( session -> { final List results = session - .getNamedNativeQuery( "hbm-implicit-resultset" ) + .createNamedQuery( "hbm-implicit-resultset" ) .list(); assertThat( results.size(), is( 1 ) ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/NamedRepoTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/NamedRepoTests.java index 591e95b9aa57..bd790dfbd8d1 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/NamedRepoTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/NamedRepoTests.java @@ -9,8 +9,8 @@ import org.hibernate.query.internal.ResultSetMappingResolutionContext; import org.hibernate.query.named.NamedObjectRepository; import org.hibernate.query.named.NamedResultSetMappingMemento; -import org.hibernate.query.results.ResultBuilderBasicValued; -import org.hibernate.query.results.ResultSetMapping; +import org.hibernate.query.results.spi.ResultBuilderBasicValued; +import org.hibernate.query.results.spi.ResultSetMapping; import org.hibernate.query.results.internal.ResultSetMappingImpl; import org.hibernate.query.spi.QueryEngine; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/dynamic/Book.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/dynamic/Book.java new file mode 100644 index 000000000000..7863b68d3a2f --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/dynamic/Book.java @@ -0,0 +1,77 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.query.resultmapping.dynamic; + +import jakarta.persistence.ColumnResult; +import jakarta.persistence.ConstructorResult; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityResult; +import jakarta.persistence.FieldResult; +import jakarta.persistence.Id; +import jakarta.persistence.SqlResultSetMapping; +import jakarta.persistence.Table; +import org.hibernate.annotations.NaturalId; + +import java.time.LocalDate; + +/** + * @author Steve Ebersole + */ +@SuppressWarnings("FieldCanBeLocal") +@Entity(name = "Book") +@Table(name = "books") +@SqlResultSetMapping(name = "book-dto", + classes = @ConstructorResult(targetClass = Book.class, + columns = { + @ColumnResult(name = "id", type = Integer.class), + @ColumnResult(name = "name", type = String.class), + @ColumnResult(name = "isbn", type = String.class), + @ColumnResult(name = "published", type = LocalDate.class) + } + ) +) +@SqlResultSetMapping(name = "book-drop-down", + classes = @ConstructorResult(targetClass = DropDownItem.class, + columns = { + @ColumnResult(name = "id", type = Integer.class), + @ColumnResult(name = "name", type = String.class) + } + ) +) +@SqlResultSetMapping(name = "id", + columns = @ColumnResult(name = "id", type = Integer.class) +) +@SqlResultSetMapping(name = "book-implicit", + entities = @EntityResult(entityClass = Book.class) +) +@SqlResultSetMapping(name = "book-explicit", + entities = @EntityResult( + entityClass = Book.class, + fields = { + @FieldResult(name = "id", column = "id_"), + @FieldResult(name = "name", column = "name_"), + @FieldResult(name = "isbn", column = "isbn_"), + @FieldResult(name = "published", column = "published_"), + } + ) +) +public class Book { + @Id + private Integer id; + private String name; + @NaturalId + private String isbn; + private LocalDate published; + + public Book() { + } + + public Book(Integer id, String name, String isbn, LocalDate published) { + this.id = id; + this.name = name; + this.isbn = isbn; + this.published = published; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/dynamic/DropDownItem.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/dynamic/DropDownItem.java new file mode 100644 index 000000000000..991a81a620c8 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/dynamic/DropDownItem.java @@ -0,0 +1,19 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.query.resultmapping.dynamic; + +/** + * @author Steve Ebersole + */ +@SuppressWarnings("FieldCanBeLocal") +public class DropDownItem { + private final Integer key; + private final String text; + + public DropDownItem(Integer key, String text) { + this.key = key; + this.text = text; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/dynamic/NamedToDynamicTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/dynamic/NamedToDynamicTests.java new file mode 100644 index 000000000000..36a559653ba3 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/dynamic/NamedToDynamicTests.java @@ -0,0 +1,73 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.query.resultmapping.dynamic; + +import jakarta.persistence.sql.ColumnMapping; +import jakarta.persistence.sql.ConstructorMapping; +import jakarta.persistence.sql.EntityMapping; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/// Tests for [jakarta.persistence.EntityManagerFactory#getResultSetMappings] +/// based on named mappings. +/// +/// @author Steve Ebersole +@DomainModel( annotatedClasses = { Book.class, DropDownItem.class }) +@SessionFactory +public class NamedToDynamicTests { + @Test + void testConstructorConversions(SessionFactoryScope factoryScope) { + final SessionFactoryImplementor sessionFactory = factoryScope.getSessionFactory(); + + var mappingsToBook = sessionFactory.getResultSetMappings( Book.class ); + assertThat( mappingsToBook ).containsKey( "book-dto" ); + var bootDto = (ConstructorMapping) mappingsToBook.get( "book-dto" ); + assertThat( bootDto.getJavaType() ).isEqualTo( Book.class ); + assertThat( bootDto.arguments() ).hasSize( 4 ); + + var mappingsToDropDownItem = sessionFactory.getResultSetMappings( DropDownItem.class ); + assertThat( mappingsToDropDownItem ).containsKey( "book-drop-down" ); + var bookDropDown = (ConstructorMapping) mappingsToDropDownItem.get( "book-drop-down" ); + assertThat( bookDropDown.getJavaType() ).isEqualTo( DropDownItem.class ); + assertThat( bookDropDown.arguments() ).hasSize( 2 ); + } + + @Test + void testColumnConversions(SessionFactoryScope factoryScope) { + var sessionFactory = factoryScope.getSessionFactory(); + + var integerMappings = sessionFactory.getResultSetMappings( Integer.class ); + assertThat( integerMappings ).containsKey( "id" ); + var idMapping = (ColumnMapping) integerMappings.get( "id" ); + assertThat( idMapping.getJavaType() ).isEqualTo( Integer.class ); + assertThat( idMapping.columnName() ).isEqualTo( "id" ); + } + + @Test + void testEntityConversions(SessionFactoryScope factoryScope) { + var sessionFactory = factoryScope.getSessionFactory(); + + var bookMappings = sessionFactory.getResultSetMappings( Book.class ); + + assertThat( bookMappings ).containsKey( "book-implicit" ); + var bookImplicitMapping = (EntityMapping) bookMappings.get( "book-implicit" ); + assertThat( bookImplicitMapping.getJavaType() ).isEqualTo( Book.class ); + assertThat( bookImplicitMapping.discriminatorColumn() ).isNull(); + assertThat( bookImplicitMapping.fields() ).isEmpty(); + + assertThat( bookMappings ).containsKey( "book-explicit" ); + var bookExplicitMapping = (EntityMapping) bookMappings.get( "book-explicit" ); + assertThat( bookExplicitMapping.getJavaType() ).isEqualTo( Book.class ); + assertThat( bookExplicitMapping.discriminatorColumn() ).isNull(); + assertThat( bookExplicitMapping.fields() ).hasSize( 4 ); + // "unfortunately" our memento objects do not keep the ordering + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/dynamic/NestedDropDownItem.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/dynamic/NestedDropDownItem.java new file mode 100644 index 000000000000..e369a9acf83a --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/dynamic/NestedDropDownItem.java @@ -0,0 +1,26 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.query.resultmapping.dynamic; + +/** + * @author Steve Ebersole + */ +public class NestedDropDownItem { + private final Object key; + private final String text; + private final DropDownItem nested; + + public NestedDropDownItem(Integer key, String text, DropDownItem nested) { + this.key = key; + this.text = text; + this.nested = nested; + } + + public NestedDropDownItem(Object key, String text, DropDownItem nested) { + this.key = key; + this.text = text; + this.nested = nested; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/dynamic/SimpleResultSetMappingTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/dynamic/SimpleResultSetMappingTests.java new file mode 100644 index 000000000000..8c8d60f2c9ea --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/dynamic/SimpleResultSetMappingTests.java @@ -0,0 +1,183 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.query.resultmapping.dynamic; + +import jakarta.persistence.Tuple; +import jakarta.persistence.sql.ResultSetMapping; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; + +import static org.assertj.core.api.Assertions.assertThat; + +/// Tests for [ResultSetMapping] creation/usage. +/// +/// @author Steve Ebersole +@DomainModel( annotatedClasses = { Book.class, DropDownItem.class }) +@SessionFactory +public class SimpleResultSetMappingTests { + @BeforeEach + void setUp(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + session.persist( new Book( 1, "The Fellowship of the Ring", "123-456", LocalDate.now() ) ); + } ); + } + + @AfterEach + void tearDown(SessionFactoryScope factoryScope) { + factoryScope.dropData(); + } + + @Test + void testColumnMappings(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + var mapping = ResultSetMapping.column( "id", Integer.class ); + var result = session.createNativeQuery( "select id from books", mapping ).list(); + assertThat( result ).hasSize( 1 ); + assertThat( result.get( 0 ) ).isInstanceOf( Integer.class ); + } ); + factoryScope.inTransaction( (session) -> { + var mapping = ResultSetMapping.column( "name", String.class ); + var result = session.createNativeQuery( "select name from books", mapping ).list(); + assertThat( result ).hasSize( 1 ); + assertThat( result.get( 0 ) ).isInstanceOf( String.class ); + } ); + factoryScope.inTransaction( (session) -> { + var mapping = ResultSetMapping.column( "published", LocalDate.class ); + var result = session.createNativeQuery( "select published from books", mapping ).list(); + assertThat( result ).hasSize( 1 ); + assertThat( result.get( 0 ) ).isInstanceOf( LocalDate.class ); + } ); + } + + /// @see NamedToDynamicTests#testConstructorConversions + @Test + void testConstructorMappings(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + var mapping = ResultSetMapping.constructor( + Book.class, + ResultSetMapping.column( "id", Integer.class ), + ResultSetMapping.column( "name", String.class ), + ResultSetMapping.column( "isbn", String.class ), + ResultSetMapping.column( "published", LocalDate.class ) + ); + var result = session.createNativeQuery( "select * from books", mapping ).list(); + assertThat( result ).hasSize( 1 ); + assertThat( result.get( 0 ) ).isInstanceOf( Book.class ); + } ); + + factoryScope.inTransaction( (session) -> { + var mapping = ResultSetMapping.constructor( + DropDownItem.class, + ResultSetMapping.column( "id", Integer.class ), + ResultSetMapping.column( "name", String.class ) + ); + var result = session.createNativeQuery( "select * from books", mapping ).list(); + assertThat( result ).hasSize( 1 ); + assertThat( result.get( 0 ) ).isInstanceOf( DropDownItem.class ); + } ); + + factoryScope.inTransaction( (session) -> { + var mapping = ResultSetMapping.constructor( + NestedDropDownItem.class, + ResultSetMapping.column( "isbn", String.class ), + ResultSetMapping.column( "name", String.class ), + ResultSetMapping.constructor( + DropDownItem.class, + ResultSetMapping.column( "id", Integer.class ), + ResultSetMapping.column( "name", String.class ) + ) + ); + var result = session.createNativeQuery( "select * from books", mapping ).list(); + assertThat( result ).hasSize( 1 ); + assertThat( result.get( 0 ) ).isInstanceOf( NestedDropDownItem.class ); + } ); + } + + @Test + void testEntityMapping(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + var mapping = ResultSetMapping.entity( + Book.class, + ResultSetMapping.field( Book_.id, "id" ), + ResultSetMapping.field( Book_.name, "name" ), + ResultSetMapping.field( Book_.isbn, "isbn" ), + ResultSetMapping.field( Book_.published, "published" ) + ); + var result = session.createNativeQuery( "select * from books", mapping ).list(); + assertThat( result ).hasSize( 1 ); + assertThat( result.get( 0 ) ).isInstanceOf( Book.class ); + } ); + } + + @Test + void testTupleMapping(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + var mapping = ResultSetMapping.tuple( + ResultSetMapping.column( "id", Integer.class ), + ResultSetMapping.column( "name", String.class ), + ResultSetMapping.column( "isbn", String.class ), + ResultSetMapping.column( "published", LocalDate.class ) + ); + var result = session.createNativeQuery( "select * from books", mapping ).list(); + assertThat( result ).hasSize( 1 ); + + final Tuple tuple = result.get( 0 ); + assertThat( tuple.getElements() ).hasSize( 4 ); + // should be the id + assertThat( tuple.get( "id" ) ).isEqualTo( 1 ); + assertThat( tuple.get( 0 ) ).isEqualTo( 1 ); + // should be the name + assertThat( tuple.get( "name" ) ).isEqualTo( "The Fellowship of the Ring" ); + assertThat( tuple.get( 1 ) ).isEqualTo( "The Fellowship of the Ring" ); + } ); + + factoryScope.inTransaction( (session) -> { + var mapping = ResultSetMapping.tuple( + ResultSetMapping.constructor( + DropDownItem.class, + ResultSetMapping.column( "id", Integer.class ), + ResultSetMapping.column( "name", String.class ) + ), + ResultSetMapping.column( "isbn", String.class ), + ResultSetMapping.column( "published", LocalDate.class ) + ); + var result = session.createNativeQuery( "select * from books", mapping ).list(); + assertThat( result ).hasSize( 1 ); + + final Tuple tuple = result.get( 0 ); + assertThat( tuple.getElements() ).hasSize( 3 ); + // note: currently not an easy way to alias the constructor mapping + assertThat( tuple.get( 0 ) ).isInstanceOf( DropDownItem.class ); + assertThat( tuple.get( 1 ) ).isEqualTo( "123-456" ); + assertThat( tuple.get( "isbn" ) ).isEqualTo( "123-456" ); + } ); + } + + @Test + void testCompoundMapping(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + var mapping = ResultSetMapping.compound( + ResultSetMapping.column( "id", Integer.class ), + ResultSetMapping.column( "name", String.class ), + ResultSetMapping.column( "isbn", String.class ), + ResultSetMapping.column( "published", LocalDate.class ) + ); + var result = session.createNativeQuery( "select * from books", mapping ).list(); + assertThat( result ).hasSize( 1 ); + final Object[] row = result.get( 0 ); + assertThat( row ).hasSize( 4 ); + // should be the id + assertThat( row[0] ).isEqualTo( 1 ); + // should be the name + assertThat( row[1] ).isEqualTo( "The Fellowship of the Ring" ); + } ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/results/ImplicitSelectWithJoinTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/results/ImplicitSelectWithJoinTests.java index 90dbea7516b9..a7dc4e49e87a 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/results/ImplicitSelectWithJoinTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/results/ImplicitSelectWithJoinTests.java @@ -14,7 +14,6 @@ import org.hibernate.testing.orm.domain.retail.Product; import org.hibernate.testing.orm.domain.retail.Vendor; import org.hibernate.testing.orm.junit.DomainModel; -import org.hibernate.testing.orm.junit.FailureExpected; import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.testing.orm.junit.SessionFactory; import org.hibernate.testing.orm.junit.SessionFactoryScope; @@ -23,7 +22,6 @@ import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; /** * @author Steve Ebersole @@ -40,28 +38,7 @@ public class ImplicitSelectWithJoinTests { @Test public void testNoExpectedTypeWithThis(SessionFactoryScope scope) { scope.inTransaction( (session) -> { - final SelectionQuery query = session.createSelectionQuery( HQL0 ); - - { - final List results = query.list(); - assertThat( results ).hasSize( 1 ); - final Object result = results.get( 0 ); - assertThat( result ).isInstanceOf( Product.class ); - } - - try (ScrollableResults results = query.scroll()) { - assertThat( results.next() ).isTrue(); - final Object result = results.get(); - assertThat( result ).isInstanceOf( Product.class ); - assertThat( results.next() ).isFalse(); - } - } ); - } - - @Test @FailureExpected(reason = "this functionality was disabled, and an exception is now thrown") - public void testNoExpectedType(SessionFactoryScope scope) { - scope.inTransaction( (session) -> { - final SelectionQuery query = session.createSelectionQuery( HQL ); + final SelectionQuery query = session.createSelectionQuery( HQL0, Object.class ); { final List results = query.list(); @@ -100,59 +77,6 @@ public void testProductResult(SessionFactoryScope scope) { } ); } - @Test @FailureExpected(reason = "this functionality was disabled, and an exception is now thrown") - public void testArrayResultNoResultType(SessionFactoryScope scope) { - scope.inTransaction( (session) -> { - final SelectionQuery query = session.createSelectionQuery( HQL3 ); - - { - final List results = query.list(); - assertThat( results ).hasSize( 1 ); - final Object result = results.get( 0 ); - assertThat( result ).isNotNull(); - assertInstanceOf( Object[].class, result ); - assertThat( (Object[]) result ).hasSize(4); - assertThat( (Object[]) result ).hasExactlyElementsOfTypes(Product.class, Vendor.class, Product.class, Vendor.class); - } - - try (ScrollableResults results = query.scroll()) { - assertThat( results.next() ).isTrue(); - final Object result = results.get(); - assertThat( result ).isNotNull(); - assertInstanceOf( Object[].class, result ); - assertThat( (Object[]) result ).hasSize(4); - assertThat( (Object[]) result ).hasExactlyElementsOfTypes(Product.class, Vendor.class, Product.class, Vendor.class); - assertThat( results.next() ).isFalse(); - } - } ); - - // frankly, this would be more consistent and more backward-compatible -// scope.inTransaction( (session) -> { -// final SelectionQuery query = session.createSelectionQuery( HQL ); -// -// { -// final List results = query.list(); -// assertThat( results ).hasSize( 1 ); -// final Object result = results.get( 0 ); -// assertThat( result ).isNotNull(); -// assertInstanceOf( Object[].class, result ); -// assertThat( (Object[]) result ).hasSize(2); -// assertThat( (Object[]) result ).hasExactlyElementsOfTypes(Product.class, Vendor.class); -// } -// -// { -// final ScrollableResults results = query.scroll(); -// assertThat( results.next() ).isTrue(); -// final Object result = results.get(); -// assertThat( result ).isNotNull(); -// assertInstanceOf( Object[].class, result ); -// assertThat( (Object[]) result ).hasSize(2); -// assertThat( (Object[]) result ).hasExactlyElementsOfTypes(Product.class, Vendor.class); -// assertThat( results.next() ).isFalse(); -// } -// } ); - } - @Test public void testArrayResult(SessionFactoryScope scope) { scope.inTransaction( (session) -> { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/sql/NativeQueryResultCheckingTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/sql/NativeQueryResultCheckingTests.java index fba4161d3101..46e86448f6e6 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/sql/NativeQueryResultCheckingTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/sql/NativeQueryResultCheckingTests.java @@ -39,7 +39,7 @@ public void testForHHH19376(SessionFactoryScope scope) { scope.inTransaction( session -> { String sql = "SELECT p.*, COUNT(*) OVER() AS total_count " - + "FROM Person p " + + "FROM persons p " + "WHERE p.name ILIKE :name " + "ORDER BY p.id"; // Declare Person as result type @@ -59,7 +59,7 @@ public void testOneColumn(SessionFactoryScope scope) { scope.inTransaction( session -> assertDoesNotThrow( - () -> session.createNativeQuery( "select isbn from Book", String.class ) + () -> session.createNativeQuery( "select isbn from books", String.class ) .addScalar( "isbn", String.class ) .getResultList() ) @@ -67,7 +67,7 @@ public void testOneColumn(SessionFactoryScope scope) { scope.inTransaction( session -> assertThrows( IllegalArgumentException.class, - () -> session.createNativeQuery( "select isbn from Book", Integer.class ) + () -> session.createNativeQuery( "select isbn from books", Integer.class ) .addScalar( "isbn", String.class ) .getResultList() ) @@ -75,7 +75,7 @@ public void testOneColumn(SessionFactoryScope scope) { scope.inTransaction( session -> assertDoesNotThrow( - () -> session.createNativeQuery( "select isbn from Book", Object[].class ) + () -> session.createNativeQuery( "select isbn from books", Object[].class ) .addScalar( "isbn", String.class ) .getResultList() ) @@ -83,7 +83,7 @@ public void testOneColumn(SessionFactoryScope scope) { scope.inTransaction( session -> assertDoesNotThrow( - () -> session.createNativeQuery( "select isbn from Book", Tuple.class ) + () -> session.createNativeQuery( "select isbn from books", Tuple.class ) .addScalar( "isbn", String.class ) .getResultList() ) @@ -91,7 +91,7 @@ public void testOneColumn(SessionFactoryScope scope) { scope.inTransaction( session -> assertDoesNotThrow( - () -> session.createNativeQuery( "select isbn from Book", Map.class ) + () -> session.createNativeQuery( "select isbn from books", Map.class ) .addScalar( "isbn", String.class ) .getResultList() ) @@ -99,7 +99,7 @@ public void testOneColumn(SessionFactoryScope scope) { scope.inTransaction( session -> assertDoesNotThrow( - () -> session.createNativeQuery( "select isbn from Book", Object.class ) + () -> session.createNativeQuery( "select isbn from books", Object.class ) .addScalar( "isbn", String.class ) .getResultList() ) @@ -107,7 +107,7 @@ public void testOneColumn(SessionFactoryScope scope) { scope.inTransaction( session -> assertDoesNotThrow( - () -> session.createNativeQuery( "select isbn from Book" ) + () -> session.createNativeQuery( "select isbn from books" ) .addScalar( "isbn", String.class ) .getResultList() ) @@ -119,7 +119,7 @@ public void testTwoStringColumns(SessionFactoryScope scope) { scope.inTransaction( session -> assertThrows( IllegalArgumentException.class, - () -> session.createNativeQuery( "select name, isbn from Book", String.class ) + () -> session.createNativeQuery( "select name, isbn from books", String.class ) .addScalar( "name", String.class ) .addScalar( "isbn", String.class ) .getResultList() @@ -128,7 +128,7 @@ public void testTwoStringColumns(SessionFactoryScope scope) { scope.inTransaction( session -> assertDoesNotThrow( - () -> session.createNativeQuery( "select name, isbn from Book", Object[].class ) + () -> session.createNativeQuery( "select name, isbn from books", Object[].class ) .addScalar( "name", String.class ) .addScalar( "isbn", String.class ) .getResultList() @@ -137,7 +137,7 @@ public void testTwoStringColumns(SessionFactoryScope scope) { scope.inTransaction( session -> assertDoesNotThrow( - () -> session.createNativeQuery( "select name, isbn from Book", Tuple.class ) + () -> session.createNativeQuery( "select name, isbn from books", Tuple.class ) .addScalar( "name", String.class ) .addScalar( "isbn", String.class ) .getResultList() @@ -146,7 +146,7 @@ public void testTwoStringColumns(SessionFactoryScope scope) { scope.inTransaction( session -> assertDoesNotThrow( - () -> session.createNativeQuery( "select name, isbn from Book", Map.class ) + () -> session.createNativeQuery( "select name, isbn from books", Map.class ) .addScalar( "name", String.class ) .addScalar( "isbn", String.class ) .getResultList() @@ -155,7 +155,7 @@ public void testTwoStringColumns(SessionFactoryScope scope) { scope.inTransaction( session -> assertDoesNotThrow( - () -> session.createNativeQuery( "select name, isbn from Book", Object.class ) + () -> session.createNativeQuery( "select name, isbn from books", Object.class ) .addScalar( "name", String.class ) .addScalar( "isbn", String.class ) .getResultList() @@ -164,7 +164,7 @@ public void testTwoStringColumns(SessionFactoryScope scope) { scope.inTransaction( session -> assertDoesNotThrow( - () -> session.createNativeQuery( "select name, isbn from Book" ) + () -> session.createNativeQuery( "select name, isbn from books" ) .addScalar( "name", String.class ) .addScalar( "isbn", String.class ) .getResultList() @@ -173,7 +173,7 @@ public void testTwoStringColumns(SessionFactoryScope scope) { scope.inTransaction( session -> assertThrows( IllegalArgumentException.class, - () -> session.createNativeQuery( "select name, isbn from Book", Book.class ) + () -> session.createNativeQuery( "select name, isbn from books", Book.class ) // this mapping doesn't have an appropriate constructor in Book, should throw error .addScalar( "name", String.class ) .addScalar( "isbn", String.class ) @@ -187,7 +187,7 @@ public void testOkMutateResultSetMappingWithBook(SessionFactoryScope scope) { scope.inTransaction( session -> assertDoesNotThrow( - () -> session.createNativeQuery( "select id, name from Book", Book.class ) + () -> session.createNativeQuery( "select id, name from books", Book.class ) .addScalar( "id", Integer.class ) .addScalar( "name", String.class ) .getResultList() @@ -201,7 +201,7 @@ public void testAllColumns(SessionFactoryScope scope) { session -> assertDoesNotThrow( () -> { - session.createNativeQuery( "select * from Book", Object[].class ) + session.createNativeQuery( "select * from books", Object[].class ) .addScalar( "id", Integer.class ) .addScalar( "name", String.class ) .getResultList(); @@ -212,7 +212,7 @@ public void testAllColumns(SessionFactoryScope scope) { session -> assertDoesNotThrow( () -> { - session.createNativeQuery( "select * from Book", Tuple.class ) + session.createNativeQuery( "select * from books", Tuple.class ) .addScalar( "id", Integer.class ) .addScalar( "name", String.class ) .getResultList(); @@ -223,7 +223,7 @@ public void testAllColumns(SessionFactoryScope scope) { session -> assertDoesNotThrow( () -> { - session.createNativeQuery( "select * from Book", Map.class ) + session.createNativeQuery( "select * from books", Map.class ) .addScalar( "id", Integer.class ) .addScalar( "name", String.class ) .getResultList(); @@ -234,7 +234,7 @@ public void testAllColumns(SessionFactoryScope scope) { session -> assertDoesNotThrow( () -> { - session.createNativeQuery( "select * from Book", Object.class ) + session.createNativeQuery( "select * from books", Object.class ) .addScalar( "id", Integer.class ) .addScalar( "name", String.class ) .getResultList(); @@ -245,7 +245,7 @@ public void testAllColumns(SessionFactoryScope scope) { session -> assertDoesNotThrow( () -> { - session.createNativeQuery( "select * from Book", Book.class ) + session.createNativeQuery( "select * from books", Book.class ) .addScalar( "id", Integer.class ) .addScalar( "name", String.class ) .getResultList(); @@ -256,7 +256,7 @@ public void testAllColumns(SessionFactoryScope scope) { session -> assertDoesNotThrow( () -> { - session.createNativeQuery( "select * from Book", List.class ) + session.createNativeQuery( "select * from books", List.class ) .addScalar( "id", Integer.class ) .addScalar( "name", String.class ) .getResultList(); @@ -266,7 +266,7 @@ public void testAllColumns(SessionFactoryScope scope) { scope.inTransaction( session -> assertThrows( IllegalArgumentException.class, - () -> session.createNativeQuery( "select * from Book", Book.class ) + () -> session.createNativeQuery( "select * from books", Book.class ) .addScalar( "isbn", String.class ) .addScalar( "name", String.class ) .getResultList() @@ -279,7 +279,7 @@ public void testRecordWithPrimitiveField(SessionFactoryScope scope) { scope.inTransaction( session -> assertDoesNotThrow( - () -> session.createNativeQuery( "select id, name from Person", Record.class) + () -> session.createNativeQuery( "select id, name from persons", Record.class) // map a Long onto a primitive long, shouldn't throw an exception .addScalar("id", Long.class) .addScalar("name", String.class) diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/sqm/BasicSelectionQueryTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/sqm/BasicSelectionQueryTests.java index 48a3871a63c5..806f86525545 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/sqm/BasicSelectionQueryTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/sqm/BasicSelectionQueryTests.java @@ -54,7 +54,7 @@ public void typedEntitySelectTest(SessionFactoryScope scope) { public void rawEntitySelectTest(SessionFactoryScope scope) { scope.inTransaction( (session) -> { // its unbounded - final SelectionQuery query = session.createSelectionQuery( "select c from DummyEntity c" ); + final SelectionQuery query = session.createSelectionQuery( "select c from DummyEntity c", Object.class ); checkResults( query, session ); } ); } @@ -119,10 +119,10 @@ public void dropTestData(SessionFactoryScope scope) { @Test public void rawScalarSelectTest(SessionFactoryScope scope) { scope.inTransaction( (session) -> { - final SelectionQuery nameQuery = session.createSelectionQuery( "select c.name from Contact c" ); + final SelectionQuery nameQuery = session.createSelectionQuery( "select c.name from Contact c", Object.class ); checkResults( nameQuery, session ); - final SelectionQuery firstNameQuery = session.createSelectionQuery( "select c.name.first from Contact c" ); + final SelectionQuery firstNameQuery = session.createSelectionQuery( "select c.name.first from Contact c", Object.class ); checkResults( firstNameQuery, session ); } ); } @@ -141,10 +141,10 @@ public void typesNamedSelectTest(SessionFactoryScope scope) { @Test public void rawNamedSelectTest(SessionFactoryScope scope) { scope.inTransaction( (session) -> { - final SelectionQuery nameQuery = session.createNamedSelectionQuery( "hql-name" ); + final SelectionQuery nameQuery = session.createNamedSelectionQuery( "hql-name", Object.class ); checkResults( nameQuery, session ); - final SelectionQuery firstNameQuery = session.createNamedSelectionQuery( "hql-first-name" ); + final SelectionQuery firstNameQuery = session.createNamedSelectionQuery( "hql-first-name", Object.class ); checkResults( firstNameQuery, session ); } ); } @@ -153,7 +153,7 @@ public void rawNamedSelectTest(SessionFactoryScope scope) { public void mutationAsSelectTest(SessionFactoryScope scope) { scope.inTransaction( (session) -> { try { - session.createSelectionQuery( "delete from Contact" ); + session.createSelectionQuery( "delete from Contact", Object.class ); fail( "Expecting IllegalSelectQueryException" ); } catch (IllegalSelectQueryException expected) { @@ -165,7 +165,7 @@ public void mutationAsSelectTest(SessionFactoryScope scope) { public void namedMutationAsSelectTest(SessionFactoryScope scope) { scope.inTransaction( (session) -> { try { - session.createNamedSelectionQuery( "hql-mutation" ); + session.createNamedSelectionQuery( "hql-mutation", Object.class ); fail( "Expecting IllegalSelectQueryException" ); } catch (IllegalSelectQueryException expected) { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/querycache/AbstractQueryCacheResultTransformerTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/querycache/AbstractQueryCacheResultTransformerTest.java index d4f4a12106ac..08fd1d498302 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/querycache/AbstractQueryCacheResultTransformerTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/querycache/AbstractQueryCacheResultTransformerTest.java @@ -752,7 +752,7 @@ protected JpaCriteriaQuery getCriteria(Session s) { CriteriaBuilder builder = s.getCriteriaBuilder(); JpaCriteriaQuery criteria = (JpaCriteriaQuery) builder.createQuery( Object[].class ); JpaRoot root = criteria.from( Student.class ); - Join preferredCourse = root.join( "preferredCourse", JoinType.LEFT ); + Join preferredCourse = root.join( "preferredCourse", JoinType.LEFT ); root.fetch( "enrolments", JoinType.LEFT ); criteria.orderBy( builder.asc( root.get( "studentNumber" ) ) ); @@ -1509,7 +1509,7 @@ protected JpaCriteriaQuery getCriteria(Session s) { JpaCriteriaQuery criteria = (JpaCriteriaQuery) builder.createQuery( Object[].class ); Root root = criteria.from( Student.class ); - Join preferredCourse = root.join( "preferredCourse", JoinType.LEFT ); + Join preferredCourse = root.join( "preferredCourse", JoinType.LEFT ); criteria.multiselect( root, preferredCourse ); @@ -1848,7 +1848,7 @@ protected JpaCriteriaQuery getCriteria(Session s) { CriteriaBuilder builder = s.getCriteriaBuilder(); JpaCriteriaQuery criteria = (JpaCriteriaQuery) builder.createQuery(); Root root = criteria.from( Student.class ); - final ListJoin secretCodes = root.joinList( "secretCodes" ); + final ListJoin secretCodes = root.joinList( "secretCodes" ); criteria.select( secretCodes ); return criteria; } @@ -3114,7 +3114,7 @@ protected JpaCriteriaQuery getCriteria(Session s) { JpaCriteriaQuery criteria = (JpaCriteriaQuery) builder.createQuery(); Root root = criteria.from( Student.class ); - final MapJoin addresses = root.joinMap( "addresses", JoinType.INNER ); + final MapJoin addresses = root.joinMap( "addresses", JoinType.INNER ); criteria.select( addresses.key() ); /* @@ -3155,7 +3155,7 @@ protected JpaCriteriaQuery getCriteria(Session s) { JpaCriteriaQuery criteria = (JpaCriteriaQuery) builder.createQuery(); Root root = criteria.from( Student.class ); - final MapJoin addresses = root.joinMap( "addresses", JoinType.INNER ); + final MapJoin addresses = root.joinMap( "addresses", JoinType.INNER ); criteria.select( addresses.value() ); /* @@ -3196,7 +3196,7 @@ protected JpaCriteriaQuery getCriteria(Session s) { JpaCriteriaQuery criteria = (JpaCriteriaQuery) builder.createQuery(); Root root = criteria.from( Student.class ); - final MapJoin addresses = root.joinMap( "addresses", JoinType.INNER ); + final MapJoin addresses = root.joinMap( "addresses", JoinType.INNER ); criteria.select( addresses.entry() ); /* diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/queryhint/OracleQueryHintTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/queryhint/OracleQueryHintTest.java index 84d0f30f4973..bc34a8818832 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/queryhint/OracleQueryHintTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/queryhint/OracleQueryHintTest.java @@ -118,7 +118,7 @@ public void testQueryHint(SessionFactoryScope scope) { final CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder(); CriteriaQuery criteria = criteriaBuilder.createQuery( Employee.class ); Root root = criteria.from( Employee.class ); - Join departmentJoin = root.join( "department" ); + Join departmentJoin = root.join( "department" ); criteria.select( root ).where( criteriaBuilder.equal( departmentJoin.get( "name" ), "Sales" ) ); // Criteria criteria = s.createCriteria( Employee.class ) // .addQueryHint( "ALL_ROWS" ) diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/queryhint/QueryHintSQLServer2012Test.java b/hibernate-core/src/test/java/org/hibernate/orm/test/queryhint/QueryHintSQLServer2012Test.java index e444a1025b59..f797fd76f4fa 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/queryhint/QueryHintSQLServer2012Test.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/queryhint/QueryHintSQLServer2012Test.java @@ -133,7 +133,7 @@ public void testQueryHint(SessionFactoryScope scope) { CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder(); CriteriaQuery criteria = criteriaBuilder.createQuery( Employee.class ); Root root = criteria.from( Employee.class ); - Join departement = root.join( "department", JoinType.INNER ); + Join departement = root.join( "department", JoinType.INNER ); criteria.select( root ).where( criteriaBuilder.equal( departement.get( "name" ), "Sales" ) ); // Criteria criteria = s.createCriteria( Employee.class ).addQueryHint( "MAXDOP 2" ).createCriteria( "department" ) // .add( Restrictions.eq( "name", "Sales" ) ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/readonly/ReadOnlyProxyTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/readonly/ReadOnlyProxyTest.java index 7ae48f5fe2ff..893a9bbd02f3 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/readonly/ReadOnlyProxyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/readonly/ReadOnlyProxyTest.java @@ -1072,7 +1072,7 @@ public void testReadOnlyDelete(SessionFactoryScope scope) { scope.inTransaction( session -> { - DataPoint dp = session.get( DataPoint.class, dpOrig.getId() ); + DataPoint dp = session.find( DataPoint.class, dpOrig.getId() ); assertNull( dp ); } ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/readonly/ReadOnlySessionLazyNonLazyTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/readonly/ReadOnlySessionLazyNonLazyTest.java index e3dd528e934d..3a681753f74e 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/readonly/ReadOnlySessionLazyNonLazyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/readonly/ReadOnlySessionLazyNonLazyTest.java @@ -184,7 +184,8 @@ public void testExistingReadOnlyAfterSetSessionModifiable(SessionFactoryScope sc s = openSession(scope); t = s.beginTransaction(); s.setDefaultReadOnly( true ); - Container c = ( Container ) s.get( Container.class, cOrig.getId() ); + Container c = s.get( Container.class, cOrig.getId() ); + Hibernate.initialize( c ); assertNotSame( cOrig, c ); expectedInitializedObjects = new HashSet( Arrays.asList( diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/resulttransformer/ResultTransformerTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/resulttransformer/ResultTransformerTest.java index 2224f8946496..db902662e3f3 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/resulttransformer/ResultTransformerTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/resulttransformer/ResultTransformerTest.java @@ -49,7 +49,7 @@ public void testResultTransformerIsAppliedToScrollableResults(SessionFactoryScop } ); scope.inSession( (session) -> { - Query q = session.getNamedQuery(Contract.class.getName() + ".testQuery"); + Query q = session.createNamedQuery(Contract.class.getName() + ".testQuery"); q.setFetchSize(100); q.setResultTransformer( (ResultTransformer) (arg0, arg1) -> { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/softdelete/ImplicitSoftDeleteTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/softdelete/ImplicitSoftDeleteTests.java index fa85d32293a8..2dda64fef7ef 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/softdelete/ImplicitSoftDeleteTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/softdelete/ImplicitSoftDeleteTests.java @@ -77,7 +77,7 @@ void testSelectionQuery(SessionFactoryScope scope) { void testLoading(SessionFactoryScope scope) { // Load scope.inTransaction( (session) -> { - assertThat( session.get( ImplicitEntity.class, 1 ) ).isNull(); + assertThat( session.find( ImplicitEntity.class, 1 ) ).isNull(); assertThat( session.get( ImplicitEntity.class, 2 ) ).isNotNull(); assertThat( session.get( ImplicitEntity.class, 3 ) ).isNotNull(); } ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/softdelete/discovery/secondary/JoinedSubclassSoftDeleteTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/softdelete/discovery/secondary/JoinedSubclassSoftDeleteTests.java index 6de72d4ee2cb..a9eebb673b39 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/softdelete/discovery/secondary/JoinedSubclassSoftDeleteTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/softdelete/discovery/secondary/JoinedSubclassSoftDeleteTests.java @@ -82,13 +82,13 @@ void testCountQuery(SessionFactoryScope scope) { @Test void testLoading(SessionFactoryScope scope) { scope.inTransaction( (session) -> { - assertThat( session.get( JoinedRoot.class, 1 ) ).isNull(); + assertThat( session.find( JoinedRoot.class, 1 ) ).isNull(); assertThat( session.get( JoinedRoot.class, 2 ) ).isNotNull(); assertThat( session.get( JoinedRoot.class, 3 ) ).isNotNull(); } ); scope.inTransaction( (session) -> { - assertThat( session.get( JoinedSub.class, 1 ) ).isNull(); + assertThat( session.find( JoinedSub.class, 1 ) ).isNull(); assertThat( session.get( JoinedSub.class, 2 ) ).isNotNull(); assertThat( session.get( JoinedSub.class, 3 ) ).isNotNull(); } ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/sorted/map/SortComparatorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/sorted/map/SortComparatorTest.java index f8c510994812..5b49f36d8cf3 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/sorted/map/SortComparatorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/sorted/map/SortComparatorTest.java @@ -83,7 +83,7 @@ static class Owner { private long id; @OneToMany(mappedBy = "owner", cascade = CascadeType.ALL) - @MapKey(name = "nickname") + @MapKey("nickname") @SortComparator( StringCaseInsensitiveComparator.class ) private SortedMap cats = new TreeMap<>(); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/sorted/map/SortNaturalTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/sorted/map/SortNaturalTest.java index cfe88284dd17..f9f2df2a0dc3 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/sorted/map/SortNaturalTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/sorted/map/SortNaturalTest.java @@ -80,7 +80,7 @@ static class Owner { private long id; @OneToMany(mappedBy = "owner", cascade = CascadeType.ALL) - @MapKey(name = "name") + @MapKey("name") @SortNatural private SortedMap cats = new TreeMap<>(); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/sql/exec/manytoone/ManyToOneTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/exec/manytoone/ManyToOneTest.java index 040ae9cc0d43..1d5a4996b98f 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/sql/exec/manytoone/ManyToOneTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/exec/manytoone/ManyToOneTest.java @@ -294,8 +294,8 @@ public void testDelete(SessionFactoryScope scope) { ); scope.inTransaction( session -> { - assertThat( session.get( OtherEntity.class, 2 ), nullValue() ); - assertThat( session.get( SimpleEntity.class, 1 ), notNullValue() ); + assertThat( session.find( OtherEntity.class, 2 ), nullValue() ); + assertThat( session.find( SimpleEntity.class, 1 ), notNullValue() ); } ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/sql/hand/custom/CustomSQLTestSupport.java b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/hand/custom/CustomSQLTestSupport.java index a0989511949c..3f55ebe7787b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/sql/hand/custom/CustomSQLTestSupport.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/hand/custom/CustomSQLTestSupport.java @@ -83,7 +83,7 @@ public void testHandSQL(SessionFactoryScope scope) { scope.inTransaction( session -> { - Iterator itr = session.getNamedQuery( "allOrganizationsWithEmployees" ).list().iterator(); + Iterator itr = session.createNamedQuery( "allOrganizationsWithEmployees" ).list().iterator(); assertThat( itr.hasNext() ).isTrue(); Organization o = (Organization) itr.next(); assertThat( o.getEmployments() ).hasSize( 3 ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/sql/hand/query/NativeSQLQueriesTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/hand/query/NativeSQLQueriesTest.java index b8d980201181..5da61cbc4a40 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/sql/hand/query/NativeSQLQueriesTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/hand/query/NativeSQLQueriesTest.java @@ -317,11 +317,11 @@ public void testScalarValues(SessionFactoryScope scope) { scope.inTransaction( session -> { - List result = session.getNamedQuery( "orgNamesOnly" ).list(); + List result = session.createNamedQuery( "orgNamesOnly" ).list(); assertTrue( result.contains( "IFA" ) ); assertTrue( result.contains( "JBoss" ) ); - result = session.getNamedQuery( "orgNamesOnly" ).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list(); + result = session.createNamedQuery( "orgNamesOnly" ).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list(); Map m = (Map) result.get(0); assertEquals( 2, result.size() ); assertEquals( 1, m.size() ); @@ -331,7 +331,7 @@ public void testScalarValues(SessionFactoryScope scope) { scope.inTransaction( session -> { - Iterator iter = session.getNamedQuery( "orgNamesAndOrgs" ).list().iterator(); + Iterator iter = session.createNamedQuery( "orgNamesAndOrgs" ).list().iterator(); Object[] o = ( Object[] ) iter.next(); assertEquals( 2, o.length, "expecting 2 values" ); assertEquals( "IFA", o[0] ); @@ -345,7 +345,7 @@ public void testScalarValues(SessionFactoryScope scope) { scope.inTransaction( session -> { // test that the ordering of the results is truly based on the order in which they were defined - Iterator iter = session.getNamedQuery( "orgsAndOrgNames" ).list().iterator(); + Iterator iter = session.createNamedQuery( "orgsAndOrgNames" ).list().iterator(); Object[] row = ( Object[] ) iter.next(); assertEquals( 2, row.length, "expecting 2 values" ); assertEquals( Organization.class, row[0].getClass(), "expecting non-scalar result first" ); @@ -363,7 +363,7 @@ public void testScalarValues(SessionFactoryScope scope) { scope.inTransaction( session -> { - Iterator iter = session.getNamedQuery( "orgIdsAndOrgNames" ).list().iterator(); + Iterator iter = session.createNamedQuery( "orgIdsAndOrgNames" ).list().iterator(); Object[] o = ( Object[] ) iter.next(); assertEquals( "IFA", o[1] ); assertEquals( o[0], idIfa ); @@ -395,7 +395,7 @@ public void testMappedAliasStrategy(SessionFactoryScope scope) { scope.inTransaction( session -> { - Query namedQuery = session.getNamedQuery("AllEmploymentAsMapped"); + Query namedQuery = session.createNamedQuery("AllEmploymentAsMapped"); List list = namedQuery.list(); assertEquals(1,list.size()); Employment emp2 = (Employment) list.get(0); @@ -407,7 +407,7 @@ public void testMappedAliasStrategy(SessionFactoryScope scope) { scope.inTransaction( session -> { - Query sqlQuery = session.getNamedQuery("EmploymentAndPerson"); + Query sqlQuery = session.createNamedQuery("EmploymentAndPerson"); sqlQuery.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP); List list = sqlQuery.list(); assertEquals(1,list.size() ); @@ -420,7 +420,7 @@ public void testMappedAliasStrategy(SessionFactoryScope scope) { scope.inTransaction( session -> { - Query sqlQuery = session.getNamedQuery( "organizationreturnproperty" ); + Query sqlQuery = session.createNamedQuery( "organizationreturnproperty" ); sqlQuery.setResultTransformer( Transformers.ALIAS_TO_ENTITY_MAP ); List list = sqlQuery.list(); assertEquals( 2,list.size() ); @@ -443,7 +443,7 @@ public void testMappedAliasStrategy(SessionFactoryScope scope) { scope.inTransaction( session -> { - Query namedQuery = session.getNamedQuery("EmploymentAndPerson"); + Query namedQuery = session.createNamedQuery("EmploymentAndPerson"); List list = namedQuery.list(); assertEquals(1,list.size() ); Object[] objs = (Object[]) list.get(0); @@ -591,7 +591,7 @@ public void testAutoDetectAliasing(SessionFactoryScope scope) { - Query queryWithCollection = session.getNamedQuery("organizationEmploymentsExplicitAliases"); + Query queryWithCollection = session.createNamedQuery("organizationEmploymentsExplicitAliases"); queryWithCollection.setParameter("id", jboss.getId() ); list = queryWithCollection.list(); assertEquals( 1, list.size() ); @@ -615,13 +615,13 @@ public void testAutoDetectAliasing(SessionFactoryScope scope) { session.clear(); // TODO : why twice? - session.getNamedQuery( "organizationreturnproperty" ).list(); - list = session.getNamedQuery( "organizationreturnproperty" ).list(); + session.createNamedQuery( "organizationreturnproperty" ).list(); + list = session.createNamedQuery( "organizationreturnproperty" ).list(); assertEquals( 2,list.size() ); session.clear(); - list = session.getNamedQuery( "organizationautodetect" ).list(); + list = session.createNamedQuery( "organizationautodetect" ).list(); assertEquals( 2,list.size() ); } ); @@ -655,7 +655,7 @@ public void testAutoDetectAliasing(SessionFactoryScope scope) { enterprise.setDimensions( d ); session.persist( enterprise ); session.flush(); - Object[] result = (Object[]) session.getNamedQuery( "spaceship" ).uniqueResult(); + Object[] result = (Object[]) session.createNamedQuery( "spaceship" ).uniqueResult(); assertEquals( 3, result.length, "expecting 3 result values" ); enterprise = ( SpaceShip ) result[0]; assertEquals( 50d, enterprise.getSpeed() ); @@ -810,7 +810,7 @@ public void testAddJoinForManyToMany(SessionFactoryScope scope) { // .addEntity("groupp", Group.class) // .addJoin("gp","groupp.persons") // .list(); - List l = session.getNamedQuery( "manyToManyFetch" ).list(); + List l = session.createNamedQuery( "manyToManyFetch" ).list(); //assertEquals( 2, l.size() ); } ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/sql/hand/quotedidentifiers/NativeSqlAndQuotedIdentifiersTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/hand/quotedidentifiers/NativeSqlAndQuotedIdentifiersTest.java index dbaabb56f0ac..33c172badfad 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/sql/hand/quotedidentifiers/NativeSqlAndQuotedIdentifiersTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/hand/quotedidentifiers/NativeSqlAndQuotedIdentifiersTest.java @@ -53,7 +53,7 @@ protected void cleanupTest(SessionFactoryScope scope) throws Exception { public void testCompleteScalarDiscovery(SessionFactoryScope scope) { scope.inTransaction( session -> - session.getNamedQuery( "query-person" ).list() + session.createNamedQuery( "query-person" ).list() ); } @@ -61,7 +61,7 @@ public void testCompleteScalarDiscovery(SessionFactoryScope scope) { public void testPartialScalarDiscovery(SessionFactoryScope scope) { scope.inTransaction( session -> { - NativeQuery query = session.getNamedNativeQuery( "query-person", "person-scalar" ); + NativeQuery query = session.createNamedQuery( "query-person", "person-scalar" ); query.list(); } ); @@ -71,7 +71,7 @@ public void testPartialScalarDiscovery(SessionFactoryScope scope) { public void testBasicEntityMapping(SessionFactoryScope scope) { scope.inTransaction( session -> { - NativeQuery query = session.getNamedNativeQuery( "query-person", "person-entity-basic" ); + NativeQuery query = session.createNamedQuery( "query-person", "person-entity-basic" ); query.list(); } ); @@ -81,7 +81,7 @@ public void testBasicEntityMapping(SessionFactoryScope scope) { public void testExpandedEntityMapping(SessionFactoryScope scope) { scope.inTransaction( session -> { - NativeQuery query = session.getNamedNativeQuery( "query-person", "person-entity-expanded" ); + NativeQuery query = session.createNamedQuery( "query-person", "person-entity-expanded" ); query.list(); } ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/sql/results/graph/embeddable/internal/EmbeddableFetchImplTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/results/graph/embeddable/internal/EmbeddableFetchImplTests.java index 6eeed062c504..eaf9a185e2cf 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/sql/results/graph/embeddable/internal/EmbeddableFetchImplTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/results/graph/embeddable/internal/EmbeddableFetchImplTests.java @@ -38,7 +38,7 @@ void testTableGroupJoin(SessionFactoryScope scope) { scope.inTransaction( // will throw exception if the patch accompanying this test is not applied // for 'country' alias shows up in 'select', but not in 'from' clause - session -> session.get( ExpressCompany.class, "nonexistent" ) + session -> session.find( ExpressCompany.class, "nonexistent" ) ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/StatelessCollectionsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/StatelessCollectionsTest.java index 151c7b49378e..149e6eff7fb3 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/StatelessCollectionsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/StatelessCollectionsTest.java @@ -66,7 +66,7 @@ void test(SessionFactoryScope scope) { }); scope.inStatelessTransaction(s -> { - WithCollection loaded = s.get(WithCollection.class, inserted.id); + WithCollection loaded = s.find(WithCollection.class, inserted.id); assertNull(loaded); }); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/StatelessSessionQueryTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/StatelessSessionQueryTest.java index af2d00373ba8..16a047da0d71 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/StatelessSessionQueryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/StatelessSessionQueryTest.java @@ -61,7 +61,7 @@ public void testNewQueryApis(SessionFactoryScope scope) { Query query = session.createQuery( queryString ); assertEquals( 1, query.getResultList().size() ); - query = session.getNamedQuery( Contact.class.getName() + ".contacts" ); + query = session.createNamedQuery( Contact.class.getName() + ".contacts" ); assertEquals( 1, query.getResultList().size() ); NativeQuery sqlQuery = session.createNativeQuery( "select id from Contact" ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/StatelessSessionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/StatelessSessionTest.java index ca13effe6d9d..395f86cfa05b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/StatelessSessionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/StatelessSessionTest.java @@ -117,15 +117,15 @@ public void testCreateUpdateReadDelete(SessionFactoryScope scope) { } @Test - public void testGetNull(SessionFactoryScope scope) { + public void testFindNull(SessionFactoryScope scope) { scope.inStatelessSession( statelessSession -> { - assertNull( statelessSession.get( Document.class, "Blank" ) ); + assertNull( statelessSession.find( Document.class, "Blank" ) ); } ); scope.inStatelessTransaction( statelessSession -> { - assertNull( statelessSession.get( Document.class, "Blank", LockMode.PESSIMISTIC_WRITE ) ); + assertNull( statelessSession.find( Document.class, "Blank", LockMode.PESSIMISTIC_WRITE ) ); } ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/transactions/TransactionsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/transactions/TransactionsTest.java index b5e6423c4ff0..c94cb9ec0363 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/transactions/TransactionsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/transactions/TransactionsTest.java @@ -114,7 +114,7 @@ public void cmt(ServiceRegistryScope registryScope) { // no-ops session.getTransaction().begin(); - Number customerCount = (Number) session.createSelectionQuery("select count(c) from Customer c").uniqueResult(); + Number customerCount = session.createSelectionQuery("select count(c) from Customer c", Number.class).uniqueResult(); // Since we did not start the transaction (CMT), // we also will not end it. This call essentially @@ -176,7 +176,7 @@ public void bmt(ServiceRegistryScope registryScope) { session.getTransaction().begin(); session.persist(new Customer()); - Customer customer = (Customer) session.createSelectionQuery("select c from Customer c").uniqueResult(); + Customer customer = (Customer) session.createSelectionQuery("select c from Customer c", Customer.class).uniqueResult(); // calls TM/UT commit method, assuming we are initiator. session.getTransaction().commit(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/type/contributor/usertype/ContributedUserTypeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/type/contributor/usertype/ContributedUserTypeTest.java index 01d516eee41e..2e7de1f54951 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/type/contributor/usertype/ContributedUserTypeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/type/contributor/usertype/ContributedUserTypeTest.java @@ -77,7 +77,7 @@ public void testComposite(SessionFactoryScope scope) { public void testParameter(SessionFactoryScope scope) { scope.inSession( session -> { - session.createSelectionQuery( "from StringWrapperTestEntity e where e.stringWrapper = :p" ) + session.createSelectionQuery( "from StringWrapperTestEntity e where e.stringWrapper = :p", StringWrapperTestEntity.class ) .setParameter( "p", new StringWrapper( "abc" ) ) .getResultList(); } @@ -89,7 +89,7 @@ public void testParameter(SessionFactoryScope scope) { public void testCompositeParameter(SessionFactoryScope scope) { scope.inSession( session -> { - session.createSelectionQuery( "from MyCompositeValueTestEntity e where e.compositeValue = :c" ) + session.createSelectionQuery( "from MyCompositeValueTestEntity e where e.compositeValue = :c", MyCompositeValueTestEntity.class ) .setParameter( "c", new MyCompositeValue( 1L, "1" ) ) .getResultList(); } diff --git a/hibernate-core/src/test/resources/mappings/models/column/complete.xml b/hibernate-core/src/test/resources/mappings/models/column/complete.xml index eb3f68321867..7314d8b2c399 100644 --- a/hibernate-core/src/test/resources/mappings/models/column/complete.xml +++ b/hibernate-core/src/test/resources/mappings/models/column/complete.xml @@ -18,8 +18,8 @@ insertable="true" updatable="true" unique="true" - comment="The name column" options="the options" > + The name column diff --git a/hibernate-core/src/test/resources/org/hibernate/orm/test/schemaupdate/tablecomment/TestEntity.xml b/hibernate-core/src/test/resources/org/hibernate/orm/test/schemaupdate/tablecomment/TestEntity.xml index f5c64f7ea90f..277d23b9c97f 100644 --- a/hibernate-core/src/test/resources/org/hibernate/orm/test/schemaupdate/tablecomment/TestEntity.xml +++ b/hibernate-core/src/test/resources/org/hibernate/orm/test/schemaupdate/tablecomment/TestEntity.xml @@ -3,11 +3,15 @@ ~ SPDX-License-Identifier: Apache-2.0 ~ Copyright Red Hat Inc. and Hibernate Authors --> - + org.hibernate.orm.test.schemaupdate.tablecomment - - +
+ This is the primary table +
+ + This is the secondary table + @@ -17,8 +21,9 @@ - + + This is the join table +
diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/reader/AuditedPropertiesReader.java b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/reader/AuditedPropertiesReader.java index 0146d14d3208..dcc96f9762ee 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/reader/AuditedPropertiesReader.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/reader/AuditedPropertiesReader.java @@ -52,6 +52,7 @@ import static org.hibernate.envers.internal.tools.Tools.newHashMap; import static org.hibernate.envers.internal.tools.Tools.newHashSet; import static org.hibernate.internal.util.ReflectHelper.OBJECT_CLASS_NAME; +import static org.hibernate.internal.util.StringHelper.coalesce; /** * Reads persistent properties form a {@link PersistentPropertiesSource} and adds the ones that are audited to a @@ -774,7 +775,7 @@ private void setPropertyAuditMappedBy(MemberDetails memberDetails, PropertyAudit private void addPropertyMapKey(MemberDetails memberDetails, PropertyAuditingData propertyData) { final MapKey mapKey = memberDetails.getDirectAnnotationUsage( MapKey.class ); if ( mapKey != null ) { - propertyData.setMapKey( mapKey.name() ); + propertyData.setMapKey( coalesce( mapKey.value(), mapKey.name() ) ); } else { final MapKeyEnumerated mapKeyEnumerated = memberDetails.getDirectAnnotationUsage( MapKeyEnumerated.class ); diff --git a/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/collection/mapkey/ComponentMapKeyEntity.java b/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/collection/mapkey/ComponentMapKeyEntity.java index 319342abbc4b..c08bbde5c3fc 100644 --- a/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/collection/mapkey/ComponentMapKeyEntity.java +++ b/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/collection/mapkey/ComponentMapKeyEntity.java @@ -29,7 +29,7 @@ public class ComponentMapKeyEntity { @Audited @ManyToMany - @MapKey(name = "comp1") + @MapKey("comp1") private Map idmap; public ComponentMapKeyEntity() { diff --git a/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/onetomany/RefEdMapKeyEntity.java b/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/onetomany/RefEdMapKeyEntity.java index 71348e00ddc9..a1b7fbe1f04a 100644 --- a/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/onetomany/RefEdMapKeyEntity.java +++ b/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/onetomany/RefEdMapKeyEntity.java @@ -25,7 +25,7 @@ public class RefEdMapKeyEntity { @Audited @OneToMany(mappedBy = "reference") - @MapKey(name = "data") + @MapKey("data") private Map idmap; public RefEdMapKeyEntity() { diff --git a/hibernate-jcache/src/test/java/org/hibernate/orm/test/caching/FirstLevelCacheTest.java b/hibernate-jcache/src/test/java/org/hibernate/orm/test/caching/FirstLevelCacheTest.java index 8257725a9822..90714728a8b2 100644 --- a/hibernate-jcache/src/test/java/org/hibernate/orm/test/caching/FirstLevelCacheTest.java +++ b/hibernate-jcache/src/test/java/org/hibernate/orm/test/caching/FirstLevelCacheTest.java @@ -69,7 +69,7 @@ public void testCache(EntityManagerFactoryScope scope) { List dtos = new ArrayList<>(); //tag::caching-management-native-evict-example[] Session session = entityManager.unwrap(Session.class); - for(Person person : (List) session.createSelectionQuery("select p from Person p").list()) { + for(Person person : session.createSelectionQuery("select p from Person p",Person.class).list()) { dtos.add(toDTO(person)); session.evict(person); } diff --git a/hibernate-jfr/src/test/java/org/hibernate/event/jfr/JdbcPreparedStatementEventTests.java b/hibernate-jfr/src/test/java/org/hibernate/event/jfr/JdbcPreparedStatementEventTests.java index 7f508aef0803..dceb2f429e77 100644 --- a/hibernate-jfr/src/test/java/org/hibernate/event/jfr/JdbcPreparedStatementEventTests.java +++ b/hibernate-jfr/src/test/java/org/hibernate/event/jfr/JdbcPreparedStatementEventTests.java @@ -41,7 +41,7 @@ public void testJdbcPreparedStatementEvent(SessionFactoryScope scope) { jfrEvents.reset(); scope.inTransaction( session -> { - session.createQuery( "select t from TestEntity t" ).list(); + session.createQuery( "select t from TestEntity t", TestEntity.class ).list(); final List events = jfrEvents.events() .filter( recordedEvent -> diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/library/Book.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/library/Book.java index 9269ce64b4b9..901f9a3f3fd1 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/library/Book.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/library/Book.java @@ -7,6 +7,7 @@ import java.util.HashSet; import java.util.Set; +import jakarta.persistence.Table; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; @@ -15,15 +16,18 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinTable; import jakarta.persistence.ManyToMany; +import org.hibernate.annotations.NaturalId; /** * @author Steve Ebersole */ @Entity +@Table(name = "books") public class Book { @Id private Integer id; private String name; + @NaturalId private String isbn; @ManyToMany @@ -51,6 +55,12 @@ public Book(Integer id, String name) { this.name = name; } + public Book(Integer id, String name, String isbn) { + this.id = id; + this.name = name; + this.isbn = isbn; + } + public Integer getId() { return id; } diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/library/Person.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/library/Person.java index 7107012771a7..79a255a3eea0 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/library/Person.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/library/Person.java @@ -7,11 +7,13 @@ import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.Basic; +import jakarta.persistence.Table; /** * @author Steve Ebersole */ @Entity +@Table(name="persons") public class Person { @Id private Integer id; diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/userguide/Phone.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/userguide/Phone.java index 591dcaec3ba5..664218c1fc96 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/userguide/Phone.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/userguide/Phone.java @@ -85,7 +85,7 @@ public class Phone { //tag::hql-collection-qualification-example[] @OneToMany(mappedBy = "phone") - @MapKey(name = "timestamp") + @MapKey("timestamp") private Map callHistory = new HashMap<>(); //end::hql-collection-qualification-example[] diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/jpa/PersistenceUnitDescriptorAdapter.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/jpa/PersistenceUnitDescriptorAdapter.java index 331830e83c7b..3769353db452 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/jpa/PersistenceUnitDescriptorAdapter.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/jpa/PersistenceUnitDescriptorAdapter.java @@ -4,20 +4,21 @@ */ package org.hibernate.testing.orm.jpa; -import java.net.URL; -import java.util.Collections; -import java.util.List; -import java.util.Properties; +import jakarta.persistence.FetchType; +import jakarta.persistence.PersistenceUnitTransactionType; import jakarta.persistence.SharedCacheMode; import jakarta.persistence.ValidationMode; -import jakarta.persistence.PersistenceUnitTransactionType; -import javax.sql.DataSource; - import org.hibernate.bytecode.enhance.spi.EnhancementContext; import org.hibernate.bytecode.spi.ClassTransformer; import org.hibernate.jpa.HibernatePersistenceProvider; import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor; +import javax.sql.DataSource; +import java.net.URL; +import java.util.Collections; +import java.util.List; +import java.util.Properties; + /** * @author Steve Ebersole */ @@ -45,11 +46,6 @@ public PersistenceUnitTransactionType getPersistenceUnitTransactionType() { return null; } - @Override @SuppressWarnings("removal") - public jakarta.persistence.spi.PersistenceUnitTransactionType getTransactionType() { - return null; - } - @Override public DataSource getJtaDataSource() { return null; @@ -85,6 +81,11 @@ public boolean isExcludeUnlistedClasses() { return false; } + @Override + public FetchType getDefaultToOneFetchType() { + return FetchType.EAGER; + } + @Override public SharedCacheMode getSharedCacheMode() { return null; @@ -114,11 +115,12 @@ public ClassLoader getTempClassLoader() { } @Override - public void pushClassTransformer(EnhancementContext enhancementContext) { + public boolean isClassTransformerRegistrationDisabled() { + return true; } @Override - public ClassTransformer getClassTransformer() { + public ClassTransformer pushClassTransformer(EnhancementContext enhancementContext) { return null; } } diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/jpa/PersistenceUnitInfoAdapter.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/jpa/PersistenceUnitInfoAdapter.java index f9873f6577f5..e88da0dbb7a2 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/jpa/PersistenceUnitInfoAdapter.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/jpa/PersistenceUnitInfoAdapter.java @@ -7,11 +7,13 @@ import java.net.URL; import java.util.List; import java.util.Properties; + +import jakarta.persistence.FetchType; import jakarta.persistence.SharedCacheMode; import jakarta.persistence.ValidationMode; import jakarta.persistence.spi.ClassTransformer; import jakarta.persistence.spi.PersistenceUnitInfo; -import jakarta.persistence.spi.PersistenceUnitTransactionType; +import jakarta.persistence.PersistenceUnitTransactionType; import javax.sql.DataSource; import org.hibernate.jpa.HibernatePersistenceProvider; @@ -50,7 +52,7 @@ public List getQualifierAnnotationNames() { return List.of(); } - @Override @SuppressWarnings("removal") + @Override public PersistenceUnitTransactionType getTransactionType() { return null; } @@ -79,6 +81,11 @@ public List getManagedClassNames() { return emptyList(); } + @Override + public List getAllManagedClassNames() { + return getManagedClassNames(); + } + public boolean excludeUnlistedClasses() { return false; } @@ -91,6 +98,11 @@ public ValidationMode getValidationMode() { return null; } + @Override + public FetchType getDefaultToOneFetchType() { + return FetchType.EAGER; + } + public Properties getProperties() { if ( properties == null ) { properties = new Properties(); diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/jpa/PersistenceUnitInfoImpl.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/jpa/PersistenceUnitInfoImpl.java index b5c6427c8611..dd470f47edcf 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/jpa/PersistenceUnitInfoImpl.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/jpa/PersistenceUnitInfoImpl.java @@ -9,11 +9,13 @@ import java.util.Collections; import java.util.List; import java.util.Properties; + +import jakarta.persistence.FetchType; import jakarta.persistence.SharedCacheMode; import jakarta.persistence.ValidationMode; import jakarta.persistence.spi.ClassTransformer; import jakarta.persistence.spi.PersistenceUnitInfo; -import jakarta.persistence.spi.PersistenceUnitTransactionType; +import jakarta.persistence.PersistenceUnitTransactionType; import javax.sql.DataSource; import org.hibernate.jpa.HibernatePersistenceProvider; @@ -38,7 +40,7 @@ public class PersistenceUnitInfoImpl implements PersistenceUnitInfo { private List qualifierAnnotationNames = List.of(); private SharedCacheMode cacheMode; private ValidationMode validationMode; - @SuppressWarnings("removal") + private FetchType defaultToOneFetchType = FetchType.EAGER; private PersistenceUnitTransactionType transactionType; private List mappingFiles; @@ -83,7 +85,7 @@ public String getPersistenceProviderClassName() { return HibernatePersistenceProvider.class.getName(); } - @Override @SuppressWarnings("removal") + @Override public PersistenceUnitTransactionType getTransactionType() { return transactionType; } @@ -106,6 +108,15 @@ public ValidationMode getValidationMode() { return validationMode; } + @Override + public FetchType getDefaultToOneFetchType() { + return defaultToOneFetchType; + } + + public void setDefaultToOneFetchType(FetchType defaultToOneFetchType) { + this.defaultToOneFetchType = defaultToOneFetchType; + } + public void setValidationMode(ValidationMode validationMode) { this.validationMode = validationMode; } @@ -127,6 +138,11 @@ public List getManagedClassNames() { return managedClassNames == null ? emptyList() : managedClassNames; } + @Override + public List getAllManagedClassNames() { + return getManagedClassNames(); + } + public void applyManagedClassNames(String... managedClassNames) { if ( this.managedClassNames == null ) { this.managedClassNames = new ArrayList<>(); diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/EntityManagerFactoryBasedFunctionalTest.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/EntityManagerFactoryBasedFunctionalTest.java index b0b6d3aab913..dfea79b09331 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/EntityManagerFactoryBasedFunctionalTest.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/EntityManagerFactoryBasedFunctionalTest.java @@ -4,17 +4,12 @@ */ package org.hibernate.testing.orm.junit; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.function.Consumer; -import java.util.function.Function; - +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.FetchType; import jakarta.persistence.PersistenceUnitTransactionType; +import jakarta.persistence.SharedCacheMode; +import jakarta.persistence.ValidationMode; import org.hibernate.bytecode.enhance.spi.EnhancementContext; import org.hibernate.bytecode.spi.ClassTransformer; import org.hibernate.cfg.AvailableSettings; @@ -26,15 +21,19 @@ import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableMutationStrategy; import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableMutationStrategy; import org.hibernate.query.sqm.mutation.internal.temptable.PersistentTableStrategy; - import org.hibernate.testing.util.ServiceRegistryUtil; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; -import jakarta.persistence.EntityManager; -import jakarta.persistence.EntityManagerFactory; -import jakarta.persistence.SharedCacheMode; -import jakarta.persistence.ValidationMode; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.function.Consumer; +import java.util.function.Function; import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; @@ -214,9 +213,9 @@ public boolean isExcludeUnlistedClasses() { return false; } - @Override @SuppressWarnings("removal") - public jakarta.persistence.spi.PersistenceUnitTransactionType getTransactionType() { - return null; + @Override + public FetchType getDefaultToOneFetchType() { + return FetchType.EAGER; } @Override @@ -275,11 +274,12 @@ public ClassLoader getTempClassLoader() { } @Override - public void pushClassTransformer(EnhancementContext enhancementContext) { + public boolean isClassTransformerRegistrationDisabled() { + return true; } @Override - public ClassTransformer getClassTransformer() { + public ClassTransformer pushClassTransformer(EnhancementContext enhancementContext) { return null; } } diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/Jpa.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/Jpa.java index c590df2f4d97..e5df9e0e302f 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/Jpa.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/Jpa.java @@ -12,7 +12,7 @@ import jakarta.persistence.SharedCacheMode; import jakarta.persistence.ValidationMode; -import jakarta.persistence.spi.PersistenceUnitTransactionType; +import jakarta.persistence.PersistenceUnitTransactionType; import org.hibernate.testing.jdbc.SQLStatementInspector; import org.hibernate.testing.orm.domain.DomainModelDescriptor; diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/util/jpa/DelegatingPersistenceUnitInfo.java b/hibernate-testing/src/main/java/org/hibernate/testing/util/jpa/DelegatingPersistenceUnitInfo.java index f0355c76fe62..7ade02577bd8 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/util/jpa/DelegatingPersistenceUnitInfo.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/util/jpa/DelegatingPersistenceUnitInfo.java @@ -4,11 +4,12 @@ */ package org.hibernate.testing.util.jpa; +import jakarta.persistence.FetchType; import jakarta.persistence.SharedCacheMode; import jakarta.persistence.ValidationMode; import jakarta.persistence.spi.ClassTransformer; import jakarta.persistence.spi.PersistenceUnitInfo; -import jakarta.persistence.spi.PersistenceUnitTransactionType; +import jakarta.persistence.PersistenceUnitTransactionType; import javax.sql.DataSource; import java.net.URL; import java.util.List; @@ -41,7 +42,7 @@ public List getQualifierAnnotationNames() { return delegate.getQualifierAnnotationNames(); } - @Override @SuppressWarnings("removal") + @Override public PersistenceUnitTransactionType getTransactionType() { return delegate.getTransactionType(); } @@ -76,6 +77,11 @@ public List getManagedClassNames() { return delegate.getManagedClassNames(); } + @Override + public List getAllManagedClassNames() { + return delegate.getAllManagedClassNames(); + } + @Override public boolean excludeUnlistedClasses() { return delegate.excludeUnlistedClasses(); @@ -91,6 +97,11 @@ public ValidationMode getValidationMode() { return delegate.getValidationMode(); } + @Override + public FetchType getDefaultToOneFetchType() { + return delegate.getDefaultToOneFetchType(); + } + @Override public Properties getProperties() { return delegate.getProperties(); diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/util/jpa/PersistenceUnitInfoAdapter.java b/hibernate-testing/src/main/java/org/hibernate/testing/util/jpa/PersistenceUnitInfoAdapter.java index f2a22bd6992e..63dd7226d8aa 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/util/jpa/PersistenceUnitInfoAdapter.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/util/jpa/PersistenceUnitInfoAdapter.java @@ -4,11 +4,12 @@ */ package org.hibernate.testing.util.jpa; +import jakarta.persistence.FetchType; import jakarta.persistence.SharedCacheMode; import jakarta.persistence.ValidationMode; import jakarta.persistence.spi.ClassTransformer; import jakarta.persistence.spi.PersistenceUnitInfo; -import jakarta.persistence.spi.PersistenceUnitTransactionType; +import jakarta.persistence.PersistenceUnitTransactionType; import javax.sql.DataSource; import java.net.URL; import java.util.Collections; @@ -48,7 +49,7 @@ public List getQualifierAnnotationNames() { return List.of(); } - @Override @SuppressWarnings("removal") + @Override public PersistenceUnitTransactionType getTransactionType() { return PersistenceUnitTransactionType.RESOURCE_LOCAL; } @@ -83,6 +84,11 @@ public List getManagedClassNames() { return Collections.emptyList(); } + @Override + public List getAllManagedClassNames() { + return List.of(); + } + @Override public boolean excludeUnlistedClasses() { return false; @@ -98,6 +104,11 @@ public ValidationMode getValidationMode() { return ValidationMode.NONE; } + @Override + public FetchType getDefaultToOneFetchType() { + return FetchType.EAGER; + } + @Override public Properties getProperties() { return properties; diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/util/jpa/PersistenceUnitInfoPropertiesWrapper.java b/hibernate-testing/src/main/java/org/hibernate/testing/util/jpa/PersistenceUnitInfoPropertiesWrapper.java deleted file mode 100644 index 1cd1bc300a9f..000000000000 --- a/hibernate-testing/src/main/java/org/hibernate/testing/util/jpa/PersistenceUnitInfoPropertiesWrapper.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.testing.util.jpa; - -import java.net.URL; -import java.util.Collections; -import java.util.List; -import java.util.Properties; -import jakarta.persistence.SharedCacheMode; -import jakarta.persistence.ValidationMode; -import jakarta.persistence.spi.ClassTransformer; -import jakarta.persistence.spi.PersistenceUnitInfo; -import jakarta.persistence.spi.PersistenceUnitTransactionType; -import javax.sql.DataSource; - -import org.hibernate.jpa.HibernatePersistenceProvider; - -import static java.lang.Thread.currentThread; - -/** - * TODO : javadoc - * - * @author Steve Ebersole - */ -public class PersistenceUnitInfoPropertiesWrapper implements PersistenceUnitInfo { - private final Properties properties; - - public PersistenceUnitInfoPropertiesWrapper() { - properties = new Properties(); - } - - public PersistenceUnitInfoPropertiesWrapper(Properties properties) { - this.properties = properties; - } - - public String getPersistenceUnitName() { - return "persistenceUnitAdapter"; - } - - public String getPersistenceProviderClassName() { - return HibernatePersistenceProvider.class.getName(); - } - - @Override - public String getScopeAnnotationName() { - return null; - } - - @Override - public List getQualifierAnnotationNames() { - return List.of(); - } - - @SuppressWarnings("removal") - public PersistenceUnitTransactionType getTransactionType() { - return null; - } - - public DataSource getJtaDataSource() { - return null; - } - - public DataSource getNonJtaDataSource() { - return null; - } - - public List getMappingFileNames() { - return Collections.emptyList(); - } - - public List getJarFileUrls() { - return Collections.emptyList(); - } - - public URL getPersistenceUnitRootUrl() { - return null; - } - - public List getManagedClassNames() { - return Collections.emptyList(); - } - - public boolean excludeUnlistedClasses() { - return false; - } - - public SharedCacheMode getSharedCacheMode() { - return null; - } - - public ValidationMode getValidationMode() { - return null; - } - - public Properties getProperties() { - return properties; - } - - public String getPersistenceXMLSchemaVersion() { - return null; - } - - public ClassLoader getClassLoader() { - return currentThread().getContextClassLoader(); - } - - public void addTransformer(ClassTransformer transformer) { - } - - public ClassLoader getNewTempClassLoader() { - return null; - } -} diff --git a/jpa4-followups.adoc b/jpa4-followups.adoc new file mode 100644 index 000000000000..20212fac314c --- /dev/null +++ b/jpa4-followups.adoc @@ -0,0 +1,32 @@ += Follow Up to JPA 4 Work +:toc: + +Things to do after JPA 4.0 work... + +== TCK Tests + +For tests to add to the TCK, see - + +* `org.hibernate.orm.test.query.resultmapping.dynamic` +* `org.hibernate.orm.test.event.AddListenerTests` +* `org.hibernate.orm.test.query.graph.QueryWithGraphTests`[1] + +[1] Though this test needs https://github.com/jakartaee/persistence/pull/842 + +== Build Items + +Things to fix in the build after JPA 4.0 gets a named release + +=== settings.gradle + +* temporarily commented out `if` statement for using Jakarta snapshot repo (~ line 33). Fix this after spec goes final. +* `jpaVersion` set to 4.0.0-SNAPSHOT + + +=== JpaVersion (local-build-plugins) + +Changed `DEFAULT_VERSION` to 4.0 + +=== Maven plugin integration testing + +Re-enable `:hibernate-maven-plugin:integrationTest` \ No newline at end of file diff --git a/local-build-plugins/src/main/java/org/hibernate/build/JpaVersion.java b/local-build-plugins/src/main/java/org/hibernate/build/JpaVersion.java index b6053eb9dd11..e9489a6d376a 100644 --- a/local-build-plugins/src/main/java/org/hibernate/build/JpaVersion.java +++ b/local-build-plugins/src/main/java/org/hibernate/build/JpaVersion.java @@ -16,7 +16,7 @@ public class JpaVersion { public static final String EXT_KEY = "jakartaJpaVersion"; public static final String VERSION_KEY = "jakartaJpaVersionOverride"; - public static final String DEFAULT_VERSION = "3.2"; + public static final String DEFAULT_VERSION = "4.0"; private final String name; private final String osgiName; diff --git a/migration-guide.adoc b/migration-guide.adoc index fa6c5b3c0285..da1b62fb0049 100644 --- a/migration-guide.adoc +++ b/migration-guide.adoc @@ -2,7 +2,7 @@ :toc2: :sectanchors: :toclevels: 4 -:version: 7.3 +:version: 8.0 :docsBase: https://docs.jboss.org/hibernate/orm :versionDocBase: {docsBase}/{version} :userGuideBase: {versionDocBase}/userguide/html_single/Hibernate_User_Guide.html @@ -23,6 +23,12 @@ earlier versions, see any other pertinent migration guides as well. See the link:{releaseSeriesBase}[website] for the list of requirements for the {version} series. +[[jpa4] +=== Jakarta Persistence 4.0 + +One specific requirement change that is important to call out is the move to from Jakarta Persistence version 3.2 to 4.0 which has a number of impacts, many of which are discussed below. + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // New Features @@ -44,6 +50,45 @@ See the link:{releaseSeriesBase}#whats-new[website] for the list of new features This section describes changes to contracts (classes, interfaces, methods, etc.) which are considered https://hibernate.org/community/compatibility-policy/#api[API]. +[[stateless] +=== StatelessSession + +Jakarta Persistence now defines a contract for "stateless" processing, named `EntityAgent`, similar to Hibernate's `StatelessSession`. +Hibernate's `StatelessSession` now implements `EntityAgent`. +2 methods on `EntityAgent` clash with methods already defined on `StatelessSession` - + +* `insert()` - `EntityAgent` defines a `void` return type, whereas Hibernate has historically returned the identifier of the inserted entity. +* `fetch()` - `EntityAgent` defines that the fetched value be returned, whereas `StatelessSession` has historically defined a `void` return type. + +In both cases, `StatelessSession` has been changed to match the `EntityAgent` signatures. + + +[[timeout] +=== Query and Transaction Timeouts + +Historically, both Hibernate and Jakarta Persistence have defined timeouts as integer values. +Confusingly, Hibernate generally used second precision while Jakarta Persistence used millisecond precision. +Starting in 3.2, Jakarta Persistence added a new `Timeout` class which helps alleviate this potential confusion. +Originally this new `Timeout` type was not exposed on any API directly, so there was no impact from an API perspective. +However, this has changed a bit in 4.0 where `Timeout` *is* now exposed on certain APIs. +This causes a signature conflict with a few of Hibernate API methods; as part of fixing those conflicts, it was decided to change all exposures of timeout in Hibernate APIs to use `Timeout` as this helps clarify these confusions. + + +[[graph-attr-node] +=== AttributeNode Subgraphs + +As part of its support for "entity graphs", Hibernate's `org.hibernate.graph.AttributeNode` contract extends fropm the Jakarta Persistence `jakarta.persistence.AttributeNode`. +Starting in version 4.0, Jakarta Persistence has "fixed" the use of raw types for the `AttributeNode#getSubgraphs` and `AttributeNode#getKeySubgraphs` methods. +Hibernate has therefore needed to do the same in its `org.hibernate.graph.AttributeNode`. + + +[[criteria-join-fetch] +=== Join and Fetch in Criteria + +Jakarta Persistence has changed/fixed the type signature of methods in the Criteria API which return Join and Fetch based on the String name of attributes. This can lead to compilation issues if an application uses these methods in certain ways. + + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // SPI changes // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -63,6 +108,23 @@ In particular, `ClassmateContext` was completely removed. Raw `Map` types were eliminated from the signatures of methods of the class `org.hibernate.jpa.boot.spi.Bootstrap`. +[[query-memento] +=== Query Memento + +Hibernate uses a number of implementations of its `NamedQueryMemento` contract to +model "named queries". Starting in version 3.2, Jakarta Persistence added the +`TypedQueryReference` contract intended to serve the much the same goal. +Hibernate's `NamedQueryMemento` implementations were changed to extend from +`TypedQueryReference`. + +In version 4.0, Jakarta Persistence has added some additional methods to +`TypedQueryReference` which now conflict with some of Hibernate's existing methods +requiring a rename. Notably, the addition of `TypedQueryReference#getParameterTypes` +caused conflict's with Hibernate's `NamedSqmQueryMemento#getParameterTypes`. To +address this conflict, we've renamed the `NamedSqmQueryMemento` method to +`#getAnticipatedParameterTypes`. + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Changes in Behavior // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -85,6 +147,59 @@ query.setResultListTransformer(ResultListTransformer.uniqueResultTransformer()) which collapses duplicate results according to value equality. +[[session-get] +=== Session.get + +Jakarta Persistence now defines a series of overloaded `EntityHandler.get()` methods as corollaries to `EntityHandler.find()`. +These methods are defined to throw an `EntityNotFoundException` rather than return null. +This operates quite differently from the older Hibernate `Session.get()` methods which + +* still returned null if no entity with that is was found +* force initialized the entity, if there was one and it was previously uninitialized. + +Applications which use(d) `Session.get()` should be aware of this change in behavior. + + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// XSD changes +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[[behavior-changes]] +== Changes in XSD + +This section describes changes in XML Schema Descriptors + +[[xsd-comments] +=== Table and Column Comments + +Previous versions of the `mapping.xsd` defined table and column comments (for schema export) +using XSD attributes. This was a decision made at the time to facilitate users migrating +from `hbm.xml` mapping format. In the intervening period, Jakarta Persistence has +also added comments to its table and column XSD types, but using dedicated element. + +We now align with the Jakarta Persistence approach of using elements. This will require +changes any `mapping.xml` documents which define table or column comments. E.g., + +[source,xml] +---- + + + +---- + +would need to be changed to + +[source,xml] +---- + +
+ some comment +
+
+---- + + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // DDL changes // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -96,6 +211,10 @@ This section describes changes to DDL generated by the schema export tooling. Such changes typically do not impact programs using a relational schema managed externally to Hibernate. +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Dependency changes +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [[dependency-changes]] == Changes in Dependencies diff --git a/settings.gradle b/settings.gradle index ed5c6d5b8feb..26bbbffa92f8 100644 --- a/settings.gradle +++ b/settings.gradle @@ -30,6 +30,11 @@ dependencyResolutionManagement { mavenCentral() + // temporary for 4.0 snapshot testing + maven { + url "https://central.sonatype.com/repository/maven-snapshots/" + } + if (System.getProperty('JPA_PREVIEW') != null) { maven { url "https://jakarta.oss.sonatype.org/content/repositories/releases/" @@ -137,7 +142,7 @@ dependencyResolutionManagement { } jakartaLibs { // `jakartaJpaVersion` comes from the local-build-plugins to allow for command-line overriding of the JPA version to use - def jpaVersion = version "jpa", "${jakartaJpaVersion}" + def jpaVersion = version "jpa", "4.0.0-SNAPSHOT" def annotationVersion = version "annotation", "3.0.0" def cdiVersion = version "cdi", "4.1.0" diff --git a/tooling/hibernate-maven-plugin/hibernate-maven-plugin.gradle b/tooling/hibernate-maven-plugin/hibernate-maven-plugin.gradle index 39ad462f2191..3f93771c1d8b 100644 --- a/tooling/hibernate-maven-plugin/hibernate-maven-plugin.gradle +++ b/tooling/hibernate-maven-plugin/hibernate-maven-plugin.gradle @@ -52,6 +52,8 @@ tasks.register('integrationTest', Test) { useJUnitPlatform() + // for now because JPA 4.0 is still snapshot which is a problem + enabled = false } tasks.forbiddenApisIntTest {