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:
@@ -325,6 +325,7 @@ public abstract class Streamer
|
|||||||
protected ClassStreamer (Class<?> target)
|
protected ClassStreamer (Class<?> target)
|
||||||
{
|
{
|
||||||
_target = target;
|
_target = target;
|
||||||
|
initConstructor();
|
||||||
initMarshallers();
|
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
|
// if we have a zero argument constructor, we have to use that one
|
||||||
for (Constructor<?> ctor : _target.getDeclaredConstructors()) {
|
for (Constructor<?> ctor : _target.getDeclaredConstructors()) {
|
||||||
if (ctor.getParameterTypes().length == 0) {
|
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
|
// 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
|
// 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();
|
Constructor<?>[] ctors = _target.getDeclaredConstructors();
|
||||||
if (ctors.length > 1) {
|
if (ctors.length > 1) {
|
||||||
throw new RuntimeException(
|
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
|
@Override
|
||||||
protected Objects.ToStringHelper toStringHelper (Objects.ToStringHelper otsh)
|
protected Objects.ToStringHelper toStringHelper (Objects.ToStringHelper otsh)
|
||||||
{
|
{
|
||||||
@@ -525,17 +530,6 @@ public abstract class Streamer
|
|||||||
_writer = writer;
|
_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
|
@Override
|
||||||
public void writeObject (Object object, ObjectOutputStream out, boolean useWriter)
|
public void writeObject (Object object, ObjectOutputStream out, boolean useWriter)
|
||||||
throws IOException
|
throws IOException
|
||||||
|
|||||||
Reference in New Issue
Block a user