/* * Copyright (C) 2003, 2004 Joe Walnes. * Copyright (C) 2006, 2007 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 26. September 2003 by Joe Walnes */ package com.thoughtworks.acceptance; import com.thoughtworks.acceptance.objects.StandardObject; import com.thoughtworks.xstream.converters.reflection.ReflectionConverter; import com.thoughtworks.xstream.core.JVM; import com.thoughtworks.xstream.io.xml.XppReader; import java.io.StringReader; public class CustomClassesTest extends AbstractAcceptanceTest { public static class SamplePerson extends StandardObject { int anInt; String firstName; String lastName; transient String aComment = ""; } public void testCustomObjectWithBasicFields() { xstream.alias("friend", SamplePerson.class); SamplePerson person = new SamplePerson(); person.anInt = 3; person.firstName = "Joe"; person.lastName = "Walnes"; String expected = "<friend>\n" + " <anInt>3</anInt>\n" + " <firstName>Joe</firstName>\n" + " <lastName>Walnes</lastName>\n" + "</friend>"; assertBothWays(person, expected); } public static class SamplePersonHolder { String aString; SamplePerson brother; public boolean equals(Object obj) { SamplePersonHolder containerObject = (SamplePersonHolder) obj; return (aString == null ? containerObject.aString == null : aString.equals(containerObject.aString)) && brother.equals(containerObject.brother); } } public void testCustomObjectWithCustomObjectField() { xstream.alias("friend", SamplePerson.class); xstream.alias("personHolder", SamplePersonHolder.class); SamplePersonHolder personHolder = new SamplePersonHolder(); personHolder.aString = "hello world"; SamplePerson person = new SamplePerson(); person.anInt = 3; person.firstName = "Joe"; person.lastName = "Walnes"; personHolder.brother = person; String expected = "<personHolder>\n" + " <aString>hello world</aString>\n" + " <brother>\n" + " <anInt>3</anInt>\n" + " <firstName>Joe</firstName>\n" + " <lastName>Walnes</lastName>\n" + " </brother>\n" + "</personHolder>"; assertBothWays(personHolder, expected); } public void testCustomObjectWithCustomObjectFieldsSetToNull() { xstream.alias("friend", SamplePerson.class); xstream.alias("personHolder", SamplePersonHolder.class); SamplePersonHolder personHolder = new SamplePersonHolder(); personHolder.aString = null; SamplePerson person = new SamplePerson(); person.anInt = 3; person.firstName = "Joe"; person.lastName = null; personHolder.brother = person; String expected = "<personHolder>\n" + " <brother>\n" + " <anInt>3</anInt>\n" + " <firstName>Joe</firstName>\n" + " </brother>\n" + "</personHolder>"; assertBothWays(personHolder, expected); } public void testCustomObjectCanBeInstantiatedExternallyBeforeDeserialization() { xstream.alias("friend", SamplePerson.class); xstream.alias("personHolder", SamplePersonHolder.class); String xml = "<personHolder>\n" + " <aString>hello world</aString>\n" + " <brother>\n" + " <anInt>3</anInt>\n" + " <firstName>Joe</firstName>\n" + " <lastName>Walnes</lastName>\n" + " </brother>\n" + "</personHolder>"; // execute SamplePersonHolder alreadyInstantiated = new SamplePersonHolder(); xstream.unmarshal(new XppReader(new StringReader(xml)), alreadyInstantiated); // verify SamplePersonHolder expectedResult = new SamplePersonHolder(); expectedResult.aString = "hello world"; SamplePerson expectedPerson = new SamplePerson(); expectedPerson.anInt = 3; expectedPerson.firstName = "Joe"; expectedPerson.lastName = "Walnes"; expectedResult.brother = expectedPerson; assertEquals(expectedResult, alreadyInstantiated); } public void testCustomObjectWillNotUnmarshalTransientFields() { xstream.alias("friend", SamplePerson.class); String xml = "<friend>\n" + " <anInt>3</anInt>\n" + " <firstName>Joe</firstName>\n" + " <lastName>Walnes</lastName>\n" + " <aComment>XStream Despot</aComment>\n" + "</friend>"; SamplePerson person = (SamplePerson)xstream.fromXML(xml); if (JVM.is14()) { assertNull(person.aComment); } else { assertEquals("", person.aComment); } } static class Joe extends SamplePerson { boolean aBoolean; } public void testCustomObjectWillNotUnmarshalInheritedTransientFields() { xstream.alias("joe", Joe.class); String xml = "<joe>\n" + " <anInt>3</anInt>\n" + " <firstName>Joe</firstName>\n" + " <lastName>Walnes</lastName>\n" + " <aComment>XStream Despot</aComment>\n" + " <aBoolean>true</aBoolean>\n" + "</joe>"; Joe joe = (Joe)xstream.fromXML(xml); if (JVM.is14()) { assertNull(joe.aComment); } else { assertEquals("", joe.aComment); } } public void testCustomObjectWillNotUnmarshalTransientFieldsFromAttributes() { xstream.alias("friend", SamplePerson.class); String xml = "<friend aComment='XStream Despot'>\n" + " <anInt>3</anInt>\n" + " <firstName>Joe</firstName>\n" + " <lastName>Walnes</lastName>\n" + "</friend>"; // without attribute definition SamplePerson person = (SamplePerson)xstream.fromXML(xml); if (JVM.is14()) { assertNull(person.aComment); } else { assertEquals("", person.aComment); } xstream.useAttributeFor("aComment", String.class); // with attribute definition person = (SamplePerson)xstream.fromXML(xml); if (JVM.is14()) { assertNull(person.aComment); } else { assertEquals("", person.aComment); } } public void testNullObjectsDoNotHaveFieldsWritten() { xstream.alias("cls", WithSomeFields.class); WithSomeFields obj = new WithSomeFields(); String expected = "<cls/>"; assertBothWays(obj, expected); } public void testEmptyStringsAreNotTreatedAsNulls() { xstream.alias("cls", WithSomeFields.class); WithSomeFields obj = new WithSomeFields(); obj.b = ""; String expected = "" + "<cls>\n" + " <b></b>\n" + "</cls>"; assertBothWays(obj, expected); } public static class WithSomeFields extends StandardObject { Object a; String b; } public void testNullsAreDistinguishedFromEmptyStrings() { LotsOfStrings in = new LotsOfStrings(); in.a = "."; in.b = ""; in.c = null; String xml = xstream.toXML(in); LotsOfStrings out = (LotsOfStrings) xstream.fromXML(xml); assertEquals(".", out.a); assertEquals("", out.b); assertNull(out.c); } public static class LotsOfStrings { String a; String b; String c; } public void testFieldWithObjectType() { String expected = "" + "<thing>\n" + " <one>1.0</one>\n" + " <two class=\"double\">2.0</two>\n" + "</thing>"; xstream.alias("thing", FieldWithObjectType.class); assertBothWays(new FieldWithObjectType(), expected); } public static class FieldWithObjectType extends StandardObject { Double one = new Double(1.0); Object two = new Double(2.0); } public void testFailsFastIfFieldIsDefinedTwice() { String input = "" + "<thing>\n" + " <one>1.0</one>\n" + " <one>2.0</one>\n" + "</thing>"; xstream.alias("thing", FieldWithObjectType.class); try { xstream.fromXML(input); fail("Expected exception"); } catch (ReflectionConverter.DuplicateFieldException expected) { assertEquals("one", expected.getShortMessage()); } } public static class TransientInitializingClass extends StandardObject { private transient String s = ""; private Object readResolve() { this.s = "foo"; return this; } } public void testCustomObjectWithTransientFieldInitialization() { xstream.alias("tran", TransientInitializingClass.class); TransientInitializingClass tran = new TransientInitializingClass(); String expected = "<tran/>"; TransientInitializingClass serialized = (TransientInitializingClass)assertBothWays(tran, expected); assertEquals("foo", serialized.s); } }