flesh out serialization/deserialization code and fix build

This commit is contained in:
Joel Dice 2007-08-12 18:50:25 -06:00
parent 92ba1880d8
commit c20219df19
21 changed files with 285 additions and 163 deletions

View File

@ -0,0 +1,11 @@
package java.io;
public class EOFException extends IOException {
public EOFException(String message) {
super(message);
}
public EOFException() {
this(null);
}
}

View File

@ -0,0 +1,11 @@
package java.io;
public class NotSerializableException extends ObjectStreamException {
public NotSerializableException(String message) {
super(message);
}
public NotSerializableException() {
this(null);
}
}

View File

@ -1,8 +1,13 @@
package java.io; package java.io;
import java.util.HashMap;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class ObjectInputStream extends InputStream { public class ObjectInputStream extends InputStream {
private final InputStream in; private final InputStream in;
private final Reader r; private final PushbackReader r;
public ObjectInputStream(InputStream in) { public ObjectInputStream(InputStream in) {
this.in = in; this.in = in;
@ -21,7 +26,7 @@ public class ObjectInputStream extends InputStream {
in.close(); in.close();
} }
public Object readObject() throws IOException { public Object readObject() throws IOException, ClassNotFoundException {
return readObject(new HashMap()); return readObject(new HashMap());
} }
@ -67,7 +72,7 @@ public class ObjectInputStream extends InputStream {
private void skipSpace() throws IOException { private void skipSpace() throws IOException {
int c; int c;
while ((c = r.read()) != -1 && Character.isSpace((char) c)); while ((c = r.read()) != -1 && Character.isWhitespace((char) c));
if (c != -1) { if (c != -1) {
r.unread(c); r.unread(c);
} }
@ -91,7 +96,7 @@ public class ObjectInputStream extends InputStream {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
int c; int c;
while ((c = r.read()) != -1 && ! Character.isSpace((char) c)) { while ((c = r.read()) != -1 && ! Character.isWhitespace((char) c)) {
sb.append((char) c); sb.append((char) c);
} }
if (c != -1) { if (c != -1) {
@ -108,13 +113,15 @@ public class ObjectInputStream extends InputStream {
return Double.parseDouble(readStringToken()); return Double.parseDouble(readStringToken());
} }
private Object readObject(HashMap<Integer, Object> map) throws IOException { private Object readObject(HashMap<Integer, Object> map)
throws IOException, ClassNotFoundException
{
skipSpace(); skipSpace();
switch (r.read()) { switch (r.read()) {
case 'a': case 'a':
return deserializeArray(map); return deserializeArray(map);
case 'l': case 'l':
return deserialize(map); return deserializeObject(map);
case 'n': case 'n':
return null; return null;
case -1: case -1:
@ -124,153 +131,85 @@ public class ObjectInputStream extends InputStream {
} }
} }
private Object deserializeArray(HashMap<Integer, Object> map) private Object deserialize(HashMap<Integer, Object> map)
throws IOException throws IOException, ClassNotFoundException
{ {
read('(');
int id = (int) readLongToken();
Class c = Class.forName(readStringToken());
int length = (int) readLongToken();
Object o = Array.newInstance(c.getComponentType(), length);
map.put(id, o);
for (int i = 0; i < length; ++i) {
skipSpace(); skipSpace();
switch (r.read()) { switch (r.read()) {
case 'a': case 'a':
Array.set(o, i, deserializeArray(map)); return deserializeArray(map);
break;
case 'l': case 'l':
Array.set(o, i, deserialize(map)); return deserializeObject(map);
break;
case 'r': case 'r':
Array.set(o, i, map.get((int) readLongToken())); return map.get((int) readLongToken());
break;
case 'n': case 'n':
Array.set(o, i, null); return null;
break;
case 'z': case 'z':
f.setBoolean(o, readLongToken() != 0); return (readLongToken() == 0);
break;
case 'b': case 'b':
f.setByte(o, (byte) readLongToken()); return (byte) readLongToken();
break;
case 'c': case 'c':
f.setChar(o, (char) readLongToken()); return (char) readLongToken();
break;
case 's': case 's':
f.setShort(o, (short) readLongToken()); return (short) readLongToken();
break;
case 'i': case 'i':
f.setInt(o, (int) readLongToken()); return (int) readLongToken();
break;
case 'j': case 'j':
f.setLong(o, readLongToken()); return readLongToken();
break;
case 'f': case 'f':
f.setFloat(o, (float) readDoubleToken()); return (float) readDoubleToken();
break;
case 'd': case 'd':
f.setDouble(o, readDoubleToken()); return readDoubleToken();
break;
case -1: case -1:
throw new EOFException(); throw new EOFException();
default: default:
throw new StreamCorruptedException(); throw new StreamCorruptedException();
} }
} }
read(')'); private Object deserializeArray(HashMap<Integer, Object> map)
} throws IOException, ClassNotFoundException
private Object deserialize(HashMap<Integer, Object> map)
throws IOException
{ {
read('('); read('(');
int id = (int) readLongToken(); int id = (int) readLongToken();
Class c = Class.forName(readStringToken()); Class c = Class.forName(readStringToken());
Object o = c.newInstance(); int length = (int) readLongToken();
Class t = c.getComponentType();
Object o = Array.newInstance(t, length);
map.put(id, o);
for (int i = 0; i < length; ++i) {
Array.set(o, i, deserialize(map));
}
read(')');
return o;
}
private static native Object makeInstance(Class c);
private Object deserializeObject(HashMap<Integer, Object> map)
throws IOException, ClassNotFoundException
{
read('(');
int id = (int) readLongToken();
Class c = Class.forName(readStringToken());
Object o = makeInstance(c);
map.put(id, o); map.put(id, o);
for (Field f: c.getFields()) { for (Field f: c.getFields()) {
int modifiers = f.getModifiers(); int modifiers = f.getModifiers();
if ((modifiers & (Modifier.TRANSIENT | Modifier.STATIC)) == 0) { if ((modifiers & (Modifier.TRANSIENT | Modifier.STATIC)) == 0) {
skipSpace(); f.set(o, deserialize(map));
switch (r.read()) {
case 'a':
Array.set(o, i, deserializeArray(map));
break;
case 'l':
Array.set(o, i, deserialize(map));
break;
case 'r':
Array.set(o, i, map.get((int) readLongToken()));
break;
case 'n':
Array.set(o, i, null);
break;
case 'z':
Array.setBoolean(o, i, readLongToken() != 0);
break;
case 'b':
Array.setByte(o, i, (byte) readLongToken());
break;
case 'c':
Array.setChar(o, i, (char) readLongToken());
break;
case 's':
Array.setShort(o, i, (short) readLongToken());
break;
case 'i':
Array.setInt(o, i, (int) readLongToken());
break;
case 'j':
Array.setLong(o, i, readLongToken());
break;
case 'f':
Array.setFloat(o, i, (float) readDoubleToken());
break;
case 'd':
Array.setDouble(o, i, readDoubleToken());
break;
case -1:
throw new EOFException();
default:
throw new StreamCorruptedException();
}
} }
} }
read(')'); read(')');
return o;
} }
} }

View File

@ -1,6 +1,9 @@
package java.io; package java.io;
import java.util.IdentityHashMap; import java.util.IdentityHashMap;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class ObjectOutputStream extends OutputStream { public class ObjectOutputStream extends OutputStream {
private final PrintStream out; private final PrintStream out;
@ -76,15 +79,15 @@ public class ObjectOutputStream extends OutputStream {
if (o == null) { if (o == null) {
out.print("n"); out.print("n");
} else { } else {
Integer id = map.get(new Identity(o)); Integer id = map.get(o);
if (id == null) { if (id == null) {
map.put(new Identity(o), nextId); map.put(o, nextId);
Class c = o.getClass(); Class c = o.getClass();
if (c.isArray()) { if (c.isArray()) {
serializeArray(o, map, nextId); serializeArray(o, map, nextId);
} else if (Serializable.class.isAssignableFrom(c)) { } else if (Serializable.class.isAssignableFrom(c)) {
serialize(o, map, nextId); serializeObject(o, map, nextId);
} else { } else {
throw new NotSerializableException(c.getName()); throw new NotSerializableException(c.getName());
} }
@ -112,31 +115,32 @@ public class ObjectOutputStream extends OutputStream {
for (int i = 0; i < length; ++i) { for (int i = 0; i < length; ++i) {
out.print(" "); out.print(" ");
Object v = Array.get(o, i);
if (t.equals(boolean.class)) { if (t.equals(boolean.class)) {
writeBoolean(Array.getBoolean(o)); writeBoolean((Boolean) v);
} else if (t.equals(byte.class)) { } else if (t.equals(byte.class)) {
writeByte(Array.getByte(o)); writeByte((Byte) v);
} else if (t.equals(char.class)) { } else if (t.equals(char.class)) {
writeChar(Array.getChar(o)); writeChar((Character) v);
} else if (t.equals(short.class)) { } else if (t.equals(short.class)) {
writeShort(Array.getShort(o)); writeShort((Short) v);
} else if (t.equals(int.class)) { } else if (t.equals(int.class)) {
writeInt(Array.getInt(o)); writeInt((Integer) v);
} else if (t.equals(long.class)) { } else if (t.equals(long.class)) {
writeLong(Array.getLong(o)); writeLong((Long) v);
} else if (t.equals(float.class)) { } else if (t.equals(float.class)) {
writeFloat(Array.getFloat(o)); writeFloat((Float) v);
} else if (t.equals(double.class)) { } else if (t.equals(double.class)) {
writeDouble(Array.getDouble(o)); writeDouble((Double) v);
} else { } else {
writeObject(Array.get(o), map, nextId); writeObject(v, map, nextId);
} }
} }
out.print(")"); out.print(")");
} }
private void serialize(Object o, IdentityHashMap<Object, Integer> map, private void serializeObject(Object o, IdentityHashMap<Object, Integer> map,
int nextId) int nextId)
throws IOException throws IOException
{ {
@ -151,25 +155,26 @@ public class ObjectOutputStream extends OutputStream {
int modifiers = f.getModifiers(); int modifiers = f.getModifiers();
if ((modifiers & (Modifier.TRANSIENT | Modifier.STATIC)) == 0) { if ((modifiers & (Modifier.TRANSIENT | Modifier.STATIC)) == 0) {
out.print(" "); out.print(" ");
Object v = f.get(o);
Class t = f.getType(); Class t = f.getType();
if (t.equals(boolean.class)) { if (t.equals(boolean.class)) {
writeBoolean(f.getBoolean(o)); writeBoolean((Boolean) v);
} else if (t.equals(byte.class)) { } else if (t.equals(byte.class)) {
writeByte(f.getByte(o)); writeByte((Byte) v);
} else if (t.equals(char.class)) { } else if (t.equals(char.class)) {
writeChar(f.getChar(o)); writeChar((Character) v);
} else if (t.equals(short.class)) { } else if (t.equals(short.class)) {
writeShort(f.getShort(o)); writeShort((Short) v);
} else if (t.equals(int.class)) { } else if (t.equals(int.class)) {
writeInt(f.getInt(o)); writeInt((Integer) v);
} else if (t.equals(long.class)) { } else if (t.equals(long.class)) {
writeLong(f.getLong(o)); writeLong((Long) v);
} else if (t.equals(float.class)) { } else if (t.equals(float.class)) {
writeFloat(f.getFloat(o)); writeFloat((Float) v);
} else if (t.equals(double.class)) { } else if (t.equals(double.class)) {
writeDouble(f.getDouble(o)); writeDouble((Double) v);
} else { } else {
writeObject(f.get(o), map, nextId); writeObject(v, map, nextId);
} }
} }
} }

View File

@ -0,0 +1,69 @@
package java.io;
public class PushbackReader extends Reader {
private final Reader in;
private final char[] buffer;
private int position;
private int limit;
public PushbackReader(Reader in, int bufferSize) {
this.in = in;
this.buffer = new char[bufferSize];
}
public PushbackReader(Reader in) {
this(in, 1);
}
public int read(char[] b, int offset, int length) throws IOException {
int count = 0;
if (position < limit) {
int remaining = limit - position;
if (remaining > length) {
remaining = length;
}
System.arraycopy(buffer, position, b, offset, remaining);
count += remaining;
position += remaining;
offset += remaining;
length -= remaining;
}
if (length > 0) {
int c = in.read(b, offset, length);
if (c == -1) {
if (count == 0) {
count = -1;
}
} else {
count += c;
}
}
return count;
}
public void unread(char[] b, int offset, int length) throws IOException {
if (position < length) {
throw new IOException(length + " not in [0," + position + "]");
} else {
System.arraycopy(buffer, position - length, b, offset, length);
position -= length;
}
}
public void unread(char[] b) throws IOException {
unread(b, 0, b.length);
}
public void unread(int c) throws IOException {
unread(new char[] { (char) c });
}
public void close() throws IOException {
in.close();
}
}

View File

@ -0,0 +1,11 @@
package java.io;
public class StreamCorruptedException extends IOException {
public StreamCorruptedException(String message) {
super(message);
}
public StreamCorruptedException() {
this(null);
}
}

View File

@ -12,6 +12,10 @@ public final class Boolean {
this.value = value; this.value = value;
} }
public static Boolean valueOf(boolean value) {
return (value ? Boolean.TRUE : Boolean.FALSE);
}
public boolean equals(Object o) { public boolean equals(Object o) {
return o instanceof Boolean && ((Boolean) o).value == value; return o instanceof Boolean && ((Boolean) o).value == value;
} }

View File

@ -9,6 +9,10 @@ public final class Byte extends Number {
this.value = value; this.value = value;
} }
public static Byte valueOf(byte value) {
return new Byte(value);
}
public boolean equals(Object o) { public boolean equals(Object o) {
return o instanceof Byte && ((Byte) o).value == value; return o instanceof Byte && ((Byte) o).value == value;
} }

View File

@ -9,6 +9,10 @@ public final class Character {
this.value = value; this.value = value;
} }
public static Character valueOf(char value) {
return new Character(value);
}
public boolean equals(Object o) { public boolean equals(Object o) {
return o instanceof Character && ((Character) o).value == value; return o instanceof Character && ((Character) o).value == value;
} }

View File

@ -47,7 +47,7 @@ public final class Class <T> {
private native void initialize(); private native void initialize();
static Class forCanonicalName(String name) { public static Class forCanonicalName(String name) {
try { try {
if (name.startsWith("[")) { if (name.startsWith("[")) {
return forName(name); return forName(name);
@ -65,6 +65,14 @@ public final class Class <T> {
} }
} }
public Class getComponentType() {
if (isArray()) {
return forCanonicalName(new String(name, 1, name.length - 2, false));
} else {
return null;
}
}
public native boolean isAssignableFrom(Class c); public native boolean isAssignableFrom(Class c);
private Field findField(String name) { private Field findField(String name) {

View File

@ -13,6 +13,10 @@ public final class Double extends Number {
this.value = value; this.value = value;
} }
public static Double valueOf(double value) {
return new Double(value);
}
public boolean equals(Object o) { public boolean equals(Object o) {
return o instanceof Double && ((Double) o).value == value; return o instanceof Double && ((Double) o).value == value;
} }

View File

@ -9,6 +9,10 @@ public final class Float extends Number {
this.value = value; this.value = value;
} }
public static Float valueOf(float value) {
return new Float(value);
}
public boolean equals(Object o) { public boolean equals(Object o) {
return o instanceof Float && ((Float) o).value == value; return o instanceof Float && ((Float) o).value == value;
} }

View File

@ -12,6 +12,10 @@ public final class Integer extends Number {
this.value = value; this.value = value;
} }
public static Integer valueOf(int value) {
return new Integer(value);
}
public boolean equals(Object o) { public boolean equals(Object o) {
return o instanceof Integer && ((Integer) o).value == value; return o instanceof Integer && ((Integer) o).value == value;
} }

View File

@ -9,6 +9,10 @@ public final class Long extends Number {
this.value = value; this.value = value;
} }
public static Long valueOf(long value) {
return new Long(value);
}
public boolean equals(Object o) { public boolean equals(Object o) {
return o instanceof Long && ((Long) o).value == value; return o instanceof Long && ((Long) o).value == value;
} }

View File

@ -9,6 +9,10 @@ public final class Short extends Number {
this.value = value; this.value = value;
} }
public static Short valueOf(short value) {
return new Short(value);
}
public boolean equals(Object o) { public boolean equals(Object o) {
return o instanceof Short && ((Short) o).value == value; return o instanceof Short && ((Short) o).value == value;
} }

View File

@ -29,6 +29,8 @@ public abstract class System {
public static native long currentTimeMillis(); public static native long currentTimeMillis();
public static native int identityHashCode(Object o);
public static void loadLibrary(String name) { public static void loadLibrary(String name) {
Runtime.getRuntime().loadLibrary(name); Runtime.getRuntime().loadLibrary(name);
} }

View File

@ -31,6 +31,10 @@ public class Field<T> extends AccessibleObject {
return new String(name, 0, name.length - 1, false); return new String(name, 0, name.length - 1, false);
} }
public Class getType() {
return Class.forCanonicalName(getName());
}
public native Object get(Object instance); public native Object get(Object instance);
public native void set(Object instance, Object value); public native void set(Object instance, Object value);

View File

@ -64,9 +64,9 @@ public class HashMap<K, V> implements Map<K, V> {
private Cell<K, V> find(K key) { private Cell<K, V> find(K key) {
if (array != null) { if (array != null) {
int index = hash(key) & (array.length - 1); int index = helper.hash(key) & (array.length - 1);
for (Cell<K, V> c = array[index]; c != null; c = c.next()) { for (Cell<K, V> c = array[index]; c != null; c = c.next()) {
if (equal(key, c.getKey())) { if (helper.equal(key, c.getKey())) {
return c; return c;
} }
} }
@ -131,10 +131,10 @@ public class HashMap<K, V> implements Map<K, V> {
public Cell<K, V> removeCell(K key) { public Cell<K, V> removeCell(K key) {
Cell<K, V> old = null; Cell<K, V> old = null;
if (array != null) { if (array != null) {
int index = hash(key) & (array.length - 1); int index = helper.hash(key) & (array.length - 1);
Cell<K, V> p = null; Cell<K, V> p = null;
for (Cell<K, V> c = array[index]; c != null; c = c.next()) { for (Cell<K, V> c = array[index]; c != null; c = c.next()) {
if (equal(key, c.getKey())) { if (helper.equal(key, c.getKey())) {
old = c; old = c;
if (p == null) { if (p == null) {
array[index] = c.next(); array[index] = c.next();
@ -196,15 +196,17 @@ public class HashMap<K, V> implements Map<K, V> {
public boolean equal(K a, K b); public boolean equal(K a, K b);
} }
private class MyCell<K, V> implements Cell<K, V> { private static class MyCell<K, V> implements Cell<K, V> {
public final K key; public final K key;
public V value; public V value;
public Cell<K, V> next; public Cell<K, V> next;
public int hashCode;
public MyCell(K key, V value, Cell<K, V> next) { public MyCell(K key, V value, Cell<K, V> next, int hashCode) {
this.key = key; this.key = key;
this.value = value; this.value = value;
this.next = next; this.next = next;
this.hashCode = hashCode;
} }
public K getKey() { public K getKey() {
@ -228,13 +230,13 @@ public class HashMap<K, V> implements Map<K, V> {
} }
public int hashCode() { public int hashCode() {
return helper.hash(key); return hashCode;
} }
} }
static class MyHelper<K, V> implements Helper<K, V> { static class MyHelper<K, V> implements Helper<K, V> {
public Cell<K, V> make(K key, V value, Cell<K, V> next) { public Cell<K, V> make(K key, V value, Cell<K, V> next) {
return new MyCell(key, value, next); return new MyCell(key, value, next, hash(key));
} }
public int hash(K a) { public int hash(K a) {

View File

@ -79,11 +79,11 @@ public class WeakHashMap<K, V> implements Map<K, V> {
public HashMap.Cell<K, V> next; public HashMap.Cell<K, V> next;
public int hashCode; public int hashCode;
public MyCell(K key, V value, HashMap.Cell<K, V> next) { public MyCell(K key, V value, HashMap.Cell<K, V> next, int hashCode) {
super(key); super(key);
this.value = value; this.value = value;
this.next = next; this.next = next;
this.hashCode = (key == null ? 0 : key.hashCode()); this.hashCode = hashCode;
} }
public K getKey() { public K getKey() {
@ -115,7 +115,7 @@ public class WeakHashMap<K, V> implements Map<K, V> {
extends HashMap.MyHelper<K, V> extends HashMap.MyHelper<K, V>
{ {
public HashMap.Cell<K, V> make(K key, V value, HashMap.Cell<K, V> next) { public HashMap.Cell<K, V> make(K key, V value, HashMap.Cell<K, V> next) {
return new MyCell(key, value, next); return new MyCell(key, value, next, hash(key));
} }
} }
} }

View File

@ -16,7 +16,7 @@ src = src
classpath = classpath classpath = classpath
test = test test = test
input = $(cls)/Reflection.class input = $(cls)/References.class
cxx = g++ cxx = g++
cc = gcc cc = gcc

View File

@ -49,13 +49,19 @@ Object_wait(Thread* t, jobject this_, jlong milliseconds)
void void
Object_notify(Thread* t, jobject this_) Object_notify(Thread* t, jobject this_)
{ {
vm::notify(t, *this_); notify(t, *this_);
} }
void void
Object_notifyAll(Thread* t, jobject this_) Object_notifyAll(Thread* t, jobject this_)
{ {
vm::notifyAll(t, *this_); notifyAll(t, *this_);
}
jint
Object_hashCode(Thread* t, jobject this_)
{
return objectHash(t, *this_);
} }
jclass jclass
@ -119,6 +125,12 @@ SystemClassLoader_resourceExists(Thread* t, jclass, jstring name)
} }
} }
jobject
ObjectInputStream_makeInstance(Thread* t, jclass, jclass c)
{
return pushReference(t, make(t, *c));
}
jclass jclass
Class_primitiveClass(Thread* t, jclass, jchar name) Class_primitiveClass(Thread* t, jclass, jchar name)
{ {
@ -547,6 +559,17 @@ System_arraycopy(Thread* t, jclass, jobject src, jint srcOffset, jobject dst,
t->exception = makeArrayStoreException(t); t->exception = makeArrayStoreException(t);
} }
jint
System_identityHashCode(Thread* t, jclass, jobject o)
{
if (LIKELY(o)) {
return objectHash(t, *o);
} else {
t->exception = makeNullPointerException(t);
return 0;
}
}
void void
Runtime_loadLibrary(Thread* t, jobject, jstring name) Runtime_loadLibrary(Thread* t, jobject, jstring name)
{ {
@ -791,6 +814,8 @@ populateBuiltinMap(Thread* t, object map)
reinterpret_cast<void*>(::Object_toString) }, reinterpret_cast<void*>(::Object_toString) },
{ "Java_java_lang_Object_wait", { "Java_java_lang_Object_wait",
reinterpret_cast<void*>(::Object_wait) }, reinterpret_cast<void*>(::Object_wait) },
{ "Java_java_lang_Object_hashCode",
reinterpret_cast<void*>(::Object_hashCode) },
{ "Java_java_lang_reflect_Array_get", { "Java_java_lang_reflect_Array_get",
reinterpret_cast<void*>(::Array_get) }, reinterpret_cast<void*>(::Array_get) },
@ -823,6 +848,9 @@ populateBuiltinMap(Thread* t, object map)
{ "Java_java_net_URL_00024ResourceInputStream_close", { "Java_java_net_URL_00024ResourceInputStream_close",
reinterpret_cast<void*>(::ResourceInputStream_close) }, reinterpret_cast<void*>(::ResourceInputStream_close) },
{ "Java_java_io_ObjectInputStream_makeInstance",
reinterpret_cast<void*>(::ObjectInputStream_makeInstance) },
{ 0, 0 } { 0, 0 }
}; };