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
This commit is contained in:
Michael Bayne
2011-03-30 01:17:39 +00:00
parent 54c8226ea2
commit d4b2999c91
+45 -51
View File
@@ -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<Field> 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<Field> 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<Field> 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<Field> 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