/* * Copyright (C) 2004, 2005 Joe Walnes. * Copyright (C) 2006, 2007, 2008 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. * * Created on 24. August 2004 by Joe Walnes */ package com.thoughtworks.acceptance; import com.thoughtworks.acceptance.objects.Original; import com.thoughtworks.acceptance.objects.Replaced; import com.thoughtworks.acceptance.objects.StandardObject; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.Serializable; import java.util.ArrayList; import java.util.List; public class WriteReplaceTest extends AbstractAcceptanceTest { public static class Thing extends StandardObject implements Serializable { int a; int b; public Thing() { } public Thing(int a, int b) { this.a = a; this.b = b; } private Object writeReplace() { return new Thing(a * 1000, b * 1000); } private Object readResolve() { return new Thing(a / 1000, b / 1000); } } public void testReplacesAndResolves() { xstream.alias("thing", Thing.class); Thing thing = new Thing(3, 6); String expectedXml = "" + "<thing>\n" + " <a>3000</a>\n" + " <b>6000</b>\n" + "</thing>"; assertBothWays(thing, expectedXml); } public void testAllowsDifferentTypeToBeSubstituted() { xstream.alias("original-class", Original.class); xstream.alias("replaced-class", Replaced.class); Original in = new Original("hello world"); String expectedXml = "" + "<original-class resolves-to=\"replaced-class\">\n" + " <replacedValue>HELLO WORLD</replacedValue>\n" + "</original-class>"; assertBothWays(in, expectedXml); } public void testAllowsDifferentTypeToBeSubstitutedInList() { xstream.alias("original-class", Original.class); xstream.alias("replaced-class", Replaced.class); List in = new ArrayList(); in.add(new Original("hello world")); String expectedXml = "" + "<list>\n" + " <original-class resolves-to=\"replaced-class\">\n" + " <replacedValue>HELLO WORLD</replacedValue>\n" + " </original-class>\n" + "</list>"; assertBothWays(in, expectedXml); } public static class Container extends StandardObject { Original original; } public void testAllowsDifferentTypeToBeSubstitutedAsMember() { xstream.alias("container", Container.class); xstream.alias("original-class", Original.class); xstream.alias("replaced-class", Replaced.class); Container in = new Container(); in.original = new Original("hello world"); String expectedXml = "" + "<container>\n" + " <original resolves-to=\"replaced-class\">\n" + " <replacedValue>HELLO WORLD</replacedValue>\n" + " </original>\n" + "</container>"; assertBothWays(in, expectedXml); } public static class ExtenalizableContainer extends StandardObject implements Externalizable { Original original; public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { original = (Original)in.readObject(); } public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(original); } } public void testAllowsDifferentTypeToBeSubstitutedInExternalizable() { xstream.alias("container", ExtenalizableContainer.class); xstream.alias("original-class", Original.class); xstream.alias("replaced-class", Replaced.class); ExtenalizableContainer in = new ExtenalizableContainer(); in.original = new Original("hello world"); String expectedXml = "" + "<container>\n" + " <original-class resolves-to=\"replaced-class\">\n" + " <replacedValue>HELLO WORLD</replacedValue>\n" + " </original-class>\n" + "</container>"; assertBothWays(in, expectedXml); } public void testAllowsDifferentTypeToBeSubstitutedWithNonExistingClass() { xstream.alias("original-class", Original.class); xstream.alias("replaced-class", Replaced.class); Original in = new Original("hello world"); String xml = "" + "<original-class resolves-to=\"replaced-class\" class=\"not.Existing\">\n" + " <replacedValue>HELLO WORLD</replacedValue>\n" + "</original-class>"; assertEquals(in, xstream.fromXML(xml)); } public void testAllowsDifferentTypeToBeSubstitutedWithNonExistingClassInList() { xstream.alias("original-class", Original.class); xstream.alias("replaced-class", Replaced.class); List in = new ArrayList(); in.add(new Original("hello world")); String xml = "" + "<list>\n" + " <original-class resolves-to=\"replaced-class\" class=\"not.Existing\">\n" + " <replacedValue>HELLO WORLD</replacedValue>\n" + " </original-class>\n" + "</list>"; assertEquals(in, xstream.fromXML(xml)); } public void testAllowsDifferentTypeToBeSubstitutedWithNonExistingClassAsMember() { xstream.alias("container", Container.class); xstream.alias("original-class", Original.class); xstream.alias("replaced-class", Replaced.class); Container in = new Container(); in.original = new Original("hello world"); String xml = "" + "<container>\n" + " <original resolves-to=\"replaced-class\" class=\"not.Existing\">\n" + " <replacedValue>HELLO WORLD</replacedValue>\n" + " </original>\n" + "</container>"; assertEquals(in, xstream.fromXML(xml)); } public void testAllowsDifferentTypeToBeSubstitutedWithNonExistingClassInExternalizable() { xstream.alias("container", ExtenalizableContainer.class); xstream.alias("original-class", Original.class); xstream.alias("replaced-class", Replaced.class); ExtenalizableContainer in = new ExtenalizableContainer(); in.original = new Original("hello world"); String xml = "" + "<container>\n" + " <original-class resolves-to=\"replaced-class\" class=\"not.Existing\">\n" + " <replacedValue>HELLO WORLD</replacedValue>\n" + " </original-class>\n" + "</container>"; assertEquals(in, xstream.fromXML(xml)); } public static class OriginalSerializable extends StandardObject { String originalValue; public OriginalSerializable() { } public OriginalSerializable(String originalValue) { this.originalValue = originalValue; } private Object writeReplace() { return new ReplacedSerializable(originalValue.toUpperCase()); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); } } public static class ReplacedSerializable extends StandardObject { String replacedValue; public ReplacedSerializable() { } public ReplacedSerializable(String replacedValue) { this.replacedValue = replacedValue; } private Object readResolve() { return new OriginalSerializable(replacedValue.toLowerCase()); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); } } public void testAllowsDifferentTypeToBeSubstitutedForCustomSerializableObjects() { xstream.alias("original-serializable-class", OriginalSerializable.class); xstream.alias("replaced-serializable-class", ReplacedSerializable.class); OriginalSerializable in = new OriginalSerializable("hello world"); String expectedXml = "" + "<original-serializable-class resolves-to=\"replaced-serializable-class\" serialization=\"custom\">\n" + " <replaced-serializable-class>\n" + " <default>\n" + " <replacedValue>HELLO WORLD</replacedValue>\n" + " </default>\n" + " </replaced-serializable-class>\n" + "</original-serializable-class>"; assertBothWays(in, expectedXml); } }