You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by dw...@apache.org on 2010/04/01 04:24:32 UTC
svn commit: r929784 - in /openjpa/branches/1.3.x:
openjpa-kernel/src/main/java/org/apache/openjpa/conf/
openjpa-kernel/src/main/java/org/apache/openjpa/kernel/
openjpa-kernel/src/main/java/org/apache/openjpa/util/
openjpa-persistence-jdbc/src/test/java...
Author: dwoods
Date: Thu Apr 1 02:24:32 2010
New Revision: 929784
URL: http://svn.apache.org/viewvc?rev=929784&view=rev
Log:
OPENJPA-1597 Add Compatibility option to use new 2.0 behavior of removing proxy classes unless DetachedStateField=true, but default is still the old behavior.
Modified:
openjpa/branches/1.3.x/openjpa-kernel/src/main/java/org/apache/openjpa/conf/Compatibility.java
openjpa/branches/1.3.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateManager.java
openjpa/branches/1.3.x/openjpa-kernel/src/main/java/org/apache/openjpa/util/Proxies.java
openjpa/branches/1.3.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detach/TestDetachNoProxy.java
openjpa/branches/1.3.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/proxy/TestDetachMerge.java
Modified: openjpa/branches/1.3.x/openjpa-kernel/src/main/java/org/apache/openjpa/conf/Compatibility.java
URL: http://svn.apache.org/viewvc/openjpa/branches/1.3.x/openjpa-kernel/src/main/java/org/apache/openjpa/conf/Compatibility.java?rev=929784&r1=929783&r2=929784&view=diff
==============================================================================
--- openjpa/branches/1.3.x/openjpa-kernel/src/main/java/org/apache/openjpa/conf/Compatibility.java (original)
+++ openjpa/branches/1.3.x/openjpa-kernel/src/main/java/org/apache/openjpa/conf/Compatibility.java Thu Apr 1 02:24:32 2010
@@ -57,6 +57,7 @@ public class Compatibility {
private boolean _storeMapCollectionInEntityAsBlob = false;
private boolean _flushBeforeDetach = true;
private boolean _reloadOnDetach = true;
+ private boolean _ignoreDetachedStateFieldForProxySerialization = true;
/**
* Whether to require exact identity value types when creating object
@@ -255,6 +256,39 @@ public class Compatibility {
}
/**
+ * Whether OpenJPA should ignore the DetachedStateField value when
+ * determining if our Proxy classes should be removed during serialization.
+ * <P>Now, when the DetachedStateFiled==true, the
+ * build time $proxy classes will not be removed.
+ * <P>Prior behavior, was that 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 1.3.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.
+ * <P>Now, when the DetachedStateFiled==true, the
+ * build time $proxy classes will not be removed.
+ * <P>Prior behavior, was that the DetachedStateFiled was not used and
+ * the $proxy classes were not being removed during serialization after
+ * the Persistence context was cleared.
+ *
+ * @since 1.3.0
+ * @return true (default) 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
* (ie JDO) may expect it to be true.
Modified: openjpa/branches/1.3.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateManager.java
URL: http://svn.apache.org/viewvc/openjpa/branches/1.3.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateManager.java?rev=929784&r1=929783&r2=929784&view=diff
==============================================================================
--- openjpa/branches/1.3.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateManager.java (original)
+++ openjpa/branches/1.3.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateManager.java Thu Apr 1 02:24:32 2010
@@ -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 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 1.3.0
+ */
+ public boolean getUseDSFForUnproxy() {
+ return _useDSFForUnproxy;
+ }
+
public BitSet getFlushed() {
throw new UnsupportedOperationException();
}
Modified: openjpa/branches/1.3.x/openjpa-kernel/src/main/java/org/apache/openjpa/util/Proxies.java
URL: http://svn.apache.org/viewvc/openjpa/branches/1.3.x/openjpa-kernel/src/main/java/org/apache/openjpa/util/Proxies.java?rev=929784&r1=929783&r2=929784&view=diff
==============================================================================
--- openjpa/branches/1.3.x/openjpa-kernel/src/main/java/org/apache/openjpa/util/Proxies.java (original)
+++ openjpa/branches/1.3.x/openjpa-kernel/src/main/java/org/apache/openjpa/util/Proxies.java Thu Apr 1 02:24:32 2010
@@ -20,9 +20,12 @@ 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;
+import org.apache.openjpa.meta.ClassMetaData;
/**
* Utility methods for managing proxies.
@@ -80,10 +83,87 @@ public class Proxies {
* Used by proxy types to serialize non-proxy versions.
*/
public static Object writeReplace(Proxy proxy, boolean detachable) {
- if (detachable && (proxy == null || proxy.getOwner() == null
- || proxy.getOwner().isDetached()))
+ /* OPENJPA-1097 Remove $proxy classes during serialization based on:
+ * 1) No Proxy, then return as-is
+ * 2) Runtime created proxy (!detachable), then unproxy
+ * 3) No StateManager (DetachedStateField==false), then 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
+ * 2) No Proxy, then return as-is
+ * 3) No StateManager (DetachedStateField==false), then return as-is
+ * 4) If detached, then return as-is <--- ERROR as EM.clear() marks
+ * entity as detached but doesn't remove any $proxy usage
+ * 5) Else, unproxy
+ *
+ * if (detachable && (proxy == null || proxy.getOwner() == null
+ * || proxy.getOwner().isDetached()))
+ * return proxy;
+ *
+ */
+ if (proxy == null) {
return proxy;
+ } else if (!detachable) {
+ // OPENJPA-1571 - using our runtime generated proxies, so remove any $proxy
return proxy.copy(proxy);
+ } else if (proxy.getOwner() == null) {
+ // no StateManager (DetachedStateField==false), so no $proxy to remove
+ return proxy;
+ } else {
+ // using a StateManager, so determine what DetachedState is being used
+ 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 {
+ // 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);
+ }
+ }
}
}
Modified: openjpa/branches/1.3.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detach/TestDetachNoProxy.java
URL: http://svn.apache.org/viewvc/openjpa/branches/1.3.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detach/TestDetachNoProxy.java?rev=929784&r1=929783&r2=929784&view=diff
==============================================================================
--- openjpa/branches/1.3.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detach/TestDetachNoProxy.java (original)
+++ openjpa/branches/1.3.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detach/TestDetachNoProxy.java Thu Apr 1 02:24:32 2010
@@ -186,9 +186,9 @@ public class TestDetachNoProxy extends S
/*
* Verify that after EM.clear() entities still contain proxy classes.
*/
- public void testClear() {
+ public void testClear10() {
if (log.isTraceEnabled())
- log.trace("***** testClear() *****");
+ log.trace("***** testClear10() *****");
OpenJPAEntityManager em = emf.createEntityManager();
em.clear();
@@ -197,7 +197,7 @@ public class TestDetachNoProxy extends S
Entity20 e20 = em.find(Entity20.class, new Integer(i));
e20List.add(e20);
if (log.isTraceEnabled())
- log.trace("** after find Entity20(" + i + ")");
+ log.trace("** testClear10() - after find Entity20(" + i + ")");
assertTrue(em.contains(e20));
assertFalse(em.isDetached(e20));
verifySerializable(e20, true, false);
@@ -207,7 +207,7 @@ public class TestDetachNoProxy extends S
for (int i=0; i<numEntities; i++) {
if (log.isTraceEnabled())
- log.trace("** after EM.clear() verify Entity20(" + i + ")");
+ log.trace("** testClear10() - after EM.clear() verify Entity20(" + i + ")");
Entity20 e20 = e20List.get(i);
assertFalse(em.contains(e20));
assertTrue(em.isDetached(e20));
@@ -215,8 +215,46 @@ public class TestDetachNoProxy extends S
// Current Behavior -
// the $proxy classes are not removed during serialization
verifySerializable(e20, true, true);
- // Proposed OPENJPA-1097 new behavior - $proxy classes are removed
- // verifySerializable(e20, true, false);
+ }
+
+ em.close();
+ }
+
+ /*
+ * Verify that after EM.clear() entities do not contain proxy classes for 2.0 behavior.
+ */
+ public void testClear20() {
+ if (log.isTraceEnabled())
+ log.trace("***** testClear20() *****");
+ Compatibility compat = emf.getConfiguration().getCompatibilityInstance();
+ assertNotNull(compat);
+ // use new 2.0 behavior
+ compat.setIgnoreDetachedStateFieldForProxySerialization(false);
+
+ OpenJPAEntityManager em = emf.createEntityManager();
+ em.clear();
+
+ ArrayList<Entity20> e20List = new ArrayList<Entity20>(numEntities);
+ for (int i=0; i<numEntities; i++) {
+ Entity20 e20 = em.find(Entity20.class, new Integer(i));
+ e20List.add(e20);
+ if (log.isTraceEnabled())
+ log.trace("** testClear20() - after find Entity20(" + i + ")");
+ assertTrue(em.contains(e20));
+ assertFalse(em.isDetached(e20));
+ verifySerializable(e20, true, false);
+ }
+
+ em.clear();
+
+ for (int i=0; i<numEntities; i++) {
+ if (log.isTraceEnabled())
+ log.trace("** after EM.clear() verify Entity20(" + i + ")");
+ Entity20 e20 = e20List.get(i);
+ assertFalse(em.contains(e20));
+ assertTrue(em.isDetached(e20));
+ // Verify new OPENJPA-1097/1597 behavior - $proxy classes are removed
+ verifySerializable(e20, true, false);
}
em.close();
Modified: openjpa/branches/1.3.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/proxy/TestDetachMerge.java
URL: http://svn.apache.org/viewvc/openjpa/branches/1.3.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/proxy/TestDetachMerge.java?rev=929784&r1=929783&r2=929784&view=diff
==============================================================================
--- openjpa/branches/1.3.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/proxy/TestDetachMerge.java (original)
+++ openjpa/branches/1.3.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/proxy/TestDetachMerge.java Thu Apr 1 02:24:32 2010
@@ -21,15 +21,17 @@ package org.apache.openjpa.persistence.p
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.UUID;
import javax.persistence.EntityManager;
-//import org.apache.openjpa.conf.Compatibility;
+import org.apache.openjpa.conf.Compatibility;
import org.apache.openjpa.lib.log.Log;
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
import org.apache.openjpa.persistence.OpenJPAPersistence;
-//import org.apache.openjpa.persistence.test.AllowFailure;
+import org.apache.openjpa.persistence.test.AllowFailure;
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
import org.apache.openjpa.persistence.proxy.entities.Address;
@@ -83,6 +85,15 @@ public class TestDetachMerge extends Sin
Log log = emf1.getConfiguration().getLog("test");
+ if (log.isTraceEnabled()) {
+ Compatibility compat = emf1.getConfiguration().getCompatibilityInstance();
+ assertNotNull(compat);
+ log.trace("started testAnnuity1Compat()");
+ log.trace("FlushBeforeDetach=" + compat.getFlushBeforeDetach());
+ log.trace("IgnoreDetachedStateFieldForProxySerialization=" +
+ compat.getIgnoreDetachedStateFieldForProxySerialization());
+ }
+
try {
execute(emf1);
} catch (RuntimeException e) {
@@ -93,12 +104,12 @@ public class TestDetachMerge extends Sin
}
/*
- * Test 2.0 behavior with Compatibility flag and DetachedStateField=true, which should FAIL
+ * Test default 2.0 compatibility behavior, which should PASS
*
- public void testAnnuity1Fail() throws Exception {
+ public void testAnnuity2Compat() throws Exception {
OpenJPAEntityManagerFactorySPI emf2 =
(OpenJPAEntityManagerFactorySPI) OpenJPAPersistence.createEntityManagerFactory(
- "Annuity1Fail", "org/apache/openjpa/persistence/proxy/persistence1.xml");
+ "Annuity2Compat", "org/apache/openjpa/persistence/proxy/persistence2.xml");
assertNotNull(emf2);
Log log = emf2.getConfiguration().getLog("test");
@@ -106,26 +117,23 @@ public class TestDetachMerge extends Sin
if (log.isTraceEnabled()) {
Compatibility compat = emf2.getConfiguration().getCompatibilityInstance();
assertNotNull(compat);
- log.trace("started testAnnuity1Fail()");
+ log.trace("started testAnnuity2Compat()");
+ log.trace("FlushBeforeDetach=" + compat.getFlushBeforeDetach());
+ log.trace("CopyOnDetach=" + compat.getCopyOnDetach());
+ log.trace("CascadeWithDetach=" + compat.getCascadeWithDetach());
log.trace("IgnoreDetachedStateFieldForProxySerialization=" +
compat.getIgnoreDetachedStateFieldForProxySerialization());
}
try {
execute(emf2);
- fail("testAnuity2Fail() should have caused an execption!");
} catch (RuntimeException e) {
- if (e.getMessage().startsWith("Annuity:")) {
- // no-op caught our expected exception
- } else {
- fail("testAnuity2Fail() caught an unexpected execption!" + e);
- }
+ fail("testAnuity2Compat() should not have caused an execption!" + e);
} finally {
emf2.close();
}
}
- */
-
+ */
private void execute(OpenJPAEntityManagerFactorySPI myEMF) throws Exception {
Log log = myEMF.getConfiguration().getLog("test");
@@ -545,7 +553,8 @@ public class TestDetachMerge extends Sin
if (payors == null)
throw new RuntimeException("Annuity: IPayor list not the same (payors was null)!");
if (payors.size() != payors2.size())
- throw new RuntimeException("Annuity: IPayor list not the same (payors size not the same)!");
+ throw new RuntimeException("Annuity: IPayor list not the same (payors size not the same)! payors=" +
+ payors.toArray().toString() + ", payors2=" + payors2.toString());
for (int i = 0; i < payors.size(); i++) {
IPayor payor = payors.get(i);
boolean found = false;