diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/conf/Compatibility.java b/openjpa-kernel/src/main/java/org/apache/openjpa/conf/Compatibility.java index 7896fdd39..fbff958b8 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/conf/Compatibility.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/conf/Compatibility.java @@ -66,6 +66,7 @@ public class Compatibility { private boolean _isNonDefaultMappingAllowed = false; private boolean _reorderMetaDataResolution = true; private boolean _reloadOnDetach = false; + private boolean _ignoreDetachedStateFieldForProxySerialization = false; /** * Whether to require exact identity value types when creating object @@ -295,6 +296,39 @@ public class Compatibility { return _flushBeforeDetach; } + /** + * Whether OpenJPA should ignore the DetachedStateField value when + * determining if our Proxy classes should be removed during serialization. + *

Starting with version 2.0.0, when the DetachedStateFiled==true, the + * build time $proxy classes will not be removed. + *

Prior to version 2.0.0, the DetachedStateFiled was not used and + * the $proxy classes were not being removed during serialization after + * the Persistence context was cleared. + * + * @param ignoreDSF if true the old Proxy serialization behavior will be used. + * + * @since 2.0.0 + */ + public void setIgnoreDetachedStateFieldForProxySerialization(boolean ignoreDSF) { + _ignoreDetachedStateFieldForProxySerialization = ignoreDSF; + } + + /** + * Whether OpenJPA should ignore the DetachedStateField value when + * determining if our Proxy classes should be removed during serialization. + *

Starting with version 2.0.0, when the DetachedStateFiled==true, the + * build time $proxy classes will not be removed. + *

Prior to version 2.0.0, the DetachedStateFiled was not used and + * the $proxy classes were not being removed during serialization after + * the Persistence context was cleared. + * + * @since 2.0.0 + * @return true if the old Proxy serialization will be used, otherwise false. + */ + public boolean getIgnoreDetachedStateFieldForProxySerialization() { + return _ignoreDetachedStateFieldForProxySerialization; + } + /** * Whether OpenJPA should flush changes before detaching or serializing an * entity. In JPA this is usually false, but other persistence frameworks diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachManager.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachManager.java index b309ab908..33c6761e3 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachManager.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachManager.java @@ -708,10 +708,8 @@ public class DetachManager * Set the owner of the field's proxy to the detached state manager. */ private Object reproxy(Object obj, int field) { - if (obj != null && _detSM != null && obj instanceof Proxy) { + if (obj != null && _detSM != null && obj instanceof Proxy) ((Proxy) obj).setOwner(_detSM, field); - return ((Proxy) obj).copy(obj); - } return obj; } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateManager.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateManager.java index b8f48a1ee..1c58524f3 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateManager.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateManager.java @@ -25,6 +25,7 @@ import java.util.BitSet; import java.util.Collection; import java.util.Map; +import org.apache.openjpa.conf.Compatibility; import org.apache.openjpa.enhance.PersistenceCapable; import org.apache.openjpa.enhance.StateManager; import org.apache.openjpa.lib.util.Localizer; @@ -62,6 +63,7 @@ public class DetachedStateManager private final Object _oid; private final Object _version; private final ReentrantLock _lock; + private final boolean _useDSFForUnproxy; // old releases will default to FALSE, which is the old behavior /** * Constructor. @@ -89,6 +91,14 @@ public class DetachedStateManager _lock = new ReentrantLock(); else _lock = null; + if (sm.getContext() != null && sm.getContext().getConfiguration() != null) { + Compatibility compat = sm.getContext().getConfiguration().getCompatibilityInstance(); + if (compat != null && !compat.getIgnoreDetachedStateFieldForProxySerialization()) + _useDSFForUnproxy = true; // new 2.0 behavior + else + _useDSFForUnproxy = false; + } else + _useDSFForUnproxy = false; } ///////////////////////////////// @@ -731,6 +741,15 @@ public class DetachedStateManager return _dirty; } + /** + * Should DetachedStateField be used by Proxies to determine when to remove + * $proxy wrappers during serialization. + * @since 2.0.0 + */ + public boolean getUseDSFForUnproxy() { + return _useDSFForUnproxy; + } + public BitSet getFlushed() { throw new UnsupportedOperationException(); } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/util/Proxies.java b/openjpa-kernel/src/main/java/org/apache/openjpa/util/Proxies.java index 70f020a9f..ca944ae78 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/util/Proxies.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/util/Proxies.java @@ -20,6 +20,8 @@ package org.apache.openjpa.util; import java.security.AccessController; +import org.apache.openjpa.conf.Compatibility; +import org.apache.openjpa.kernel.DetachedStateManager; import org.apache.openjpa.kernel.OpenJPAStateManager; import org.apache.openjpa.lib.util.J2DoPrivHelper; import org.apache.openjpa.lib.util.Localizer; @@ -85,10 +87,18 @@ public class Proxies { * 1) No Proxy, then return as-is * 2) Runtime created proxy (!detachable), then unproxy * 3) No StateManager (DetachedStateField==false), then return as-is - * 4) If detached, then unproxy - * 5) If ClassMetaData exists and DetachedStateField != TRUE - * (default of DetachedStateField==transient), then unproxy - * 6) Else, return as-is + * Get the new IgnoreDetachedStateFieldForProxySerialization + * Compatibility flag from either the metadata/configuration if + * this is a normal StateManager, otherwise use the new flag + * added to the DetachedStateManager + * 4) If new 2.0 behavior + * 4a) If ClassMetaData exists and DetachedStateField == TRUE + * then do not remove the proxy and return as-is + * 4b) Else, using DetachedStateField of transient(default) or + * false, so unproxy + * 5) If 1.0 app or requested old 1.0 behavior + * 5a) If detached, then do not unproxy and return as-is + * 5b) Else, unproxy * * Original code - * 1) Runtime created proxy (!detachable), then unproxy @@ -111,19 +121,47 @@ public class Proxies { } else if (proxy.getOwner() == null) { // no StateManager (DetachedStateField==false), so no $proxy to remove return proxy; - } else if (proxy.getOwner().isDetached()) { - // already detached, so remove any $proxy - return proxy.copy(proxy); } else { // using a StateManager, so determine what DetachedState is being used - OpenJPAStateManager sm = proxy.getOwner(); // !null checked for above - ClassMetaData meta = sm.getMetaData(); // if null, no proxies? - if ((meta != null) && (!Boolean.TRUE.equals(meta.usesDetachedState()))) { - // configured to use transient (null) or no (FALSE) StateManger, so remove any $proxy - return proxy.copy(proxy); + OpenJPAStateManager sm = proxy.getOwner(); // null checked for above + ClassMetaData meta = null; // if null, no proxies? + boolean useDSFForUnproxy = false; // default to false for old 1.0 behavior + + // DetachedStateMnager has no context or metadata, so we can't get configuration settings + if (!proxy.getOwner().isDetached()) { + Compatibility compat = null; + meta = sm.getMetaData(); + if (meta != null) { + compat = meta.getRepository().getConfiguration().getCompatibilityInstance(); + } else if (sm.getContext() != null && sm.getContext().getConfiguration() != null) { + compat = sm.getContext().getConfiguration().getCompatibilityInstance(); + } else { + // no-op - using a StateManager, but no Compatibility settings available + } + if (compat != null) { + // new 2.0 behavior of using DetachedStateField to determine unproxy during serialization + useDSFForUnproxy = !compat.getIgnoreDetachedStateFieldForProxySerialization(); + } } else { - // DetachedStateField==true, which means to keep the SM and $proxy in the serialized objects - return proxy; + // Using a DetachedStateManager, so use the new flag since there is no context or metadata + useDSFForUnproxy = ((DetachedStateManager)sm).getUseDSFForUnproxy(); + } + + if (useDSFForUnproxy) { + // use new 2.0 behavior + if ((meta != null) && (Boolean.TRUE.equals(meta.usesDetachedState()))) { + // configured to always use and serialize a StateManger, so keep any $proxy + return proxy; + } else { + // already detached or using DetachedStateField==false or transient, so remove any $proxy + return proxy.copy(proxy); + } + } else { + // use old 1.0 behavior + if (proxy.getOwner().isDetached()) + return proxy; + else + return proxy.copy(proxy); } } } diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/compat/TestContainerSpecCompatibilityOptions.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/compat/TestContainerSpecCompatibilityOptions.java index 4bc3624be..73109aa4b 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/compat/TestContainerSpecCompatibilityOptions.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/compat/TestContainerSpecCompatibilityOptions.java @@ -71,6 +71,7 @@ public class TestContainerSpecCompatibilityOptions Compatibility compat = emf1.getConfiguration().getCompatibilityInstance(); assertTrue(compat.getFlushBeforeDetach()); assertTrue(compat.getCopyOnDetach()); + assertTrue(compat.getIgnoreDetachedStateFieldForProxySerialization()); assertTrue(compat.getPrivatePersistentProperties()); assertFalse(compat.isAbstractMappingUniDirectional()); assertFalse(compat.isNonDefaultMappingAllowed()); @@ -92,6 +93,7 @@ public class TestContainerSpecCompatibilityOptions Compatibility compat = emf.getConfiguration().getCompatibilityInstance(); assertFalse(compat.getFlushBeforeDetach()); assertFalse(compat.getCopyOnDetach()); + assertFalse(compat.getIgnoreDetachedStateFieldForProxySerialization()); assertFalse(compat.getPrivatePersistentProperties()); assertTrue(compat.isAbstractMappingUniDirectional()); assertTrue(compat.isNonDefaultMappingAllowed()); diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/compat/TestSpecCompatibilityOptions.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/compat/TestSpecCompatibilityOptions.java index 9436dc78e..a2a0089ba 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/compat/TestSpecCompatibilityOptions.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/compat/TestSpecCompatibilityOptions.java @@ -57,6 +57,7 @@ extends AbstractCachedEMFTestCase { Compatibility compat = emf.getConfiguration().getCompatibilityInstance(); assertTrue(compat.getFlushBeforeDetach()); assertTrue(compat.getCopyOnDetach()); + assertTrue(compat.getIgnoreDetachedStateFieldForProxySerialization()); assertTrue(compat.getPrivatePersistentProperties()); String vMode = emf.getConfiguration().getValidationMode(); assertEquals("NONE", vMode); @@ -65,7 +66,6 @@ extends AbstractCachedEMFTestCase { assertEquals(spec.getVersion(), 1); emf.close(); - } /* @@ -82,6 +82,7 @@ extends AbstractCachedEMFTestCase { Compatibility compat = emf.getConfiguration().getCompatibilityInstance(); assertFalse(compat.getFlushBeforeDetach()); assertFalse(compat.getCopyOnDetach()); + assertFalse(compat.getIgnoreDetachedStateFieldForProxySerialization()); assertFalse(compat.getPrivatePersistentProperties()); String vMode = emf.getConfiguration().getValidationMode(); assertEquals("AUTO", vMode); diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detach/TestDetachNoProxy.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detach/TestDetachNoProxy.java index b2faf88d8..5f0e07155 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detach/TestDetachNoProxy.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detach/TestDetachNoProxy.java @@ -28,34 +28,19 @@ import java.util.ArrayList; import org.apache.openjpa.conf.Compatibility; import org.apache.openjpa.lib.log.Log; import org.apache.openjpa.persistence.OpenJPAEntityManager; +import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI; +import org.apache.openjpa.persistence.OpenJPAPersistence; import org.apache.openjpa.persistence.test.SingleEMFTestCase; public class TestDetachNoProxy extends SingleEMFTestCase { private static final int numEntities = 3; private static final String PROXY = new String("$proxy"); - private Log log; + private Log _log; public void setUp() { setUp(DROP_TABLES, Entity20.class); - log = emf.getConfiguration().getLog("test"); - - // check and set Compatibility values to new 2.0 values - Compatibility compat = emf.getConfiguration().getCompatibilityInstance(); - assertNotNull(compat); - if (log.isTraceEnabled()) { - log.trace("Before set, FlushBeforeDetach=" + compat.getFlushBeforeDetach()); - log.trace("Before set, CopyOnDetach=" + compat.getCopyOnDetach()); - log.trace("Before set, CascadeWithDetach=" + compat.getCascadeWithDetach()); - } - compat.setFlushBeforeDetach(false); - compat.setCopyOnDetach(false); - compat.setCascadeWithDetach(false); - if (log.isTraceEnabled()) { - log.trace("After set, FlushBeforeDetach=" + compat.getFlushBeforeDetach()); - log.trace("After set, CopyOnDetach=" + compat.getCopyOnDetach()); - log.trace("After set, CascadeWithDetach=" + compat.getCascadeWithDetach()); - } + _log = emf.getConfiguration().getLog("test"); createEntities(numEntities); } @@ -74,16 +59,33 @@ public class TestDetachNoProxy extends SingleEMFTestCase { /* * Verify that an in-place detached entity does not use the proxy classes. */ - public void testDetach() { - if (log.isTraceEnabled()) - log.trace("***** testDetach() *****"); + public void testDetach20() { Integer id = new Integer(0); - OpenJPAEntityManager em = emf.createEntityManager(); + OpenJPAEntityManagerFactorySPI emf2 = + (OpenJPAEntityManagerFactorySPI) OpenJPAPersistence.createEntityManagerFactory( + "NoProxy2New", "org/apache/openjpa/persistence/detach/persistence2.xml"); + assertNotNull(emf2); + + Log log = emf2.getConfiguration().getLog("test"); + if (log.isTraceEnabled()) + log.trace("***** testDetach20() *****"); + if (log.isTraceEnabled()) { + Compatibility compat = emf2.getConfiguration().getCompatibilityInstance(); + assertNotNull(compat); + log.trace("FlushBeforeDetach=" + compat.getFlushBeforeDetach()); + log.trace("CopyOnDetach=" + compat.getCopyOnDetach()); + log.trace("CascadeWithDetach=" + compat.getCascadeWithDetach()); + log.trace("IgnoreDetachedStateFieldForProxySerialization=" + + compat.getIgnoreDetachedStateFieldForProxySerialization()); + } + + OpenJPAEntityManager em = emf2.createEntityManager(); em.clear(); + Entity20 e20 = em.find(Entity20.class, id); if (log.isTraceEnabled()) - log.trace("** after find"); + log.trace("** testDetach20() - after find"); assertTrue(em.contains(e20)); assertFalse(em.isDetached(e20)); verifySerializable(e20, true, false); @@ -91,28 +93,46 @@ public class TestDetachNoProxy extends SingleEMFTestCase { // new openjpa-2.0.0 behavior, where detach() doesn't return updated entity, but does it in-place em.detach(e20); if (log.isTraceEnabled()) - log.trace("** after detach"); + log.trace("** testDetach20() - after detach"); // in-place updated entity should not have any proxy classes and should be detached assertFalse(em.contains(e20)); assertTrue(em.isDetached(e20)); - verifySerializable(e20, false, false); + verifySerializable(e20, true, false); em.close(); + emf2.close(); } /* * Verify that a detachCopy() returned entity does not contain any proxy classes. */ - public void testDetachCopy() { - if (log.isTraceEnabled()) - log.trace("***** testDetachCopy() *****"); + public void testDetachCopy20() { Integer id = new Integer(0); - OpenJPAEntityManager em = emf.createEntityManager(); + OpenJPAEntityManagerFactorySPI emf2 = + (OpenJPAEntityManagerFactorySPI) OpenJPAPersistence.createEntityManagerFactory( + "NoProxy2New", "org/apache/openjpa/persistence/detach/persistence2.xml"); + assertNotNull(emf2); + + Log log = emf2.getConfiguration().getLog("test"); + if (log.isTraceEnabled()) + log.trace("***** testDetachCopy20() *****"); + + if (log.isTraceEnabled()) { + Compatibility compat = emf2.getConfiguration().getCompatibilityInstance(); + assertNotNull(compat); + log.trace("FlushBeforeDetach=" + compat.getFlushBeforeDetach()); + log.trace("CopyOnDetach=" + compat.getCopyOnDetach()); + log.trace("CascadeWithDetach=" + compat.getCascadeWithDetach()); + log.trace("IgnoreDetachedStateFieldForProxySerialization=" + + compat.getIgnoreDetachedStateFieldForProxySerialization()); + } + + OpenJPAEntityManager em = emf2.createEntityManager(); em.clear(); Entity20 e20 = em.find(Entity20.class, id); if (log.isTraceEnabled()) - log.trace("** after find"); + log.trace("** testDetachCopy20() - after find"); assertTrue(em.contains(e20)); assertFalse(em.isDetached(e20)); verifySerializable(e20, true, false); @@ -120,7 +140,7 @@ public class TestDetachNoProxy extends SingleEMFTestCase { // Test new detachCopy() method added in 2.0.0 Entity20 e20copy = em.detachCopy(e20); if (log.isTraceEnabled()) - log.trace("** after detachCopy"); + log.trace("** TestDetachCopy20() - after detachCopy"); // verify e20 is same as above assertTrue(em.contains(e20)); assertFalse(em.isDetached(e20)); @@ -131,15 +151,33 @@ public class TestDetachNoProxy extends SingleEMFTestCase { verifySerializable(e20copy, false, false); em.close(); + emf2.close(); } /* * Verify that in-place detachAll entities do not use the proxy classes. */ - public void testDetachAll() { + public void testDetachAll20() { + OpenJPAEntityManagerFactorySPI emf2 = + (OpenJPAEntityManagerFactorySPI) OpenJPAPersistence.createEntityManagerFactory( + "NoProxy2New", "org/apache/openjpa/persistence/detach/persistence2.xml"); + assertNotNull(emf2); + + Log log = emf2.getConfiguration().getLog("test"); if (log.isTraceEnabled()) - log.trace("***** testDetachAll() *****"); - OpenJPAEntityManager em = emf.createEntityManager(); + log.trace("***** testDetachAll20() *****"); + + if (log.isTraceEnabled()) { + Compatibility compat = emf2.getConfiguration().getCompatibilityInstance(); + assertNotNull(compat); + log.trace("FlushBeforeDetach=" + compat.getFlushBeforeDetach()); + log.trace("CopyOnDetach=" + compat.getCopyOnDetach()); + log.trace("CascadeWithDetach=" + compat.getCascadeWithDetach()); + log.trace("IgnoreDetachedStateFieldForProxySerialization=" + + compat.getIgnoreDetachedStateFieldForProxySerialization()); + } + + OpenJPAEntityManager em = emf2.createEntityManager(); em.clear(); ArrayList e20List = new ArrayList(numEntities); @@ -147,7 +185,7 @@ public class TestDetachNoProxy extends SingleEMFTestCase { Entity20 e20 = em.find(Entity20.class, new Integer(i)); e20List.add(e20); if (log.isTraceEnabled()) - log.trace("** after find Entity20(" + i + ")"); + log.trace("** testDetachAll20() - after find Entity20(" + i + ")"); assertTrue(em.contains(e20)); assertFalse(em.isDetached(e20)); verifySerializable(e20, true, false); @@ -159,24 +197,42 @@ public class TestDetachNoProxy extends SingleEMFTestCase { em.detachAll(e20List.get(0), e20List.get(1), e20List.get(2)); for (int i=0; i + + + + + org.apache.openjpa.persistence.detach.Entity20 + true + + + + + diff --git a/openjpa-persistence-jdbc/src/test/resources/org/apache/openjpa/persistence/detach/persistence2.xml b/openjpa-persistence-jdbc/src/test/resources/org/apache/openjpa/persistence/detach/persistence2.xml new file mode 100644 index 000000000..b768a65e4 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/resources/org/apache/openjpa/persistence/detach/persistence2.xml @@ -0,0 +1,55 @@ + + + + + + + org.apache.openjpa.persistence.detach.Entity20 + true + + + + + + + + org.apache.openjpa.persistence.detach.Entity20 + true + + + + + + + diff --git a/openjpa-persistence-jdbc/src/test/resources/org/apache/openjpa/persistence/proxy/persistence2.xml b/openjpa-persistence-jdbc/src/test/resources/org/apache/openjpa/persistence/proxy/persistence2.xml index f564e6d66..3e8ddd4b9 100644 --- a/openjpa-persistence-jdbc/src/test/resources/org/apache/openjpa/persistence/proxy/persistence2.xml +++ b/openjpa-persistence-jdbc/src/test/resources/org/apache/openjpa/persistence/proxy/persistence2.xml @@ -26,58 +26,6 @@ - - org.apache.openjpa.persistence.proxy.entities.Address - org.apache.openjpa.persistence.proxy.entities.Annuity - org.apache.openjpa.persistence.proxy.entities.AnnuityHolder - org.apache.openjpa.persistence.proxy.entities.AnnuityPersistebleObject - org.apache.openjpa.persistence.proxy.entities.Contact - org.apache.openjpa.persistence.proxy.entities.EquityAnnuity - org.apache.openjpa.persistence.proxy.entities.FixedAnnuity - org.apache.openjpa.persistence.proxy.entities.Payor - org.apache.openjpa.persistence.proxy.entities.Payout - org.apache.openjpa.persistence.proxy.entities.Person - org.apache.openjpa.persistence.proxy.entities.Rider - true - - - - - - - - - - org.apache.openjpa.persistence.proxy.entities.Address - org.apache.openjpa.persistence.proxy.entities.Annuity - org.apache.openjpa.persistence.proxy.entities.AnnuityHolder - org.apache.openjpa.persistence.proxy.entities.AnnuityPersistebleObject - org.apache.openjpa.persistence.proxy.entities.Contact - org.apache.openjpa.persistence.proxy.entities.EquityAnnuity - org.apache.openjpa.persistence.proxy.entities.FixedAnnuity - org.apache.openjpa.persistence.proxy.entities.Payor - org.apache.openjpa.persistence.proxy.entities.Payout - org.apache.openjpa.persistence.proxy.entities.Person - org.apache.openjpa.persistence.proxy.entities.Rider - true - - - - - - - - org.apache.openjpa.persistence.proxy.entities.Address org.apache.openjpa.persistence.proxy.entities.Annuity @@ -92,11 +40,11 @@ org.apache.openjpa.persistence.proxy.entities.Rider true - - - + + value="buildSchema(ForeignKeys=true)" /> + diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProductDerivation.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProductDerivation.java index 3c37a2caa..9c74950e9 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProductDerivation.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProductDerivation.java @@ -287,6 +287,7 @@ public class PersistenceProductDerivation compatibility.setFlushBeforeDetach(true); compatibility.setCopyOnDetach(true); compatibility.setPrivatePersistentProperties(true); + compatibility.setIgnoreDetachedStateFieldForProxySerialization(true); // Disable bean validation for spec level < 2 configurations conf.validationMode.set(String.valueOf(ValidationMode.NONE)); } else {