Allow streaming Class references.
git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@5524 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -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
|
||||
{
|
||||
|
||||
@@ -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<ClassMapping>();
|
||||
// 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 <code>null</code> to represent a null value.
|
||||
*/
|
||||
protected ClassMapping readClassMapping ()
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
// create our classmap if necessary
|
||||
if (_classmap == null) {
|
||||
_classmap = new ArrayList<ClassMapping>();
|
||||
// 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.
|
||||
*/
|
||||
|
||||
@@ -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<Class<?>, 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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user