From bf2bc323f67214c629d5bc7c07c4c9bb03d4593d Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Tue, 25 Oct 2016 18:37:11 +0100 Subject: [PATCH] HHH-11188 - SessionImpl.refresh() throws IllegalArgumentException, 'Entity not managed' for detached instances when JPA bootstrapped --- .../userguide/appendices/Configurations.adoc | 2 + .../chapters/pc/PersistenceContext.adoc | 15 +++++ .../internal/SessionFactoryBuilderImpl.java | 20 +++++++ .../internal/SessionFactoryOptionsImpl.java | 7 +++ .../internal/SessionFactoryOptionsState.java | 2 + ...stractDelegatingSessionFactoryOptions.java | 5 ++ .../spi/SessionFactoryBuilderImplementor.java | 3 + .../boot/spi/SessionFactoryOptions.java | 4 ++ .../org/hibernate/cfg/AvailableSettings.java | 14 +++++ .../org/hibernate/internal/SessionImpl.java | 3 +- .../EntityManagerFactoryBuilderImpl.java | 6 +- ...reshDetachedInstanceWhenIsAllowedTest.java | 59 +++++++++++++++++++ ...hDetachedInstanceWhenIsNotAllowedTest.java | 50 ++++++++++++++++ .../jpa/test/refresh/TestEntity.java | 21 +++++++ ...reshDetachedInstanceWhenIsAllowedTest.java | 44 ++++++++++++++ ...hDetachedInstanceWhenIsNotAllowedTest.java | 49 +++++++++++++++ .../hibernate/test/refresh/TestEntity.java | 21 +++++++ 17 files changed, 323 insertions(+), 2 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/jpa/test/refresh/RefreshDetachedInstanceWhenIsAllowedTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/jpa/test/refresh/RefreshDetachedInstanceWhenIsNotAllowedTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/jpa/test/refresh/TestEntity.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/refresh/RefreshDetachedInstanceWhenIsAllowedTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/refresh/RefreshDetachedInstanceWhenIsNotAllowedTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/refresh/TestEntity.java 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:
    *
  • in-VM serialization
  • diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java index fcb87fa2e0..4a1577c807 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java @@ -1558,4 +1558,18 @@ public interface AvailableSettings { * @since 5.2 */ String COLLECTION_JOIN_SUBQUERY = "hibernate.collection_join_subquery"; + + /** + * Setting that allows to call {@link javax.persistence.EntityManager#refresh(Object)} * + * (or {@link org.hibernate.Session#refresh(Object)} on a detached entity instance when the {@link org.hibernate.Session} is obtained from + * a JPA {@link javax.persistence.EntityManager}). + *

    + *

    + * Values are {@code true} permits the refresh, {@code false} does not permit the detached instance refresh and an {@link IllegalArgumentException} is thrown. + *

    + * The default value is {@code false} when the Session is bootstrapped via JPA {@link javax.persistence.EntityManagerFactory}, otherwise is {@code true} + * + * @since 5.2 + */ + String ALLOW_REFRESH_DETACHED_ENTITY = "hibernate.allow_refresh_detached_entity"; } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java index 41870b7267..359421f58d 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -73,6 +73,7 @@ import org.hibernate.TypeHelper; import org.hibernate.TypeMismatchException; import org.hibernate.UnknownProfileException; import org.hibernate.UnresolvableObjectException; +import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.criterion.NaturalIdentifier; import org.hibernate.engine.internal.StatefulPersistenceContext; @@ -1264,7 +1265,7 @@ public final class SessionImpl private void fireRefresh(RefreshEvent event) { try { - if ( getSessionFactory().getSessionFactoryOptions().isJpaBootstrap() ) { + if ( !getSessionFactory().getSessionFactoryOptions().isAllowRefreshDetachedEntity() ) { if ( !contains( event.getObject() ) ) { throw new IllegalArgumentException( "Entity not managed" ); } diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java index 32a3aef5d0..fd37e2d037 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java @@ -103,7 +103,6 @@ import static org.hibernate.internal.HEMLogging.messageLogger; import static org.hibernate.jpa.AvailableSettings.CFG_FILE; import static org.hibernate.jpa.AvailableSettings.CLASS_CACHE_PREFIX; import static org.hibernate.jpa.AvailableSettings.COLLECTION_CACHE_PREFIX; -import static org.hibernate.jpa.AvailableSettings.DISCARD_PC_ON_CLOSE; import static org.hibernate.jpa.AvailableSettings.PERSISTENCE_UNIT_NAME; /** @@ -901,6 +900,11 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil ( ( SessionFactoryBuilderImplementor ) sfBuilder ).disableJtaTransactionAccess(); } + final boolean allowRefreshDetachedEntity = readBooleanConfigurationValue( org.hibernate.cfg.AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY ); + if ( !allowRefreshDetachedEntity ) { + ( (SessionFactoryBuilderImplementor) sfBuilder ).disableRefreshDetachedEntity(); + } + // Locate and apply any requested SessionFactoryObserver final Object sessionFactoryObserverSetting = configurationValues.remove( AvailableSettings.SESSION_FACTORY_OBSERVER ); if ( sessionFactoryObserverSetting != null ) { diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/refresh/RefreshDetachedInstanceWhenIsAllowedTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/refresh/RefreshDetachedInstanceWhenIsAllowedTest.java new file mode 100644 index 0000000000..9317ae2b4b --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/refresh/RefreshDetachedInstanceWhenIsAllowedTest.java @@ -0,0 +1,59 @@ +/* + * 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 . + */ +package org.hibernate.jpa.test.refresh; + +import java.util.Map; +import javax.persistence.EntityManager; + +import org.hibernate.Session; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +import org.hibernate.testing.TestForIssue; +import org.junit.Before; +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; + +/** + * @author Andrea Boriero + */ +@TestForIssue(jiraKey = "HHH-11188") +public class RefreshDetachedInstanceWhenIsAllowedTest extends BaseEntityManagerFunctionalTestCase { + private TestEntity testEntity; + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] {TestEntity.class}; + } + + @Override + protected void addConfigOptions(Map options) { + options.put( AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, "true" ); + } + + @Before + public void setUp() { + testEntity = new TestEntity(); + doInJPA( this::entityManagerFactory, entityManager -> { + entityManager.persist( testEntity ); + } ); + } + + @Test + public void testUnwrappedSessionRefreshDetachedInstance() { + final EntityManager entityManager = createEntityManager(); + final Session session = entityManager.unwrap( Session.class ); + session.refresh( testEntity ); + } + + @Test + public void testRefreshDetachedInstance() { + final EntityManager entityManager = createEntityManager(); + entityManager.refresh( testEntity ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/refresh/RefreshDetachedInstanceWhenIsNotAllowedTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/refresh/RefreshDetachedInstanceWhenIsNotAllowedTest.java new file mode 100644 index 0000000000..efc5c447a0 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/refresh/RefreshDetachedInstanceWhenIsNotAllowedTest.java @@ -0,0 +1,50 @@ +/* + * 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 . + */ +package org.hibernate.jpa.test.refresh; + +import javax.persistence.EntityManager; + +import org.hibernate.Session; +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +import org.junit.Before; +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; + +/** + * @author Andrea Boriero + */ +public class RefreshDetachedInstanceWhenIsNotAllowedTest extends BaseEntityManagerFunctionalTestCase { + private TestEntity testEntity; + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] {TestEntity.class}; + } + + @Before + public void setUp() { + testEntity = new TestEntity(); + doInJPA( this::entityManagerFactory, entityManager -> { + entityManager.persist( testEntity ); + } ); + } + + @Test(expected = IllegalArgumentException.class) + public void testUnwrappedSessionRefreshDetachedInstance() { + final EntityManager entityManager = createEntityManager(); + final Session session = entityManager.unwrap( Session.class ); + session.refresh( testEntity ); + } + + @Test(expected = IllegalArgumentException.class) + public void testRefreshDetachedInstance() { + final EntityManager entityManager = createEntityManager(); + entityManager.refresh( testEntity ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/refresh/TestEntity.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/refresh/TestEntity.java new file mode 100644 index 0000000000..ab98854f36 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/refresh/TestEntity.java @@ -0,0 +1,21 @@ +/* + * 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 . + */ +package org.hibernate.jpa.test.refresh; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +/** + * @author Andrea Boriero + */ +@Entity +public class TestEntity { + @Id + @GeneratedValue + public long id; +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/refresh/RefreshDetachedInstanceWhenIsAllowedTest.java b/hibernate-core/src/test/java/org/hibernate/test/refresh/RefreshDetachedInstanceWhenIsAllowedTest.java new file mode 100644 index 0000000000..600820c179 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/refresh/RefreshDetachedInstanceWhenIsAllowedTest.java @@ -0,0 +1,44 @@ +/* + * 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 . + */ +package org.hibernate.test.refresh; + +import org.hibernate.Session; +import org.hibernate.jpa.test.refresh.TestEntity; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Before; +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; + +/** + * @author Andrea Boriero + */ +@TestForIssue(jiraKey = "HHH-11188") +public class RefreshDetachedInstanceWhenIsAllowedTest extends BaseCoreFunctionalTestCase { + private TestEntity testEntity; + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] {TestEntity.class}; + } + + @Before + public void setUp() { + testEntity = new TestEntity(); + doInHibernate( this::sessionFactory, session -> { + session.save( testEntity ); + } ); + } + + @Test + public void testRefreshDetachedInstance() { + final Session session = openSession(); + session.refresh( testEntity ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/refresh/RefreshDetachedInstanceWhenIsNotAllowedTest.java b/hibernate-core/src/test/java/org/hibernate/test/refresh/RefreshDetachedInstanceWhenIsNotAllowedTest.java new file mode 100644 index 0000000000..35ad7d5f42 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/refresh/RefreshDetachedInstanceWhenIsNotAllowedTest.java @@ -0,0 +1,49 @@ +/* + * 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 . + */ +package org.hibernate.test.refresh; + +import org.hibernate.Session; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Configuration; +import org.hibernate.jpa.test.refresh.TestEntity; + +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Before; +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; + +/** + * @author Andrea Boriero + */ +public class RefreshDetachedInstanceWhenIsNotAllowedTest extends BaseCoreFunctionalTestCase { + private TestEntity testEntity; + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] {TestEntity.class}; + } + + @Override + protected void configure(Configuration configuration) { + configuration.setProperty( AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, "false" ); + } + + @Before + public void setUp() { + testEntity = new TestEntity(); + doInHibernate( this::sessionFactory, session -> { + session.save( testEntity ); + } ); + } + + @Test(expected = IllegalArgumentException.class) + public void testRefreshDetachedInstance() { + final Session session = openSession(); + session.refresh( testEntity ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/refresh/TestEntity.java b/hibernate-core/src/test/java/org/hibernate/test/refresh/TestEntity.java new file mode 100644 index 0000000000..9f87667775 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/refresh/TestEntity.java @@ -0,0 +1,21 @@ +/* + * 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 . + */ +package org.hibernate.test.refresh; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +/** + * @author Andrea Boriero + */ +@Entity +public class TestEntity { + @Id + @GeneratedValue + public long id; +}