diff --git a/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc b/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc index a92eb3d1e4..7ce3381bb6 100644 --- a/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc +++ b/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc @@ -772,5 +772,7 @@ false:: does not allow |`hibernate.collection_join_subquery`| `true` (default value) or `false` | Setting which indicates whether or not the new JOINS over collection tables should be rewritten to subqueries. +|`hibernate.allow_refresh_detached_entity`| `true` (default value when using Hibernate native bootstrapping) or `false` (default value when using JPA bootstrapping) | Setting that allows to call `javax.persistence.EntityManager#refresh()` or `org.hibernate.Session#refresh()` on a detached instance even when the `org.hibernate.Session` is obtained from a JPA `javax.persistence.EntityManager`. + |===================================================================================================================================================================================================================================================== diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/PersistenceContext.adoc b/documentation/src/main/asciidoc/userguide/chapters/pc/PersistenceContext.adoc index 8a51cde14d..ff6c7a1bbc 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/PersistenceContext.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/pc/PersistenceContext.adoc @@ -285,6 +285,21 @@ However, please note that Hibernate has the capability to handle this automatica See the discussion of non-identifier <>. ==== +[IMPORTANT] +==== +Traditionally, Hibernate has been allowing detached entities to be refreshed. +Unfortunately, JPA prohibits this practice and specifies that an `IllegalArgumentException` should be thrown instead. + +For this reason, when bootstrapping the Hibernate `SessionFactory` using the native API, the legacy detached entity refresh behavior is going to be preserved. +On the other hand, when bootstrapping Hibernate through JPA `EntityManagerFactory` building process, detached entities are not allowed to be refreshed by default. + +However, this default behavior can be overwritten through the `hibernate.allow_refresh_detached_entity` configuration property. +If this property is explicitly set to `true`, then you can refresh detached entities even when using the JPA bootstraps mechanism, therefore bypassing the JPA specification restriction. + +For more about the `hibernate.allow_refresh_detached_entity` configuration property, +check out the <> section as well. +==== + [[pc-detach]] === Working with detached data diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryBuilderImpl.java index 5290597373..b4c02b0649 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryBuilderImpl.java @@ -450,6 +450,11 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement this.options.jpaBootstrap = true; } + @Override + public void disableRefreshDetachedEntity() { + this.options.allowRefreshDetachedEntity = false; + } + @Override public void disableJtaTransactionAccess() { this.options.jtaTransactionAccessEnabled = false; @@ -482,6 +487,7 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement private boolean jtaTransactionAccessEnabled; private boolean allowOutOfTransactionUpdateOperations; private boolean releaseResourcesOnCloseEnabled; + private boolean allowRefreshDetachedEntity; // (JTA) transaction handling private boolean jtaTrackByThread; @@ -581,6 +587,12 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement true ); + this.allowRefreshDetachedEntity = cfgService.getSetting( + ALLOW_REFRESH_DETACHED_ENTITY, + BOOLEAN, + true + ); + this.flushBeforeCompletionEnabled = cfgService.getSetting( FLUSH_BEFORE_COMPLETION, BOOLEAN, true ); this.autoCloseSessionEnabled = cfgService.getSetting( AUTO_CLOSE_SESSION, BOOLEAN, false ); @@ -871,6 +883,10 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement return jtaTransactionAccessEnabled; } + public boolean isAllowRefreshDetachedEntity() { + return allowRefreshDetachedEntity; + } + public boolean isAllowOutOfTransactionUpdateOperations() { return allowOutOfTransactionUpdateOperations; } @@ -1181,6 +1197,10 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement return options.isJtaTransactionAccessEnabled(); } + public boolean isAllowRefreshDetachedEntity() { + return options.isAllowRefreshDetachedEntity(); + } + public boolean isAllowOutOfTransactionUpdateOperations() { return options.isAllowOutOfTransactionUpdateOperations(); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsImpl.java index 40090b6ecf..0ea8db51df 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsImpl.java @@ -53,6 +53,7 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions { private final boolean flushBeforeCompletionEnabled; private final boolean autoCloseSessionEnabled; private boolean jtaTransactionAccessEnabled; + private boolean allowRefreshDetachedEntity; private boolean allowOutOfTransactionUpdateOperations; private boolean releaseResourcesOnCloseEnabled; @@ -132,6 +133,7 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions { this.jpaBootstrap = state.isJpaBootstrap(); this.jtaTransactionAccessEnabled = state.isJtaTransactionAccessEnabled(); + this.allowRefreshDetachedEntity = state.isAllowRefreshDetachedEntity(); this.allowOutOfTransactionUpdateOperations = state.isAllowOutOfTransactionUpdateOperations(); this.sessionFactoryName = state.getSessionFactoryName(); this.sessionFactoryNameAlsoJndiName = state.isSessionFactoryNameAlsoJndiName(); @@ -215,6 +217,11 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions { return jtaTransactionAccessEnabled; } + @Override + public boolean isAllowRefreshDetachedEntity() { + return allowRefreshDetachedEntity; + } + @Override public Object getBeanManagerReference() { return beanManagerReference; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsState.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsState.java index 5a935d3457..a1f3d1da23 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsState.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsState.java @@ -49,6 +49,8 @@ public interface SessionFactoryOptionsState { boolean isJtaTransactionAccessEnabled(); + boolean isAllowRefreshDetachedEntity(); + boolean isAllowOutOfTransactionUpdateOperations(); boolean isReleaseResourcesOnCloseEnabled(); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java index b11972146f..552383b730 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java @@ -59,6 +59,11 @@ public class AbstractDelegatingSessionFactoryOptions implements SessionFactoryOp return delegate.isJtaTransactionAccessEnabled(); } + @Override + public boolean isAllowRefreshDetachedEntity() { + return delegate.isAllowRefreshDetachedEntity(); + } + @Override public Object getBeanManagerReference() { return delegate.getBeanManagerReference(); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryBuilderImplementor.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryBuilderImplementor.java index d4c93a2ae4..ba9f8c920f 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryBuilderImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryBuilderImplementor.java @@ -30,6 +30,9 @@ public interface SessionFactoryBuilderImplementor extends SessionFactoryBuilder void disableJtaTransactionAccess(); + default void disableRefreshDetachedEntity() { + } + /** * Build the SessionFactoryOptions that will ultimately be passed to SessionFactoryImpl constructor. * 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 d5d648fe7d..72ba981aa9 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 @@ -61,6 +61,10 @@ public interface SessionFactoryOptions { boolean isJtaTransactionAccessEnabled(); + default boolean isAllowRefreshDetachedEntity() { + return false; + } + /** * The name to be used for the SessionFactory. This is use both in: