You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by an...@apache.org on 2010/03/21 15:30:02 UTC

svn commit: r925773 - in /cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src: main/java/org/apache/cayenne/remote/hessian/ main/java/org/apache/cayenne/remote/hessian/service/ main/java/org/apache/cayenne/util/ test/java/org/apache/cayenne/rem...

Author: andrey
Date: Sun Mar 21 14:30:02 2010
New Revision: 925773

URL: http://svn.apache.org/viewvc?rev=925773&view=rev
Log:
CAY-1404 ClassCastException during ObjectDetachOperation

Added:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/ROPPrefetchToManyMapTest.java
Modified:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/hessian/ClientSerializerFactory.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/hessian/service/ServerSerializerFactory.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/util/DeepMergeOperation.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/util/ObjectDetachOperation.java

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/hessian/ClientSerializerFactory.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/hessian/ClientSerializerFactory.java?rev=925773&r1=925772&r2=925773&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/hessian/ClientSerializerFactory.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/hessian/ClientSerializerFactory.java Sun Mar 21 14:30:02 2010
@@ -19,11 +19,9 @@
 
 package org.apache.cayenne.remote.hessian;
 
-import java.util.HashMap;
-import java.util.Map;
-
 import org.apache.cayenne.DataRow;
 import org.apache.cayenne.util.PersistentObjectList;
+import org.apache.cayenne.util.PersistentObjectMap;
 
 import com.caucho.hessian.io.AbstractSerializerFactory;
 import com.caucho.hessian.io.Deserializer;
@@ -38,8 +36,9 @@ import com.caucho.hessian.io.Serializer;
  */
 class ClientSerializerFactory extends AbstractSerializerFactory {
 
-    private Map<Class, Deserializer> deserializers;
     private Deserializer dataRowDeserializer;
+    private Deserializer listDeserializer;
+    private Deserializer mapDeserializer;
 
     @Override
     public Serializer getSerializer(Class cl) throws HessianProtocolException {
@@ -48,28 +47,22 @@ class ClientSerializerFactory extends Ab
 
     @Override
     public Deserializer getDeserializer(Class cl) throws HessianProtocolException {
-        Deserializer deserializer = null;
-
+        //turns out Hessian uses its own (incorrect) serialization mechanism for maps
+        if (PersistentObjectMap.class.isAssignableFrom(cl)) {
+            if (mapDeserializer == null) {
+                mapDeserializer = new JavaDeserializer(cl);
+            }
+            return mapDeserializer;
+        }
+        
         if (PersistentObjectList.class.isAssignableFrom(cl)) {
-
-            synchronized (this) {
-
-                if (deserializers != null) {
-                    deserializer = deserializers.get(cl);
-                }
-
-                if (deserializer == null) {
-                    deserializer = new JavaDeserializer(cl);
-
-                    if (deserializers == null) {
-                        deserializers = new HashMap<Class, Deserializer>();
-                    }
-
-                    deserializers.put(cl, deserializer);
-                }
+            if (listDeserializer == null) {
+                listDeserializer = new JavaDeserializer(cl);
             }
+            return listDeserializer;
         }
-        else if(DataRow.class.isAssignableFrom(cl)) {
+        
+        if(DataRow.class.isAssignableFrom(cl)) {
             if(dataRowDeserializer == null) {
                 dataRowDeserializer = new DataRowDeserializer();
             }
@@ -77,6 +70,6 @@ class ClientSerializerFactory extends Ab
             return dataRowDeserializer;
         }
 
-        return deserializer;
+        return null;
     }
 }

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/hessian/service/ServerSerializerFactory.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/hessian/service/ServerSerializerFactory.java?rev=925773&r1=925772&r2=925773&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/hessian/service/ServerSerializerFactory.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/hessian/service/ServerSerializerFactory.java Sun Mar 21 14:30:02 2010
@@ -21,10 +21,12 @@ package org.apache.cayenne.remote.hessia
 
 import org.apache.cayenne.DataRow;
 import org.apache.cayenne.util.PersistentObjectList;
+import org.apache.cayenne.util.PersistentObjectMap;
 
 import com.caucho.hessian.io.AbstractSerializerFactory;
 import com.caucho.hessian.io.Deserializer;
 import com.caucho.hessian.io.HessianProtocolException;
+import com.caucho.hessian.io.JavaSerializer;
 import com.caucho.hessian.io.Serializer;
 
 /**
@@ -35,6 +37,7 @@ import com.caucho.hessian.io.Serializer;
 class ServerSerializerFactory extends AbstractSerializerFactory {
     private ServerPersistentObjectListSerializer persistentObjectListSerializer;
     private ServerDataRowSerializer dataRowSerilaizer;
+    private Serializer javaSerializer;
 
     ServerSerializerFactory() {
         this.persistentObjectListSerializer = new ServerPersistentObjectListSerializer();
@@ -50,6 +53,13 @@ class ServerSerializerFactory extends Ab
         else if (DataRow.class.isAssignableFrom(cl)) {
             return dataRowSerilaizer;
         }
+        //turns out Hessian uses its own (incorrect) serialization mechanism for maps
+        else if (PersistentObjectMap.class.isAssignableFrom(cl)) {
+            if (javaSerializer == null) {
+                javaSerializer = new JavaSerializer(cl);
+            }
+            return javaSerializer;
+        }
 
         return null;
     }

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/util/DeepMergeOperation.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/util/DeepMergeOperation.java?rev=925773&r1=925772&r2=925773&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/util/DeepMergeOperation.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/util/DeepMergeOperation.java Sun Mar 21 14:30:02 2010
@@ -22,8 +22,8 @@ package org.apache.cayenne.util;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.Map;
+import java.util.Map.Entry;
 
 import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.ObjectContext;
@@ -32,6 +32,7 @@ import org.apache.cayenne.Persistent;
 import org.apache.cayenne.reflect.AttributeProperty;
 import org.apache.cayenne.reflect.ClassDescriptor;
 import org.apache.cayenne.reflect.PropertyVisitor;
+import org.apache.cayenne.reflect.ToManyMapProperty;
 import org.apache.cayenne.reflect.ToManyProperty;
 import org.apache.cayenne.reflect.ToOneProperty;
 
@@ -99,21 +100,38 @@ public class DeepMergeOperation {
 
             public boolean visitToMany(ToManyProperty property) {
                 if (!property.isFault(source)) {
-                    Collection collection = (Collection) property.readProperty(source);
-
-                    Collection targetCollection = new ArrayList(collection.size());
-
-                    Iterator it = collection.iterator();
-                    while (it.hasNext()) {
-                        Object destinationSource = it.next();
-                        Object destinationTarget = destinationSource != null ? merge(
-                                destinationSource,
-                                property.getTargetDescriptor()) : null;
-
-                        targetCollection.add(destinationTarget);
+                    Object value = property.readProperty(source);
+                    Object targetValue; 
+                    
+                    if (property instanceof ToManyMapProperty) {
+                        Map<?, ?> map = (Map) value;
+                        Map targetMap = new HashMap();
+                        
+                        for (Entry entry : map.entrySet()) {
+                            Object destinationSource = entry.getValue();
+                            Object destinationTarget = destinationSource != null
+                                ? merge(destinationSource, property.getTargetDescriptor())
+                                    : null;
+
+                            targetMap.put(entry.getKey(), destinationTarget);
+                        }
+                        targetValue = targetMap;
+                    }
+                    else {
+                        Collection collection = (Collection) value;
+                        Collection targetCollection = new ArrayList(collection.size());
+
+                        for (Object destinationSource : collection) {
+                            Object destinationTarget = destinationSource != null
+                                    ? merge(destinationSource, property.getTargetDescriptor())
+                                    : null;
+
+                            targetCollection.add(destinationTarget);
+                        }
+                        targetValue = targetCollection;
                     }
 
-                    property.writePropertyDirectly(target, null, targetCollection);
+                    property.writePropertyDirectly(target, null, targetValue);
                 }
 
                 return true;

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/util/ObjectDetachOperation.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/util/ObjectDetachOperation.java?rev=925773&r1=925772&r2=925773&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/util/ObjectDetachOperation.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/util/ObjectDetachOperation.java Sun Mar 21 14:30:02 2010
@@ -22,8 +22,8 @@ package org.apache.cayenne.util;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.Map;
+import java.util.Map.Entry;
 
 import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.ObjectId;
@@ -34,6 +34,7 @@ import org.apache.cayenne.reflect.Attrib
 import org.apache.cayenne.reflect.ClassDescriptor;
 import org.apache.cayenne.reflect.Property;
 import org.apache.cayenne.reflect.PropertyVisitor;
+import org.apache.cayenne.reflect.ToManyMapProperty;
 import org.apache.cayenne.reflect.ToManyProperty;
 import org.apache.cayenne.reflect.ToOneProperty;
 
@@ -128,25 +129,42 @@ public class ObjectDetachOperation {
                     PrefetchTreeNode child = prefetchTree.getNode(property.getName());
 
                     if (child != null) {
-                        Collection collection = (Collection) property
-                                .readProperty(source);
-
-                        Collection targetCollection = new ArrayList(collection.size());
-
-                        Iterator it = collection.iterator();
-                        while (it.hasNext()) {
-                            Object destinationSource = it.next();
-                            Object destinationTarget = destinationSource != null
+                        Object value = property.readProperty(source);
+                        Object targetValue; 
+                        
+                        if (property instanceof ToManyMapProperty) {
+                            Map<?, ?> map = (Map) value;
+                            Map targetMap = new HashMap();
+                            
+                            for (Entry entry : map.entrySet()) {
+                                Object destinationSource = entry.getValue();
+                                Object destinationTarget = destinationSource != null
                                     ? detach(destinationSource, property
-                                            .getTargetDescriptor(), child)
-                                    : null;
+                                        .getTargetDescriptor(), child)
+                                        : null;
 
-                            targetCollection.add(destinationTarget);
+                                targetMap.put(entry.getKey(), destinationTarget);
+                            }
+                            targetValue = targetMap;
+                        }
+                        else {
+                            Collection collection = (Collection) value;
+                            Collection targetCollection = new ArrayList(collection.size());
+    
+                            for (Object destinationSource : collection) {
+                                Object destinationTarget = destinationSource != null
+                                        ? detach(destinationSource, property
+                                                .getTargetDescriptor(), child)
+                                        : null;
+    
+                                targetCollection.add(destinationTarget);
+                            }
+                            targetValue = targetCollection;
                         }
 
                         ToManyProperty targetProperty = (ToManyProperty) targetDescriptor
                                 .getProperty(property.getName());
-                        targetProperty.writeProperty(target, null, targetCollection);
+                        targetProperty.writeProperty(target, null, targetValue);
                     }
                 }
 

Added: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/ROPPrefetchToManyMapTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/ROPPrefetchToManyMapTest.java?rev=925773&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/ROPPrefetchToManyMapTest.java (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/ROPPrefetchToManyMapTest.java Sun Mar 21 14:30:02 2010
@@ -0,0 +1,53 @@
+/*****************************************************************
+ *   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.cayenne.remote;
+
+import org.apache.cayenne.Cayenne;
+import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.query.RefreshQuery;
+import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.testdo.mt.ClientMtMapToMany;
+import org.apache.cayenne.testdo.mt.ClientMtMapToManyTarget;
+
+public class ROPPrefetchToManyMapTest extends RemoteCayenneCase {
+    public void test() throws Exception {
+        deleteTestData();
+        ObjectContext context = createROPContext();
+        
+        ClientMtMapToMany map = context.newObject(ClientMtMapToMany.class);
+        ClientMtMapToManyTarget target = context.newObject(ClientMtMapToManyTarget.class);
+        target.setMapToMany(map);
+        context.commitChanges();
+        
+        context.performQuery(new RefreshQuery());
+        
+        SelectQuery query = new SelectQuery(ClientMtMapToMany.class);
+        query.addPrefetch("targets");
+        
+        map = (ClientMtMapToMany) Cayenne.objectForQuery(context, query);
+        
+        try {
+            blockQueries();
+            assertEquals(map.getTargets().size(), 1);
+        }
+        finally {
+            unblockQueries();
+        }
+    }
+}