You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2009/09/17 16:13:20 UTC
svn commit: r816205 - in /cayenne/sandbox/cayenne-serialization/src:
main/java/org/apache/cayenne/serialization/
main/java/org/apache/cayenne/serialization/xstream/
test/java/org/apache/cayenne/serialization/
test/java/org/apache/cayenne/serialization/...
Author: aadamchik
Date: Thu Sep 17 14:13:19 2009
New Revision: 816205
URL: http://svn.apache.org/viewvc?rev=816205&view=rev
Log:
prototyping (de)serializer based on XStream
callbacks support
Added:
cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/DeserializationCallback.java
- copied, changed from r816198, cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/SerializerStack.java
cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/SerializationCallback.java
- copied, changed from r816198, cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/SerializerStack.java
cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/PersistentDeserializeConverter.java
- copied, changed from r816198, cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/PersistentCloneUnmarshalConverter.java
cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/PersistentSerializeConverter.java
- copied, changed from r816198, cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/PersistentMarshalConverter.java
Removed:
cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/PersistentCloneUnmarshalConverter.java
cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/PersistentMarshalConverter.java
Modified:
cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/BaseSerializer.java
cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/Subgraph.java
cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/SubgraphNode.java
cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/DeserializerStack.java
cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/SerializerStack.java
cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/XStreamDeserializer.java
cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/XStreamSerializer.java
cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/SubgraphTest.java
cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/xstream/XStreamDeserializerTest.java
cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/xstream/XStreamSerializerTest.java
Modified: cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/BaseSerializer.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/BaseSerializer.java?rev=816205&r1=816204&r2=816205&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/BaseSerializer.java (original)
+++ cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/BaseSerializer.java Thu Sep 17 14:13:19 2009
@@ -1,3 +1,21 @@
+/*****************************************************************
+ * 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.serialization;
import java.io.OutputStream;
Copied: cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/DeserializationCallback.java (from r816198, cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/SerializerStack.java)
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/DeserializationCallback.java?p2=cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/DeserializationCallback.java&p1=cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/SerializerStack.java&r1=816198&r2=816205&rev=816205&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/SerializerStack.java (original)
+++ cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/DeserializationCallback.java Thu Sep 17 14:13:19 2009
@@ -16,34 +16,9 @@
* specific language governing permissions and limitations
* under the License.
****************************************************************/
-package org.apache.cayenne.serialization.xstream;
+package org.apache.cayenne.serialization;
-import org.apache.cayenne.serialization.Subgraph;
-import org.apache.cayenne.serialization.SubgraphNode;
+public interface DeserializationCallback {
-import com.thoughtworks.xstream.core.util.FastStack;
-
-/**
- * A single-threaded stack for {@link Subgraph} traversal.
- */
-class SerializerStack {
-
- private FastStack stack;
-
- public SerializerStack(SubgraphNode graphDescriptorRoot) {
- stack = new FastStack(graphDescriptorRoot.getMaxDepth());
- stack.push(graphDescriptorRoot);
- }
-
- public void pushNode(SubgraphNode node) {
- stack.push(node);
- }
-
- public void popNode() {
- stack.popSilently();
- }
-
- public SubgraphNode peekNode() {
- return (SubgraphNode) stack.peek();
- }
+ void postDeserialize(SubgraphNode node, Object object);
}
Copied: cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/SerializationCallback.java (from r816198, cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/SerializerStack.java)
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/SerializationCallback.java?p2=cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/SerializationCallback.java&p1=cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/SerializerStack.java&r1=816198&r2=816205&rev=816205&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/SerializerStack.java (original)
+++ cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/SerializationCallback.java Thu Sep 17 14:13:19 2009
@@ -16,34 +16,11 @@
* specific language governing permissions and limitations
* under the License.
****************************************************************/
-package org.apache.cayenne.serialization.xstream;
+package org.apache.cayenne.serialization;
-import org.apache.cayenne.serialization.Subgraph;
-import org.apache.cayenne.serialization.SubgraphNode;
+import org.apache.cayenne.query.Query;
-import com.thoughtworks.xstream.core.util.FastStack;
+public interface SerializationCallback {
-/**
- * A single-threaded stack for {@link Subgraph} traversal.
- */
-class SerializerStack {
-
- private FastStack stack;
-
- public SerializerStack(SubgraphNode graphDescriptorRoot) {
- stack = new FastStack(graphDescriptorRoot.getMaxDepth());
- stack.push(graphDescriptorRoot);
- }
-
- public void pushNode(SubgraphNode node) {
- stack.push(node);
- }
-
- public void popNode() {
- stack.popSilently();
- }
-
- public SubgraphNode peekNode() {
- return (SubgraphNode) stack.peek();
- }
+ Query relationshipQuery(SubgraphNode node, Object sourceObject);
}
Modified: cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/Subgraph.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/Subgraph.java?rev=816205&r1=816204&r2=816205&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/Subgraph.java (original)
+++ cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/Subgraph.java Thu Sep 17 14:13:19 2009
@@ -69,7 +69,7 @@
String token = tokens.nextToken();
if (tokens.hasMoreTokens()) {
- node = node.getOrAppendChild(token);
+ node = node.getChild(token, false);
} else {
// last token is the attribute name
node.excludeAttribute(token);
@@ -86,7 +86,7 @@
SubgraphNode node = rootNode;
while (tokens.hasMoreTokens()) {
- node = node.getOrAppendChild(tokens.nextToken());
+ node = node.getChild(tokens.nextToken(), true);
}
}
@@ -101,8 +101,36 @@
SubgraphNode node = rootNode;
while (tokens.hasMoreTokens()) {
String token = tokens.nextToken();
- node = node.getOrAppendChild(token);
+ node = node.getChild(token, true);
node.setSerializedByReference(!tokens.hasMoreTokens());
}
}
+
+ public void addDeserializationCallback(String path,
+ DeserializationCallback callback) {
+
+ StringTokenizer tokens = new StringTokenizer(path, ".");
+
+ SubgraphNode node = rootNode;
+ while (tokens.hasMoreTokens()) {
+ String token = tokens.nextToken();
+ node = node.getChild(token, false);
+ }
+
+ node.addDeserializationCallback(callback);
+ }
+
+ public void addSerializationCallback(String path,
+ SerializationCallback callback) {
+
+ StringTokenizer tokens = new StringTokenizer(path, ".");
+
+ SubgraphNode node = rootNode;
+ while (tokens.hasMoreTokens()) {
+ String token = tokens.nextToken();
+ node = node.getChild(token, false);
+ }
+
+ node.addSerializationCallback(callback);
+ }
}
Modified: cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/SubgraphNode.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/SubgraphNode.java?rev=816205&r1=816204&r2=816205&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/SubgraphNode.java (original)
+++ cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/SubgraphNode.java Thu Sep 17 14:13:19 2009
@@ -44,11 +44,17 @@
private Map<String, SubgraphNode> children;
private boolean serializedByReference;
private List<AttributeProperty> attributeProperties;
+ private List<SerializationCallback> serializationCallbacks;
+ private List<DeserializationCallback> deserializationCallbacks;
/**
* Creates a root subgraph node.
*/
SubgraphNode(ClassDescriptor classDescriptor) {
+
+ this.serializationCallbacks = new ArrayList<SerializationCallback>(3);
+ this.deserializationCallbacks = new ArrayList<DeserializationCallback>(
+ 3);
this.classDescriptor = classDescriptor;
// cache properties
@@ -74,21 +80,20 @@
this(incomingProperty.getTargetDescriptor());
this.incomingProperty = incomingProperty;
}
-
+
public int getMaxDepth() {
- if(children != null) {
+ if (children != null) {
int depth = 0;
- for(SubgraphNode child : children.values()) {
+ for (SubgraphNode child : children.values()) {
int childDepth = child.getMaxDepth();
-
- if(depth < childDepth) {
+
+ if (depth < childDepth) {
depth = childDepth;
}
}
-
+
return depth + 1;
- }
- else {
+ } else {
return 1;
}
}
@@ -104,38 +109,51 @@
void setSerializedByReference(boolean reference) {
this.serializedByReference = reference;
}
-
+
void excludeAttribute(String attributeName) {
Iterator<AttributeProperty> it = attributeProperties.iterator();
- while(it.hasNext()) {
+ while (it.hasNext()) {
AttributeProperty property = it.next();
- if(property.getName().equals(attributeName)) {
+ if (property.getName().equals(attributeName)) {
it.remove();
- break;
+ return;
}
}
+
+ throw new IllegalArgumentException(
+ "Attribute is either unmapped or was exlcuded before: "
+ + attributeName);
+ }
+
+ public SubgraphNode getChild(String name) {
+ return children != null ? children.get(name) : null;
}
- SubgraphNode getOrAppendChild(String path) {
+ SubgraphNode getChild(String name, boolean create) {
SubgraphNode child = null;
if (children != null) {
- child = children.get(path);
+ child = children.get(name);
} else {
children = new LinkedHashMap<String, SubgraphNode>();
}
if (child == null) {
- Property relationship = classDescriptor.getProperty(path);
+ if (!create) {
+ throw new IllegalArgumentException("Invalid child path: "
+ + name);
+ }
+
+ Property relationship = classDescriptor.getProperty(name);
if (relationship == null) {
- throw new IllegalArgumentException("Path '" + path
+ throw new IllegalArgumentException("Path '" + name
+ "' does not denote a mapped class property");
}
if (!(relationship instanceof ArcProperty)) {
- throw new IllegalArgumentException("Path '" + path
+ throw new IllegalArgumentException("Path '" + name
+ "' does not denote a mapped relationship property. "
+ "Is this an attribute?");
}
@@ -143,12 +161,20 @@
ArcProperty arc = (ArcProperty) relationship;
child = new SubgraphNode(arc);
- children.put(path, child);
+ children.put(name, child);
}
return child;
}
+ void addSerializationCallback(SerializationCallback callback) {
+ serializationCallbacks.add(callback);
+ }
+
+ void addDeserializationCallback(DeserializationCallback callback) {
+ deserializationCallbacks.add(callback);
+ }
+
public ClassDescriptor getClassDescriptor() {
return classDescriptor;
}
@@ -169,4 +195,12 @@
return children != null ? children.values() : Collections
.<SubgraphNode> emptyList();
}
+
+ public List<SerializationCallback> getSerializationCallbacks() {
+ return serializationCallbacks;
+ }
+
+ public List<DeserializationCallback> getDeserializationCallbacks() {
+ return deserializationCallbacks;
+ }
}
\ No newline at end of file
Modified: cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/DeserializerStack.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/DeserializerStack.java?rev=816205&r1=816204&r2=816205&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/DeserializerStack.java (original)
+++ cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/DeserializerStack.java Thu Sep 17 14:13:19 2009
@@ -18,49 +18,76 @@
****************************************************************/
package org.apache.cayenne.serialization.xstream;
+import org.apache.cayenne.PersistenceState;
+import org.apache.cayenne.Persistent;
import org.apache.cayenne.reflect.ArcProperty;
import org.apache.cayenne.reflect.ToManyProperty;
+import org.apache.cayenne.serialization.DeserializationCallback;
+import org.apache.cayenne.serialization.SubgraphNode;
import com.thoughtworks.xstream.core.util.FastStack;
class DeserializerStack {
- private FastStack stack;
+ private FastStack subgraphStack;
+ private FastStack objectStack;
private int counter;
- DeserializerStack() {
- stack = new FastStack(10);
+ DeserializerStack(SubgraphNode root) {
+ int maxDepth = root.getMaxDepth();
+ objectStack = new FastStack(maxDepth);
+ subgraphStack = new FastStack(maxDepth);
+ subgraphStack.push(root);
}
- int incrementCounter() {
- return ++counter;
- }
+ void pushObject(Object object) {
- void push(Object object) {
+ SubgraphNode node = (SubgraphNode) subgraphStack.peek();
// connect to parent
- Object[] peek = (Object[]) stack.peek();
- if (peek != null) {
+ ArcProperty incoming = node.getIncomingProperty();
+ if (incoming != null) {
+ Object peek = objectStack.peek();
- if (peek[1] instanceof ToManyProperty) {
- ((ToManyProperty) peek[1]).addTarget(peek[0], object, true);
+ if (incoming instanceof ToManyProperty) {
+ ((ToManyProperty) incoming).addTarget(peek, object, true);
} else {
- ((ArcProperty) peek[1]).writeProperty(peek[0], null, object);
+ incoming.writeProperty(peek, null, object);
}
}
- Object[] entry = new Object[2];
- entry[0] = object;
- stack.push(entry);
+ // apply callbacks
+ for (DeserializationCallback callback : node
+ .getDeserializationCallbacks()) {
+ callback.postDeserialize(node, object);
+ }
+
+ objectStack.push(object);
}
- void pop() {
- stack.popSilently();
+ int popObject() {
+ Persistent object = (Persistent) objectStack.pop();
+ if (object != null
+ && object.getPersistenceState() == PersistenceState.NEW) {
+ counter++;
+ }
+
+ return counter;
}
- void startRelationship(ArcProperty property) {
- Object[] peek = (Object[]) stack.peek();
- peek[1] = property;
+ boolean pushPath(String name) {
+
+ SubgraphNode child = ((SubgraphNode) subgraphStack.peek())
+ .getChild(name);
+ if (child == null) {
+ return false;
+ }
+
+ subgraphStack.push(child);
+ return true;
}
+ void popPath() {
+ subgraphStack.popSilently();
+ }
}
Copied: cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/PersistentDeserializeConverter.java (from r816198, cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/PersistentCloneUnmarshalConverter.java)
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/PersistentDeserializeConverter.java?p2=cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/PersistentDeserializeConverter.java&p1=cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/PersistentCloneUnmarshalConverter.java&r1=816198&r2=816205&rev=816205&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/PersistentCloneUnmarshalConverter.java (original)
+++ cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/PersistentDeserializeConverter.java Thu Sep 17 14:13:19 2009
@@ -27,6 +27,7 @@
import org.apache.cayenne.reflect.ClassDescriptor;
import org.apache.cayenne.reflect.Property;
import org.apache.cayenne.reflect.ToManyProperty;
+import org.apache.cayenne.serialization.SubgraphNode;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
@@ -34,22 +35,20 @@
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
-/**
- * "Clone" in {@link PersistentCloneUnmarshalConverter} means that ids of the
- * Persistent objects will be ignored, and new objects will be created.
- */
-class PersistentCloneUnmarshalConverter implements Converter {
+class PersistentDeserializeConverter implements Converter {
- private static final String TRAVERSAL_CONTEXT_KEY = PersistentCloneUnmarshalConverter.class
+ private static final String STACK_KEY = PersistentDeserializeConverter.class
.getName()
- + "_TRAVERSAL_CONTEXT";
+ + "_STACK";
private ObjectContext objectContext;
private int commitCountThreshold;
+ private SubgraphNode rootNode;
- public PersistentCloneUnmarshalConverter(ObjectContext objectContext,
- int commitCountThreshold) {
+ public PersistentDeserializeConverter(SubgraphNode rootNode,
+ ObjectContext objectContext, int commitCountThreshold) {
+ this.rootNode = rootNode;
this.objectContext = objectContext;
this.commitCountThreshold = commitCountThreshold;
}
@@ -83,9 +82,9 @@
// TODO: handle deleted objects that no longer exist...
if (object != null) {
- DeserializerStack stack = getDeserialierCounter(context);
- stack.push(object);
- stack.pop();
+ DeserializerStack stack = getStack(context);
+ stack.pushObject(object);
+ stack.popObject();
}
return object;
@@ -98,12 +97,12 @@
ClassDescriptor descriptor = objectContext.getEntityResolver()
.getClassDescriptor(entityName);
- DeserializerStack stack = getDeserialierCounter(context);
+ DeserializerStack stack = getStack(context);
Object object = descriptor.createObject();
objectContext.registerNewObject(object);
- stack.push(object);
+ stack.pushObject(object);
while (reader.hasMoreChildren()) {
reader.moveDown();
@@ -113,27 +112,31 @@
deserializeAttribute(reader, context, object,
(AttributeProperty) property);
} else {
- ArcProperty arc = (ArcProperty) property;
- stack.startRelationship(arc);
+ if (stack.pushPath(property.getName())) {
- if (arc.getRelationship().isToMany()) {
- deserializeToManyRelationship(reader, context, object,
- (ToManyProperty) arc);
- } else {
- deserializeToOneRelationship(reader, context, object, arc);
+ ArcProperty arc = (ArcProperty) property;
+ if (arc.getRelationship().isToMany()) {
+ deserializeToManyRelationship(reader, context, object,
+ (ToManyProperty) arc);
+ } else {
+ deserializeToOneRelationship(reader, context, object,
+ arc);
+ }
+
+ stack.popPath();
}
}
reader.moveUp();
}
- if (commitCountThreshold > 0
- && stack.incrementCounter() % commitCountThreshold == 0) {
+ int count = stack.popObject();
+
+ if (commitCountThreshold > 0 && count % commitCountThreshold == 0) {
objectContext.commitChanges();
}
- stack.pop();
return object;
}
@@ -152,9 +155,12 @@
Class<?> javaType = property.getTargetDescriptor().getObjectClass();
- reader.moveDown();
- context.convertAnother(parentObject, javaType);
- reader.moveUp();
+ // check for children to handle optional to-one
+ if (reader.hasMoreChildren()) {
+ reader.moveDown();
+ context.convertAnother(parentObject, javaType);
+ reader.moveUp();
+ }
}
private void deserializeToManyRelationship(HierarchicalStreamReader reader,
@@ -170,15 +176,14 @@
}
}
- private DeserializerStack getDeserialierCounter(UnmarshallingContext context) {
- DeserializerStack deserializerCounter = (DeserializerStack) context
- .get(TRAVERSAL_CONTEXT_KEY);
+ private DeserializerStack getStack(UnmarshallingContext context) {
+ DeserializerStack stack = (DeserializerStack) context.get(STACK_KEY);
- if (deserializerCounter == null) {
- deserializerCounter = new DeserializerStack();
- context.put(TRAVERSAL_CONTEXT_KEY, deserializerCounter);
+ if (stack == null) {
+ stack = new DeserializerStack(rootNode);
+ context.put(STACK_KEY, stack);
}
- return deserializerCounter;
+ return stack;
}
}
Copied: cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/PersistentSerializeConverter.java (from r816198, cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/PersistentMarshalConverter.java)
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/PersistentSerializeConverter.java?p2=cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/PersistentSerializeConverter.java&p1=cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/PersistentMarshalConverter.java&r1=816198&r2=816205&rev=816205&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/PersistentMarshalConverter.java (original)
+++ cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/PersistentSerializeConverter.java Thu Sep 17 14:13:19 2009
@@ -21,14 +21,18 @@
import org.apache.cayenne.CayenneException;
import org.apache.cayenne.CayenneRuntimeException;
import org.apache.cayenne.DataObject;
+import org.apache.cayenne.DataObjectUtils;
import org.apache.cayenne.DataRow;
+import org.apache.cayenne.ObjectContext;
import org.apache.cayenne.Persistent;
import org.apache.cayenne.access.DataContext;
import org.apache.cayenne.access.ResultIterator;
+import org.apache.cayenne.query.Query;
import org.apache.cayenne.query.RelationshipQuery;
import org.apache.cayenne.reflect.ArcProperty;
import org.apache.cayenne.reflect.AttributeProperty;
import org.apache.cayenne.reflect.Property;
+import org.apache.cayenne.serialization.SerializationCallback;
import org.apache.cayenne.serialization.Subgraph;
import org.apache.cayenne.serialization.SubgraphNode;
@@ -38,16 +42,16 @@
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
-class PersistentMarshalConverter<T> implements Converter {
+class PersistentSerializeConverter implements Converter {
- private static final String TRAVERSAL_CONTEXT_KEY = PersistentMarshalConverter.class
+ private static final String STACK_KEY = PersistentSerializeConverter.class
.getName()
- + "_TRAVERSAL_CONTEXT";
+ + "_STACK";
- private Subgraph<T> subgraph;
+ private Subgraph<?> subgraph;
private int statementFetchSize;
- public PersistentMarshalConverter(Subgraph<T> subgraph,
+ public PersistentSerializeConverter(Subgraph<?> subgraph,
int statementFetchSize) {
this.subgraph = subgraph;
this.statementFetchSize = statementFetchSize;
@@ -56,7 +60,7 @@
public void marshal(Object object, HierarchicalStreamWriter writer,
MarshallingContext context) {
- SerializerStack serializerContext = getSerializerStack(context);
+ SerializerStack serializerContext = getStack(context);
SubgraphNode node = serializerContext.peekNode();
@@ -76,13 +80,24 @@
serializerContext.pushNode(child);
+ Query query = null;
+ for (SerializationCallback callback : child
+ .getSerializationCallbacks()) {
+ query = callback.relationshipQuery(child, object);
+ if (query != null) {
+ break;
+ }
+ }
+
ArcProperty incoming = child.getIncomingProperty();
boolean byReference = child.isSerializedByReference();
if (incoming.getRelationship().isToMany()) {
- marshalToMany(object, incoming, writer, context, byReference);
+ marshalToMany(object, incoming, writer, context, byReference,
+ query);
} else {
- marshalToOne(object, incoming, writer, context, byReference);
+ marshalToOne(object, incoming, writer, context, byReference,
+ query);
}
serializerContext.popNode();
@@ -107,31 +122,47 @@
private void marshalToOne(Object object, ArcProperty arc,
HierarchicalStreamWriter writer, MarshallingContext context,
- boolean byReference) {
+ boolean byReference, Query query) {
- writer.startNode(arc.getName());
+ Persistent value = null;
- Persistent value = (Persistent) arc.readProperty(object);
+ if (query != null) {
+ ObjectContext objectContext = ((Persistent) object)
+ .getObjectContext();
+ value = (Persistent) DataObjectUtils.objectForQuery(objectContext,
+ query);
+ } else {
+ value = (Persistent) arc.readProperty(object);
+ }
+
+ // note that we don't even write an empty tag for NULL to-one. This may
+ // be a problem only if we allow non-reference nodes to be attached to
+ // reference-serialized nodes
if (value != null) {
+ writer.startNode(arc.getName());
context.convertAnother(byReference ? value.getObjectId() : value);
+ writer.endNode();
}
- writer.endNode();
}
private void marshalToMany(Object object, ArcProperty arc,
HierarchicalStreamWriter writer, MarshallingContext context,
- boolean byReference) {
+ boolean byReference, Query query) {
writer.startNode(arc.getName());
Persistent persistent = (Persistent) object;
- RelationshipQuery query = new RelationshipQuery(persistent
- .getObjectId(), arc.getName());
- // "fetchSize" is absolutely critical to avoid storing the entire
- // ResultSet in memory.
- query.setStatementFetchSize(statementFetchSize);
+ if (query == null) {
+ RelationshipQuery relationshipQuery = new RelationshipQuery(
+ persistent.getObjectId(), arc.getName());
+
+ // "fetchSize" is absolutely critical to avoid storing the entire
+ // ResultSet in memory.
+ relationshipQuery.setStatementFetchSize(statementFetchSize);
+ query = relationshipQuery;
+ }
DataContext dataContext = (DataContext) persistent.getObjectContext();
@@ -162,16 +193,15 @@
writer.endNode();
}
- private SerializerStack getSerializerStack(MarshallingContext context) {
- SerializerStack travsersalContext = (SerializerStack) context
- .get(TRAVERSAL_CONTEXT_KEY);
+ private SerializerStack getStack(MarshallingContext context) {
+ SerializerStack stack = (SerializerStack) context.get(STACK_KEY);
- if (travsersalContext == null) {
- travsersalContext = new SerializerStack(subgraph.getRootNode());
- context.put(TRAVERSAL_CONTEXT_KEY, travsersalContext);
+ if (stack == null) {
+ stack = new SerializerStack(subgraph.getRootNode());
+ context.put(STACK_KEY, stack);
}
- return travsersalContext;
+ return stack;
}
public Object unmarshal(HierarchicalStreamReader reader,
Modified: cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/SerializerStack.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/SerializerStack.java?rev=816205&r1=816204&r2=816205&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/SerializerStack.java (original)
+++ cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/SerializerStack.java Thu Sep 17 14:13:19 2009
@@ -30,9 +30,9 @@
private FastStack stack;
- public SerializerStack(SubgraphNode graphDescriptorRoot) {
- stack = new FastStack(graphDescriptorRoot.getMaxDepth());
- stack.push(graphDescriptorRoot);
+ public SerializerStack(SubgraphNode root) {
+ stack = new FastStack(root.getMaxDepth());
+ stack.push(root);
}
public void pushNode(SubgraphNode node) {
Modified: cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/XStreamDeserializer.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/XStreamDeserializer.java?rev=816205&r1=816204&r2=816205&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/XStreamDeserializer.java (original)
+++ cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/XStreamDeserializer.java Thu Sep 17 14:13:19 2009
@@ -42,8 +42,8 @@
int commitCountThreshold = isCommitting() ? getCommitCountThreshold()
: 0;
- xstream.registerConverter(new PersistentCloneUnmarshalConverter(
- context, commitCountThreshold));
+ xstream.registerConverter(new PersistentDeserializeConverter(
+ subgraph.getRootNode(), context, commitCountThreshold));
xstream.registerConverter(new ObjectIdConverter(context
.getEntityResolver()));
Modified: cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/XStreamSerializer.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/XStreamSerializer.java?rev=816205&r1=816204&r2=816205&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/XStreamSerializer.java (original)
+++ cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/XStreamSerializer.java Thu Sep 17 14:13:19 2009
@@ -40,7 +40,7 @@
XStream xstream = createXStream(subgraph.getRootNode()
.getClassDescriptor());
- xstream.registerConverter(new PersistentMarshalConverter<T>(subgraph,
+ xstream.registerConverter(new PersistentSerializeConverter(subgraph,
statementFetchSize));
xstream.registerConverter(new ObjectIdConverter(null));
Modified: cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/SubgraphTest.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/SubgraphTest.java?rev=816205&r1=816204&r2=816205&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/SubgraphTest.java (original)
+++ cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/SubgraphTest.java Thu Sep 17 14:13:19 2009
@@ -18,6 +18,7 @@
****************************************************************/
package org.apache.cayenne.serialization;
+import org.apache.cayenne.query.Query;
import org.apache.cayenne.serialization.persistent.Table1;
import org.apache.cayenne.serialization.persistent.Table2;
import org.apache.cayenne.serialization.unit.SerializationCase;
@@ -32,6 +33,53 @@
assertEquals(0, subgraph.getRootNode().getChildren().size());
}
+ public void testAddDerserializationCallback() {
+ Subgraph<Table2> subgraph = new Subgraph<Table2>(Table2.class,
+ newContext().getEntityResolver());
+ subgraph.addSerializeByReferencePath(Table2.TABLE1_PROPERTY);
+
+ SubgraphNode node = subgraph.getRootNode().getChild(
+ Table2.TABLE1_PROPERTY, false);
+
+ assertEquals(0, node.getSerializationCallbacks().size());
+ assertEquals(0, node.getDeserializationCallbacks().size());
+
+ subgraph.addDeserializationCallback(Table2.TABLE1_PROPERTY,
+ new DeserializationCallback() {
+ public void postDeserialize(SubgraphNode node, Object object) {
+ // noop
+ }
+ });
+
+ assertEquals(0, node.getSerializationCallbacks().size());
+ assertEquals(1, node.getDeserializationCallbacks().size());
+ }
+
+ public void testAddSerializationCallback() {
+ Subgraph<Table2> subgraph = new Subgraph<Table2>(Table2.class,
+ newContext().getEntityResolver());
+ subgraph.addSerializeByReferencePath(Table2.TABLE1_PROPERTY);
+
+ SubgraphNode node = subgraph.getRootNode().getChild(
+ Table2.TABLE1_PROPERTY, false);
+
+ assertEquals(0, node.getSerializationCallbacks().size());
+ assertEquals(0, node.getDeserializationCallbacks().size());
+
+ subgraph.addSerializationCallback(Table2.TABLE1_PROPERTY,
+ new SerializationCallback() {
+
+ public Query relationshipQuery(SubgraphNode node,
+ Object sourceObject) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+ });
+
+ assertEquals(1, node.getSerializationCallbacks().size());
+ assertEquals(0, node.getDeserializationCallbacks().size());
+ }
+
public void testAddSerializeByReferencePathToOne() {
Subgraph<Table2> subgraph = new Subgraph<Table2>(Table2.class,
newContext().getEntityResolver());
Modified: cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/xstream/XStreamDeserializerTest.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/xstream/XStreamDeserializerTest.java?rev=816205&r1=816204&r2=816205&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/xstream/XStreamDeserializerTest.java (original)
+++ cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/xstream/XStreamDeserializerTest.java Thu Sep 17 14:13:19 2009
@@ -27,7 +27,9 @@
import org.apache.cayenne.DataObjectUtils;
import org.apache.cayenne.ObjectContext;
import org.apache.cayenne.PersistenceState;
+import org.apache.cayenne.serialization.DeserializationCallback;
import org.apache.cayenne.serialization.Subgraph;
+import org.apache.cayenne.serialization.SubgraphNode;
import org.apache.cayenne.serialization.persistent.Table1;
import org.apache.cayenne.serialization.persistent.Table2;
import org.apache.cayenne.serialization.unit.SerializationCase;
@@ -182,4 +184,88 @@
assertTrue(names.contains("t22"));
}
+ public void testCallbackByReference() throws IOException {
+
+ ObjectContext context = newContext();
+ Table1 t11 = context.newObject(Table1.class);
+ t11.setName("t11");
+
+ Table2 t21 = context.newObject(Table2.class);
+ t21.setName("t21");
+ t21.setTable1(t11);
+
+ context.commitChanges();
+
+ final boolean[] callbackInvoked = new boolean[1];
+
+ Subgraph<Table2> subgraph = new Subgraph<Table2>(Table2.class, context
+ .getEntityResolver());
+ subgraph.addSerializeByReferencePath(Table2.TABLE1_PROPERTY);
+ subgraph.addDeserializationCallback(Table2.TABLE1_PROPERTY,
+ new DeserializationCallback() {
+ public void postDeserialize(SubgraphNode node, Object object) {
+ assertNotNull(node);
+ assertEquals(Table2.TABLE1_PROPERTY, node
+ .getIncomingProperty().getName());
+ assertNotNull(object);
+ assertTrue(object instanceof Table1);
+
+ callbackInvoked[0] = true;
+ }
+ });
+
+ XStreamDeserializer deserializer = new XStreamDeserializer();
+
+ int id = DataObjectUtils.intPKForObject(t11);
+ String xml = "<Table2><name>t21</name><table1><Table1 ref=\"true\"><PK>"
+ + id + "</PK></Table1></table1></Table2>";
+
+ InputStream in = new ByteArrayInputStream(xml.getBytes());
+ try {
+ deserializer.deserialize(context, subgraph, in);
+ } finally {
+ in.close();
+ }
+
+ assertTrue(callbackInvoked[0]);
+ }
+
+ public void testCallbackByValue() throws IOException {
+
+ ObjectContext context = newContext();
+
+ final boolean[] callbackInvoked = new boolean[1];
+
+ Subgraph<Table1> subgraph = new Subgraph<Table1>(Table1.class, context
+ .getEntityResolver());
+ subgraph.addSerializeByValuePath(Table1.TABLE2S_PROPERTY);
+ subgraph.addDeserializationCallback(Table1.TABLE2S_PROPERTY,
+ new DeserializationCallback() {
+ public void postDeserialize(SubgraphNode node, Object object) {
+ assertNotNull(node);
+ assertEquals(Table1.TABLE2S_PROPERTY, node
+ .getIncomingProperty().getName());
+ assertNotNull(object);
+ assertTrue(object instanceof Table2);
+
+ callbackInvoked[0] = true;
+ }
+ });
+
+ XStreamDeserializer deserializer = new XStreamDeserializer();
+
+ String xml = "<Table1><name>t11</name><table2s>"
+ + "<Table2><name>t21</name></Table2>"
+ + "<Table2><name>t22</name></Table2></table2s></Table1>";
+
+ InputStream in = new ByteArrayInputStream(xml.getBytes());
+ try {
+ deserializer.deserialize(context, subgraph, in);
+ } finally {
+ in.close();
+ }
+
+ assertTrue(callbackInvoked[0]);
+ }
+
}
Modified: cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/xstream/XStreamSerializerTest.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/xstream/XStreamSerializerTest.java?rev=816205&r1=816204&r2=816205&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/xstream/XStreamSerializerTest.java (original)
+++ cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/xstream/XStreamSerializerTest.java Thu Sep 17 14:13:19 2009
@@ -18,13 +18,18 @@
****************************************************************/
package org.apache.cayenne.serialization.xstream;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
import org.apache.cayenne.DataObjectUtils;
import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.query.Query;
+import org.apache.cayenne.serialization.SerializationCallback;
import org.apache.cayenne.serialization.Subgraph;
+import org.apache.cayenne.serialization.SubgraphNode;
import org.apache.cayenne.serialization.persistent.Table1;
import org.apache.cayenne.serialization.persistent.Table2;
import org.apache.cayenne.serialization.unit.SerializationCase;
@@ -175,9 +180,9 @@
assertEquals("<Table1><name>t11</name></Table1>", Util.stringFromFile(
f1).trim());
-
+
subgraph.excludeAttribute(Table1.NAME_PROPERTY);
-
+
File f2 = tempFile(".xml");
FileOutputStream out2 = new FileOutputStream(f2);
@@ -190,8 +195,48 @@
assertTrue(f2.isFile());
assertTrue(f2.length() > 0);
- assertEquals("<Table1/>", Util.stringFromFile(
- f2).trim());
-
+ assertEquals("<Table1/>", Util.stringFromFile(f2).trim());
+
}
+
+ public void testCallbackByValueToMany() throws IOException {
+
+ ObjectContext context = newContext();
+ Table1 t11 = context.newObject(Table1.class);
+ t11.setName("t11");
+
+ Table2 t21 = context.newObject(Table2.class);
+ t21.setName("t21");
+ t21.setTable1(t11);
+
+ context.commitChanges();
+
+ final boolean[] callbackInvoked = new boolean[1];
+
+ Subgraph<Table1> subgraph = new Subgraph<Table1>(Table1.class, context
+ .getEntityResolver());
+ subgraph.addSerializeByValuePath(Table1.TABLE2S_PROPERTY);
+ subgraph.addSerializationCallback(Table1.TABLE2S_PROPERTY,
+ new SerializationCallback() {
+ public Query relationshipQuery(SubgraphNode node,
+ Object sourceObject) {
+
+ callbackInvoked[0] = true;
+ return null;
+ }
+ });
+
+ XStreamSerializer serializer = new XStreamSerializer();
+ serializer.setCreatingCompactXML(true);
+
+ OutputStream out = new ByteArrayOutputStream();
+ try {
+ serializer.serialize(t11, subgraph, out);
+ } finally {
+ out.close();
+ }
+
+ assertTrue(callbackInvoked[0]);
+ }
+
}