You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by pc...@apache.org on 2008/06/12 01:14:25 UTC
svn commit: r666888 - in /openjpa/trunk:
openjpa-kernel/src/main/java/org/apache/openjpa/enhance/
openjpa-kernel/src/main/java/org/apache/openjpa/kernel/
openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/
openjpa-persistence-jdbc/src/test/jav...
Author: pcl
Date: Wed Jun 11 16:14:24 2008
New Revision: 666888
URL: http://svn.apache.org/viewvc?rev=666888&view=rev
Log:
OPENJPA-245. Backported r646082 to trunk.
Added:
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detachment/TestAttachConstructedCopy.java
- copied unchanged from r646082, openjpa/branches/1.1.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detachment/TestAttachConstructedCopy.java
Modified:
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/VersionAttachStrategy.java
openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties
openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_remote.xml
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java?rev=666888&r1=666887&r2=666888&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java Wed Jun 11 16:14:24 2008
@@ -118,7 +118,10 @@
public static final int ENHANCE_INTERFACE = 2 << 1;
public static final int ENHANCE_PC = 2 << 2;
- private static final String PRE = "pc";
+ public static final String PRE = "pc";
+ public static final String ISDETACHEDSTATEDEFINITIVE = PRE
+ + "isDetachedStateDefinitive";
+
private static final Class PCTYPE = PersistenceCapable.class;
private static final String SM = PRE + "StateManager";
private static final Class SMTYPE = StateManager.class;
@@ -2999,12 +3002,27 @@
*/
private void addIsDetachedMethod()
throws NoSuchMethodException {
- // public boolean pcIsDetached ()
+ // public boolean pcIsDetached()
BCMethod method = _pc.declareMethod(PRE + "IsDetached",
Boolean.class, null);
method.makePublic();
Code code = method.getCode(true);
- writeIsDetachedMethod(code);
+ boolean needsDefinitiveMethod = writeIsDetachedMethod(code);
+ code.calculateMaxStack();
+ code.calculateMaxLocals();
+ if (!needsDefinitiveMethod)
+ return;
+
+ // private boolean pcIsDetachedStateDefinitive()
+ // return false;
+ // auxilliary enhancers may change the return value of this method
+ // if their specs consider detached state definitive
+ method = _pc.declareMethod(ISDETACHEDSTATEDEFINITIVE, boolean.class,
+ null);
+ method.makePrivate();
+ code = method.getCode(true);
+ code.constant().setValue(false);
+ code.ireturn();
code.calculateMaxStack();
code.calculateMaxLocals();
}
@@ -3012,14 +3030,17 @@
/**
* Creates the body of the pcIsDetached() method to determine if an
* instance is detached.
+ *
+ * @return true if we need a pcIsDetachedStateDefinitive method, false
+ * otherwise
*/
- private void writeIsDetachedMethod(Code code)
+ private boolean writeIsDetachedMethod(Code code)
throws NoSuchMethodException {
// not detachable: return Boolean.FALSE
if (!_meta.isDetachable()) {
code.getstatic().setField(Boolean.class, "FALSE", Boolean.class);
code.areturn();
- return;
+ return false;
}
// if (sm != null)
@@ -3067,7 +3088,7 @@
ifins.setTarget(target);
notdeser.setTarget(target);
code.areturn();
- return;
+ return false;
}
}
@@ -3077,9 +3098,9 @@
if (notdeser != null)
notdeser.setTarget(target);
- // allow users with version fields to manually construct a "detached"
- // instance, so check version before taking into account non-existent
- // detached state
+ // allow users with version or auto-assigned pk fields to manually
+ // construct a "detached" instance, so check these before taking into
+ // account non-existent detached state
// consider detached if version is non-default
FieldMetaData version = _meta.getVersionField();
@@ -3094,41 +3115,13 @@
ifins.setTarget(code.getstatic().setField(Boolean.class, "FALSE",
Boolean.class));
code.areturn();
- return;
- }
-
- // no detached state: if instance uses detached state and it's not
- // synthetic or the instance is not serializable or the state isn't
- // transient, must not be detached
- if (state == null
- && (!ClassMetaData.SYNTHETIC.equals(_meta.getDetachedState())
- || !Serializable.class.isAssignableFrom(_meta.getDescribedType())
- || !_repos.getConfiguration().getDetachStateInstance().
- isDetachedStateTransient())) {
- // return Boolean.FALSE
- code.getstatic().setField(Boolean.class, "FALSE", Boolean.class);
- code.areturn();
- return;
- }
-
- // no detached state: if instance uses detached state (and must be
- // synthetic and transient in serializable instance at this point),
- // not detached if state not set to DESERIALIZED
- if (state == null) {
- // if (pcGetDetachedState () == null) // instead of DESERIALIZED
- // return Boolean.FALSE;
- loadManagedInstance(code, false);
- code.invokevirtual().setMethod(PRE + "GetDetachedState",
- Object.class, null);
- ifins = code.ifnonnull();
- code.getstatic().setField(Boolean.class, "FALSE", Boolean.class);
- code.areturn();
- ifins.setTarget(code.nop());
+ return false;
}
// consider detached if auto-genned primary keys are non-default
ifins = null;
JumpInstruction ifins2 = null;
+ boolean hasAutoAssignedPK = false;
if (state != Boolean.TRUE
&& _meta.getIdentityType() == ClassMetaData.ID_APPLICATION) {
// for each pk field:
@@ -3162,13 +3155,65 @@
}
}
- // give up; we just don't know
- target = code.constant().setNull();
+ // create artificial target to simplify
+ target = code.nop();
if (ifins != null)
ifins.setTarget(target);
if (ifins2 != null)
ifins2.setTarget(target);
+
+ // if has auto-assigned pk and we get to this point, must have default
+ // value, so must be new instance
+ if (hasAutoAssignedPK) {
+ code.getstatic().setField(Boolean.class, "FALSE", Boolean.class);
+ code.areturn();
+ return false;
+ }
+
+ // if detached state is not definitive, just give up now and return
+ // null so that the runtime will perform a DB lookup to determine
+ // whether we're detached or new
+ code.aload().setThis();
+ code.invokespecial().setMethod(ISDETACHEDSTATEDEFINITIVE, boolean.class,
+ null);
+ ifins = code.ifne();
+ code.constant().setNull();
code.areturn();
+ ifins.setTarget(code.nop());
+
+ // no detached state: if instance uses detached state and it's not
+ // synthetic or the instance is not serializable or the state isn't
+ // transient, must not be detached
+ if (state == null
+ && (!ClassMetaData.SYNTHETIC.equals(_meta.getDetachedState())
+ || !Serializable.class.isAssignableFrom(_meta.getDescribedType())
+ || !_repos.getConfiguration().getDetachStateInstance().
+ isDetachedStateTransient())) {
+ // return Boolean.FALSE
+ code.getstatic().setField(Boolean.class, "FALSE", Boolean.class);
+ code.areturn();
+ return true;
+ }
+
+ // no detached state: if instance uses detached state (and must be
+ // synthetic and transient in serializable instance at this point),
+ // not detached if state not set to DESERIALIZED
+ if (state == null) {
+ // if (pcGetDetachedState () == null) // instead of DESERIALIZED
+ // return Boolean.FALSE;
+ loadManagedInstance(code, false);
+ code.invokevirtual().setMethod(PRE + "GetDetachedState",
+ Object.class, null);
+ ifins = code.ifnonnull();
+ code.getstatic().setField(Boolean.class, "FALSE", Boolean.class);
+ code.areturn();
+ ifins.setTarget(code.nop());
+ }
+
+ // give up; we just don't know
+ code.constant().setNull();
+ code.areturn();
+ return true;
}
/**
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/VersionAttachStrategy.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/VersionAttachStrategy.java?rev=666888&r1=666887&r2=666888&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/VersionAttachStrategy.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/VersionAttachStrategy.java Wed Jun 11 16:14:24 2008
@@ -69,19 +69,12 @@
public Object attach(AttachManager manager, Object toAttach,
ClassMetaData meta, PersistenceCapable into, OpenJPAStateManager owner,
ValueMetaData ownerMeta, boolean explicit) {
-
- // VersionAttachStrategy is invoked in the case where no more
- // intelligent strategy could be found; let's be more lenient
- // about new vs. detached record determination.
- if (into == null)
- into = findFromDatabase(manager, toAttach);
-
BrokerImpl broker = manager.getBroker();
PersistenceCapable pc = ImplHelper.toPersistenceCapable(toAttach,
meta.getRepository().getConfiguration());
boolean embedded = ownerMeta != null && ownerMeta.isEmbeddedPC();
- boolean isNew = !broker.isDetached(pc) && into == null;
+ boolean isNew = !broker.isDetached(pc);
Object version = null;
StateManagerImpl sm;
Modified: openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties?rev=666888&r1=666887&r2=666888&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties (original)
+++ openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties Wed Jun 11 16:14:24 2008
@@ -116,7 +116,9 @@
trans-not-managed: This broker is not configured to use managed transactions.
bad-detached-op: You cannot perform operation {0} on detached object "{1}". \
This operation only applies to managed objects.
-persist-detached: Attempt to persist detached object "{0}".
+persist-detached: Attempt to persist detached object "{0}". If this is a new \
+ instance, make sure any versino and/or auto-generated primary key fields are \
+ null/default when persisting.
null-value: The field "{0}" of instance "{1}" contained a null value; \
the metadata for this field specifies that nulls are illegal.
change-identity: Attempt to change a primary key field of an instance that \
@@ -396,4 +398,4 @@
an active datastore (pessimistic) transaction.
cant-serialize-connected-broker: Serialization not allowed for brokers with \
an active connection to the database.
-no-interface-metadata: No metadata was found for managed interface {0}.
\ No newline at end of file
+no-interface-metadata: No metadata was found for managed interface {0}.
Modified: openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_remote.xml
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_remote.xml?rev=666888&r1=666887&r2=666888&view=diff
==============================================================================
--- openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_remote.xml (original)
+++ openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_remote.xml Wed Jun 11 16:14:24 2008
@@ -195,7 +195,10 @@
<para>
If the instance has a <literal>Version</literal> field,
OpenJPA will consider the object detached if the version field has a non-default
-value, and new otherwise.
+value, and new otherwise. Similarly, if the instance has
+<literal>GeneratedValue</literal> primary key fields, OpenJPA will consider the
+object detached if any of these fields have non-default values, and new
+otherwise.
</para>
<para>
When attaching null fields in these cases, OpenJPA cannot distinguish between a