mirror of
https://github.com/corda/corda.git
synced 2025-03-17 17:45:17 +00:00
ObjectInputStream: add rudimentary support for objects
This is by no means a complete support for the deserialization compliant to the Java Language Specification, but it is better to add the support incrementally, for better readability of the commits. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit is contained in:
parent
4b8285e597
commit
c78923d717
@ -127,9 +127,6 @@ public class ObjectInputStream extends InputStream implements DataInput {
|
||||
in.close();
|
||||
}
|
||||
|
||||
public Object readObject() throws IOException, ClassNotFoundException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
private int remainingBlockData;
|
||||
|
||||
private int rawBlockDataByte() throws IOException {
|
||||
@ -221,6 +218,134 @@ public class ObjectInputStream extends InputStream implements DataInput {
|
||||
return count;
|
||||
}
|
||||
|
||||
private static Class charToPrimitiveType(int c) {
|
||||
if (c == 'B') {
|
||||
return Byte.TYPE;
|
||||
} else if (c == 'C') {
|
||||
return Character.TYPE;
|
||||
} else if (c == 'D') {
|
||||
return Double.TYPE;
|
||||
} else if (c == 'F') {
|
||||
return Float.TYPE;
|
||||
} else if (c == 'I') {
|
||||
return Integer.TYPE;
|
||||
} else if (c == 'J') {
|
||||
return Long.TYPE;
|
||||
} else if (c == 'S') {
|
||||
return Short.TYPE;
|
||||
} else if (c == 'Z') {
|
||||
return Boolean.TYPE;
|
||||
}
|
||||
throw new RuntimeException("Unhandled char: " + (char)c);
|
||||
}
|
||||
|
||||
private void expectToken(int token) throws IOException {
|
||||
int c = rawByte();
|
||||
if (c != token) {
|
||||
throw new UnsupportedOperationException("Unexpected token: 0x"
|
||||
+ Integer.toHexString(c));
|
||||
}
|
||||
}
|
||||
|
||||
private void field(Field field, Object o)
|
||||
throws IOException, IllegalArgumentException, IllegalAccessException,
|
||||
ClassNotFoundException
|
||||
{
|
||||
Class type = field.getType();
|
||||
if (!type.isPrimitive()) {
|
||||
field.set(o, readObject());
|
||||
} else {
|
||||
if (type == Byte.TYPE) {
|
||||
field.setByte(o, (byte)rawByte());
|
||||
} else if (type == Character.TYPE) {
|
||||
field.setChar(o, (char)rawShort());
|
||||
} else if (type == Double.TYPE) {
|
||||
field.setDouble(o, Double.longBitsToDouble(rawLong()));
|
||||
} else if (type == Float.TYPE) {
|
||||
field.setFloat(o, Float.intBitsToFloat(rawInt()));
|
||||
} else if (type == Integer.TYPE) {
|
||||
field.setInt(o, rawInt());
|
||||
} else if (type == Long.TYPE) {
|
||||
field.setLong(o, rawLong());
|
||||
} else if (type == Short.TYPE) {
|
||||
field.setShort(o, (short)rawShort());
|
||||
} else if (type == Boolean.TYPE) {
|
||||
field.setBoolean(o, rawByte() != 0);
|
||||
} else {
|
||||
throw new IOException("Unhandled type: " + type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Object readObject() throws IOException, ClassNotFoundException {
|
||||
expectToken(TC_OBJECT);
|
||||
|
||||
// class desc
|
||||
expectToken(TC_CLASSDESC);
|
||||
String className = rawString();
|
||||
ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||
Class clazz = loader.loadClass(className);
|
||||
long serialVersionUID = rawLong();
|
||||
try {
|
||||
Field field = clazz.getField("serialVersionUID");
|
||||
long expected = field.getLong(null);
|
||||
if (expected != serialVersionUID) {
|
||||
throw new IOException("Incompatible serial version UID: 0x"
|
||||
+ Long.toHexString(serialVersionUID) + " != 0x"
|
||||
+ Long.toHexString(expected));
|
||||
}
|
||||
} catch (Exception ignored) { }
|
||||
|
||||
int flags = rawByte();
|
||||
if (flags != SC_SERIALIZABLE) {
|
||||
throw new UnsupportedOperationException("Cannot handle flags: 0x"
|
||||
+ Integer.toHexString(flags));
|
||||
}
|
||||
|
||||
int fieldCount = rawShort();
|
||||
Field[] fields = new Field[fieldCount];
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
int typeChar = rawByte();
|
||||
String fieldName = rawString();
|
||||
try {
|
||||
fields[i] = clazz.getDeclaredField(fieldName);
|
||||
} catch (Exception e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
Class type;
|
||||
if (typeChar == '[' || typeChar == 'L') {
|
||||
expectToken(TC_STRING);
|
||||
String typeName = rawString();
|
||||
type = loader.loadClass(typeName);
|
||||
} else {
|
||||
type = charToPrimitiveType(typeChar);
|
||||
}
|
||||
if (fields[i].getType() != type) {
|
||||
throw new IOException("Unexpected type of field " + fieldName
|
||||
+ ": expected " + fields[i].getType() + " but got " + type);
|
||||
}
|
||||
}
|
||||
expectToken(TC_ENDBLOCKDATA);
|
||||
expectToken(TC_NULL);
|
||||
|
||||
try {
|
||||
Object o = makeInstance(clazz.vmClass);
|
||||
|
||||
for (Field field : fields) {
|
||||
field(field, o);
|
||||
}
|
||||
|
||||
return o;
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void defaultReadObject() throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
private static native Object makeInstance(VMClass c);
|
||||
}
|
||||
|
@ -307,6 +307,13 @@ Avian_java_io_ObjectInputStream_makeInstance
|
||||
return reinterpret_cast<int64_t>(make(t, c));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_avian_LegacyObjectInputStream_makeInstance
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
return Avian_java_io_ObjectInputStream_makeInstance(t, NULL, arguments);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_reflect_Field_getPrimitive
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
|
Loading…
x
Reference in New Issue
Block a user