From 28c7609df858dded14478b684c975c7c2ba0da67 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Sat, 8 Nov 2008 01:57:42 +0000 Subject: [PATCH] Allow streaming Class references. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@5524 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../com/threerings/io/BasicStreamers.java | 20 ++++ .../com/threerings/io/ObjectInputStream.java | 110 ++++++++++-------- .../com/threerings/io/ObjectOutputStream.java | 19 ++- 3 files changed, 97 insertions(+), 52 deletions(-) diff --git a/src/java/com/threerings/io/BasicStreamers.java b/src/java/com/threerings/io/BasicStreamers.java index cf6b767cc..ad3b0402a 100644 --- a/src/java/com/threerings/io/BasicStreamers.java +++ b/src/java/com/threerings/io/BasicStreamers.java @@ -44,6 +44,7 @@ public class BasicStreamers Long.class, Float.class, Double.class, + Class.class, String.class, boolean[].class, byte[].class, @@ -68,6 +69,7 @@ public class BasicStreamers new LongStreamer(), new FloatStreamer(), new DoubleStreamer(), + new ClassStreamer(), new StringStreamer(), new BooleanArrayStreamer(), new ByteArrayStreamer(), @@ -225,6 +227,24 @@ public class BasicStreamers } } + /** Streams {@link Class} instances. */ + public static class ClassStreamer extends BasicStreamer + { + @Override + public Object createObject (ObjectInputStream in) + throws IOException, ClassNotFoundException + { + return in.readClassMapping().sclass; + } + + @Override + public void writeObject (Object object, ObjectOutputStream out, boolean useWriter) + throws IOException + { + out.writeClassMapping((Class)object); + } + } + /** Streams {@link String} instances. */ public static class StringStreamer extends BasicStreamer { diff --git a/src/java/com/threerings/io/ObjectInputStream.java b/src/java/com/threerings/io/ObjectInputStream.java index b4d25b43e..bf015e040 100644 --- a/src/java/com/threerings/io/ObjectInputStream.java +++ b/src/java/com/threerings/io/ObjectInputStream.java @@ -76,59 +76,14 @@ public class ObjectInputStream extends DataInputStream public Object readObject () throws IOException, ClassNotFoundException { - ClassMapping cmap; - - // create our classmap if necessary - if (_classmap == null) { - _classmap = new ArrayList(); - // insert a zeroth element - _classmap.add(null); - } - try { - // read in the class code for this instance - short code = readShort(); - - // a zero code indicates a null value - if (code == 0) { + // read the class mapping + ClassMapping cmap = readClassMapping(); + if (cmap == null) { if (STREAM_DEBUG) { log.info(hashCode() + ": Read null."); } return null; - - // if the code is negative, that means that we've never seen it before and class - // metadata follows - } else if (code < 0) { - // first swap the code into positive-land - code *= -1; - - // read in the class metadata - String cname = readUTF(); - // if we have a translation (used to cope when serialized classes are renamed) use - // it - if (_translations != null) { - String tname = _translations.get(cname); - if (tname != null) { - cname = tname; - } - } - - // create the class mapping - cmap = mapClass(code, cname); - - } else { - cmap = _classmap.get(code); - - // sanity check - if (cmap == null) { - // this will help with debugging - log.warning("Internal stream error, no class metadata", "code", code, - "ois", this, new Exception()); - log.warning("ObjectInputStream mappings", "map", _classmap); - String errmsg = "Read object code for which we have no registered class " + - "metadata [code=" + code + "]"; - throw new RuntimeException(errmsg); - } } if (STREAM_DEBUG) { @@ -145,6 +100,65 @@ public class ObjectInputStream extends DataInputStream } } + /** + * Reads a class mapping from the stream. + * + * @return the class mapping, or null to represent a null value. + */ + protected ClassMapping readClassMapping () + throws IOException, ClassNotFoundException + { + // create our classmap if necessary + if (_classmap == null) { + _classmap = new ArrayList(); + // insert a zeroth element + _classmap.add(null); + } + + // read in the class code for this instance + short code = readShort(); + + // a zero code indicates a null value + if (code == 0) { + return null; + + // if the code is negative, that means that we've never seen it before and class + // metadata follows + } else if (code < 0) { + // first swap the code into positive-land + code *= -1; + + // read in the class metadata + String cname = readUTF(); + // if we have a translation (used to cope when serialized classes are renamed) use + // it + if (_translations != null) { + String tname = _translations.get(cname); + if (tname != null) { + cname = tname; + } + } + + // create the class mapping + return mapClass(code, cname); + + } else { + ClassMapping cmap = _classmap.get(code); + + // sanity check + if (cmap == null) { + // this will help with debugging + log.warning("Internal stream error, no class metadata", "code", code, + "ois", this, new Exception()); + log.warning("ObjectInputStream mappings", "map", _classmap); + String errmsg = "Read object code for which we have no registered class " + + "metadata [code=" + code + "]"; + throw new RuntimeException(errmsg); + } + return cmap; + } + } + /** * Creates, adds, and returns the class mapping for the specified code and class name. */ diff --git a/src/java/com/threerings/io/ObjectOutputStream.java b/src/java/com/threerings/io/ObjectOutputStream.java index 22d7e985c..74aa08bf1 100644 --- a/src/java/com/threerings/io/ObjectOutputStream.java +++ b/src/java/com/threerings/io/ObjectOutputStream.java @@ -71,13 +71,25 @@ public class ObjectOutputStream extends DataOutputStream return; } + // otherwise, write the class mapping, then the bare object + Class sclass = Streamer.getStreamerClass(object); + ClassMapping cmap = writeClassMapping(sclass); + writeBareObject(object, cmap.streamer, true); + } + + /** + * Retrieves or creates the class mapping for the supplied class, writes it out to the stream, + * and returns a reference to it. + */ + protected ClassMapping writeClassMapping (Class sclass) + throws IOException + { // create our classmap if necessary if (_classmap == null) { _classmap = new HashMap, ClassMapping>(); } - // otherwise, look up the class mapping record - Class sclass = Streamer.getStreamerClass(object); + // look up the class mapping record ClassMapping cmap = _classmap.get(sclass); // create a class mapping for this class if we've not got one @@ -103,8 +115,7 @@ public class ObjectOutputStream extends DataOutputStream } else { writeExistingClassMapping(cmap); } - - writeBareObject(object, cmap.streamer, true); + return cmap; } /**