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,
|
Long.class,
|
||||||
Float.class,
|
Float.class,
|
||||||
Double.class,
|
Double.class,
|
||||||
|
Class.class,
|
||||||
String.class,
|
String.class,
|
||||||
boolean[].class,
|
boolean[].class,
|
||||||
byte[].class,
|
byte[].class,
|
||||||
@@ -68,6 +69,7 @@ public class BasicStreamers
|
|||||||
new LongStreamer(),
|
new LongStreamer(),
|
||||||
new FloatStreamer(),
|
new FloatStreamer(),
|
||||||
new DoubleStreamer(),
|
new DoubleStreamer(),
|
||||||
|
new ClassStreamer(),
|
||||||
new StringStreamer(),
|
new StringStreamer(),
|
||||||
new BooleanArrayStreamer(),
|
new BooleanArrayStreamer(),
|
||||||
new ByteArrayStreamer(),
|
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. */
|
/** Streams {@link String} instances. */
|
||||||
public static class StringStreamer extends BasicStreamer
|
public static class StringStreamer extends BasicStreamer
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -76,59 +76,14 @@ public class ObjectInputStream extends DataInputStream
|
|||||||
public Object readObject ()
|
public Object readObject ()
|
||||||
throws IOException, ClassNotFoundException
|
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 {
|
try {
|
||||||
// read in the class code for this instance
|
// read the class mapping
|
||||||
short code = readShort();
|
ClassMapping cmap = readClassMapping();
|
||||||
|
if (cmap == null) {
|
||||||
// a zero code indicates a null value
|
|
||||||
if (code == 0) {
|
|
||||||
if (STREAM_DEBUG) {
|
if (STREAM_DEBUG) {
|
||||||
log.info(hashCode() + ": Read null.");
|
log.info(hashCode() + ": Read null.");
|
||||||
}
|
}
|
||||||
return 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) {
|
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.
|
* Creates, adds, and returns the class mapping for the specified code and class name.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -71,13 +71,25 @@ public class ObjectOutputStream extends DataOutputStream
|
|||||||
return;
|
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
|
// create our classmap if necessary
|
||||||
if (_classmap == null) {
|
if (_classmap == null) {
|
||||||
_classmap = new HashMap<Class<?>, ClassMapping>();
|
_classmap = new HashMap<Class<?>, ClassMapping>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// otherwise, look up the class mapping record
|
// look up the class mapping record
|
||||||
Class<?> sclass = Streamer.getStreamerClass(object);
|
|
||||||
ClassMapping cmap = _classmap.get(sclass);
|
ClassMapping cmap = _classmap.get(sclass);
|
||||||
|
|
||||||
// create a class mapping for this class if we've not got one
|
// create a class mapping for this class if we've not got one
|
||||||
@@ -103,8 +115,7 @@ public class ObjectOutputStream extends DataOutputStream
|
|||||||
} else {
|
} else {
|
||||||
writeExistingClassMapping(cmap);
|
writeExistingClassMapping(cmap);
|
||||||
}
|
}
|
||||||
|
return cmap;
|
||||||
writeBareObject(object, cmap.streamer, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user