diff --git a/src/as/com/threerings/io/ObjectInputStream.as b/src/as/com/threerings/io/ObjectInputStream.as index 26b8adbf0..9ca7b3314 100644 --- a/src/as/com/threerings/io/ObjectInputStream.as +++ b/src/as/com/threerings/io/ObjectInputStream.as @@ -34,7 +34,7 @@ import com.threerings.util.Long; public class ObjectInputStream { /** Enables verbose object I/O debugging. */ - public static const DEBUG :Boolean = false; + public static const DEBUG :Boolean = true; public function ObjectInputStream (source :IDataInput = null, clientProps :Object = null) { @@ -172,7 +172,8 @@ public class ObjectInputStream * Called to read an Object of a known final type into a Streamable object. * * @param type either a String representing the java type, - * or a Class object representing the actionscript type. + * a Class representing the actionscript type, + * or the Streamer to be used to read the field. */ public function readField (type :Object) :* //throws IOError @@ -181,13 +182,18 @@ public class ObjectInputStream return null; } - var jname :String = type as String; - if (type is Class) { - jname = Translations.getToServer(ClassUtil.getClassName(type)); - } - var streamer :Streamer = Streamer.getStreamerByJavaName(jname); - if (streamer == null) { - throw new Error("Cannot field stream " + type); + var streamer :Streamer; + if (type is Streamer) { + streamer = Streamer(type); + } else { + var jname :String = type as String; + if (type is Class) { + jname = Translations.getToServer(ClassUtil.getClassName(type)); + } + streamer= Streamer.getStreamerByJavaName(jname); + if (streamer == null) { + throw new Error("Cannot field stream " + type); + } } var obj :Object = streamer.createObject(this); diff --git a/src/as/com/threerings/io/ObjectOutputStream.as b/src/as/com/threerings/io/ObjectOutputStream.as index 5e1240030..0300205eb 100644 --- a/src/as/com/threerings/io/ObjectOutputStream.as +++ b/src/as/com/threerings/io/ObjectOutputStream.as @@ -86,10 +86,13 @@ public class ObjectOutputStream writeBareObjectImpl(obj, cmap.streamer); } - public function writeBareObject (obj :Object) :void + public function writeBareObject (obj :Object, streamer :Streamer = null) :void //throws IOError { - writeBareObjectImpl(obj, Streamer.getStreamer(obj)); + if (streamer == null) { + streamer = Streamer.getStreamer(obj); + } + writeBareObjectImpl(obj, streamer); } public function writeBareObjectImpl (obj :Object, streamer :Streamer) :void @@ -125,13 +128,13 @@ public class ObjectOutputStream * } * */ - public function writeField (val :Object) :void + public function writeField (val :Object, streamer :Streamer = null) :void //throws IOError { var b :Boolean = (val != null); writeBoolean(b); if (b) { - writeBareObject(val); + writeBareObject(val, streamer); } } @@ -217,7 +220,7 @@ public class ObjectOutputStream /** The target DataOutput that we route things to. */ protected var _targ :IDataOutput; - + /** A counter used to assign codes to streamed classes. */ protected var _nextCode :int = 1; diff --git a/src/java/com/threerings/presents/net/AuthRequest.java b/src/java/com/threerings/presents/net/AuthRequest.java index 86f508335..4c549126d 100644 --- a/src/java/com/threerings/presents/net/AuthRequest.java +++ b/src/java/com/threerings/presents/net/AuthRequest.java @@ -102,6 +102,7 @@ public class AuthRequest extends UpstreamMessage // if we fail here because the client is old, leave ourselves with a partially // initialized set of credentials, which the server will generally cope with by telling // the client it is out of date + ioe.printStackTrace(); } } diff --git a/src/java/com/threerings/presents/server/ClientResolver.java b/src/java/com/threerings/presents/server/ClientResolver.java index 29546d690..e28c3258b 100644 --- a/src/java/com/threerings/presents/server/ClientResolver.java +++ b/src/java/com/threerings/presents/server/ClientResolver.java @@ -53,7 +53,7 @@ public class ClientResolver extends Invoker.Unit } /** - * Initiailizes this instance. + * Initializes this instance. * * @param username the username of the user to be resolved. */ diff --git a/src/java/com/threerings/presents/tools/GenActionScriptStreamableTask.java b/src/java/com/threerings/presents/tools/GenActionScriptStreamableTask.java index e12113d9b..1840a56d8 100644 --- a/src/java/com/threerings/presents/tools/GenActionScriptStreamableTask.java +++ b/src/java/com/threerings/presents/tools/GenActionScriptStreamableTask.java @@ -95,6 +95,11 @@ public class GenActionScriptStreamableTask extends GenActionScriptTask { this.name = f.getName(); this.simpleType = addImportAndGetShortType(f.getType(), true, imports); + + // Reading and writing Lists uses ArrayStreamer.INSTANCE directly + if (List.class.isAssignableFrom(f.getType())) { + imports.add("com.threerings.io.streamers.ArrayStreamer"); + } this.reader = toReadObject(f.getType()); this.writer = toWriteObject(f.getType(), name); } diff --git a/src/java/com/threerings/presents/tools/GenActionScriptTask.java b/src/java/com/threerings/presents/tools/GenActionScriptTask.java index eaa5603a7..70930da0d 100644 --- a/src/java/com/threerings/presents/tools/GenActionScriptTask.java +++ b/src/java/com/threerings/presents/tools/GenActionScriptTask.java @@ -25,6 +25,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.List; import java.util.Set; import java.io.BufferedWriter; @@ -247,7 +248,7 @@ public class GenActionScriptTask extends GenTask if (needsActionScriptImport(type, isField)) { imports.add(full); } - return getSimpleType(full); + return Iterables.getLast(DOT_SPLITTER.split(full)); } protected static boolean needsActionScriptImport (Class type, boolean isField) @@ -260,7 +261,7 @@ public class GenActionScriptTask extends GenTask protected static String toActionScriptType (Class type, boolean isField) { - if (type.isArray()) { + if (type.isArray() || List.class.isAssignableFrom(type)) { if (Byte.TYPE.equals(type.getComponentType())) { return "flash.utils.ByteArray"; } @@ -290,6 +291,7 @@ public class GenActionScriptTask extends GenTask return "Boolean"; } + // inner classes are not supported by ActionScript so we _ return type.getName().replaceAll("\\$", "_"); } @@ -329,6 +331,9 @@ public class GenActionScriptTask extends GenTask } else if (type.equals(Double.TYPE)) { return "readDouble()"; + } else if (List.class.isAssignableFrom(type)) { + return "readField(ArrayStreamer.INSTANCE)"; + } else if (type.isArray()) { if (!type.getComponentType().isPrimitive()) { return "readObject(TypedArray)"; @@ -347,30 +352,23 @@ public class GenActionScriptTask extends GenTask } } } else { - return "readObject(" + ActionScriptSource.toSimpleName(type.getName()) + ")"; + return "readObject(" + Iterables.getLast(DOT_SPLITTER.split(toActionScriptType(type, false))) + ")"; } } - public static String getSimpleType(String fullType) - { - return Iterables.getLast(DOT_SPLITTER.split(fullType)); - } - public static String toWriteObject (Class type, String name) { if (type.equals(Integer.class)) { return "writeObject(new Integer(" + name + "))"; - } else if (type.equals(Long.class)) { - return "writeField(" + name + ")"; - } else if (type.equals(Boolean.TYPE)) { return "writeBoolean(" + name + ")"; } else if (type.equals(Byte.TYPE)) { return "writeByte(" + name + ")"; - } else if (type.equals(Short.TYPE) || type.equals(Character.TYPE)) { + } else if (type.equals(Short.TYPE) || + type.equals(Character.TYPE)) { return "writeShort(" + name + ")"; } else if (type.equals(Integer.TYPE)) { @@ -385,10 +383,14 @@ public class GenActionScriptTask extends GenTask } else if (type.equals(Double.TYPE)) { return "writeDouble(" + name + ")"; - } else if (type.equals(String.class) || + } else if (type.equals(Long.class) || + type.equals(String.class) || (type.isArray() && type.getComponentType().isPrimitive())) { return "writeField(" + name + ")"; + } else if (List.class.isAssignableFrom(type)) { + return "writeField(" + name + ", ArrayStreamer.INSTANCE)"; + } else { return "writeObject(" + name + ")"; } diff --git a/tests/src/as/com/threerings/io/ASStreamableSubset.as b/tests/src/as/com/threerings/io/ASStreamableSubset.as index 438def271..fa1cdcaed 100644 --- a/tests/src/as/com/threerings/io/ASStreamableSubset.as +++ b/tests/src/as/com/threerings/io/ASStreamableSubset.as @@ -29,6 +29,7 @@ import com.threerings.io.SimpleStreamableObject; import com.threerings.util.Long; import com.threerings.io.TypedArray; import flash.utils.ByteArray; +import com.threerings.io.streamers.ArrayStreamer; // GENERATED PREAMBLE END import com.threerings.util.Util; @@ -64,6 +65,7 @@ public class ASStreamableSubset extends SimpleStreamableObject bytes.writeByte(2); bytes.writeByte(3); ints = TypedArray.create(int, [1, 2, 3]); + strings = TypedArray.create(String, ["one", "two", "three"]); } public function equals (o :ASStreamableSubset) :Boolean @@ -73,7 +75,8 @@ public class ASStreamableSubset extends SimpleStreamableObject byte8 === o.byte8 && string1 === o.string1 && nullString1 === o.nullString1 && Util.equals(bools, o.bools) && Util.equals(bytes, o.bytes) && Util.equals(ints, o.ints) && Util.equals(nullBools, o.nullBools) && - Util.equals(nullBytes, o.nullBytes) && Util.equals(nullInts, o.nullInts); + Util.equals(nullBytes, o.nullBytes) && Util.equals(nullInts, o.nullInts) && + Util.equals(strings, o.strings) && Util.equals(nullStrings, o.nullStrings); } @@ -94,6 +97,8 @@ public class ASStreamableSubset extends SimpleStreamableObject public var nullBools :TypedArray; public var nullBytes :ByteArray; public var nullInts :TypedArray; + public var strings :TypedArray; + public var nullStrings :TypedArray; override public function readObject (ins :ObjectInputStream) :void { @@ -114,8 +119,10 @@ public class ASStreamableSubset extends SimpleStreamableObject nullBools = ins.readField(TypedArray.getJavaType(Boolean)); nullBytes = ins.readField(ByteArray); nullInts = ins.readField(TypedArray.getJavaType(int)); + strings = ins.readField(ArrayStreamer.INSTANCE); + nullStrings = ins.readField(ArrayStreamer.INSTANCE); } - + override public function writeObject (out :ObjectOutputStream) :void { super.writeObject(out); @@ -135,6 +142,8 @@ public class ASStreamableSubset extends SimpleStreamableObject out.writeField(nullBools); out.writeField(nullBytes); out.writeField(nullInts); + out.writeField(strings, ArrayStreamer.INSTANCE); + out.writeField(nullStrings, ArrayStreamer.INSTANCE); } // GENERATED STREAMING END diff --git a/tests/src/as/com/threerings/io/StreamableTest.as b/tests/src/as/com/threerings/io/StreamableTest.as index ee7437d4c..27c7ec057 100644 --- a/tests/src/as/com/threerings/io/StreamableTest.as +++ b/tests/src/as/com/threerings/io/StreamableTest.as @@ -31,6 +31,11 @@ import asunit.framework.TestCase; public class StreamableTest extends TestCase { + public function StreamableTest (name:String = null) + { + super(name); + } + public function testStreamingToSelf ():void { var sub:ASStreamableSubset = ASStreamableSubset.createWithJavaDefaults(); @@ -49,7 +54,8 @@ public class StreamableTest extends TestCase var javaData:ByteArray = StringUtil.unhexlate( "ffff0024636f6d2e746872656572696e67732e696f2e415353747265616d61626c65537562736574" + "01000200000003000000000000000440a0000040180000000000000007080100036f6e6500010000" + - "000301000101000000030102030100000003000000010000000200000003000000"); + "0003010001010000000301020301000000030000000100000002000000030000000100000003fffe" + + "00106a6176612e6c616e672e537472696e6700036f6e650002000374776f00020005746872656500"); var input:ObjectInputStream = new ObjectInputStream(javaData); var read :ASStreamableSubset = input.readObject(ASStreamableSubset); assertTrue(sub.equals(read)); diff --git a/tests/src/java/com/threerings/io/ASStreamableSubset.java b/tests/src/java/com/threerings/io/ASStreamableSubset.java index a3ffd133f..b77ec1164 100644 --- a/tests/src/java/com/threerings/io/ASStreamableSubset.java +++ b/tests/src/java/com/threerings/io/ASStreamableSubset.java @@ -22,8 +22,10 @@ package com.threerings.io; //Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA import java.util.Arrays; +import java.util.List; import com.google.common.base.Objects; +import com.google.common.collect.Lists; public class ASStreamableSubset extends SimpleStreamableObject { @@ -47,6 +49,9 @@ public class ASStreamableSubset extends SimpleStreamableObject public byte[] nullBytes; public int[] nullInts; + public List strings = Lists.newArrayList("one", "two", "three"); + public List nullStrings; + @Override public boolean equals (Object other) { @@ -67,6 +72,10 @@ public class ASStreamableSubset extends SimpleStreamableObject Arrays.equals(bools, ow.bools) && Arrays.equals(bytes, ow.bytes) && Arrays.equals(ints, ow.ints) && - Arrays.equals(nullBools, ow.nullBools) && Arrays.equals(nullBytes, ow.nullBytes); + Arrays.equals(nullBools, ow.nullBools) && Arrays.equals(nullBytes, ow.nullBytes) + && Arrays.equals(nullInts, ow.nullInts) + && + + Objects.equal(strings, ow.strings) && Objects.equal(nullStrings, ow.nullStrings); } } diff --git a/tests/src/java/com/threerings/io/StreamableTest.java b/tests/src/java/com/threerings/io/StreamableTest.java index ab024c523..cbf40079f 100644 --- a/tests/src/java/com/threerings/io/StreamableTest.java +++ b/tests/src/java/com/threerings/io/StreamableTest.java @@ -345,11 +345,8 @@ public class StreamableTest oout.writeObject(w); byte[] data = bout.toByteArray(); - // uncomment this and rerun the tests to generate an updated WIRE_DATA blob: - // String dstr = StringUtil.wordWrap(StringUtil.hexlate(data), 80); - // dstr = StringUtil.join(dstr.split("\n"), "\" +\n \""); - // System.out.println(" protected static final byte[] WIRE_DATA = " + - // "StringUtil.unhexlate(\n \"" + dstr + "\");"); + // uncomment this and rerun the tests to generate an updated WIRE_DATA blob + // printWireData(w); // oddly, JUnit doesn't like comparing byte arrays directly (this fails: // assertEquals(WIRE_DATA, WIRE_DATA.clone())), but comparing strings is fine @@ -360,6 +357,18 @@ public class StreamableTest assertEquals(w, oin.readObject()); } + protected void printWireData (Object o) + throws IOException + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + ObjectOutputStream oout = new ObjectOutputStream(bout); + oout.writeObject(o); + String dstr = StringUtil.wordWrap(StringUtil.hexlate(bout.toByteArray()), 80); + dstr = StringUtil.join(dstr.split("\n"), "\" +\n \""); + System.out.println(" protected static final byte[] WIRE_DATA = " + + "StringUtil.unhexlate(\n \"" + dstr + "\");"); + } + @Test public void testPostStreamingMutation () throws IOException, ClassNotFoundException