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 53566875d..63444aef5 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 @@ -476,8 +476,7 @@ public class DetachManager _fullFM.reproxy(detSM); _fullFM.setStateManager(null); } else { - InstanceDetachFieldManager fm = new InstanceDetachFieldManager - (detachedPC, detSM); + InstanceDetachFieldManager fm = new InstanceDetachFieldManager(detachedPC, detSM); fm.setStateManager(sm); fm.detachFields(fields); } @@ -548,28 +547,28 @@ public class DetachManager * Unproxies second class object fields. */ public void reproxy(DetachedStateManager dsm) { - FieldMetaData[] fmds = sm.getMetaData().getFields(); - for (int i = 0; i < fmds.length; i++) { - switch (fmds[i].getDeclaredTypeCode()) { + for (FieldMetaData fmd : sm.getMetaData().getProxyFields()) { + switch (fmd.getDeclaredTypeCode()) { case JavaTypes.COLLECTION: case JavaTypes.MAP: // lrs proxies not detached - if (fmds[i].isLRS()) { + if (fmd.isLRS()) { objval = null; - sm.replaceField(getDetachedPersistenceCapable(), - this, i); + sm.replaceField(getDetachedPersistenceCapable(), this, fmd.getIndex()); break; } // no break case JavaTypes.CALENDAR: case JavaTypes.DATE: case JavaTypes.OBJECT: - sm.provideField(getDetachedPersistenceCapable(), this, i); + sm.provideField(getDetachedPersistenceCapable(), this, fmd.getIndex()); if (objval instanceof Proxy) { Proxy proxy = (Proxy) objval; if (proxy.getChangeTracker() != null) proxy.getChangeTracker().stopTracking(); - proxy.setOwner(dsm, (dsm == null) ? -1 : i); + proxy.setOwner(dsm, (dsm == null) ? -1 : fmd.getIndex()); + objval = proxy.copy(proxy); + sm.replaceField(getDetachedPersistenceCapable(), this, fmd.getIndex()); } } } @@ -711,8 +710,10 @@ 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-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detach/Entity20.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detach/Entity20.java new file mode 100644 index 000000000..b71144740 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detach/Entity20.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.openjpa.persistence.detach; + +import java.io.Serializable; +import java.sql.Date; +import java.sql.Time; +import java.sql.Timestamp; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + +@Entity +@Table(name="Entity20_detach") +public class Entity20 implements Serializable { + + private static final long serialVersionUID = 1L; + + @Id + private Integer id; + + @Column(name = "sqldate" ) + @Temporal(TemporalType.DATE) + private Date sqlDate; + + @Column(name = "sqltime") + @Temporal(TemporalType.TIME) + private Time sqlTime; + + @Column(name = "sqltimestamp") + @Temporal(TemporalType.TIMESTAMP) + private Timestamp sqlTimestamp; + + private String name; + + public Entity20() { + } + + public Entity20(int id) { + this.id = new Integer(id); + this.name = this.id.toString(); + Long time = System.currentTimeMillis(); + this.sqlTime = new Time(time); + this.sqlDate = new Date(time); + this.sqlTimestamp = new Timestamp(time); + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getId() { + return id; + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setDate(Date d) { + sqlDate = d; + } + + public Date getDate() { + return sqlDate; + } + + public void setTime(Time t) { + sqlTime = t; + } + + public Time getTime() { + return sqlTime; + } + + public void setTimestamp(Timestamp t) { + sqlTimestamp = t; + } + + public Timestamp getTimestamp() { + return sqlTimestamp; + } +} 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 new file mode 100644 index 000000000..836a6ba82 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detach/TestDetachNoProxy.java @@ -0,0 +1,262 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.openjpa.persistence.detach; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +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.test.SingleEMFTestCase; + +public class TestDetachNoProxy extends SingleEMFTestCase { + + private static final int numEntities = 3; + private static final String PROXY = new String("$proxy"); + 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.info("Before set, FlushBeforeDetach=" + compat.getFlushBeforeDetach()); + log.info("Before set, CopyOnDetach=" + compat.getCopyOnDetach()); + log.info("Before set, CascadeWithDetach=" + compat.getCascadeWithDetach()); + } + compat.setFlushBeforeDetach(false); + compat.setCopyOnDetach(false); + compat.setCascadeWithDetach(false); + if (log.isTraceEnabled()) { + log.info("After set, FlushBeforeDetach=" + compat.getFlushBeforeDetach()); + log.info("After set, CopyOnDetach=" + compat.getCopyOnDetach()); + log.info("After set, CascadeWithDetach=" + compat.getCascadeWithDetach()); + } + createEntities(numEntities); + } + + private void createEntities(int count) { + Entity20 e20 = null; + OpenJPAEntityManager em = emf.createEntityManager(); + em.getTransaction().begin(); + for (int i=0; i e20List = new ArrayList(numEntities); + for (int i=0; i e20ListCopy = new ArrayList(em.detachAll(e20List)); + // em.detachAll(e20List); // for some reason calling with Collection causes a NPE, so use Object[] instead + em.detachAll(e20List.get(0), e20List.get(1), e20List.get(2)); + for (int i=0; i e20List = new ArrayList(numEntities); + for (int i=0; i