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/16 00:05:40 UTC

svn commit: r815515 - in /cayenne/sandbox/cayenne-serialization: ./ src/main/java/org/apache/cayenne/serialization/xstream/ src/test/ src/test/java/ src/test/java/org/ src/test/java/org/apache/ src/test/java/org/apache/cayenne/ src/test/java/org/apache...

Author: aadamchik
Date: Tue Sep 15 22:05:39 2009
New Revision: 815515

URL: http://svn.apache.org/viewvc?rev=815515&view=rev
Log:
prototyping (de)serializer based on XStream:

unit tests
deserialization by ref

Added:
    cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/Attributes.java
    cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/CompactXPPDriver.java
      - copied, changed from r814869, cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/ObjectIdMarshalConverter.java
    cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/ObjectIdConverter.java
    cayenne/sandbox/cayenne-serialization/src/test/
    cayenne/sandbox/cayenne-serialization/src/test/java/
    cayenne/sandbox/cayenne-serialization/src/test/java/org/
    cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/
    cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/
    cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/
    cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/BaseDeserializerTest.java
      - copied, changed from r814869, 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/persistent/
    cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/Serialization.java
      - copied, changed from r814869, 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/persistent/Table1.java
    cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/Table2.java
    cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/auto/
    cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/auto/_Serialization.java
    cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/auto/_Table1.java
    cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/auto/_Table2.java
    cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/unit/
    cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/unit/SerializationCase.java
    cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/xstream/
    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
    cayenne/sandbox/cayenne-serialization/src/test/resources/
    cayenne/sandbox/cayenne-serialization/src/test/resources/cayenne.xml
    cayenne/sandbox/cayenne-serialization/src/test/resources/serialization.driver.xml
    cayenne/sandbox/cayenne-serialization/src/test/resources/serialization.map.xml
Removed:
    cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/ObjectIdMarshalConverter.java
    cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/XStreamUtil.java
Modified:
    cayenne/sandbox/cayenne-serialization/pom.xml
    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
    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

Modified: cayenne/sandbox/cayenne-serialization/pom.xml
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/pom.xml?rev=815515&r1=815514&r2=815515&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-serialization/pom.xml (original)
+++ cayenne/sandbox/cayenne-serialization/pom.xml Tue Sep 15 22:05:39 2009
@@ -41,6 +41,11 @@
 			<artifactId>xstream</artifactId>
 			<version>1.3.1</version>
 		</dependency>
+		<dependency>
+			<groupId>hsqldb</groupId>
+			<artifactId>hsqldb</artifactId>
+			<scope>test</scope>
+		</dependency>
 	</dependencies>
 	<build>
 		<plugins>

Added: cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/Attributes.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/Attributes.java?rev=815515&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/Attributes.java (added)
+++ cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/Attributes.java Tue Sep 15 22:05:39 2009
@@ -0,0 +1,23 @@
+/*****************************************************************
+ *   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.xstream;
+
+enum Attributes {
+	ref
+}

Copied: cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/CompactXPPDriver.java (from r814869, cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/ObjectIdMarshalConverter.java)
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/CompactXPPDriver.java?p2=cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/CompactXPPDriver.java&p1=cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/ObjectIdMarshalConverter.java&r1=814869&r2=815515&rev=815515&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/ObjectIdMarshalConverter.java (original)
+++ cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/CompactXPPDriver.java Tue Sep 15 22:05:39 2009
@@ -18,37 +18,26 @@
  ****************************************************************/
 package org.apache.cayenne.serialization.xstream;
 
-import java.util.Map;
+import java.io.Writer;
 
-import org.apache.cayenne.ObjectId;
-
-import com.thoughtworks.xstream.converters.Converter;
-import com.thoughtworks.xstream.converters.MarshallingContext;
-import com.thoughtworks.xstream.converters.UnmarshallingContext;
-import com.thoughtworks.xstream.io.HierarchicalStreamReader;
 import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
+import com.thoughtworks.xstream.io.xml.CompactWriter;
+import com.thoughtworks.xstream.io.xml.XmlFriendlyReplacer;
+import com.thoughtworks.xstream.io.xml.XppDriver;
 
-class ObjectIdMarshalConverter implements Converter {
-
-	public void marshal(Object source, HierarchicalStreamWriter writer,
-			MarshallingContext context) {
-
-		ObjectId id = (ObjectId) source;
-		for (Map.Entry<String, Object> entry : id.getIdSnapshot().entrySet()) {
+class CompactXPPDriver extends XppDriver {
 
-			writer.startNode(entry.getKey());
-			context.convertAnother(entry.getValue());
-			writer.endNode();
-		}
+	public CompactXPPDriver() {
+		super();
 	}
 
-	public Object unmarshal(HierarchicalStreamReader reader,
-			UnmarshallingContext context) {
-		throw new UnsupportedOperationException();
+	public CompactXPPDriver(XmlFriendlyReplacer replacer) {
+		super(replacer);
 	}
 
-	public boolean canConvert(Class type) {
-		return ObjectId.class.isAssignableFrom(type);
+	@Override
+	public HierarchicalStreamWriter createWriter(Writer out) {
+		return new CompactWriter(out, xmlFriendlyReplacer());
 	}
 
 }

Added: cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/ObjectIdConverter.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/ObjectIdConverter.java?rev=815515&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/ObjectIdConverter.java (added)
+++ cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/ObjectIdConverter.java Tue Sep 15 22:05:39 2009
@@ -0,0 +1,139 @@
+/*****************************************************************
+ *   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.xstream;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.cayenne.ObjectId;
+import org.apache.cayenne.dba.TypesMapping;
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.EntityResolver;
+import org.apache.cayenne.map.ObjAttribute;
+import org.apache.cayenne.reflect.AttributeProperty;
+import org.apache.cayenne.reflect.ClassDescriptor;
+import org.apache.cayenne.reflect.Property;
+import org.apache.cayenne.util.Util;
+
+import com.thoughtworks.xstream.converters.Converter;
+import com.thoughtworks.xstream.converters.MarshallingContext;
+import com.thoughtworks.xstream.converters.UnmarshallingContext;
+import com.thoughtworks.xstream.io.HierarchicalStreamReader;
+import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
+
+class ObjectIdConverter implements Converter {
+
+	private EntityResolver entityResolver;
+	private Map<String, Map<String, Class<?>>> idTypesMap;
+
+	ObjectIdConverter(EntityResolver entityResolver) {
+		this.entityResolver = entityResolver;
+		this.idTypesMap = new ConcurrentHashMap<String, Map<String, Class<?>>>();
+	}
+
+	public void marshal(Object source, HierarchicalStreamWriter writer,
+			MarshallingContext context) {
+
+		ObjectId id = (ObjectId) source;
+		writer.startNode(id.getEntityName());
+		writer.addAttribute(Attributes.ref.name(), "true");
+
+		for (Map.Entry<String, Object> entry : id.getIdSnapshot().entrySet()) {
+
+			writer.startNode(entry.getKey());
+			context.convertAnother(entry.getValue());
+			writer.endNode();
+		}
+		writer.endNode();
+	}
+
+	public Object unmarshal(HierarchicalStreamReader reader,
+			UnmarshallingContext context) {
+
+		String entityName = reader.getNodeName();
+
+		Map<String, Class<?>> idTypeMap = getIdTypesMap(entityName);
+
+		Map<String, Object> id = new HashMap<String, Object>();
+		while (reader.hasMoreChildren()) {
+			reader.moveDown();
+
+			String key = reader.getNodeName();
+
+			Object value = context.convertAnother(id, idTypeMap.get(key));
+			id.put(key, value);
+
+			reader.moveUp();
+		}
+
+		return new ObjectId(entityName, id);
+	}
+
+	public boolean canConvert(Class type) {
+		return ObjectId.class.isAssignableFrom(type);
+	}
+
+	private Map<String, Class<?>> getIdTypesMap(String entityName) {
+
+		Map<String, Class<?>> typesMap = idTypesMap.get(entityName);
+
+		if (typesMap == null) {
+			typesMap = new HashMap<String, Class<?>>();
+			ClassDescriptor descriptor = entityResolver
+					.getClassDescriptor(entityName);
+
+			Iterator<Property> mappedIdProperties = descriptor
+					.getIdProperties();
+			while (mappedIdProperties.hasNext()) {
+				AttributeProperty property = (AttributeProperty) mappedIdProperties
+						.next();
+
+				ObjAttribute attribute = property.getAttribute();
+				typesMap.put(attribute.getDbAttributeName(), attribute
+						.getJavaClass());
+			}
+
+			DbEntity dbEntity = descriptor.getEntity().getDbEntity();
+			if (dbEntity != null) {
+				for (DbAttribute attribute : dbEntity.getPrimaryKeys()) {
+					if (!typesMap.containsKey(attribute.getName())) {
+						String type = TypesMapping.getJavaBySqlType(attribute
+								.getType(), attribute.getMaxLength(), attribute
+								.getScale());
+						try {
+							typesMap.put(attribute.getName(), Util
+									.getJavaClass(type));
+						} catch (ClassNotFoundException e) {
+							throw new IllegalStateException("Invalid type: "
+									+ type, e);
+						}
+					}
+				}
+			}
+
+			idTypesMap.put(entityName, typesMap);
+		}
+
+		return typesMap;
+	}
+
+}

Modified: 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/PersistentCloneUnmarshalConverter.java?rev=815515&r1=815514&r2=815515&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/PersistentCloneUnmarshalConverter.java Tue Sep 15 22:05:39 2009
@@ -18,13 +18,14 @@
  ****************************************************************/
 package org.apache.cayenne.serialization.xstream;
 
+import org.apache.cayenne.DataObjectUtils;
 import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.ObjectId;
 import org.apache.cayenne.Persistent;
+import org.apache.cayenne.reflect.ArcProperty;
 import org.apache.cayenne.reflect.AttributeProperty;
 import org.apache.cayenne.reflect.ClassDescriptor;
-import org.apache.cayenne.reflect.PropertyVisitor;
-import org.apache.cayenne.reflect.ToManyProperty;
-import org.apache.cayenne.reflect.ToOneProperty;
+import org.apache.cayenne.reflect.Property;
 
 import com.thoughtworks.xstream.converters.Converter;
 import com.thoughtworks.xstream.converters.MarshallingContext;
@@ -36,10 +37,6 @@
  * "Clone" in {@link PersistentCloneUnmarshalConverter} means that ids of the
  * Persistent objects will be ignored, and new objects will be created.
  */
-// TODO: use Subgraph to follow the stack instead of going directly to Cayenne
-// metadata. This will ensure performance as well as alignment with the subgraph
-// mapping... (or maybe we don't care to even have a subgraph, and just
-// deserialize what's coming in??)
 class PersistentCloneUnmarshalConverter implements Converter {
 
 	private static final String TRAVERSAL_CONTEXT_KEY = PersistentCloneUnmarshalConverter.class
@@ -60,39 +57,62 @@
 		return Persistent.class.isAssignableFrom(objectClass);
 	}
 
-	public Object unmarshal(final HierarchicalStreamReader reader,
-			final UnmarshallingContext context) {
+	public void marshal(Object source, HierarchicalStreamWriter writer,
+			MarshallingContext context) {
+		throw new UnsupportedOperationException();
+	}
 
-		String entityName = reader.getNodeName();
+	public Object unmarshal(HierarchicalStreamReader reader,
+			UnmarshallingContext context) {
+
+		String ref = reader.getAttribute(Attributes.ref.name());
+		if ("true".equals(ref)) {
+			return deserializeExisting(reader, context);
+		} else {
+			return deserializeNew(reader, context);
+		}
+	}
 
+	private Object deserializeExisting(HierarchicalStreamReader reader,
+			UnmarshallingContext context) {
+
+		ObjectId id = (ObjectId) context.convertAnother(null, ObjectId.class);
+
+		return DataObjectUtils.objectForPK(objectContext, id);
+		// TODO: handle deleted objects that no longer exist...
+	}
+
+	private Object deserializeNew(HierarchicalStreamReader reader,
+			UnmarshallingContext context) {
+
+		String entityName = reader.getNodeName();
 		ClassDescriptor descriptor = objectContext.getEntityResolver()
 				.getClassDescriptor(entityName);
 
-		final Object object = descriptor.createObject();
-		
+		Object object = descriptor.createObject();
 		objectContext.registerNewObject(object);
 
 		DeserializerCounter deserializerCounter = getDeserialierCounter(context);
 
-		descriptor.visitProperties(new PropertyVisitor() {
-			public boolean visitAttribute(AttributeProperty property) {
-				reader.moveDown();
-				Object value = context.convertAnother(object, property
-						.getAttribute().getJavaClass());
-				reader.moveUp();
+		while (reader.hasMoreChildren()) {
+			reader.moveDown();
 
-				property.writeProperty(object, null, value);
-				return true;
+			Property property = descriptor.getProperty(reader.getNodeName());
+			if (property instanceof AttributeProperty) {
+				deserializeAttribute(reader, context, object,
+						(AttributeProperty) property);
+			} else {
+				ArcProperty arc = (ArcProperty) property;
+
+				if (arc.getRelationship().isToMany()) {
+					deserializeToManyRelationship(reader, context, object, arc);
+				} else {
+					deserializeToOneRelationship(reader, context, object, arc);
+				}
 			}
 
-			public boolean visitToMany(ToManyProperty property) {
-				return true;
-			}
-
-			public boolean visitToOne(ToOneProperty property) {
-				return true;
-			}
-		});
+			reader.moveUp();
+		}
 
 		if (commitCountThreshold > 0
 				&& deserializerCounter.incrementCounter()
@@ -103,9 +123,34 @@
 		return object;
 	}
 
-	public void marshal(Object source, HierarchicalStreamWriter writer,
-			MarshallingContext context) {
-		throw new UnsupportedOperationException();
+	private void deserializeAttribute(HierarchicalStreamReader reader,
+			UnmarshallingContext context, Object parentObject,
+			AttributeProperty property) {
+
+		Class<?> javaType = property.getAttribute().getJavaClass();
+		Object value = context.convertAnother(parentObject, javaType);
+		property.writeProperty(parentObject, null, value);
+	}
+
+	private void deserializeToOneRelationship(HierarchicalStreamReader reader,
+			UnmarshallingContext context, Object parentObject,
+			ArcProperty property) {
+
+		Class<?> javaType = property.getTargetDescriptor().getObjectClass();
+
+		reader.moveDown();
+
+		Object value = context.convertAnother(parentObject, javaType);
+		property.writeProperty(parentObject, null, value);
+
+		reader.moveUp();
+	}
+
+	private void deserializeToManyRelationship(HierarchicalStreamReader reader,
+			UnmarshallingContext context, Object parentObject,
+			ArcProperty property) {
+
+		throw new UnsupportedOperationException("TODO");
 	}
 
 	private DeserializerCounter getDeserialierCounter(

Modified: 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/PersistentMarshalConverter.java?rev=815515&r1=815514&r2=815515&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/PersistentMarshalConverter.java Tue Sep 15 22:05:39 2009
@@ -60,6 +60,13 @@
 
 		SubgraphNode node = serializerContext.peekNode();
 
+		// don't generate tags for the root node, as they are generated via the
+		// 'alias' mechanism
+		if (node.getIncomingProperty() != null) {
+			Persistent persistent = (Persistent) object;
+			writer.startNode(persistent.getObjectId().getEntityName());
+		}
+
 		for (AttributeProperty property : node.getAttributeProperties()) {
 			marshalAttribute(object, property, writer, context);
 		}
@@ -70,22 +77,20 @@
 			serializerContext.pushNode(child);
 
 			ArcProperty incoming = child.getIncomingProperty();
-			if (child.isSerializedByReference()) {
-				if (incoming.getRelationship().isToMany()) {
-					marshalToManyReference(object, incoming, writer, context);
-				} else {
-					marshalToOneReference(object, incoming, writer, context);
-				}
+			boolean byReference = child.isSerializedByReference();
+
+			if (incoming.getRelationship().isToMany()) {
+				marshalToMany(object, incoming, writer, context, byReference);
 			} else {
-				if (incoming.getRelationship().isToMany()) {
-					marshalToMany(object, incoming, writer, context);
-				} else {
-					marshalToOne(object, incoming, writer, context);
-				}
+				marshalToOne(object, incoming, writer, context, byReference);
 			}
 
 			serializerContext.popNode();
 		}
+
+		if (node.getIncomingProperty() != null) {
+			writer.endNode();
+		}
 	}
 
 	private void marshalAttribute(Object object, Property property,
@@ -100,45 +105,23 @@
 		}
 	}
 
-	private void marshalToOneReference(Object object, ArcProperty arc,
-			HierarchicalStreamWriter writer, MarshallingContext context) {
-
-		Persistent value = (Persistent) arc.readProperty(object);
-
-		if (value != null) {
-
-			SerializerStack serializerStack = getSerializerStack(context);
-			writer.startNode(arc.getName());
-			writer.startNode(serializerStack.getCayenneNamespace() + ":ref");
-			context.convertAnother(value.getObjectId());
-			writer.endNode();
-			writer.endNode();
-		}
-	}
-
 	private void marshalToOne(Object object, ArcProperty arc,
-			HierarchicalStreamWriter writer, MarshallingContext context) {
+			HierarchicalStreamWriter writer, MarshallingContext context,
+			boolean byReference) {
 
 		writer.startNode(arc.getName());
 
 		Persistent value = (Persistent) arc.readProperty(object);
-
 		if (value != null) {
-			writer.startNode(value.getObjectId().getEntityName());
-			context.convertAnother(value);
-			writer.endNode();
+			context.convertAnother(byReference ? value.getObjectId() : value);
 		}
 
 		writer.endNode();
 	}
 
-	private void marshalToManyReference(Object object, ArcProperty arc,
-			HierarchicalStreamWriter writer, MarshallingContext context) {
-		throw new UnsupportedOperationException("TODO: implement");
-	}
-
 	private void marshalToMany(Object object, ArcProperty arc,
-			HierarchicalStreamWriter writer, MarshallingContext context) {
+			HierarchicalStreamWriter writer, MarshallingContext context,
+			boolean byReference) {
 
 		writer.startNode(arc.getName());
 
@@ -162,12 +145,11 @@
 				while (it.hasNextRow()) {
 					DataRow next = (DataRow) it.nextRow();
 
-					writer.startNode(next.getEntityName());
 					DataObject target = dataContext.objectFromDataRow(next
 							.getEntityName(), next, true);
 
-					context.convertAnother(target);
-					writer.endNode();
+					context.convertAnother(byReference ? target.getObjectId()
+							: target);
 				}
 			} finally {
 				it.close();

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=815515&r1=815514&r2=815515&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 Tue Sep 15 22:05:39 2009
@@ -21,10 +21,12 @@
 import java.io.InputStream;
 
 import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.reflect.ClassDescriptor;
 import org.apache.cayenne.serialization.BaseDeserializer;
 import org.apache.cayenne.serialization.Subgraph;
 
 import com.thoughtworks.xstream.XStream;
+import com.thoughtworks.xstream.io.xml.XppDriver;
 
 public class XStreamDeserializer extends BaseDeserializer {
 
@@ -34,7 +36,7 @@
 
 		// TODO: make sure all the converters are stateless... then we can cache
 		// xstream instances by subgraph and reuse them
-		XStream xstream = XStreamUtil.defaultXStream(subgraph.getRootNode()
+		XStream xstream = createXStream(subgraph.getRootNode()
 				.getClassDescriptor());
 
 		int commitCountThreshold = isCommitting() ? getCommitCountThreshold()
@@ -42,6 +44,8 @@
 
 		xstream.registerConverter(new PersistentCloneUnmarshalConverter(
 				context, commitCountThreshold));
+		xstream.registerConverter(new ObjectIdConverter(context
+				.getEntityResolver()));
 
 		T object = (T) xstream.fromXML(in);
 
@@ -52,4 +56,19 @@
 		return object;
 	}
 
+	protected XStream createXStream(ClassDescriptor rootDescriptor) {
+		XStream xstream = new XStream(new XppDriver());
+
+		// this is required to get a real streaming API an release all
+		// serialized objects...
+		xstream.setMode(XStream.NO_REFERENCES);
+
+		// TODO: we need to implement our own algorithm for object cycle
+		// detection... XStream also supports Immutable classes. we may classify
+		// objects according to their participation in a cycle.
+
+		xstream.alias(rootDescriptor.getEntity().getName(), rootDescriptor
+				.getObjectClass());
+		return xstream;
+	}
 }

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=815515&r1=815514&r2=815515&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 Tue Sep 15 22:05:39 2009
@@ -20,26 +20,61 @@
 
 import java.io.OutputStream;
 
+import org.apache.cayenne.reflect.ClassDescriptor;
 import org.apache.cayenne.serialization.BaseSerializer;
 import org.apache.cayenne.serialization.Subgraph;
 
 import com.thoughtworks.xstream.XStream;
+import com.thoughtworks.xstream.io.HierarchicalStreamDriver;
+import com.thoughtworks.xstream.io.xml.XppDriver;
 
 public class XStreamSerializer extends BaseSerializer {
 
+	protected boolean creatingCompactXML;
+
 	@Override
 	public <T> void serialize(T object, Subgraph<T> subgraph, OutputStream out) {
 
 		// TODO: make sure all the converters are stateless... then we can cache
 		// xstream instances by subgraph and reuse them
-		XStream xstream = XStreamUtil.defaultXStream(subgraph.getRootNode()
+		XStream xstream = createXStream(subgraph.getRootNode()
 				.getClassDescriptor());
 
 		xstream.registerConverter(new PersistentMarshalConverter<T>(subgraph,
 				statementFetchSize));
-		xstream.registerConverter(new ObjectIdMarshalConverter());
+		xstream.registerConverter(new ObjectIdConverter(null));
 
 		xstream.toXML(object, out);
 	}
 
+	protected XStream createXStream(ClassDescriptor rootDescriptor) {
+		HierarchicalStreamDriver driver = isCreatingCompactXML() ? new CompactXPPDriver()
+				: new XppDriver();
+
+		XStream xstream = new XStream(driver);
+
+		// this is required to get a real streaming API an release all
+		// serialized objects...
+		xstream.setMode(XStream.NO_REFERENCES);
+
+		// TODO: we need to implement our own algorithm for object cycle
+		// detection... XStream also supports Immutable classes. we may classify
+		// objects according to their participation in a cycle.
+
+		xstream.alias(rootDescriptor.getEntity().getName(), rootDescriptor
+				.getObjectClass());
+		return xstream;
+	}
+
+	public boolean isCreatingCompactXML() {
+		return creatingCompactXML;
+	}
+
+	/**
+	 * Sets whether serializer should skip spaces and line breaks used for
+	 * pretty formatting, and output unformatted XML.
+	 */
+	public void setCreatingCompactXML(boolean createCompactXML) {
+		this.creatingCompactXML = createCompactXML;
+	}
 }

Copied: cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/BaseDeserializerTest.java (from r814869, 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/test/java/org/apache/cayenne/serialization/BaseDeserializerTest.java?p2=cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/BaseDeserializerTest.java&p1=cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/XStreamSerializer.java&r1=814869&r2=815515&rev=815515&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/XStreamSerializer.java (original)
+++ cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/BaseDeserializerTest.java Tue Sep 15 22:05:39 2009
@@ -16,30 +16,27 @@
  *  specific language governing permissions and limitations
  *  under the License.
  ****************************************************************/
-package org.apache.cayenne.serialization.xstream;
+package org.apache.cayenne.serialization;
 
-import java.io.OutputStream;
+import java.io.InputStream;
 
-import org.apache.cayenne.serialization.BaseSerializer;
-import org.apache.cayenne.serialization.Subgraph;
+import org.apache.cayenne.ObjectContext;
 
-import com.thoughtworks.xstream.XStream;
+import junit.framework.TestCase;
 
-public class XStreamSerializer extends BaseSerializer {
+public class BaseDeserializerTest extends TestCase {
 
-	@Override
-	public <T> void serialize(T object, Subgraph<T> subgraph, OutputStream out) {
+	public void testCommitCountThreshould() {
+		BaseDeserializer deserializer = new BaseDeserializer() {
+			@Override
+			public <T> T deserialize(ObjectContext context,
+					Subgraph<T> subgraph, InputStream in) {
+				return null;
+			}
+		};
 
-		// TODO: make sure all the converters are stateless... then we can cache
-		// xstream instances by subgraph and reuse them
-		XStream xstream = XStreamUtil.defaultXStream(subgraph.getRootNode()
-				.getClassDescriptor());
-
-		xstream.registerConverter(new PersistentMarshalConverter<T>(subgraph,
-				statementFetchSize));
-		xstream.registerConverter(new ObjectIdMarshalConverter());
-
-		xstream.toXML(object, out);
+		assertEquals(1000, deserializer.getCommitCountThreshold());
+		deserializer.setCommitCountThreshold(3);
+		assertEquals(3, deserializer.getCommitCountThreshold());
 	}
-
 }

Added: 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=815515&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/SubgraphTest.java (added)
+++ cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/SubgraphTest.java Tue Sep 15 22:05:39 2009
@@ -0,0 +1,58 @@
+/*****************************************************************
+ *   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 org.apache.cayenne.serialization.persistent.Table1;
+import org.apache.cayenne.serialization.persistent.Table2;
+import org.apache.cayenne.serialization.unit.SerializationCase;
+
+public class SubgraphTest extends SerializationCase {
+
+	public void testGetRootNode() {
+
+		Subgraph<Table1> subgraph = new Subgraph<Table1>(Table1.class,
+				newContext().getEntityResolver());
+		assertNotNull(subgraph.getRootNode());
+		assertEquals(0, subgraph.getRootNode().getChildren().size());
+	}
+
+	public void testAddSerializeByReferencePathToOne() {
+		Subgraph<Table2> subgraph = new Subgraph<Table2>(Table2.class,
+				newContext().getEntityResolver());
+		subgraph.addSerializeByReferencePath(Table2.TABLE1_PROPERTY);
+
+		SubgraphNode node = subgraph.getRootNode();
+		assertEquals(1, node.getChildren().size());
+
+		SubgraphNode child = node.getChildren().iterator().next();
+		assertTrue(child.isSerializedByReference());
+	}
+
+	public void testAddSerializeByReferencePathToMany() {
+		Subgraph<Table1> subgraph = new Subgraph<Table1>(Table1.class,
+				newContext().getEntityResolver());
+		subgraph.addSerializeByReferencePath(Table1.TABLE2S_PROPERTY);
+
+		SubgraphNode node = subgraph.getRootNode();
+		assertEquals(1, node.getChildren().size());
+
+		SubgraphNode child = node.getChildren().iterator().next();
+		assertTrue(child.isSerializedByReference());
+	}
+}

Copied: cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/Serialization.java (from r814869, 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/test/java/org/apache/cayenne/serialization/persistent/Serialization.java?p2=cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/Serialization.java&p1=cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/XStreamSerializer.java&r1=814869&r2=815515&rev=815515&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/main/java/org/apache/cayenne/serialization/xstream/XStreamSerializer.java (original)
+++ cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/Serialization.java Tue Sep 15 22:05:39 2009
@@ -16,30 +16,21 @@
  *  specific language governing permissions and limitations
  *  under the License.
  ****************************************************************/
-package org.apache.cayenne.serialization.xstream;
+package org.apache.cayenne.serialization.persistent;
 
-import java.io.OutputStream;
+import org.apache.cayenne.serialization.persistent.auto._Serialization;
 
-import org.apache.cayenne.serialization.BaseSerializer;
-import org.apache.cayenne.serialization.Subgraph;
+public class Serialization extends _Serialization {
 
-import com.thoughtworks.xstream.XStream;
+    private static Serialization instance;
 
-public class XStreamSerializer extends BaseSerializer {
+    private Serialization() {}
 
-	@Override
-	public <T> void serialize(T object, Subgraph<T> subgraph, OutputStream out) {
-
-		// TODO: make sure all the converters are stateless... then we can cache
-		// xstream instances by subgraph and reuse them
-		XStream xstream = XStreamUtil.defaultXStream(subgraph.getRootNode()
-				.getClassDescriptor());
-
-		xstream.registerConverter(new PersistentMarshalConverter<T>(subgraph,
-				statementFetchSize));
-		xstream.registerConverter(new ObjectIdMarshalConverter());
-
-		xstream.toXML(object, out);
-	}
+    public static Serialization getInstance() {
+        if(instance == null) {
+            instance = new Serialization();
+        }
 
+        return instance;
+    }
 }

Added: cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/Table1.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/Table1.java?rev=815515&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/Table1.java (added)
+++ cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/Table1.java Tue Sep 15 22:05:39 2009
@@ -0,0 +1,25 @@
+/*****************************************************************
+ *   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.persistent;
+
+import org.apache.cayenne.serialization.persistent.auto._Table1;
+
+public class Table1 extends _Table1 {
+
+}

Added: cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/Table2.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/Table2.java?rev=815515&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/Table2.java (added)
+++ cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/Table2.java Tue Sep 15 22:05:39 2009
@@ -0,0 +1,25 @@
+/*****************************************************************
+ *   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.persistent;
+
+import org.apache.cayenne.serialization.persistent.auto._Table2;
+
+public class Table2 extends _Table2 {
+
+}

Added: cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/auto/_Serialization.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/auto/_Serialization.java?rev=815515&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/auto/_Serialization.java (added)
+++ cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/auto/_Serialization.java Tue Sep 15 22:05:39 2009
@@ -0,0 +1,12 @@
+package org.apache.cayenne.serialization.persistent.auto;
+
+
+
+/**
+ * This class was generated by Cayenne.
+ * It is probably a good idea to avoid changing this class manually,
+ * since it may be overwritten next time code is regenerated.
+ * If you need to make any customizations, please use subclass.
+ */
+public class _Serialization {
+}
\ No newline at end of file

Added: cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/auto/_Table1.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/auto/_Table1.java?rev=815515&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/auto/_Table1.java (added)
+++ cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/auto/_Table1.java Tue Sep 15 22:05:39 2009
@@ -0,0 +1,40 @@
+package org.apache.cayenne.serialization.persistent.auto;
+
+import java.util.List;
+
+import org.apache.cayenne.CayenneDataObject;
+import org.apache.cayenne.serialization.persistent.Table2;
+
+/**
+ * Class _Table1 was generated by Cayenne.
+ * It is probably a good idea to avoid changing this class manually,
+ * since it may be overwritten next time code is regenerated.
+ * If you need to make any customizations, please use subclass.
+ */
+public abstract class _Table1 extends CayenneDataObject {
+
+    public static final String NAME_PROPERTY = "name";
+    public static final String TABLE2S_PROPERTY = "table2s";
+
+    public static final String PK_PK_COLUMN = "PK";
+
+    public void setName(String name) {
+        writeProperty("name", name);
+    }
+    public String getName() {
+        return (String)readProperty("name");
+    }
+
+    public void addToTable2s(Table2 obj) {
+        addToManyTarget("table2s", obj, true);
+    }
+    public void removeFromTable2s(Table2 obj) {
+        removeToManyTarget("table2s", obj, true);
+    }
+    @SuppressWarnings("unchecked")
+    public List<Table2> getTable2s() {
+        return (List<Table2>)readProperty("table2s");
+    }
+
+
+}

Added: cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/auto/_Table2.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/auto/_Table2.java?rev=815515&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/auto/_Table2.java (added)
+++ cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/persistent/auto/_Table2.java Tue Sep 15 22:05:39 2009
@@ -0,0 +1,53 @@
+package org.apache.cayenne.serialization.persistent.auto;
+
+import java.util.Date;
+
+import org.apache.cayenne.CayenneDataObject;
+import org.apache.cayenne.serialization.persistent.Table1;
+
+/**
+ * Class _Table2 was generated by Cayenne.
+ * It is probably a good idea to avoid changing this class manually,
+ * since it may be overwritten next time code is regenerated.
+ * If you need to make any customizations, please use subclass.
+ */
+public abstract class _Table2 extends CayenneDataObject {
+
+    public static final String DATE_COLUMN_PROPERTY = "dateColumn";
+    public static final String DOUBLE_COLUMN_PROPERTY = "doubleColumn";
+    public static final String NAME_PROPERTY = "name";
+    public static final String TABLE1_PROPERTY = "table1";
+
+    public static final String PK_PK_COLUMN = "PK";
+
+    public void setDateColumn(Date dateColumn) {
+        writeProperty("dateColumn", dateColumn);
+    }
+    public Date getDateColumn() {
+        return (Date)readProperty("dateColumn");
+    }
+
+    public void setDoubleColumn(Double doubleColumn) {
+        writeProperty("doubleColumn", doubleColumn);
+    }
+    public Double getDoubleColumn() {
+        return (Double)readProperty("doubleColumn");
+    }
+
+    public void setName(String name) {
+        writeProperty("name", name);
+    }
+    public String getName() {
+        return (String)readProperty("name");
+    }
+
+    public void setTable1(Table1 table1) {
+        setToOneTarget("table1", table1, true);
+    }
+
+    public Table1 getTable1() {
+        return (Table1)readProperty("table1");
+    }
+
+
+}

Added: cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/unit/SerializationCase.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/unit/SerializationCase.java?rev=815515&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/unit/SerializationCase.java (added)
+++ cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/unit/SerializationCase.java Tue Sep 15 22:05:39 2009
@@ -0,0 +1,93 @@
+/*****************************************************************
+ *   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.unit;
+
+import java.io.File;
+
+import junit.framework.TestCase;
+
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.access.DataContext;
+import org.apache.cayenne.access.DataDomain;
+import org.apache.cayenne.access.DataNode;
+import org.apache.cayenne.access.DbGenerator;
+import org.apache.cayenne.conf.Configuration;
+import org.apache.cayenne.map.DataMap;
+
+public abstract class SerializationCase extends TestCase {
+
+	static final String TEST_DIR = "target/testrun";
+
+	private static boolean pkFixed;
+
+	public SerializationCase() {
+		// this is needed until CAY-1276 is fixed
+
+		if (!pkFixed) {
+
+			DataDomain domain = Configuration.getSharedConfiguration()
+					.getDomain();
+			DataNode node = domain.getDataNodes().iterator().next();
+			DataMap dataMap = domain.getDataMaps().iterator().next();
+
+			DbGenerator dbGenerator = new DbGenerator(node.getAdapter(),
+					dataMap);
+			dbGenerator.setShouldDropPKSupport(true);
+			dbGenerator.setShouldCreatePKSupport(true);
+
+			dbGenerator.setShouldCreateTables(false);
+			dbGenerator.setShouldDropTables(false);
+			dbGenerator.setShouldCreateFKConstraints(false);
+
+			try {
+				dbGenerator.runGenerator(node.getDataSource());
+			} catch (Exception e) {
+				throw new CayenneRuntimeException("Error generating PK", e);
+			}
+
+			pkFixed = true;
+		}
+	}
+
+	protected ObjectContext newContext() {
+		return DataContext.createDataContext();
+	}
+
+	protected File tempFile(String extension) {
+		File baseDir = new File(TEST_DIR);
+		baseDir.mkdirs();
+
+		if (extension == null) {
+			extension = "";
+		}
+
+		String baseName = String.valueOf(System.currentTimeMillis());
+		for (int i = 0; i < 1000; i++) {
+			File file = new File(baseDir, baseName + extension);
+			if (!file.exists()) {
+				return file;
+			}
+		}
+
+		// should never happen
+		throw new IllegalStateException(
+				"Too many files with the same base name of " + baseName + "...");
+	}
+}

Added: 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=815515&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/xstream/XStreamDeserializerTest.java (added)
+++ cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/xstream/XStreamDeserializerTest.java Tue Sep 15 22:05:39 2009
@@ -0,0 +1,145 @@
+/*****************************************************************
+ *   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.xstream;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.cayenne.DataObjectUtils;
+import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.PersistenceState;
+import org.apache.cayenne.serialization.Subgraph;
+import org.apache.cayenne.serialization.persistent.Table1;
+import org.apache.cayenne.serialization.persistent.Table2;
+import org.apache.cayenne.serialization.unit.SerializationCase;
+
+public class XStreamDeserializerTest extends SerializationCase {
+
+	public void testDeserializeRoot() throws IOException {
+
+		ObjectContext context = newContext();
+		Table1 t11 = context.newObject(Table1.class);
+		t11.setName("t11");
+
+		context.commitChanges();
+
+		Subgraph<Table1> subgraph = new Subgraph<Table1>(Table1.class, context
+				.getEntityResolver());
+
+		XStreamDeserializer deserializer = new XStreamDeserializer();
+
+		String xml = "<Table1><name>t11</name></Table1>";
+
+		Table1 result;
+		InputStream in = new ByteArrayInputStream(xml.getBytes());
+		try {
+			result = deserializer.deserialize(context, subgraph, in);
+		} finally {
+			in.close();
+		}
+
+		assertNotNull(result);
+		assertEquals(PersistenceState.COMMITTED, result.getPersistenceState());
+		assertEquals("t11", result.getName());
+	}
+
+	public void testDeserializeByValueToOne() 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();
+
+		Subgraph<Table2> subgraph = new Subgraph<Table2>(Table2.class, context
+				.getEntityResolver());
+		subgraph.addSerializeByValuePath(Table2.TABLE1_PROPERTY);
+
+		XStreamDeserializer deserializer = new XStreamDeserializer();
+
+		String xml = "<Table2><name>t21</name><table1><Table1><name>t11</name></Table1></table1></Table2>";
+
+		Table2 result;
+		InputStream in = new ByteArrayInputStream(xml.getBytes());
+		try {
+			result = deserializer.deserialize(context, subgraph, in);
+		} finally {
+			in.close();
+		}
+
+		assertNotNull(result);
+		assertNotNull(result.getTable1());
+		assertEquals(PersistenceState.COMMITTED, result.getPersistenceState());
+		assertEquals(PersistenceState.COMMITTED, result.getTable1()
+				.getPersistenceState());
+
+		assertEquals("t21", result.getName());
+		assertNotSame(t21, result);
+		assertNotSame(t11, result.getTable1());
+		assertEquals("t11", result.getTable1().getName());
+
+	}
+
+	public void testDeserializeByReferenceToOne() 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();
+
+		Subgraph<Table2> subgraph = new Subgraph<Table2>(Table2.class, context
+				.getEntityResolver());
+		subgraph.addSerializeByReferencePath(Table2.TABLE1_PROPERTY);
+
+		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>";
+
+		Table2 result;
+		InputStream in = new ByteArrayInputStream(xml.getBytes());
+		try {
+			result = deserializer.deserialize(context, subgraph, in);
+		} finally {
+			in.close();
+		}
+
+		assertNotNull(result);
+		assertNotNull(result.getTable1());
+		assertEquals(PersistenceState.COMMITTED, result.getPersistenceState());
+		assertEquals(PersistenceState.COMMITTED, result.getTable1()
+				.getPersistenceState());
+
+		assertEquals("t21", result.getName());
+		assertNotSame(t21, result);
+		assertSame(t11, result.getTable1());
+
+	}
+}

Added: 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=815515&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/xstream/XStreamSerializerTest.java (added)
+++ cayenne/sandbox/cayenne-serialization/src/test/java/org/apache/cayenne/serialization/xstream/XStreamSerializerTest.java Tue Sep 15 22:05:39 2009
@@ -0,0 +1,149 @@
+/*****************************************************************
+ *   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.xstream;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.cayenne.DataObjectUtils;
+import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.serialization.Subgraph;
+import org.apache.cayenne.serialization.persistent.Table1;
+import org.apache.cayenne.serialization.persistent.Table2;
+import org.apache.cayenne.serialization.unit.SerializationCase;
+import org.apache.cayenne.util.Util;
+
+public class XStreamSerializerTest extends SerializationCase {
+
+	public void testCreatingCompactXML() {
+		XStreamSerializer serializer = new XStreamSerializer();
+		assertFalse(serializer.isCreatingCompactXML());
+		serializer.setCreatingCompactXML(true);
+		assertTrue(serializer.isCreatingCompactXML());
+	}
+
+	public void testSerializeByValueToOne() 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();
+
+		Subgraph<Table2> subgraph = new Subgraph<Table2>(Table2.class, context
+				.getEntityResolver());
+		subgraph.addSerializeByValuePath(Table2.TABLE1_PROPERTY);
+
+		File file = tempFile(".xml");
+		XStreamSerializer serializer = new XStreamSerializer();
+		serializer.setCreatingCompactXML(true);
+
+		FileOutputStream out = new FileOutputStream(file);
+		try {
+			serializer.serialize(t21, subgraph, out);
+		} finally {
+			out.close();
+		}
+
+		assertTrue(file.isFile());
+		assertTrue(file.length() > 0);
+
+		assertEquals("<Table2><name>t21</name><table1>"
+				+ "<Table1><name>t11</name></Table1></table1></Table2>", Util
+				.stringFromFile(file).trim());
+	}
+
+	public void testSerializeByValueToMany() 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();
+
+		Subgraph<Table1> subgraph = new Subgraph<Table1>(Table1.class, context
+				.getEntityResolver());
+		subgraph.addSerializeByValuePath(Table1.TABLE2S_PROPERTY);
+
+		File file = tempFile(".xml");
+		XStreamSerializer serializer = new XStreamSerializer();
+		serializer.setCreatingCompactXML(true);
+
+		FileOutputStream out = new FileOutputStream(file);
+		try {
+			serializer.serialize(t11, subgraph, out);
+		} finally {
+			out.close();
+		}
+
+		assertTrue(file.isFile());
+		assertTrue(file.length() > 0);
+
+		assertEquals("<Table1><name>t11</name><table2s>"
+				+ "<Table2><name>t21</name></Table2>" + "</table2s></Table1>",
+				Util.stringFromFile(file).trim());
+	}
+
+	public void testSerializeByReferenceToOne() 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();
+
+		Subgraph<Table2> subgraph = new Subgraph<Table2>(Table2.class, context
+				.getEntityResolver());
+		subgraph.addSerializeByReferencePath(Table2.TABLE1_PROPERTY);
+
+		File file = tempFile(".xml");
+		XStreamSerializer serializer = new XStreamSerializer();
+		serializer.setCreatingCompactXML(true);
+
+		FileOutputStream out = new FileOutputStream(file);
+		try {
+			serializer.serialize(t21, subgraph, out);
+		} finally {
+			out.close();
+		}
+
+		assertTrue(file.isFile());
+		assertTrue(file.length() > 0);
+
+		int id = DataObjectUtils.intPKForObject(t11);
+
+		assertEquals(
+				"<Table2><name>t21</name><table1><Table1 ref=\"true\"><PK>"
+						+ id + "</PK></Table1></table1></Table2>", Util
+						.stringFromFile(file).trim());
+	}
+}

Added: cayenne/sandbox/cayenne-serialization/src/test/resources/cayenne.xml
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/src/test/resources/cayenne.xml?rev=815515&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/test/resources/cayenne.xml (added)
+++ cayenne/sandbox/cayenne-serialization/src/test/resources/cayenne.xml Tue Sep 15 22:05:39 2009
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<domains project-version="3.0">
+<domain name="serialization">
+	<map name="serialization" location="serialization.map.xml"/>
+
+	<node name="serialization"
+		 datasource="serialization.driver.xml"
+		 factory="org.apache.cayenne.conf.DriverDataSourceFactory"
+		 schema-update-strategy="org.apache.cayenne.access.dbsync.CreateIfNoSchemaStrategy">
+			<map-ref name="serialization"/>
+	 </node>
+</domain>
+</domains>

Added: cayenne/sandbox/cayenne-serialization/src/test/resources/serialization.driver.xml
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/src/test/resources/serialization.driver.xml?rev=815515&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/test/resources/serialization.driver.xml (added)
+++ cayenne/sandbox/cayenne-serialization/src/test/resources/serialization.driver.xml Tue Sep 15 22:05:39 2009
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<driver project-version="3.0" class="org.hsqldb.jdbcDriver">
+	<url value="jdbc:hsqldb:mem:serializationdb"/>
+	<connectionPool min="1" max="1"/>
+	<login userName="sa"/>
+</driver>

Added: cayenne/sandbox/cayenne-serialization/src/test/resources/serialization.map.xml
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-serialization/src/test/resources/serialization.map.xml?rev=815515&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-serialization/src/test/resources/serialization.map.xml (added)
+++ cayenne/sandbox/cayenne-serialization/src/test/resources/serialization.map.xml Tue Sep 15 22:05:39 2009
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<data-map xmlns="http://cayenne.apache.org/schema/3.0/modelMap"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://cayenne.apache.org/schema/3.0/modelMap http://cayenne.apache.org/schema/3.0/modelMap"
+  project-version="3.0">
+	<property name="defaultPackage" value="org.apache.cayenne.serialization.persistent"/>
+	<db-entity name="table1">
+		<db-attribute name="NAME" type="VARCHAR" length="200"/>
+		<db-attribute name="PK" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
+	</db-entity>
+	<db-entity name="table2">
+		<db-attribute name="DATE_COLUMN" type="DATE"/>
+		<db-attribute name="DOUBLE_COLUMN" type="DOUBLE"/>
+		<db-attribute name="NAME" type="VARCHAR" length="200"/>
+		<db-attribute name="PK" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
+		<db-attribute name="TABLE1_FK" type="INTEGER"/>
+	</db-entity>
+	<obj-entity name="Table1" className="org.apache.cayenne.serialization.persistent.Table1" dbEntityName="table1">
+		<obj-attribute name="name" type="java.lang.String" db-attribute-path="NAME"/>
+	</obj-entity>
+	<obj-entity name="Table2" className="org.apache.cayenne.serialization.persistent.Table2" dbEntityName="table2">
+		<obj-attribute name="dateColumn" type="java.util.Date" db-attribute-path="DATE_COLUMN"/>
+		<obj-attribute name="doubleColumn" type="java.lang.Double" db-attribute-path="DOUBLE_COLUMN"/>
+		<obj-attribute name="name" type="java.lang.String" db-attribute-path="NAME"/>
+	</obj-entity>
+	<db-relationship name="table2s" source="table1" target="table2" toMany="true">
+		<db-attribute-pair source="PK" target="TABLE1_FK"/>
+	</db-relationship>
+	<db-relationship name="table1" source="table2" target="table1" toMany="false">
+		<db-attribute-pair source="TABLE1_FK" target="PK"/>
+	</db-relationship>
+	<obj-relationship name="table2s" source="Table1" target="Table2" deleteRule="Deny" db-relationship-path="table2s"/>
+	<obj-relationship name="table1" source="Table2" target="Table1" deleteRule="Nullify" db-relationship-path="table1"/>
+</data-map>