api, spi, internal, deprecation

org.hibernate.query package
This commit is contained in:
Steve Ebersole 2022-01-21 11:35:09 -06:00
parent cd9c877e93
commit 30e48401e0
13 changed files with 167 additions and 134 deletions

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.annotations;
import org.hibernate.jpa.AvailableHints;
import org.hibernate.jpa.HibernateHints;
import org.hibernate.jpa.LegacySpecHints;
import org.hibernate.jpa.SpecHints;
@ -17,10 +18,13 @@ import org.hibernate.query.Query;
* the {@link Query} interface, and so hints are only necessary for programs
* working with the JPA APIs.
*
* @see SpecHints
* @see HibernateHints
* @see AvailableHints
*
* @deprecated (since 6.0) Use {@link AvailableHints} instead
*/
public class QueryHints implements HibernateHints, SpecHints {
@SuppressWarnings("unused")
@Deprecated
public final class QueryHints {
/**
* Disallow instantiation.
*/

View File

@ -8,6 +8,8 @@ package org.hibernate.cfg;
import java.util.function.Supplier;
import org.hibernate.jpa.LegacySpecHints;
/**
* @author Steve Ebersole
*/
@ -2399,7 +2401,7 @@ public interface AvailableSettings {
* @deprecated Use {@link #JAKARTA_REMOVE_VALIDATION_GROUP} instead
*/
@Deprecated
String JPA_REMOVE_VALIDATION_GROUP = "javJPAax.persistence.validation.group.pre-remove";
String JPA_REMOVE_VALIDATION_GROUP = "javax.persistence.validation.group.pre-remove";
/**
* Used to request (hint) a pessimistic lock scope.
@ -2409,7 +2411,7 @@ public interface AvailableSettings {
* @deprecated Use {@link #JAKARTA_LOCK_SCOPE} instead
*/
@Deprecated
String JPA_LOCK_SCOPE = "javax.persistence.lock.scope";
String JPA_LOCK_SCOPE = LegacySpecHints.HINT_JAVAEE_LOCK_SCOPE;
/**
* Used to request (hint) a pessimistic lock timeout (in milliseconds).
@ -2419,7 +2421,7 @@ public interface AvailableSettings {
* @deprecated Use {@link #JAKARTA_LOCK_TIMEOUT} instead
*/
@Deprecated
String JPA_LOCK_TIMEOUT = "javax.persistence.lock.timeout";
String JPA_LOCK_TIMEOUT = LegacySpecHints.HINT_JAVAEE_LOCK_TIMEOUT;
/**
* Used to pass along the CDI {@link jakarta.enterprise.inject.spi.BeanManager},

View File

@ -104,18 +104,18 @@ public final class EntityGraphs {
/**
* Convenience method for {@linkplain Query#getResultList() executing} the Query, applying the
* given EntityGraph using the named semantic using JPA's "hint name" - see
* {@link GraphSemantic#fromJpaHintName}
* {@link GraphSemantic#fromHintName}
*
* @param query The JPA Query
* @param graph The graph to apply
* @param semanticJpaHintName See {@link GraphSemantic#fromJpaHintName}
* @param semanticJpaHintName See {@link GraphSemantic#fromHintName}
*
* @return The result list
*/
@SuppressWarnings({"unused", "unchecked"})
public static List executeList(Query query, EntityGraph graph, String semanticJpaHintName) {
return query.unwrap( org.hibernate.query.Query.class )
.applyGraph( (RootGraph) graph, GraphSemantic.fromJpaHintName( semanticJpaHintName ) )
.applyGraph( (RootGraph) graph, GraphSemantic.fromHintName( semanticJpaHintName ) )
.list();
}
@ -124,7 +124,7 @@ public final class EntityGraphs {
*
* @param query The JPA Query
* @param graph The graph to apply
* @param semanticJpaHintName See {@link GraphSemantic#fromJpaHintName}
* @param semanticJpaHintName See {@link GraphSemantic#fromHintName}
*
* @apiNote This signature assumes that the Query's return is an entity and that the graph
* applies to that entity's type. JPA does not necessarily require that, but it is by

View File

@ -6,8 +6,10 @@
*/
package org.hibernate.graph;
import static org.hibernate.jpa.LegacySpecHints.HINT_JAVAEE_FETCH_GRAPH;
import static org.hibernate.jpa.LegacySpecHints.HINT_JAVAEE_LOAD_GRAPH;
import java.util.Locale;
import org.hibernate.jpa.LegacySpecHints;
import static org.hibernate.jpa.SpecHints.HINT_SPEC_FETCH_GRAPH;
import static org.hibernate.jpa.SpecHints.HINT_SPEC_LOAD_GRAPH;
@ -27,7 +29,7 @@ public enum GraphSemantic {
* are not fetched.
* </ul>
*/
FETCH( HINT_SPEC_FETCH_GRAPH, HINT_JAVAEE_FETCH_GRAPH ),
FETCH( HINT_SPEC_FETCH_GRAPH, LegacySpecHints.HINT_JAVAEE_FETCH_GRAPH ),
/**
* Indicates that an {@link jakarta.persistence.EntityGraph} should be interpreted as a JPA "load graph".
@ -38,27 +40,28 @@ public enum GraphSemantic {
* depending on the mapping of the attribute, instead of forcing {@code FetchType.LAZY}.
* </ul>
*/
LOAD( HINT_SPEC_LOAD_GRAPH, HINT_JAVAEE_LOAD_GRAPH );
LOAD( HINT_SPEC_LOAD_GRAPH, LegacySpecHints.HINT_JAVAEE_LOAD_GRAPH );
private final String jakartaHintName;
private final String jpaHintName;
private final String javaeeHintName;
GraphSemantic(String jakartaHintName, String jpaHintName) {
GraphSemantic(String jakartaHintName, String javaeeHintName) {
this.jakartaHintName = jakartaHintName;
this.jpaHintName = jpaHintName;
this.javaeeHintName = javaeeHintName;
}
/**
* The hint name that should be used with Jakarta Persistence.
* The corresponding Jakarta Persistence hint name.
*
* @see jakarta.persistence.Query#setHint(String, Object)
* @see org.hibernate.jpa.SpecHints#HINT_SPEC_FETCH_GRAPH
* @see org.hibernate.jpa.SpecHints#HINT_SPEC_LOAD_GRAPH
*/
public String getJakartaHintName() {
return jakartaHintName;
}
/**
* The hint name that should be used with JPA.
* The hint name that should be used with Java Persistence.
*
* @see org.hibernate.jpa.LegacySpecHints#HINT_JAVAEE_FETCH_GRAPH
* @see org.hibernate.jpa.LegacySpecHints#HINT_JAVAEE_LOAD_GRAPH
@ -67,7 +70,7 @@ public enum GraphSemantic {
*/
@Deprecated
public String getJpaHintName() {
return jpaHintName;
return javaeeHintName;
}
public static GraphSemantic fromHintName(String hintName) {
@ -82,8 +85,16 @@ public enum GraphSemantic {
}
throw new IllegalArgumentException(
"Unknown EntityGraph hint name [" + hintName + "]; " +
"expecting `" + FETCH.jpaHintName + "` or `" + LOAD.jpaHintName + "`."
String.format(
Locale.ROOT,
"Unknown EntityGraph hint name - `%s`. " +
"Expecting `%s` or `%s` (or `%s` and `%s`).",
hintName,
FETCH.jakartaHintName,
LOAD.jakartaHintName,
FETCH.javaeeHintName,
LOAD.javaeeHintName
)
);
}

View File

@ -305,7 +305,8 @@ public class SessionImpl
HINT_SPEC_LOCK_TIMEOUT,
HINT_JAVAEE_LOCK_TIMEOUT,
this::getSessionProperty,
(value) -> Integer.valueOf( LockOptions.WAIT_FOREVER ).equals( value )
// treat WAIT_FOREVER the same as null
(value) -> !Integer.valueOf( LockOptions.WAIT_FOREVER ).equals( value )
);
if ( specLockTimeout != null ) {
query.setHint( HINT_SPEC_LOCK_TIMEOUT, specLockTimeout );

View File

@ -6,10 +6,11 @@
*/
package org.hibernate.jpa;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.hibernate.jpa.internal.HintsCollector;
import jakarta.persistence.LockModeType;
/**
@ -23,37 +24,8 @@ import jakarta.persistence.LockModeType;
*
* @author Steve Ebersole
*/
public class AvailableHints implements HibernateHints, SpecHints {
private static final Set<String> HINTS = buildHintsSet();
public static Set<String> getDefinedHints() {
return HINTS;
public interface AvailableHints extends HibernateHints, SpecHints {
static Set<String> getDefinedHints() {
return HintsCollector.getDefinedHints();
}
private static Set<String> buildHintsSet() {
final HashSet<String> hints = new HashSet<>();
hints.add( HibernateHints.HINT_TIMEOUT );
hints.add( HibernateHints.HINT_READ_ONLY );
hints.add( HibernateHints.HINT_FLUSH_MODE );
hints.add( HibernateHints.HINT_CACHEABLE );
hints.add( HibernateHints.HINT_CACHE_MODE );
hints.add( HibernateHints.HINT_CACHE_REGION );
hints.add( HibernateHints.HINT_FETCH_SIZE );
hints.add( HibernateHints.HINT_COMMENT );
hints.add( HibernateHints.HINT_NATIVE_SPACES );
hints.add( HibernateHints.HINT_NATIVE_LOCK_MODE );
hints.add( SpecHints.HINT_SPEC_QUERY_TIMEOUT );
hints.add( SpecHints.HINT_SPEC_FETCH_GRAPH );
hints.add( SpecHints.HINT_SPEC_LOAD_GRAPH );
hints.add( LegacySpecHints.HINT_JAVAEE_QUERY_TIMEOUT );
hints.add( LegacySpecHints.HINT_JAVAEE_FETCH_GRAPH );
hints.add( LegacySpecHints.HINT_JAVAEE_LOAD_GRAPH );
return java.util.Collections.unmodifiableSet( hints );
}
}

View File

@ -13,17 +13,27 @@ import org.hibernate.query.Query;
* List of Hibernate-specific (extension) hints available to query,
* load and lock scenarios.
*
* Some hints are only valid for certain scenarios, which is noted on
* each constant's docuementation
* Some hints are only effective in certain scenarios, which is noted on
* each constant's documentation
*
* @author Steve Ebersole
*/
public interface HibernateHints {
/**
* Hint for specifying a query timeout, in seconds.
* Hint for specifying the {@link org.hibernate.FlushMode}
* to apply to an EntityManager or a Query
*
* @see Query#setHibernateFlushMode
* @see org.hibernate.Session#setHibernateFlushMode
*/
String HINT_FLUSH_MODE = "org.hibernate.flushMode";
/**
* Hint for specifying a Query timeout, in seconds.
*
* @see org.hibernate.query.Query#setTimeout
* @see java.sql.Statement#setQueryTimeout
* @see SpecHints#HINT_SPEC_QUERY_TIMEOUT
*/
String HINT_TIMEOUT = "org.hibernate.timeout";
@ -33,11 +43,12 @@ public interface HibernateHints {
* persistence context as read-only.
*
* @see Query#setReadOnly
* @see org.hibernate.Session#setDefaultReadOnly
*/
String HINT_READ_ONLY = "org.hibernate.readOnly";
/**
* Hint for specifying a JDBC fetch size to be applied to the
* Hint for specifying a fetch size to be applied to the
* JDBC statement.
*
* @see Query#setFetchSize
@ -45,26 +56,6 @@ public interface HibernateHints {
*/
String HINT_FETCH_SIZE = "org.hibernate.fetchSize";
/**
* Hint for specifying a database comment to be applied to
* the SQL sent to the database.
*
* @implSpec Not valid for {@link org.hibernate.procedure.ProcedureCall}
* nor {@link jakarta.persistence.StoredProcedureQuery} scenarios
*
* @see Query#setComment
*/
String HINT_COMMENT = "org.hibernate.comment";
/**
* Hint for specifying the {@link org.hibernate.FlushMode}
* to apply to Query execution
*
* @see Query#setHibernateFlushMode
* @see org.hibernate.Session#setHibernateFlushMode
*/
String HINT_FLUSH_MODE = "org.hibernate.flushMode";
/**
* Hint for specifying whether results from a query should
* be stored in the query cache
@ -92,6 +83,17 @@ public interface HibernateHints {
*/
String HINT_CACHE_MODE = "org.hibernate.cacheMode";
/**
* Hint for specifying a database comment to be applied to
* the SQL sent to the database.
*
* @implSpec Not valid for {@link org.hibernate.procedure.ProcedureCall}
* nor {@link jakarta.persistence.StoredProcedureQuery} scenarios
*
* @see Query#setComment
*/
String HINT_COMMENT = "org.hibernate.comment";
/**
* Hint to enable/disable the follow-on-locking mechanism provided by
* {@link org.hibernate.dialect.Dialect#useFollowOnLocking(String, org.hibernate.query.spi.QueryOptions)}.

View File

@ -6,16 +6,20 @@
*/
package org.hibernate.jpa;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.jpa.internal.HintsCollector;
/**
* List of all supported hints that may be passed to {@link jakarta.persistence.Query#setHint(String, Object)}.
*
* @see SpecHints
* @see HibernateHints
* @see AvailableHints
*
* @deprecated (since 6.0) Use {@link AvailableHints} instead
*/
public class QueryHints {
@SuppressWarnings("unused")
@Deprecated
public final class QueryHints {
/**
* @see SpecHints#HINT_SPEC_QUERY_TIMEOUT
*/
@ -113,38 +117,10 @@ public class QueryHints {
*/
public static final String SPEC_HINT_TIMEOUT = LegacySpecHints.HINT_JAVAEE_QUERY_TIMEOUT;
private static final Set<String> HINTS = buildHintsSet();
private static Set<String> buildHintsSet() {
final HashSet<String> hints = new HashSet<>();
hints.add( HibernateHints.HINT_TIMEOUT );
hints.add( HibernateHints.HINT_READ_ONLY );
hints.add( HibernateHints.HINT_FLUSH_MODE );
hints.add( HibernateHints.HINT_CACHEABLE );
hints.add( HibernateHints.HINT_CACHE_MODE );
hints.add( HibernateHints.HINT_CACHE_REGION );
hints.add( HibernateHints.HINT_FETCH_SIZE );
hints.add( HibernateHints.HINT_COMMENT );
hints.add( HibernateHints.HINT_NATIVE_SPACES );
hints.add( HibernateHints.HINT_NATIVE_LOCK_MODE );
hints.add( SpecHints.HINT_SPEC_QUERY_TIMEOUT );
hints.add( SpecHints.HINT_SPEC_FETCH_GRAPH );
hints.add( SpecHints.HINT_SPEC_LOAD_GRAPH );
hints.add( LegacySpecHints.HINT_JAVAEE_QUERY_TIMEOUT );
hints.add( LegacySpecHints.HINT_JAVAEE_FETCH_GRAPH );
hints.add( LegacySpecHints.HINT_JAVAEE_LOAD_GRAPH );
return java.util.Collections.unmodifiableSet( hints );
}
public static Set<String> getDefinedHints() {
return HINTS;
return HintsCollector.getDefinedHints();
}
protected QueryHints() {
private QueryHints() {
}
}

View File

@ -16,9 +16,10 @@ import jakarta.persistence.LockModeType;
* The hints explicitly defined by the Jakarta Persistence specification
* which are available for both queries and loading
*
* @see jakarta.persistence.EntityManager#setProperty
* @see jakarta.persistence.EntityManager#find(Class, Object, Map)
* @see jakarta.persistence.EntityManager#find(Class, Object, LockModeType, Map)
* @see org.hibernate.Session#lock(Object, LockModeType, Map)
* @see jakarta.persistence.EntityManager#lock(Object, LockModeType, Map)
* @see jakarta.persistence.Query#setHint
*
* @author Steve Ebersole

View File

@ -0,0 +1,64 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.jpa.internal;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.jpa.HibernateHints;
import org.hibernate.jpa.SpecHints;
import static java.util.Collections.unmodifiableSet;
/**
* Collects all available hints for use the Jakarta Persistence hint system
*
* @author Steve Ebersole
*/
public class HintsCollector {
private static final Set<String> HINTS = buildHintsSet();
public static Set<String> getDefinedHints() {
return HINTS;
}
private static Set<String> buildHintsSet() {
final HashSet<String> hints = new HashSet<>();
applyHints( hints, HibernateHints.class );
applyHints( hints, SpecHints.class );
return unmodifiableSet( hints );
}
private static void applyHints(HashSet<String> hints, Class<?> hintsClass) {
final Field[] fields = hintsClass.getDeclaredFields();
for ( int i = 0; i < fields.length; i++ ) {
final Field field = fields[i];
if ( !field.getName().startsWith( "HINT_" ) ) {
continue;
}
if ( !field.getType().equals( String.class ) ) {
continue;
}
// the field's value is the hint name
try {
hints.add( (String) field.get( hintsClass ) );
}
catch (IllegalAccessException e) {
throw new HibernateException(
"Unable to generate set of all hints - " + hintsClass.getName(),
e
);
}
}
}
}

View File

@ -24,7 +24,6 @@ import java.util.stream.Stream;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.ScrollMode;
import org.hibernate.annotations.QueryHints;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.graph.GraphSemantic;

View File

@ -539,7 +539,7 @@ public class QuerySqmImpl<R>
@Override
protected void applyEntityGraphQueryHint(String hintName, @SuppressWarnings("rawtypes") RootGraphImplementor entityGraph) {
final GraphSemantic graphSemantic = GraphSemantic.fromJpaHintName( hintName );
final GraphSemantic graphSemantic = GraphSemantic.fromHintName( hintName );
applyGraph( entityGraph, graphSemantic );
}

View File

@ -7,6 +7,22 @@
package org.hibernate.orm.test.dialect.functional;
import java.util.List;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.Session;
import org.hibernate.boot.SessionFactoryBuilder;
import org.hibernate.dialect.OracleDialect;
import org.hibernate.jpa.AvailableHints;
import org.hibernate.query.IllegalQueryOperationException;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.jdbc.SQLStatementInterceptor;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.junit.Before;
import org.junit.Test;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
@ -16,21 +32,6 @@ import jakarta.persistence.LockModeType;
import jakarta.persistence.NamedQuery;
import jakarta.persistence.QueryHint;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.Session;
import org.hibernate.annotations.QueryHints;
import org.hibernate.boot.SessionFactoryBuilder;
import org.hibernate.dialect.OracleDialect;
import org.hibernate.query.IllegalQueryOperationException;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.hibernate.testing.jdbc.SQLStatementInterceptor;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@ -514,7 +515,7 @@ public class OracleFollowOnLockingTest extends
name = "product_by_name",
query = "select p from Product p where p.name is not null",
lockMode = LockModeType.PESSIMISTIC_WRITE,
hints = @QueryHint(name = QueryHints.FOLLOW_ON_LOCKING, value = "true")
hints = @QueryHint(name = AvailableHints.HINT_FOLLOW_ON_LOCKING, value = "true")
)
@Entity(name = "Product")
public static class Product {