HHH-12139 - Allow Hibernate's Transaction act like JPA's EntityTransaction
This commit is contained in:
parent
6ba328e7a0
commit
f669c4bcdf
|
@ -19,6 +19,7 @@ import org.hibernate.cache.spi.QueryCacheFactory;
|
|||
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
|
||||
import org.hibernate.dialect.function.SQLFunction;
|
||||
import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy;
|
||||
import org.hibernate.jpa.JpaCompliance;
|
||||
import org.hibernate.loader.BatchFetchStyle;
|
||||
import org.hibernate.proxy.EntityNotFoundDelegate;
|
||||
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
|
||||
|
@ -718,6 +719,28 @@ public interface SessionFactoryBuilder {
|
|||
*/
|
||||
SessionFactoryBuilder enableReleaseResourcesOnCloseEnabled(boolean enable);
|
||||
|
||||
|
||||
/**
|
||||
* @see JpaCompliance#isJpaQueryComplianceEnabled()
|
||||
*/
|
||||
SessionFactoryBuilder enableJpaQueryCompliance(boolean enabled);
|
||||
|
||||
/**
|
||||
* @see JpaCompliance#isJpaTransactionComplianceEnabled()
|
||||
*/
|
||||
SessionFactoryBuilder enableJpaTransactionCompliance(boolean enabled);
|
||||
|
||||
/**
|
||||
* @see JpaCompliance#isJpaListComplianceEnabled()
|
||||
*/
|
||||
SessionFactoryBuilder enableJpaListCompliance(boolean enabled);
|
||||
|
||||
/**
|
||||
* @see JpaCompliance#isJpaClosedComplianceEnabled()
|
||||
*/
|
||||
SessionFactoryBuilder enableJpaClosedCompliance(boolean enabled);
|
||||
|
||||
|
||||
/**
|
||||
* Allows unwrapping this builder as another, more specific type.
|
||||
*
|
||||
|
|
|
@ -52,6 +52,8 @@ import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy;
|
|||
import org.hibernate.internal.SessionFactoryImpl;
|
||||
import org.hibernate.internal.log.DeprecationLogger;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.hibernate.jpa.JpaCompliance;
|
||||
import org.hibernate.jpa.spi.JpaComplianceImpl;
|
||||
import org.hibernate.loader.BatchFetchStyle;
|
||||
import org.hibernate.proxy.EntityNotFoundDelegate;
|
||||
import org.hibernate.query.criteria.LiteralHandlingMode;
|
||||
|
@ -502,6 +504,30 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionFactoryBuilder enableJpaQueryCompliance(boolean enabled) {
|
||||
this.options.jpaCompliance.setQueryCompliance( enabled );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionFactoryBuilder enableJpaTransactionCompliance(boolean enabled) {
|
||||
this.options.jpaCompliance.setTransactionCompliance( enabled );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionFactoryBuilder enableJpaListCompliance(boolean enabled) {
|
||||
this.options.jpaCompliance.setListCompliance( enabled );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionFactoryBuilder enableJpaClosedCompliance(boolean enabled) {
|
||||
this.options.jpaCompliance.setClosedCompliance( enabled );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends SessionFactoryBuilder> T unwrap(Class<T> type) {
|
||||
|
@ -636,6 +662,8 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
|||
|
||||
private Map<String, SQLFunction> sqlFunctions;
|
||||
|
||||
private JpaComplianceImpl jpaCompliance;
|
||||
|
||||
public SessionFactoryOptionsStateStandardImpl(StandardServiceRegistry serviceRegistry) {
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
|
||||
|
@ -855,6 +883,9 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
|||
configurationSettings,
|
||||
false
|
||||
);
|
||||
|
||||
// added the boolean parameter in case we want to define some form of "all" as discussed
|
||||
this.jpaCompliance = new JpaComplianceImpl( configurationSettings, false );
|
||||
}
|
||||
|
||||
private static Interceptor determineInterceptor(Map configurationSettings, StrategySelector strategySelector) {
|
||||
|
@ -996,6 +1027,7 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
|||
return allowOutOfTransactionUpdateOperations;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isReleaseResourcesOnCloseEnabled() {
|
||||
return releaseResourcesOnCloseEnabled;
|
||||
|
@ -1313,6 +1345,11 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
|||
public boolean jdbcStyleParamsZeroBased() {
|
||||
return this.jdbcStyleParamsZeroBased;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JpaCompliance getJpaCompliance() {
|
||||
return jpaCompliance;
|
||||
}
|
||||
}
|
||||
|
||||
private static Supplier<? extends Interceptor> interceptorSupplier(Class<? extends Interceptor> clazz) {
|
||||
|
@ -1354,6 +1391,11 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
|||
return options.releaseResourcesOnCloseEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JpaCompliance getJpaCompliance() {
|
||||
return options.jpaCompliance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getBeanManagerReference() {
|
||||
return options.getBeanManagerReference();
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
|
|||
import org.hibernate.dialect.function.SQLFunction;
|
||||
import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy;
|
||||
import org.hibernate.internal.log.DeprecationLogger;
|
||||
import org.hibernate.jpa.JpaCompliance;
|
||||
import org.hibernate.loader.BatchFetchStyle;
|
||||
import org.hibernate.proxy.EntityNotFoundDelegate;
|
||||
import org.hibernate.query.criteria.LiteralHandlingMode;
|
||||
|
@ -133,6 +134,7 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions {
|
|||
private boolean queryParametersValidationEnabled;
|
||||
private LiteralHandlingMode criteriaLiteralHandlingMode;
|
||||
private boolean jdbcStyleParamsZeroBased;
|
||||
private final JpaCompliance jpaCompliance;
|
||||
|
||||
public SessionFactoryOptionsImpl(SessionFactoryOptionsState state) {
|
||||
this.serviceRegistry = state.getServiceRegistry();
|
||||
|
@ -218,6 +220,8 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions {
|
|||
this.sqlFunctions = state.getCustomSqlFunctionMap();
|
||||
|
||||
this.jdbcTimeZone = state.getJdbcTimeZone();
|
||||
|
||||
this.jpaCompliance = state.getJpaCompliance();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -568,4 +572,9 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions {
|
|||
public boolean jdbcStyleParamsZeroBased() {
|
||||
return jdbcStyleParamsZeroBased;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JpaCompliance getJpaCompliance() {
|
||||
return jpaCompliance;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.hibernate.cfg.BaselineSessionEventsListenerBuilder;
|
|||
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
|
||||
import org.hibernate.dialect.function.SQLFunction;
|
||||
import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy;
|
||||
import org.hibernate.jpa.JpaCompliance;
|
||||
import org.hibernate.loader.BatchFetchStyle;
|
||||
import org.hibernate.proxy.EntityNotFoundDelegate;
|
||||
import org.hibernate.query.criteria.LiteralHandlingMode;
|
||||
|
@ -58,6 +59,8 @@ public interface SessionFactoryOptionsState {
|
|||
|
||||
boolean isReleaseResourcesOnCloseEnabled();
|
||||
|
||||
JpaCompliance getJpaCompliance();
|
||||
|
||||
Object getBeanManagerReference();
|
||||
|
||||
Object getValidatorFactoryReference();
|
||||
|
|
|
@ -389,6 +389,30 @@ public abstract class AbstractDelegatingSessionFactoryBuilder<T extends SessionF
|
|||
return getThis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionFactoryBuilder enableJpaQueryCompliance(boolean enabled) {
|
||||
delegate.enableJpaQueryCompliance( enabled );
|
||||
return getThis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionFactoryBuilder enableJpaTransactionCompliance(boolean enabled) {
|
||||
delegate.enableJpaTransactionCompliance( enabled );
|
||||
return getThis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionFactoryBuilder enableJpaListCompliance(boolean enabled) {
|
||||
delegate.enableJpaListCompliance( enabled );
|
||||
return getThis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionFactoryBuilder enableJpaClosedCompliance(boolean enabled) {
|
||||
delegate.enableJpaClosedCompliance( enabled );
|
||||
return getThis();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <S extends SessionFactoryBuilder> S unwrap(Class<S> type) {
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.hibernate.cfg.BaselineSessionEventsListenerBuilder;
|
|||
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
|
||||
import org.hibernate.dialect.function.SQLFunction;
|
||||
import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy;
|
||||
import org.hibernate.jpa.JpaCompliance;
|
||||
import org.hibernate.loader.BatchFetchStyle;
|
||||
import org.hibernate.proxy.EntityNotFoundDelegate;
|
||||
import org.hibernate.query.criteria.LiteralHandlingMode;
|
||||
|
@ -400,4 +401,9 @@ public class AbstractDelegatingSessionFactoryOptions implements SessionFactoryOp
|
|||
public boolean jdbcStyleParamsZeroBased() {
|
||||
return delegate.jdbcStyleParamsZeroBased();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JpaCompliance getJpaCompliance() {
|
||||
return delegate.getJpaCompliance();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.hibernate.cfg.BaselineSessionEventsListenerBuilder;
|
|||
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
|
||||
import org.hibernate.dialect.function.SQLFunction;
|
||||
import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy;
|
||||
import org.hibernate.jpa.JpaCompliance;
|
||||
import org.hibernate.loader.BatchFetchStyle;
|
||||
import org.hibernate.proxy.EntityNotFoundDelegate;
|
||||
import org.hibernate.query.criteria.LiteralHandlingMode;
|
||||
|
@ -250,4 +251,6 @@ public interface SessionFactoryOptions {
|
|||
}
|
||||
|
||||
boolean jdbcStyleParamsZeroBased();
|
||||
|
||||
JpaCompliance getJpaCompliance();
|
||||
}
|
||||
|
|
|
@ -10,9 +10,11 @@ import java.util.function.Supplier;
|
|||
|
||||
import javax.persistence.GeneratedValue;
|
||||
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.boot.MetadataBuilder;
|
||||
import org.hibernate.boot.registry.classloading.internal.TcclLookupPrecedence;
|
||||
import org.hibernate.internal.log.DeprecationLogger;
|
||||
import org.hibernate.jpa.JpaCompliance;
|
||||
import org.hibernate.query.internal.ParameterMetadataImpl;
|
||||
import org.hibernate.resource.transaction.spi.TransactionCoordinator;
|
||||
import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder;
|
||||
|
@ -1741,4 +1743,51 @@ public interface AvailableSettings {
|
|||
* `hibernate_sequence` name should disable this setting,
|
||||
*/
|
||||
String PREFER_GENERATOR_NAME_AS_DEFAULT_SEQUENCE_NAME = "hibernate.model.generator_name_as_sequence_name";
|
||||
|
||||
/**
|
||||
* Should Hibernate's {@link Transaction} behave as
|
||||
* defined by the spec for JPA's {@link javax.persistence.EntityTransaction}
|
||||
* since it extends the JPA one.
|
||||
*
|
||||
* @see JpaCompliance#isJpaTransactionComplianceEnabled()
|
||||
*/
|
||||
String JPA_TRANSACTION_COMPLIANCE = "hibernate.jpa.compliance.transaction";
|
||||
|
||||
/**
|
||||
* Controls whether Hibernate's handling of {@link javax.persistence.Query}
|
||||
* (JPQL, Criteria and native-query) should strictly follow the JPA spec.
|
||||
* Tis includes both in terms of parsing or translating a query as well
|
||||
* as calls to the {@link javax.persistence.Query} methods throwing spec
|
||||
* defined exceptions where as Hibernate might not.
|
||||
*
|
||||
* Deviations result in an exception if enabled
|
||||
*
|
||||
* @see JpaCompliance#isJpaQueryComplianceEnabled()
|
||||
*/
|
||||
String JPA_QUERY_COMPLIANCE = "hibernate.jpa.compliance.query";
|
||||
|
||||
/**
|
||||
* Controls whether Hibernate should recognize what it considers a "bag"
|
||||
* ({@link org.hibernate.collection.internal.PersistentBag}) as a List
|
||||
* ({@link org.hibernate.collection.internal.PersistentList}) or as a bag.
|
||||
*
|
||||
* If enabled, we will recognize it as a List where {@link @{@link javax.persistence.OrderColumn}}
|
||||
* is just missing (and its defaults will apply).
|
||||
*
|
||||
* @see JpaCompliance#isJpaListComplianceEnabled()
|
||||
*/
|
||||
String JPA_LIST_COMPLIANCE = "hibernate.jpa.compliance.list";
|
||||
|
||||
/**
|
||||
* JPA defines specific exceptions on specific methods when called on
|
||||
* {@link javax.persistence.EntityManager} and {@link javax.persistence.EntityManagerFactory}
|
||||
* when those objects have been closed. This setting controls
|
||||
* whether the spec defined behavior or Hibernate's behavior will be used.
|
||||
*
|
||||
* If enabled Hibernate will operate in the JPA specified way throwing
|
||||
* exceptions when the spec says it should.
|
||||
*
|
||||
* @see JpaCompliance#isJpaClosedComplianceEnabled()
|
||||
*/
|
||||
String JPA_CLOSED_COMPLIANCE = "hibernate.jpa.compliance.closed";
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.hibernate.TransactionException;
|
|||
import org.hibernate.engine.spi.ExceptionConverter;
|
||||
import org.hibernate.engine.transaction.spi.TransactionImplementor;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
import org.hibernate.jpa.JpaCompliance;
|
||||
import org.hibernate.resource.transaction.spi.TransactionCoordinator;
|
||||
import org.hibernate.resource.transaction.spi.TransactionStatus;
|
||||
|
||||
|
@ -29,12 +30,24 @@ public class TransactionImpl implements TransactionImplementor {
|
|||
|
||||
private final TransactionCoordinator transactionCoordinator;
|
||||
private final ExceptionConverter exceptionConverter;
|
||||
private final JpaCompliance jpaCompliance;
|
||||
|
||||
private TransactionDriver transactionDriverControl;
|
||||
|
||||
public TransactionImpl(TransactionCoordinator transactionCoordinator, ExceptionConverter exceptionConverter) {
|
||||
public TransactionImpl(
|
||||
TransactionCoordinator transactionCoordinator,
|
||||
ExceptionConverter exceptionConverter,
|
||||
JpaCompliance jpaCompliance) {
|
||||
this.transactionCoordinator = transactionCoordinator;
|
||||
this.exceptionConverter = exceptionConverter;
|
||||
transactionDriverControl = transactionCoordinator.getTransactionDriverControl();
|
||||
this.jpaCompliance = jpaCompliance;
|
||||
|
||||
this.transactionDriverControl = transactionCoordinator.getTransactionDriverControl();
|
||||
|
||||
LOG.debugf(
|
||||
"On TransactionImpl creation, JpaCompliance#isJpaTransactionComplianceEnabled == %s",
|
||||
jpaCompliance.isJpaTransactionComplianceEnabled()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -82,7 +95,14 @@ public class TransactionImpl implements TransactionImplementor {
|
|||
|
||||
@Override
|
||||
public void rollback() {
|
||||
// todo : may need a "JPA compliant" flag here
|
||||
if ( jpaCompliance.isJpaTransactionComplianceEnabled() ) {
|
||||
if ( !isActive() ) {
|
||||
throw new IllegalStateException(
|
||||
"JPA compliance dictates throwing IllegalStateException when #rollback " +
|
||||
"is called on non-active transaction"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TransactionStatus status = getStatus();
|
||||
if ( status == TransactionStatus.ROLLED_BACK || status == TransactionStatus.NOT_ACTIVE ) {
|
||||
|
@ -140,11 +160,29 @@ public class TransactionImpl implements TransactionImplementor {
|
|||
|
||||
@Override
|
||||
public void setRollbackOnly() {
|
||||
if ( jpaCompliance.isJpaTransactionComplianceEnabled() ) {
|
||||
if ( !isActive() ) {
|
||||
throw new IllegalStateException(
|
||||
"JPA compliance dictates throwing IllegalStateException when #setRollbackOnly " +
|
||||
"is called on non-active transaction"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
internalGetTransactionDriverControl().markRollbackOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getRollbackOnly() {
|
||||
if ( jpaCompliance.isJpaTransactionComplianceEnabled() ) {
|
||||
if ( !isActive() ) {
|
||||
throw new IllegalStateException(
|
||||
"JPA compliance dictates throwing IllegalStateException when #getRollbackOnly " +
|
||||
"is called on non-active transaction"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return getStatus() == TransactionStatus.MARKED_ROLLBACK;
|
||||
}
|
||||
|
||||
|
|
|
@ -374,7 +374,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
|
||||
@Override
|
||||
public Transaction getTransaction() throws HibernateException {
|
||||
if ( getFactory().getSessionFactoryOptions().isJpaBootstrap() ) {
|
||||
if ( getFactory().getSessionFactoryOptions().getJpaCompliance().isJpaTransactionComplianceEnabled() ) {
|
||||
// JPA requires that we throw IllegalStateException if this is called
|
||||
// on a JTA EntityManager
|
||||
if ( getTransactionCoordinator().getTransactionCoordinatorBuilder().isJta() ) {
|
||||
|
@ -383,6 +383,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return accessTransaction();
|
||||
}
|
||||
|
||||
|
@ -391,7 +392,8 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
if ( this.currentHibernateTransaction == null || this.currentHibernateTransaction.getStatus() != TransactionStatus.ACTIVE ) {
|
||||
this.currentHibernateTransaction = new TransactionImpl(
|
||||
getTransactionCoordinator(),
|
||||
getExceptionConverter()
|
||||
getExceptionConverter(),
|
||||
getFactory().getSessionFactoryOptions().getJpaCompliance()
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
@ -110,19 +110,32 @@ public final class ConfigurationHelper {
|
|||
* @return The value.
|
||||
*/
|
||||
public static boolean getBoolean(String name, Map values, boolean defaultValue) {
|
||||
Object value = values.get( name );
|
||||
final Object raw = values.get( name );
|
||||
|
||||
final Boolean value = toBoolean( raw, defaultValue );
|
||||
if ( value == null ) {
|
||||
throw new ConfigurationException(
|
||||
"Could not determine how to handle configuration raw [name=" + name + ", value=" + raw + "] as boolean"
|
||||
);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static Boolean toBoolean(Object value, boolean defaultValue) {
|
||||
if ( value == null ) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if ( Boolean.class.isInstance( value ) ) {
|
||||
return ( (Boolean) value ).booleanValue();
|
||||
return (Boolean) value;
|
||||
}
|
||||
|
||||
if ( String.class.isInstance( value ) ) {
|
||||
return Boolean.parseBoolean( (String) value );
|
||||
}
|
||||
throw new ConfigurationException(
|
||||
"Could not determine how to handle configuration value [name=" + name + ", value=" + value + "] as boolean"
|
||||
);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import org.hibernate.Transaction;
|
||||
|
||||
/**
|
||||
* Encapsulates settings controlling whether certain aspects of the JPA spec
|
||||
* should be strictly followed.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface JpaCompliance {
|
||||
/**
|
||||
* Controls whether Hibernate's handling of JPA's
|
||||
* {@link javax.persistence.Query} (JPQL, Criteria and native-query) should
|
||||
* strictly follow the JPA spec. This includes both in terms of parsing or
|
||||
* translating a query as well as calls to the {@link javax.persistence.Query}
|
||||
* methods throwing spec defined exceptions where as Hibernate might not.
|
||||
*
|
||||
* Deviations result in an exception if enabled
|
||||
*
|
||||
* @return {@code true} indicates to behave in the spec-defined way
|
||||
*/
|
||||
boolean isJpaQueryComplianceEnabled();
|
||||
|
||||
/**
|
||||
* Indicates that Hibernate's {@link Transaction} should behave as
|
||||
* defined by the spec for JPA's {@link javax.persistence.EntityTransaction}
|
||||
* since it extends the JPA one.
|
||||
*
|
||||
* @return {@code true} indicates to behave in the spec-defined way
|
||||
*/
|
||||
boolean isJpaTransactionComplianceEnabled();
|
||||
|
||||
/**
|
||||
* Controls how Hibernate interprets a mapped List without an "order columns"
|
||||
* specified. Historically Hibernate defines this as a "bag", which is a concept
|
||||
* JPA does not have.
|
||||
*
|
||||
* If enabled, Hibernate will recognize this condition as defining
|
||||
* a {@link org.hibernate.collection.internal.PersistentList}, otherwise
|
||||
* Hibernate will treat is as a {@link org.hibernate.collection.internal.PersistentBag}
|
||||
*
|
||||
* @return {@code true} indicates to behave in the spec-defined way, interpreting the
|
||||
* mapping as a "list", rather than a "bag"
|
||||
*/
|
||||
boolean isJpaListComplianceEnabled();
|
||||
|
||||
/**
|
||||
*JPA defines specific exceptions on specific methods when called on
|
||||
* {@link javax.persistence.EntityManager} and {@link javax.persistence.EntityManagerFactory}
|
||||
* when those objects have been closed. This setting controls
|
||||
* whether the spec defined behavior or Hibernate's behavior will be used.
|
||||
*
|
||||
* If enabled Hibernate will operate in the JPA specified way throwing
|
||||
* exceptions when the spec says it should with regard to close checking
|
||||
*
|
||||
* @return {@code true} indicates to behave in the spec-defined way
|
||||
*/
|
||||
boolean isJpaClosedComplianceEnabled();
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* 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.spi;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.hibernate.jpa.JpaCompliance;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class JpaComplianceImpl implements JpaCompliance {
|
||||
private boolean queryCompliance;
|
||||
private boolean transactionCompliance;
|
||||
private boolean listCompliance;
|
||||
private boolean closedCompliance;
|
||||
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public JpaComplianceImpl(Map configurationSettings, boolean jpaByDefault) {
|
||||
final Object legacyQueryCompliance = configurationSettings.get( AvailableSettings.JPAQL_STRICT_COMPLIANCE );
|
||||
|
||||
queryCompliance = ConfigurationHelper.getBoolean(
|
||||
AvailableSettings.JPA_QUERY_COMPLIANCE,
|
||||
configurationSettings,
|
||||
legacyQueryCompliance == null ? jpaByDefault : ConfigurationHelper.toBoolean( legacyQueryCompliance, jpaByDefault )
|
||||
);
|
||||
transactionCompliance = ConfigurationHelper.getBoolean(
|
||||
AvailableSettings.JPA_TRANSACTION_COMPLIANCE,
|
||||
configurationSettings,
|
||||
jpaByDefault
|
||||
);
|
||||
listCompliance = ConfigurationHelper.getBoolean(
|
||||
AvailableSettings.JPA_LIST_COMPLIANCE,
|
||||
configurationSettings,
|
||||
jpaByDefault
|
||||
);
|
||||
closedCompliance = ConfigurationHelper.getBoolean(
|
||||
AvailableSettings.JPA_CLOSED_COMPLIANCE,
|
||||
configurationSettings,
|
||||
jpaByDefault
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJpaQueryComplianceEnabled() {
|
||||
return queryCompliance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJpaTransactionComplianceEnabled() {
|
||||
return transactionCompliance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJpaListComplianceEnabled() {
|
||||
return listCompliance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJpaClosedComplianceEnabled() {
|
||||
return closedCompliance;
|
||||
}
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Mutators
|
||||
|
||||
public void setQueryCompliance(boolean queryCompliance) {
|
||||
this.queryCompliance = queryCompliance;
|
||||
}
|
||||
|
||||
public void setTransactionCompliance(boolean transactionCompliance) {
|
||||
this.transactionCompliance = transactionCompliance;
|
||||
}
|
||||
|
||||
public void setListCompliance(boolean listCompliance) {
|
||||
this.listCompliance = listCompliance;
|
||||
}
|
||||
|
||||
public void setClosedCompliance(boolean closedCompliance) {
|
||||
this.closedCompliance = closedCompliance;
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@ public interface TransactionCoordinatorBuilder extends Service {
|
|||
/**
|
||||
* Access to options to are specific to each TransactionCoordinator instance
|
||||
*/
|
||||
static interface Options {
|
||||
interface Options {
|
||||
/**
|
||||
* Indicates whether an active transaction should be automatically joined. Only relevant
|
||||
* for JTA-based TransactionCoordinator instances.
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class JpaComplianceTestingImpl implements JpaCompliance {
|
||||
public static JpaCompliance normal() {
|
||||
return new JpaComplianceTestingImpl();
|
||||
}
|
||||
|
||||
public static JpaCompliance withTransactionCompliance() {
|
||||
final JpaComplianceTestingImpl compliance = new JpaComplianceTestingImpl();
|
||||
compliance.transactionCompliance = true;
|
||||
return compliance;
|
||||
}
|
||||
|
||||
public static JpaCompliance withQueryCompliance() {
|
||||
final JpaComplianceTestingImpl compliance = new JpaComplianceTestingImpl();
|
||||
compliance.queryCompliance = true;
|
||||
return compliance;
|
||||
}
|
||||
|
||||
public static JpaCompliance withListCompliance() {
|
||||
final JpaComplianceTestingImpl compliance = new JpaComplianceTestingImpl();
|
||||
compliance.listCompliance = true;
|
||||
return compliance;
|
||||
}
|
||||
|
||||
public static JpaCompliance withClosedCompliance() {
|
||||
final JpaComplianceTestingImpl compliance = new JpaComplianceTestingImpl();
|
||||
compliance.closedCompliance = true;
|
||||
return compliance;
|
||||
}
|
||||
|
||||
private boolean queryCompliance;
|
||||
private boolean transactionCompliance;
|
||||
private boolean listCompliance;
|
||||
private boolean closedCompliance;
|
||||
|
||||
@Override
|
||||
public boolean isJpaQueryComplianceEnabled() {
|
||||
return queryCompliance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJpaTransactionComplianceEnabled() {
|
||||
return transactionCompliance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJpaListComplianceEnabled() {
|
||||
return listCompliance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJpaClosedComplianceEnabled() {
|
||||
return closedCompliance;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* 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.test.jpa.compliance.tck2_2;
|
||||
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil2.inSession;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class EntityTransactionTests extends BaseUnitTestCase {
|
||||
|
||||
@Test
|
||||
public void testGetRollbackOnlyExpectations() {
|
||||
final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder()
|
||||
.applySetting( AvailableSettings.JPA_TRANSACTION_COMPLIANCE, "true" )
|
||||
.build();
|
||||
|
||||
try {
|
||||
final SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) new MetadataSources( ssr )
|
||||
.buildMetadata()
|
||||
.buildSessionFactory();
|
||||
|
||||
try {
|
||||
inSession(
|
||||
sessionFactory,
|
||||
session -> {
|
||||
final Transaction transaction = session.getTransaction();
|
||||
assertFalse( transaction.isActive() );
|
||||
try {
|
||||
transaction.getRollbackOnly();
|
||||
fail( "Expecting failure #getRollbackOnly on non-active txn" );
|
||||
}
|
||||
catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
finally {
|
||||
sessionFactory.close();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
StandardServiceRegistryBuilder.destroy( ssr );
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetRollbackOnlyExpectations() {
|
||||
final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder()
|
||||
.applySetting( AvailableSettings.JPA_TRANSACTION_COMPLIANCE, "true" )
|
||||
.build();
|
||||
|
||||
try {
|
||||
final SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) new MetadataSources( ssr )
|
||||
.buildMetadata()
|
||||
.buildSessionFactory();
|
||||
|
||||
try {
|
||||
inSession(
|
||||
sessionFactory,
|
||||
session -> {
|
||||
final Transaction transaction = session.getTransaction();
|
||||
assertFalse( transaction.isActive() );
|
||||
try {
|
||||
transaction.setRollbackOnly();
|
||||
fail( "Expecting failure #setRollbackOnly on non-active txn" );
|
||||
}
|
||||
catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
finally {
|
||||
sessionFactory.close();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
StandardServiceRegistryBuilder.destroy( ssr );
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRollbackExpectations() {
|
||||
final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder()
|
||||
.applySetting( AvailableSettings.JPA_TRANSACTION_COMPLIANCE, "true" )
|
||||
.build();
|
||||
|
||||
try {
|
||||
final SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) new MetadataSources( ssr )
|
||||
.buildMetadata()
|
||||
.buildSessionFactory();
|
||||
|
||||
try {
|
||||
inSession(
|
||||
sessionFactory,
|
||||
session -> {
|
||||
final Transaction transaction = session.getTransaction();
|
||||
assertFalse( transaction.isActive() );
|
||||
try {
|
||||
transaction.rollback();
|
||||
fail( "Expecting failure #rollback on non-active txn" );
|
||||
}
|
||||
catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
finally {
|
||||
sessionFactory.close();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
StandardServiceRegistryBuilder.destroy( ssr );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,7 +9,6 @@ package org.hibernate.test.resource.transaction.jdbc;
|
|||
import org.hibernate.TransactionException;
|
||||
import org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorBuilderImpl;
|
||||
import org.hibernate.resource.transaction.spi.TransactionCoordinator;
|
||||
import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder;
|
||||
import org.hibernate.resource.transaction.spi.TransactionStatus;
|
||||
|
||||
import org.hibernate.test.resource.common.SynchronizationCollectorImpl;
|
||||
|
@ -31,12 +30,7 @@ public class BasicJdbcTransactionTests {
|
|||
|
||||
final TransactionCoordinator transactionCoordinator = transactionCoordinatorBuilder.buildTransactionCoordinator(
|
||||
owner,
|
||||
new TransactionCoordinatorBuilder.Options() {
|
||||
@Override
|
||||
public boolean shouldAutoJoinTransaction() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
() -> false
|
||||
);
|
||||
|
||||
SynchronizationCollectorImpl sync = new SynchronizationCollectorImpl();
|
||||
|
@ -63,12 +57,7 @@ public class BasicJdbcTransactionTests {
|
|||
|
||||
final TransactionCoordinator transactionCoordinator = transactionCoordinatorBuilder.buildTransactionCoordinator(
|
||||
owner,
|
||||
new TransactionCoordinatorBuilder.Options() {
|
||||
@Override
|
||||
public boolean shouldAutoJoinTransaction() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
() -> false
|
||||
);
|
||||
|
||||
assertEquals( TransactionStatus.NOT_ACTIVE, transactionCoordinator.getTransactionDriverControl().getStatus() );
|
||||
|
@ -98,12 +87,7 @@ public class BasicJdbcTransactionTests {
|
|||
|
||||
final TransactionCoordinator transactionCoordinator = transactionCoordinatorBuilder.buildTransactionCoordinator(
|
||||
owner,
|
||||
new TransactionCoordinatorBuilder.Options() {
|
||||
@Override
|
||||
public boolean shouldAutoJoinTransaction() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
() -> false
|
||||
);
|
||||
|
||||
assertEquals( TransactionStatus.NOT_ACTIVE, transactionCoordinator.getTransactionDriverControl().getStatus() );
|
||||
|
|
|
@ -60,11 +60,6 @@ import org.junit.After;
|
|||
import org.junit.Test;
|
||||
import junit.framework.AssertionFailedError;
|
||||
|
||||
import org.infinispan.Cache;
|
||||
import org.infinispan.test.TestingUtil;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
@ -339,7 +334,10 @@ public abstract class AbstractRegionAccessStrategyTest<R extends BaseRegion, S e
|
|||
.buildTransactionCoordinator(txOwner, null);
|
||||
when(session.getTransactionCoordinator()).thenReturn(txCoord);
|
||||
when(session.beginTransaction()).then(invocation -> {
|
||||
Transaction tx = new TransactionImpl(txCoord, session.getExceptionConverter());
|
||||
Transaction tx = new TransactionImpl(
|
||||
txCoord,
|
||||
session.getExceptionConverter(),
|
||||
session.getFactory().getSessionFactoryOptions().getJpaCompliance() );
|
||||
tx.begin();
|
||||
return tx;
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue