From d4b2999c913a0dc6ee12a2d71aeffa8c4f1c3cc3 Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Wed, 30 Mar 2011 01:17:39 +0000 Subject: [PATCH] Initialize our constructor separately from our marshallers, so that sneaky classes that rely on the marshallers never being initialized don't break. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@6560 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- src/main/java/com/threerings/io/Streamer.java | 96 +++++++++---------- 1 file changed, 45 insertions(+), 51 deletions(-) diff --git a/src/main/java/com/threerings/io/Streamer.java b/src/main/java/com/threerings/io/Streamer.java index d8bdc9a43..3a47b016b 100644 --- a/src/main/java/com/threerings/io/Streamer.java +++ b/src/main/java/com/threerings/io/Streamer.java @@ -325,6 +325,7 @@ public abstract class Streamer protected ClassStreamer (Class target) { _target = target; + initConstructor(); initMarshallers(); } @@ -408,47 +409,10 @@ public abstract class Streamer } /** - * Initialize the marshallers. + * Locates the appropriate constructor for creating instances. */ - protected void initMarshallers () + protected void initConstructor () { - // reflect on all the object's fields - List fields = Lists.newArrayList(); - // this will read all non-static, non-transient fields into our fields list - ClassUtil.getFields(_target, fields); - - // Checks whether or not we should stream the fields in alphabetical order. - // This ensures cross-JVM compatibility since Class.getDeclaredFields() does not - // define an order. Due to legacy issues, this is not used by default. - if (SORT_FIELDS) { - QuickSort.sort(fields, FIELD_NAME_ORDER); - } - - // note whether this class is a streamable closure - final boolean isClosure = Streamable.Closure.class.isAssignableFrom(_target); - - // remove all marked with NotStreamable, and if we're a streamable closure, remove any - // anonymous inner class reference - Predicate filter = isClosure ? IS_STREAMCLOSURE : IS_STREAMABLE; - _fields = Iterables.toArray(Iterables.filter(fields, filter), Field.class); - int fcount = _fields.length; - - // obtain field marshallers for all of our fields - _marshallers = new FieldMarshaller[fcount]; - for (int ii = 0; ii < fcount; ii++) { - _marshallers[ii] = FieldMarshaller.getFieldMarshaller(_fields[ii]); - if (_marshallers[ii] == null) { - String errmsg = "Unable to marshall field [class=" + _target.getName() + - ", field=" + _fields[ii].getName() + - ", type=" + _fields[ii].getType().getName() + "]"; - throw new RuntimeException(errmsg); - } - if (ObjectInputStream.STREAM_DEBUG) { - log.info("Using " + _marshallers[ii] + " for " + _target.getName() + "." + - _fields[ii].getName() + "."); - } - } - // if we have a zero argument constructor, we have to use that one for (Constructor ctor : _target.getDeclaredConstructors()) { if (ctor.getParameterTypes().length == 0) { @@ -460,7 +424,7 @@ public abstract class Streamer // if we're an anonymous closure, we also support having a single constructor to which // we'll pass zero-valued arguments, which will then be overwritten by unstreaming - if (isClosure && _ctor == null) { + if (Streamable.Closure.class.isAssignableFrom(_target) && _ctor == null) { Constructor[] ctors = _target.getDeclaredConstructors(); if (ctors.length > 1) { throw new RuntimeException( @@ -488,6 +452,47 @@ public abstract class Streamer } } + /** + * Initialize the reading and writing marshallers. + */ + protected void initMarshallers () + { + // reflect on all the object's fields + List fields = Lists.newArrayList(); + // this will read all non-static, non-transient fields into our fields list + ClassUtil.getFields(_target, fields); + + // Checks whether or not we should stream the fields in alphabetical order. + // This ensures cross-JVM compatibility since Class.getDeclaredFields() does not + // define an order. Due to legacy issues, this is not used by default. + if (SORT_FIELDS) { + QuickSort.sort(fields, FIELD_NAME_ORDER); + } + + // remove all marked with NotStreamable, and if we're a streamable closure, remove any + // anonymous inner class reference + Predicate filter = Streamable.Closure.class.isAssignableFrom(_target) ? + IS_STREAMCLOSURE : IS_STREAMABLE; + _fields = Iterables.toArray(Iterables.filter(fields, filter), Field.class); + int fcount = _fields.length; + + // obtain field marshallers for all of our fields + _marshallers = new FieldMarshaller[fcount]; + for (int ii = 0; ii < fcount; ii++) { + _marshallers[ii] = FieldMarshaller.getFieldMarshaller(_fields[ii]); + if (_marshallers[ii] == null) { + String errmsg = "Unable to marshall field [class=" + _target.getName() + + ", field=" + _fields[ii].getName() + + ", type=" + _fields[ii].getType().getName() + "]"; + throw new RuntimeException(errmsg); + } + if (ObjectInputStream.STREAM_DEBUG) { + log.info("Using " + _marshallers[ii] + " for " + _target.getName() + "." + + _fields[ii].getName() + "."); + } + } + } + @Override protected Objects.ToStringHelper toStringHelper (Objects.ToStringHelper otsh) { @@ -525,17 +530,6 @@ public abstract class Streamer _writer = writer; } - @Override - public Object createObject (ObjectInputStream in) - throws IOException, ClassNotFoundException - { - // we need to initialize in order to access the constructor - if (_marshallers == null) { - super.initMarshallers(); - } - return super.createObject(in); - } - @Override public void writeObject (Object object, ObjectOutputStream out, boolean useWriter) throws IOException