Some work on streaming.
git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@3855 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -51,3 +51,10 @@ Notes
|
||||
- constructors do not defaultly call super()- be sure to do it explicitely.
|
||||
Maybe we should get in the habit of doing it in Java for consistency and
|
||||
explicitness.
|
||||
|
||||
- I'm a little shaky still about how I'm going to handle arrays. In
|
||||
ActionScript all arrays (except ByteArray) are the same type: Array.
|
||||
If class A is extended by B and C, the server could pass around an array of
|
||||
A, filled with B and C elements. I would have no way on the client to
|
||||
inspect an array like that and know to tell the server that it's an A[].
|
||||
Punting completely on Arrays for now.
|
||||
|
||||
@@ -1,6 +1,51 @@
|
||||
package com.threerings.io {
|
||||
|
||||
import flash.util.ByteArray;
|
||||
|
||||
public class ArrayMask
|
||||
implements Streamable
|
||||
{
|
||||
public function ArrayMask (length :int = 0)
|
||||
{
|
||||
var mlength :int = length / 8;
|
||||
if (length % 8 != 0) {
|
||||
mlength++;
|
||||
}
|
||||
_mask.length = mlength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the specified index as containing a non-null element in the
|
||||
* array we're representing.
|
||||
*/
|
||||
public function setBit (index :int) :void
|
||||
{
|
||||
_mask[index/8] |= (1 << (index % 8));
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the specified array element non-null?
|
||||
*/
|
||||
public function isSet (index :int) :Boolean
|
||||
{
|
||||
return (_mask[index/8] & (1 << (index % 8))) != 0;
|
||||
}
|
||||
|
||||
// documentation inherited from interface Streamable
|
||||
public function writeObject (out :ObjectOutputStream) :void
|
||||
{
|
||||
out.writeShort(_mask.length);
|
||||
out.writeBytes(_mask);
|
||||
}
|
||||
|
||||
// documentation inherited from interface Streamable
|
||||
public function readObject (ins :ObjectInputStream) :void
|
||||
{
|
||||
_mask.length = ins.readShort();
|
||||
ins.readBytes(_mask, 0, _mask.length);
|
||||
}
|
||||
|
||||
/** The array mask. */
|
||||
protected var _mask :ByteArray = new ByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,6 @@ public class ObjectInputStream
|
||||
public function readObject () :*
|
||||
//throws IOError
|
||||
{
|
||||
var cmap :ClassMapping;
|
||||
|
||||
try {
|
||||
// read in the class code for this instance
|
||||
var code :int = readShort();
|
||||
@@ -38,16 +36,19 @@ public class ObjectInputStream
|
||||
// a zero code indicates a null value
|
||||
if (code == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var cmap :ClassMapping;
|
||||
|
||||
// if the code is negative, that means we've never seen it
|
||||
// before and class metadata follows
|
||||
} else if (code < 0) {
|
||||
if (code < 0) {
|
||||
// first swap the code into positive land
|
||||
code *= -1;
|
||||
|
||||
// read in the class metadata
|
||||
var cname :String = readUTF();
|
||||
var streamer :Streamer = Streamer.getStreamer(cname);
|
||||
var streamer :Streamer = Streamer.getStreamerByJavaName(cname);
|
||||
|
||||
cmap = new ClassMapping(code, cname, streamer);
|
||||
_classMap[code] = cmap;
|
||||
@@ -60,34 +61,41 @@ public class ObjectInputStream
|
||||
}
|
||||
}
|
||||
|
||||
// create an instance of the appropriate object
|
||||
_streamer = cmap.streamer;
|
||||
var target :* = _streamer.createObject(this);
|
||||
_current = target;
|
||||
var target :*;
|
||||
if (cmap.streamer === null) {
|
||||
var clazz :Class = flash.util.getClassByName(cmap.cname);
|
||||
target = new clazz();
|
||||
|
||||
// now read the instance data
|
||||
_streamer.readObject(target, this, true);
|
||||
|
||||
// and return the newly read object
|
||||
} else {
|
||||
target = cmap.streamer.createObject(this);
|
||||
}
|
||||
readBareObjectImpl(target, cmap.streamer);
|
||||
return target;
|
||||
|
||||
} finally {
|
||||
// clear out our current object references
|
||||
_current = null;
|
||||
_streamer = null;
|
||||
} catch (MemoryError me) {
|
||||
throw new IOError("out of memory" + me.message);
|
||||
}
|
||||
}
|
||||
|
||||
public function readBareObject (obj :*) :void
|
||||
//throws IOError
|
||||
{
|
||||
try {
|
||||
// obtain the streamer for the objects of this class
|
||||
_streamer = Streamer.getStreamer(ClassUtil.getClassName(obj));
|
||||
_current = obj;
|
||||
readBareObjectImpl(obj, Streamer.getStreamer(obj));
|
||||
}
|
||||
|
||||
// now read the instance data
|
||||
_streamer.readObject(obj, this, true);
|
||||
protected function readBareObjectImpl (obj :*, streamer :Streamer) :void
|
||||
{
|
||||
// streamable objects
|
||||
if (streamer == null) {
|
||||
var sable :Streamable = (obj as Streamable);
|
||||
sable.readObject(this);
|
||||
return;
|
||||
}
|
||||
|
||||
_current = obj;
|
||||
_streamer = steamer;
|
||||
try {
|
||||
_streamer.readObject(obj, this);
|
||||
|
||||
} finally {
|
||||
// clear out our current object references
|
||||
@@ -125,9 +133,15 @@ public class ObjectInputStream
|
||||
}
|
||||
|
||||
public function readBytes (bytes :ByteArray, offset :uint = 0,
|
||||
length :uint = 0) :void
|
||||
length :uint = undefined) :void
|
||||
//throws IOError
|
||||
{
|
||||
// IDataInput reads all available bytes if a length is not passed
|
||||
// in. Protect against an easy error to make by using the length of
|
||||
// the array
|
||||
if (length === undefined) {
|
||||
length = bytes.length;
|
||||
}
|
||||
_source.readBytes(bytes, offset, length);
|
||||
}
|
||||
|
||||
@@ -180,6 +194,6 @@ public class ObjectInputStream
|
||||
protected var _streamer :Streamer;
|
||||
|
||||
/** A map of short class code to ClassMapping info. */
|
||||
protected var _classMap :SimpleMap = new SimpleMap();
|
||||
protected var _classMap :Array = new Array();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import com.threerings.util.ClassUtil;
|
||||
import com.threerings.util.SimpleMap;
|
||||
|
||||
public class ObjectOutputStream
|
||||
// implements IDataOutput
|
||||
{
|
||||
public function ObjectOutputStream (targ :IDataOutput)
|
||||
{
|
||||
@@ -23,57 +22,55 @@ public class ObjectOutputStream
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var cname :String = ClassUtil.getClassName(obj);
|
||||
var cname :String = ClassUtil.getClassName(obj);
|
||||
// look up the class mapping record
|
||||
var cmap :ClassMapping = _classMap[cname];
|
||||
|
||||
// look up the class mapping record
|
||||
var cmap :ClassMapping = _classMap[cname];
|
||||
_current = obj;
|
||||
|
||||
// create a class mapping if we've not got one
|
||||
if (cmap === undefined) {
|
||||
var streamer :Streamer = Streamer.getStreamer(cname);
|
||||
if (streamer === undefined) {
|
||||
// TODO
|
||||
trace("OMG, cannot stream ", cname);
|
||||
return;
|
||||
}
|
||||
|
||||
cmap = new ClassMapping(_nextCode++, cname, streamer);
|
||||
_classMap[cname] = cmap;
|
||||
|
||||
// TODO: if _nextCode blows short, log an error
|
||||
|
||||
writeShort(-cmap.code);
|
||||
writeUTF(cname);
|
||||
|
||||
} else {
|
||||
writeShort(cmap.code);
|
||||
// create a class mapping if we've not got one
|
||||
if (cmap === undefined) {
|
||||
var streamer :Streamer = Streamer.getStreamer(obj);
|
||||
if (streamer === undefined) {
|
||||
// TODO
|
||||
trace("OMG, cannot stream ", cname);
|
||||
return;
|
||||
}
|
||||
|
||||
// now write the instance data
|
||||
_streamer = cmap.streamer;
|
||||
_streamer.writeObject(obj, this, true);
|
||||
cmap = new ClassMapping(_nextCode++, cname, streamer);
|
||||
_classMap[cname] = cmap;
|
||||
|
||||
} finally {
|
||||
_current = null;
|
||||
_streamer = null;
|
||||
// TODO: if _nextCode blows short, log an error
|
||||
|
||||
writeShort(-cmap.code);
|
||||
writeUTF((streamer == null) ? cname : streamer.getJavaClassName());
|
||||
|
||||
} else {
|
||||
writeShort(cmap.code);
|
||||
}
|
||||
|
||||
writeBareObjectImpl(obj, cmap.streamer);
|
||||
}
|
||||
|
||||
public function writeBareObject (obj :*) :void
|
||||
//throws IOError
|
||||
{
|
||||
writeBareObjectImpl(obj, Streamer.getStreamer(obj));
|
||||
}
|
||||
|
||||
protected function writeBareObjectImpl (obj :*, streamer :Streamer)
|
||||
{
|
||||
// if it's Streamable, it goes straight through
|
||||
if (streamer == null) {
|
||||
var sable :Streamable = (obj as Streamable);
|
||||
sable.writeObject(this);
|
||||
return;
|
||||
}
|
||||
|
||||
// otherwise, stream it!
|
||||
_current = obj;
|
||||
_streamer = streamer;
|
||||
try {
|
||||
// get the streamer for objects of this type
|
||||
_streamer = Streamer.getStreamer(ClassUtil.getClassName(obj));
|
||||
_current = obj;
|
||||
|
||||
// now write the instance data
|
||||
_streamer.writeObject(obj, this, true);
|
||||
|
||||
_streamer.writeObject(obj, this);
|
||||
} finally {
|
||||
// clear out our current object references
|
||||
_current = null;
|
||||
_streamer = null;
|
||||
}
|
||||
@@ -147,7 +144,7 @@ public class ObjectOutputStream
|
||||
public function writeShort (value :int) :void
|
||||
//throws IOError
|
||||
{
|
||||
_targ.writeInt(value);
|
||||
_targ.writeShort(value);
|
||||
}
|
||||
|
||||
public function writeUTF (value :String) :void
|
||||
|
||||
@@ -32,87 +32,76 @@ public class Streamer
|
||||
|
||||
public static function getStreamer (obj :*) :Streamer
|
||||
{
|
||||
if (_streamerMap == null) {
|
||||
if (obj is Streamable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (_streamers == null) {
|
||||
createStreamers();
|
||||
}
|
||||
|
||||
if (obj is Streamable) {
|
||||
return null;
|
||||
|
||||
} else if (obj is String) {
|
||||
return STRING_STREAMER;
|
||||
|
||||
} else if (obj is int) {
|
||||
return INT_STREAMER;
|
||||
|
||||
} else if (obj is Number) {
|
||||
return NUMBER_STREAMER;
|
||||
|
||||
} else if (obj is Array) {
|
||||
return ARRAY_STREAMER;
|
||||
|
||||
} else if (obj is ByteArray) {
|
||||
return BYTE_ARRAY_STREAMER;
|
||||
|
||||
} else {
|
||||
return undefined;
|
||||
var s :Streamer;
|
||||
for (var ii :int = 0; ii < _streamers.lenght; ii++) {
|
||||
s = (_streamers[ii] as Streamer);
|
||||
if (s.isStreamerFor(obj)) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public static function getStreamerByJavaName (jname :String) :Streamer
|
||||
{
|
||||
if (jname === "java.lang.String") {
|
||||
return STRING_STREAMER;
|
||||
|
||||
} else if (jname === "java.lang.Integer") {
|
||||
return INT_STREAMER;
|
||||
|
||||
} else if (jname === "java.lang.Double") {
|
||||
return NUMBER_STREAMER;
|
||||
|
||||
} else if (jname === "[Ljava.lang.Object") {
|
||||
return ARRAY_STREAMER;
|
||||
|
||||
} else if (jname === "[B") {
|
||||
return BYTE_ARRAY_STREAMER;
|
||||
|
||||
} else {
|
||||
return null;
|
||||
if (_streamers == null) {
|
||||
createStreamers();
|
||||
}
|
||||
|
||||
var s :Streamer;
|
||||
for (var ii :int = 0; ii < _streamers.length; ii++) {
|
||||
s = (_streamers[ii] as Streamer);
|
||||
if (s.getJavaClassName() === jname) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/** This should be a protected constructor. */
|
||||
public function Streamer (targ :Class)
|
||||
public function Streamer (targ :Class, jname :String)
|
||||
//throws IOError
|
||||
{
|
||||
_targ = targ;
|
||||
_jname = jname;
|
||||
}
|
||||
|
||||
public function isStreamerFor (obj :*) :Boolean
|
||||
{
|
||||
return (obj is _targ); // scripting langs are weird
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the String to use to identify the class that we're streaming.
|
||||
*/
|
||||
// TODO
|
||||
public function getClassName () :String
|
||||
public function getJavaClassName () :String
|
||||
{
|
||||
return "TODO: javaname";
|
||||
return _jname;
|
||||
}
|
||||
|
||||
public function writeObject (obj :*, out :ObjectOutputStream,
|
||||
useWriter :Boolean) :void
|
||||
public function writeObject (obj :*, out :ObjectOutputStream) :void
|
||||
//throws IOError
|
||||
{
|
||||
// TODO: check use of isProtoTypeOf, it's unclear if it's
|
||||
// going to do what we want
|
||||
if (useWriter && obj.isPrototypeOf(Streamable)) {
|
||||
obj.writeObject(out);
|
||||
return;
|
||||
trace("TODO");
|
||||
|
||||
if (obj is Array) {
|
||||
trace("Arrays not yet done. Crap!");
|
||||
/**
|
||||
var arr :Array = (obj as Array); // not strictly necessary
|
||||
var length :int = arr.length;
|
||||
out.writeInt(length);
|
||||
*/
|
||||
}
|
||||
|
||||
// TODO: cope with arrays
|
||||
|
||||
// write out the fields... this is bogus because
|
||||
// we just want to call the streamer method
|
||||
obj.writeObject(out);
|
||||
}
|
||||
|
||||
public function createObject (ins :ObjectInputStream) :*
|
||||
@@ -122,22 +111,10 @@ public class Streamer
|
||||
return new _targ();
|
||||
}
|
||||
|
||||
public function readObject (obj :*, ins :ObjectInputStream,
|
||||
useReader :Boolean) :void
|
||||
public function readObject (obj :*, ins :ObjectInputStream) :void
|
||||
//throws IOError
|
||||
{
|
||||
// TODO: check use of isProtoTypeOf, it's unclear if it's
|
||||
// going to do what we want
|
||||
if (useReader && obj.isPrototypeOf(Streamable)) {
|
||||
obj.readObject(ins);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: cope with arrays
|
||||
|
||||
// read in the fields... this is bogus because we just
|
||||
// want to call the streamer method
|
||||
obj.readObject(ins);
|
||||
trace("TODO");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,19 +123,23 @@ public class Streamer
|
||||
*/
|
||||
protected static function createStreamers () :void
|
||||
{
|
||||
_streamerMap = new SimpleMap();
|
||||
_streamers = new Array();
|
||||
|
||||
// add our default streamers
|
||||
_streamers.push(
|
||||
new StringStreamer(),
|
||||
new IntStreamer(),
|
||||
new NumberStreamer(),
|
||||
new ArrayStreamer(),
|
||||
new ByteArrayStreamer()
|
||||
);
|
||||
}
|
||||
|
||||
protected var _targ :Class;
|
||||
|
||||
protected static var _streamerMap :SimpleMap;
|
||||
protected var _jname :String;
|
||||
|
||||
|
||||
protected static const STRING_STREAMER :Streamer = new StringStreamer();
|
||||
protected static const BYTE_ARRAY_STREAMER :Streamer =
|
||||
new ByteArrayStreamer();
|
||||
protected static const ARRAY_STREAMER :Streamer = new ArrayStreamer();
|
||||
protected static const INT_STREAMER :Streamer = new IntStreamer();
|
||||
protected static const NUMBER_STREAMER :Streamer = new NumberStreamer();
|
||||
/** Just a list of our standard streamers. */
|
||||
protected static var _streamers :Array;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ public class ArrayStreamer extends Streamer
|
||||
{
|
||||
public function ArrayStreamer ()
|
||||
{
|
||||
super(Array);
|
||||
super(Array, "[Ljava.lang.Object");
|
||||
}
|
||||
|
||||
public override function createObject (ins :ObjectInputStream) :*
|
||||
@@ -19,8 +19,7 @@ public class ArrayStreamer extends Streamer
|
||||
return new Array(ins.readInt());
|
||||
}
|
||||
|
||||
public override function writeObject (obj :*, out :ObjectOutputStream,
|
||||
useWriter :Boolean) :void
|
||||
public override function writeObject (obj :*, out :ObjectOutputStream) :void
|
||||
{
|
||||
var arr :Array = (obj as Array);
|
||||
out.writeInt(arr.length);
|
||||
@@ -29,8 +28,7 @@ public class ArrayStreamer extends Streamer
|
||||
}
|
||||
}
|
||||
|
||||
public override function readObject (obj :*, ins :ObjectInputStream,
|
||||
useReader :Boolean) :void
|
||||
public override function readObject (obj :*, ins :ObjectInputStream) :void
|
||||
{
|
||||
var arr :Array = (obj as Array);
|
||||
for (var ii :int = 0; ii < arr.length; ii++) {
|
||||
|
||||
@@ -13,7 +13,7 @@ public class ByteArrayStreamer extends Streamer
|
||||
{
|
||||
public function ByteArrayStreamer ()
|
||||
{
|
||||
super(ByteArray);
|
||||
super(ByteArray, "[B"); // yes, that's the Java class for a byte[].
|
||||
}
|
||||
|
||||
public override function createObject (ins :ObjectInputStream) :*
|
||||
@@ -23,16 +23,14 @@ public class ByteArrayStreamer extends Streamer
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public override function writeObject (obj :*, out :ObjectOutputStream,
|
||||
useWriter :Boolean) :void
|
||||
public override function writeObject (obj :*, out :ObjectOutputStream) :void
|
||||
{
|
||||
var bytes :ByteArray = (obj as ByteArray);
|
||||
out.writeInt(bytes.length);
|
||||
out.writeBytes(bytes);
|
||||
}
|
||||
|
||||
public override function readObject (obj :*, ins :ObjectInputStream,
|
||||
useReader :Boolean) :void
|
||||
public override function readObject (obj :*, ins :ObjectInputStream) :void
|
||||
{
|
||||
var bytes :ByteArray = (obj as ByteArray);
|
||||
ins.readBytes(bytes, 0, bytes.length);
|
||||
|
||||
@@ -11,7 +11,7 @@ public class IntStreamer extends Streamer
|
||||
{
|
||||
public function IntStreamer ()
|
||||
{
|
||||
super(int);
|
||||
super(int, "java.lang.Integer");
|
||||
}
|
||||
|
||||
public override function createObject (ins :ObjectInputStream) :*
|
||||
@@ -19,15 +19,13 @@ public class IntStreamer extends Streamer
|
||||
return ins.readInt();
|
||||
}
|
||||
|
||||
public override function writeObject (obj :*, out :ObjectOutputStream,
|
||||
useWriter :Boolean) :void
|
||||
public override function writeObject (obj :*, out :ObjectOutputStream) :void
|
||||
{
|
||||
var i :int = (obj as int);
|
||||
out.writeInt(i);
|
||||
}
|
||||
|
||||
public override function readObject (obj :*, ins :ObjectInputStream,
|
||||
useReader :Boolean) :void
|
||||
public override function readObject (obj :*, ins :ObjectInputStream) :void
|
||||
{
|
||||
// nothing here, the int is fully read in createObject()
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ public class NumberStreamer extends Streamer
|
||||
{
|
||||
public function NumberStreamer ()
|
||||
{
|
||||
super(Number);
|
||||
super(Number, "java.lang.Double");
|
||||
}
|
||||
|
||||
public override function createObject (ins :ObjectInputStream) :*
|
||||
@@ -19,15 +19,13 @@ public class NumberStreamer extends Streamer
|
||||
return ins.readDouble();
|
||||
}
|
||||
|
||||
public override function writeObject (obj :*, out :ObjectOutputStream,
|
||||
useWriter :Boolean) :void
|
||||
public override function writeObject (obj :*, out :ObjectOutputStream) :void
|
||||
{
|
||||
var n :Number = (obj as Number);
|
||||
out.writeDouble(n);
|
||||
}
|
||||
|
||||
public override function readObject (obj :*, ins :ObjectInputStream,
|
||||
useReader :Boolean) :void
|
||||
public override function readObject (obj :*, ins :ObjectInputStream) :void
|
||||
{
|
||||
// nothing here, the Number is fully read in createObject()
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ public class StringStreamer extends Streamer
|
||||
{
|
||||
public function StringStreamer ()
|
||||
{
|
||||
super(String);
|
||||
super(String, "java.lang.String");
|
||||
}
|
||||
|
||||
public override function createObject (ins :ObjectInputStream) :*
|
||||
@@ -19,15 +19,13 @@ public class StringStreamer extends Streamer
|
||||
return ins.readUTF();
|
||||
}
|
||||
|
||||
public override function writeObject (obj :*, out :ObjectOutputStream,
|
||||
useWriter :Boolean) :void
|
||||
public override function writeObject (obj :*, out :ObjectOutputStream) :void
|
||||
{
|
||||
var s :String = (obj as String);
|
||||
out.writeUTF(s);
|
||||
}
|
||||
|
||||
public override function readObject (obj :*, ins :ObjectInputStream,
|
||||
useReader :Boolean) :void
|
||||
public override function readObject (obj :*, ins :ObjectInputStream) :void
|
||||
{
|
||||
// nothing here, the String is fully read in createObject()
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ public class Communicator
|
||||
{
|
||||
// create the socket and set up listeners
|
||||
_socket = new Socket();
|
||||
_socket.endian = Endian.BIG_ENDIAN;
|
||||
_socket.addEventListener(Event.CONNECT, socketOpened);
|
||||
_socket.addEventListener(IOErrorEvent.IO_ERROR, socketError);
|
||||
_socket.addEventListener(Event.CLOSE, socketClosed);
|
||||
|
||||
@@ -1,12 +1,20 @@
|
||||
package com.threerings.util {
|
||||
|
||||
import flash.util.*;
|
||||
|
||||
public class ClassUtil extends Object
|
||||
public class ClassUtil
|
||||
{
|
||||
public static function getClassName (obj :*) :String
|
||||
{
|
||||
return getQualifiedClassName(obj).replace("::", ".");
|
||||
return flash.util.getQualifiedClassName(obj).replace("::", ".");
|
||||
}
|
||||
|
||||
public static function getClass (obj :*) :Class
|
||||
{
|
||||
return flash.util.getClassByName(getClassName(obj));
|
||||
}
|
||||
|
||||
public static function getClassByName (cname :String) :Class
|
||||
{
|
||||
return flash.util.getClassByName(cname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ public class Name extends Object
|
||||
return Name.isBlank(this);
|
||||
}
|
||||
|
||||
public /*override*/ function toString () :String
|
||||
public override function toString () :String
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
@@ -65,8 +65,6 @@ public class Name extends Object
|
||||
out.writeUTF(_name);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
}
|
||||
|
||||
// documentation inherited from interface Streamable
|
||||
|
||||
Reference in New Issue
Block a user