diff --git a/gradle.properties b/gradle.properties index 299ccf3b9..be7612bc5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -35,7 +35,7 @@ org.gradle.java.installations.auto-download=false #enableMavenLocalRepo = true # The default Hibernate ORM version (override using `-PhibernateOrmVersion=the.version.you.want`) -hibernateOrmVersion = 7.0.0.Beta4 +hibernateOrmVersion = 7.0.0.Beta5 # Override default Hibernate ORM Gradle plugin version # Using the stable version because I don't know how to configure the build to download the snapshot version from diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveDeleteEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveDeleteEventListener.java index 664b09da3..f490d5366 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveDeleteEventListener.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveDeleteEventListener.java @@ -436,11 +436,8 @@ protected CompletionStage deleteEntity( persister ).nullifyTransientReferences( entityEntry.getDeletedState() ) .thenAccept( vv -> { - new Nullability( session ).checkNullability( - entityEntry.getDeletedState(), - persister, - Nullability.NullabilityCheckType.DELETE - ); + new Nullability( session, Nullability.NullabilityCheckType.DELETE ) + .checkNullability( entityEntry.getDeletedState(), persister ); persistenceContext.registerNullifiableEntityKey( key ); final ReactiveActionQueue actionQueue = actionQueue( session ); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveEntityBatchLoaderArrayParam.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveEntityBatchLoaderArrayParam.java index ba69fd407..04f971ffd 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveEntityBatchLoaderArrayParam.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveEntityBatchLoaderArrayParam.java @@ -10,7 +10,6 @@ import java.util.concurrent.CompletionStage; import org.hibernate.LockOptions; -import org.hibernate.engine.internal.BatchFetchQueueHelper; import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.SessionFactoryImplementor; @@ -160,7 +159,8 @@ private CompletionStage initializeEntities( continue; } // found or not, remove the key from the batch-fetch queue - BatchFetchQueueHelper.removeBatchLoadableEntityKey( id, getLoadable(), session ); + session.getPersistenceContextInternal().getBatchFetchQueue() + .removeBatchLoadableEntityKey( session.generateEntityKey( id, getLoadable().getEntityPersister() ) ); } } ); } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderArrayParam.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderArrayParam.java index 8495d115b..8239a6e15 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderArrayParam.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderArrayParam.java @@ -13,7 +13,6 @@ import org.hibernate.LockMode; import org.hibernate.LockOptions; -import org.hibernate.engine.internal.BatchFetchQueueHelper; import org.hibernate.engine.spi.BatchFetchQueue; import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityKey; @@ -206,7 +205,7 @@ protected CompletionStage> performOrderedMultiLoad( // the element value at this position in the result List should be // the EntityKey for that entity - reuse it final EntityKey entityKey = (EntityKey) result.get( resultIndex ); - BatchFetchQueueHelper.removeBatchLoadableEntityKey( entityKey, session ); + session.getPersistenceContextInternal().getBatchFetchQueue().removeBatchLoadableEntityKey( entityKey ); Object entity = persistenceContext.getEntity( entityKey ); if ( entity != null && !loadOptions.isReturnOfDeletedEntitiesEnabled() ) { // make sure it is not DELETED @@ -293,7 +292,8 @@ protected CompletionStage> performUnorderedMultiLoad( continue; } // found or not, remove the key from the batch-fetch queue - BatchFetchQueueHelper.removeBatchLoadableEntityKey( id, getLoadable(), session ); + session.getPersistenceContextInternal().getBatchFetchQueue() + .removeBatchLoadableEntityKey( session.generateEntityKey( id, getLoadable().getEntityPersister() ) ); } return result; diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionImpl.java index 929987b55..87cf50bb0 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionImpl.java @@ -173,7 +173,7 @@ public MutationQuery createQuery(CriteriaDelete criteriaDelete) { @Override public Query createNamedQuery(String queryName) { - return new MutinyQueryImpl<>( delegate.createReactiveNamedQuery( queryName, null ), factory ); + return new MutinyQueryImpl<>( delegate.createReactiveNamedQuery( queryName ), factory ); } @Override diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinyStatelessSessionImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinyStatelessSessionImpl.java index d6e8e984e..5605a7911 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinyStatelessSessionImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinyStatelessSessionImpl.java @@ -93,7 +93,7 @@ public Mutiny.MutationQuery createMutationQuery(String queryString) { @Override public Query createNamedQuery(String queryName) { - return new MutinyQueryImpl<>( delegate.createReactiveNamedQuery( queryName, null ), factory ); + return new MutinyQueryImpl<>( delegate.createReactiveNamedQuery( queryName ), factory ); } @Override diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/ReactiveQueryImplementor.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/ReactiveQueryImplementor.java index 7c7588a7c..0354a59e5 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/ReactiveQueryImplementor.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/ReactiveQueryImplementor.java @@ -5,7 +5,6 @@ */ package org.hibernate.reactive.query; -import java.io.Serializable; import java.time.Instant; import java.util.Calendar; import java.util.Collection; @@ -23,12 +22,6 @@ public interface ReactiveQueryImplementor extends ReactiveQuery { - void setOptionalId(Serializable id); - - void setOptionalEntityName(String entityName); - - void setOptionalObject(Object optionalObject); - QueryParameterBindings getParameterBindings(); @Override diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sql/internal/ReactiveNativeQueryImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sql/internal/ReactiveNativeQueryImpl.java index 6d162882a..ac8f4e9b4 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sql/internal/ReactiveNativeQueryImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sql/internal/ReactiveNativeQueryImpl.java @@ -26,7 +26,6 @@ import org.hibernate.graph.GraphSemantic; import org.hibernate.graph.RootGraph; import org.hibernate.graph.spi.RootGraphImplementor; -import org.hibernate.internal.AbstractSharedSessionContract; import org.hibernate.metamodel.model.domain.BasicDomainType; import org.hibernate.query.BindableType; import org.hibernate.query.Order; @@ -65,8 +64,18 @@ public class ReactiveNativeQueryImpl extends NativeQueryImpl private final ReactiveAbstractSelectionQuery selectionQueryDelegate; - public ReactiveNativeQueryImpl(String memento, SharedSessionContractImplementor session) { - super( memento, session ); + public ReactiveNativeQueryImpl(String sql, SharedSessionContractImplementor session) { + super( sql, null, session ); + this.selectionQueryDelegate = createSelectionQueryDelegate( session ); + } + + public ReactiveNativeQueryImpl(String sql, Class resultClass, SharedSessionContractImplementor session) { + super( sql, resultClass, session ); + this.selectionQueryDelegate = createSelectionQueryDelegate( session ); + } + + public ReactiveNativeQueryImpl(String sql, NamedResultSetMappingMemento resultSetMappingMemento, Class resultClass, SharedSessionContractImplementor session) { + super( sql, resultSetMappingMemento, resultClass, session); this.selectionQueryDelegate = createSelectionQueryDelegate( session ); } @@ -91,14 +100,6 @@ public ReactiveNativeQueryImpl( this.selectionQueryDelegate = createSelectionQueryDelegate( session ); } - public ReactiveNativeQueryImpl( - String sqlString, - NamedResultSetMappingMemento resultSetMappingMemento, - AbstractSharedSessionContract session) { - super( sqlString, resultSetMappingMemento, session ); - this.selectionQueryDelegate = createSelectionQueryDelegate( session ); - } - // Convenient for passing parameters to ReactiveAbstractSelectionQuery using method reference private T getNull() { return null; diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveSimpleDeleteQueryPlan.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveSimpleDeleteQueryPlan.java index a17d1eb73..eb055a38a 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveSimpleDeleteQueryPlan.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveSimpleDeleteQueryPlan.java @@ -37,9 +37,7 @@ import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.tree.AbstractUpdateOrDeleteStatement; import org.hibernate.sql.ast.tree.MutationStatement; -import org.hibernate.sql.ast.tree.expression.ColumnReference; import org.hibernate.sql.ast.tree.expression.Expression; -import org.hibernate.sql.ast.tree.expression.JdbcLiteral; import org.hibernate.sql.ast.tree.from.MutatingTableReferenceGroupWrapper; import org.hibernate.sql.ast.tree.from.NamedTableReference; import org.hibernate.sql.ast.tree.predicate.InSubQueryPredicate; @@ -95,29 +93,28 @@ protected SqlAstTranslator createTranslato return factory.getJdbcServices() .getJdbcEnvironment() .getSqlAstTranslatorFactory() - .buildMutationTranslator( factory, mutationStatement() ); + .buildMutationTranslator( factory, createDeleteAst() ); } - private MutationStatement mutationStatement() { + // Copy and paste from superclass + private MutationStatement createDeleteAst() { + final MutationStatement ast; if ( entityDescriptor.getSoftDeleteMapping() == null ) { - return sqmInterpretation.getSqlAst(); + ast = sqmInterpretation.getSqlAst(); } - final AbstractUpdateOrDeleteStatement sqlDeleteAst = sqmInterpretation.getSqlAst(); - final NamedTableReference targetTable = sqlDeleteAst.getTargetTable(); - final SoftDeleteMapping columnMapping = getEntityDescriptor().getSoftDeleteMapping(); - final ColumnReference columnReference = new ColumnReference( targetTable, columnMapping ); - //noinspection rawtypes,unchecked - final JdbcLiteral jdbcLiteral = new JdbcLiteral( - columnMapping.getDeletedLiteralValue(), - columnMapping.getJdbcMapping() - ); - final Assignment assignment = new Assignment( columnReference, jdbcLiteral ); - - return new UpdateStatement( - targetTable, - Collections.singletonList( assignment ), - sqlDeleteAst.getRestriction() - ); + else { + final AbstractUpdateOrDeleteStatement sqlDeleteAst = sqmInterpretation.getSqlAst(); + final NamedTableReference targetTable = sqlDeleteAst.getTargetTable(); + final SoftDeleteMapping columnMapping = getEntityDescriptor().getSoftDeleteMapping(); + final Assignment assignment = columnMapping.createSoftDeleteAssignment( targetTable ); + + ast = new UpdateStatement( + targetTable, + Collections.singletonList( assignment ), + sqlDeleteAst.getRestriction() + ); + } + return ast; } @Override diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveQueryProducer.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveQueryProducer.java index 25a7402ef..a3b667fea 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveQueryProducer.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveQueryProducer.java @@ -57,6 +57,8 @@ public interface ReactiveQueryProducer extends ReactiveConnectionSupplier { ReactiveQuery createReactiveQuery(String queryString, Class resultType); + ReactiveQueryImplementor createReactiveNamedQuery(String queryString); + ReactiveQueryImplementor createReactiveNamedQuery(String queryString, Class resultType); ReactiveNativeQuery createReactiveNativeQuery(String sqlString); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveSessionImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveSessionImpl.java index fc8ee8ae6..72157e46e 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveSessionImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveSessionImpl.java @@ -72,13 +72,16 @@ import org.hibernate.proxy.HibernateProxy; import org.hibernate.proxy.LazyInitializer; import org.hibernate.query.IllegalMutationQueryException; +import org.hibernate.query.UnknownNamedQueryException; import org.hibernate.query.criteria.JpaCriteriaInsert; import org.hibernate.query.hql.spi.SqmQueryImplementor; import org.hibernate.query.named.NamedResultSetMappingMemento; import org.hibernate.query.spi.HqlInterpretation; import org.hibernate.query.spi.QueryImplementor; +import org.hibernate.query.sql.spi.NamedNativeQueryMemento; import org.hibernate.query.sql.spi.NativeQueryImplementor; import org.hibernate.query.sqm.internal.SqmUtil; +import org.hibernate.query.sqm.spi.NamedSqmQueryMemento; import org.hibernate.query.sqm.tree.SqmStatement; import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement; import org.hibernate.query.sqm.tree.insert.SqmInsertStatement; @@ -131,7 +134,6 @@ import static org.hibernate.engine.spi.NaturalIdResolutions.INVALID_NATURAL_ID_REFERENCE; import static org.hibernate.event.spi.LoadEventListener.IMMEDIATE_LOAD; import static org.hibernate.internal.util.StringHelper.isEmpty; -import static org.hibernate.internal.util.StringHelper.isNotEmpty; import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer; import static org.hibernate.reactive.common.InternalStateAssertions.assertUseOnEventLoop; import static org.hibernate.reactive.persister.entity.impl.ReactiveEntityPersister.forceInitialize; @@ -443,14 +445,16 @@ public ReactiveNativeQuery createReactiveNativeQuery(String sqlString, Cl @Override @Deprecated(forRemoval = true) public ReactiveNativeQuery createReactiveNativeQuery(String sqlString, String resultSetMappingName) { + if ( isEmpty( resultSetMappingName ) ) { + throw new IllegalArgumentException( "Result set mapping name was not specified" ); + } + checkOpen(); pulseTransactionCoordinator(); delayedAfterCompletion(); try { - return isNotEmpty( resultSetMappingName ) - ? new ReactiveNativeQueryImpl<>( sqlString, getResultSetMappingMemento( resultSetMappingName ), this ) - : new ReactiveNativeQueryImpl<>( sqlString, this ); + return new ReactiveNativeQueryImpl<>( sqlString, getResultSetMappingMemento( resultSetMappingName ), null, this ); //TODO: why no applyQuerySettingsAndHints( query ); ??? } catch (RuntimeException he) { @@ -497,9 +501,78 @@ private ReactiveSelectionQuery createSelectionQuery(String hql, Class return query; } + @Override + public ReactiveQueryImplementor createReactiveNamedQuery(String name) { + checksBeforeQueryCreation(); + try { + return (ReactiveQueryImplementor) buildNamedQuery( + name, + this::createSqmQueryImplementor, + this::createNativeQueryImplementor + ); + } + catch (RuntimeException e) { + throw convertNamedQueryException( e ); + } + } + @Override public ReactiveQueryImplementor createReactiveNamedQuery(String name, Class resultType) { - return (ReactiveQueryImplementor) buildNamedQuery( name, resultType ); + checksBeforeQueryCreation(); + if ( resultType == null ) { + throw new IllegalArgumentException( "Result class is null" ); + } + try { + return buildNamedQuery( + name, + memento -> createReactiveSqmQueryImplementor( resultType, memento ), + memento -> createReactiveNativeQueryImplementor( resultType, memento ) + ); + } + catch (RuntimeException e) { + throw convertNamedQueryException( e ); + } + } + + private void checksBeforeQueryCreation() { + checkOpen(); + checkTransactionSynchStatus(); + } + + protected ReactiveNativeQueryImpl createReactiveNativeQueryImplementor(Class resultType, NamedNativeQueryMemento memento) { + final NativeQueryImplementor query = memento.toQuery(this, resultType ); + if ( isEmpty( query.getComment() ) ) { + query.setComment( "dynamic native SQL query" ); + } + applyQuerySettingsAndHints( query ); + return (ReactiveNativeQueryImpl) query; + } + + protected ReactiveQuerySqmImpl createReactiveSqmQueryImplementor(Class resultType, NamedSqmQueryMemento memento) { + final SqmQueryImplementor query = memento.toQuery( this, resultType ); + if ( isEmpty( query.getComment() ) ) { + query.setComment( "dynamic query" ); + } + applyQuerySettingsAndHints( query ); + if ( memento.getLockOptions() != null ) { + query.setLockOptions( memento.getLockOptions() ); + } + return (ReactiveQuerySqmImpl) query; + } + + private RuntimeException convertNamedQueryException(RuntimeException e) { + if ( e instanceof UnknownNamedQueryException ) { + // JPA expects this to mark the transaction for rollback only + getTransactionCoordinator().getTransactionDriverControl().markRollbackOnly(); + // it also expects an IllegalArgumentException, so wrap UnknownNamedQueryException + return new IllegalArgumentException( e.getMessage(), e ); + } + else if ( e instanceof IllegalArgumentException ) { + return e; + } + else { + return getExceptionConverter().convert( e ); + } } @Override @@ -584,7 +657,7 @@ public ReactiveNativeQuery createReactiveNativeQuery(String queryString, delayedAfterCompletion(); try { - final ReactiveNativeQueryImpl query = new ReactiveNativeQueryImpl<>( queryString, this ); + final ReactiveNativeQueryImpl query = new ReactiveNativeQueryImpl<>( queryString, null, this ); addAffectedEntities( affectedEntities, query ); if ( isEmpty( query.getComment() ) ) { query.setComment( "dynamic native SQL query" ); @@ -622,12 +695,11 @@ public ReactiveNativeQueryImpl createReactiveNativeQuery(String queryStri checkOpen(); pulseTransactionCoordinator(); delayedAfterCompletion(); - + // Should we throw an exception? + NamedResultSetMappingMemento memento = resultSetMapping == null ? null : getResultSetMappingMemento( resultSetMapping.getName() ); try { // Same approach as AbstractSharedSessionContract#createNativeQuery(String, String) - final ReactiveNativeQueryImpl nativeQuery = resultSetMapping != null - ? new ReactiveNativeQueryImpl<>( queryString, getResultSetMappingMemento( resultSetMapping.getName() ), this ) - : new ReactiveNativeQueryImpl<>( queryString, this ); + final ReactiveNativeQueryImpl nativeQuery = new ReactiveNativeQueryImpl<>( queryString, memento, null, this ); applyQuerySettingsAndHints( nativeQuery ); return nativeQuery; } @@ -652,20 +724,13 @@ public ResultSetMapping getResultSetMapping(Class resultType, String m if ( mapping == null ) { throw new IllegalArgumentException( "result set mapping does not exist: " + mappingName ); } -// -// ResultSetMappingImpl resultSetMapping = new ResultSetMappingImpl( "impl" ); -// if ( resultType != null ) { -// Class mappedResultType = resultSetMapping.; -// if ( !resultType.equals( mappedResultType ) ) { -// throw new IllegalArgumentException( "incorrect result type for result set mapping: " + mappingName + " has type " + mappedResultType.getName() ); -// } -// } return new ResultSetMapping<>() { @Override public String getName() { return mappingName; } + @Override public Class getResultType() { return resultType; diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveStatelessSessionImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveStatelessSessionImpl.java index 4941dda50..2d3efe4f5 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveStatelessSessionImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveStatelessSessionImpl.java @@ -22,6 +22,7 @@ import org.hibernate.cache.spi.access.EntityDataAccess; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.dialect.Dialect; +import org.hibernate.engine.internal.ReactivePersistenceContextAdapter; import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.PersistenceContext; @@ -47,10 +48,12 @@ import org.hibernate.proxy.HibernateProxy; import org.hibernate.proxy.LazyInitializer; import org.hibernate.query.IllegalMutationQueryException; +import org.hibernate.query.UnknownNamedQueryException; import org.hibernate.query.criteria.JpaCriteriaInsert; import org.hibernate.query.criteria.JpaCriteriaQuery; import org.hibernate.query.criteria.JpaRoot; import org.hibernate.query.hql.spi.SqmQueryImplementor; +import org.hibernate.query.named.NamedResultSetMappingMemento; import org.hibernate.query.spi.HqlInterpretation; import org.hibernate.query.spi.QueryImplementor; import org.hibernate.query.sql.spi.NativeQueryImplementor; @@ -64,7 +67,6 @@ import org.hibernate.query.sqm.tree.update.SqmUpdateStatement; import org.hibernate.reactive.common.AffectedEntities; import org.hibernate.reactive.common.ResultSetMapping; -import org.hibernate.engine.internal.ReactivePersistenceContextAdapter; import org.hibernate.reactive.id.ReactiveIdentifierGenerator; import org.hibernate.reactive.logging.impl.Log; import org.hibernate.reactive.persister.collection.impl.ReactiveCollectionPersister; @@ -905,7 +907,7 @@ public ReactiveNativeQueryImplementor createReactiveNativeQuery(String sq delayedAfterCompletion(); try { - final ReactiveNativeQueryImpl query = new ReactiveNativeQueryImpl<>( sqlString, this ); + final ReactiveNativeQueryImpl query = new ReactiveNativeQueryImpl<>( sqlString, null, this); if ( isEmpty( query.getComment() ) ) { query.setComment( "dynamic native SQL query" ); } @@ -956,9 +958,19 @@ public ReactiveNativeQuery createReactiveNativeQuery(String sqlString, St delayedAfterCompletion(); try { - return isNotEmpty( resultSetMappingName ) - ? new ReactiveNativeQueryImpl<>( sqlString, getResultSetMappingMemento( resultSetMappingName ), this ) - : new ReactiveNativeQueryImpl<>( sqlString, this ); + if ( isNotEmpty( resultSetMappingName ) ) { + final NamedResultSetMappingMemento resultSetMappingMemento = getFactory().getQueryEngine() + .getNamedObjectRepository() + .getResultSetMappingMemento( resultSetMappingName ); + + if ( resultSetMappingMemento == null ) { + throw new HibernateException( "Could not resolve specified result-set mapping name : " + resultSetMappingName ); + } + return new ReactiveNativeQueryImpl<>( sqlString, resultSetMappingMemento, null, this ); + } + else { + return new ReactiveNativeQueryImpl<>( sqlString, this ); + } //TODO: why no applyQuerySettingsAndHints( query ); ??? } catch (RuntimeException he) { @@ -1069,11 +1081,64 @@ public ReactiveMutationQuery createNamedReactiveMutationQuery(String quer ); } + @Override + public ReactiveQueryImplementor createReactiveNamedQuery(String queryName) { + checksBeforeQueryCreation(); + try { + return (ReactiveQueryImplementor) buildNamedQuery( + queryName, + this::createSqmQueryImplementor, + this::createNativeQueryImplementor + ); + } + catch (RuntimeException e) { + throw convertNamedQueryException( e ); + } + } + + @Override + public ReactiveQueryImplementor createReactiveNamedQuery(String queryName, Class resultType) { + checksBeforeQueryCreation(); + if ( resultType == null ) { + throw new IllegalArgumentException( "Result class is null" ); + } + try { + return (ReactiveQueryImplementor) buildNamedQuery( + queryName, + memento -> createSqmQueryImplementor( resultType, memento ), + memento -> createNativeQueryImplementor( resultType, memento ) + ); + } + catch (RuntimeException e) { + throw convertNamedQueryException( e ); + } + } + + private RuntimeException convertNamedQueryException(RuntimeException e) { + if ( e instanceof UnknownNamedQueryException ) { + // JPA expects this to mark the transaction for rollback only + getTransactionCoordinator().getTransactionDriverControl().markRollbackOnly(); + // it also expects an IllegalArgumentException, so wrap UnknownNamedQueryException + return new IllegalArgumentException( e.getMessage(), e ); + } + else if ( e instanceof IllegalArgumentException ) { + return e; + } + else { + return getExceptionConverter().convert( e ); + } + } + @Override public ReactiveSelectionQuery createNamedReactiveSelectionQuery(String queryName, Class expectedResultType) { return (ReactiveSelectionQuery) createNamedSelectionQuery( queryName , expectedResultType ); } + private void checksBeforeQueryCreation() { + checkOpen(); + checkTransactionSynchStatus(); + } + @Override public ReactiveMutationQuery createNativeReactiveMutationQuery(String sqlString) { final ReactiveNativeQueryImplementor query = createReactiveNativeQuery( sqlString ); @@ -1083,11 +1148,6 @@ public ReactiveMutationQuery createNativeReactiveMutationQuery(String sql return query; } - @Override - public ReactiveQueryImplementor createReactiveNamedQuery(String queryName, Class resultType) { - return (ReactiveQueryImplementor) buildNamedQuery( queryName, resultType ); - } - @Override public ReactiveNativeQuery createReactiveNativeQuery(String queryString, AffectedEntities affectedEntities) { checkOpen(); @@ -1131,11 +1191,13 @@ public ReactiveNativeQueryImpl createReactiveNativeQuery(String queryStri pulseTransactionCoordinator(); delayedAfterCompletion(); + if ( resultSetMapping == null ) { + throw new IllegalArgumentException( "Result set mapping was not specified" ); + } + try { - // Same approach as AbstractSharedSessionContract#createNativeQuery(String, String) - final ReactiveNativeQueryImpl nativeQuery = resultSetMapping != null - ? new ReactiveNativeQueryImpl<>( queryString, getResultSetMappingMemento( resultSetMapping.getName() ), this ) - : new ReactiveNativeQueryImpl<>( queryString, this ); + final NamedResultSetMappingMemento memento = getResultSetMappingMemento( resultSetMapping.getName() ); + final ReactiveNativeQueryImpl nativeQuery = new ReactiveNativeQueryImpl<>( queryString, memento, null, this ); applyQuerySettingsAndHints( nativeQuery ); return nativeQuery; } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSessionImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSessionImpl.java index 78ce3c891..150c2ec96 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSessionImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSessionImpl.java @@ -5,16 +5,11 @@ */ package org.hibernate.reactive.stage.impl; -import jakarta.persistence.CacheRetrieveMode; -import jakarta.persistence.CacheStoreMode; -import jakarta.persistence.EntityGraph; -import jakarta.persistence.FlushModeType; -import jakarta.persistence.LockModeType; -import jakarta.persistence.PersistenceException; -import jakarta.persistence.criteria.CriteriaDelete; -import jakarta.persistence.criteria.CriteriaQuery; -import jakarta.persistence.criteria.CriteriaUpdate; -import jakarta.persistence.metamodel.Attribute; +import java.lang.invoke.MethodHandles; +import java.util.List; +import java.util.concurrent.CompletionStage; +import java.util.function.Function; + import org.hibernate.CacheMode; import org.hibernate.Filter; import org.hibernate.FlushMode; @@ -39,10 +34,16 @@ import org.hibernate.reactive.stage.Stage.Query; import org.hibernate.reactive.stage.Stage.SelectionQuery; -import java.lang.invoke.MethodHandles; -import java.util.List; -import java.util.concurrent.CompletionStage; -import java.util.function.Function; +import jakarta.persistence.CacheRetrieveMode; +import jakarta.persistence.CacheStoreMode; +import jakarta.persistence.EntityGraph; +import jakarta.persistence.FlushModeType; +import jakarta.persistence.LockModeType; +import jakarta.persistence.PersistenceException; +import jakarta.persistence.criteria.CriteriaDelete; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.CriteriaUpdate; +import jakarta.persistence.metamodel.Attribute; import static org.hibernate.reactive.util.impl.CompletionStages.applyToAll; import static org.hibernate.reactive.util.impl.CompletionStages.returnOrRethrow; @@ -556,7 +557,7 @@ public MutationQuery createQuery(CriteriaDelete criteriaDelete) { @Override public Query createNamedQuery(String queryName) { - return new StageQueryImpl<>( delegate.createReactiveNamedQuery( queryName, null ) ); + return new StageQueryImpl<>( delegate.createReactiveNamedQuery( queryName ) ); } @Override diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageStatelessSessionImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageStatelessSessionImpl.java index aadd76285..c48a7eab8 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageStatelessSessionImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageStatelessSessionImpl.java @@ -326,7 +326,7 @@ public Query createNativeQuery(String queryString) { @Override public Query createNamedQuery(String queryName) { - return new StageQueryImpl<>( delegate.createReactiveNamedQuery( queryName, null ) ); + return new StageQueryImpl<>( delegate.createReactiveNamedQuery( queryName ) ); } @Override diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/ReactiveStatelessWithBatchTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/ReactiveStatelessWithBatchTest.java similarity index 99% rename from hibernate-reactive-core/src/test/java/org/hibernate/ReactiveStatelessWithBatchTest.java rename to hibernate-reactive-core/src/test/java/org/hibernate/reactive/ReactiveStatelessWithBatchTest.java index 563fad40b..a30cc1364 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/ReactiveStatelessWithBatchTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/ReactiveStatelessWithBatchTest.java @@ -3,11 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright: Red Hat Inc. and Hibernate Authors */ -package org.hibernate; +package org.hibernate.reactive; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.Configuration; -import org.hibernate.reactive.BaseReactiveTest; import org.hibernate.reactive.annotations.EnabledFor; import org.hibernate.reactive.testing.SqlStatementTracker;