From f4294557b7ebb12ab58c9b57e1309d5f2fcfb019 Mon Sep 17 00:00:00 2001 From: Bryce McKinlay Date: Tue, 22 Feb 2005 03:13:35 +0000 Subject: [multiple changes] 2005-02-21 Bryce McKinlay Merge serialization from GNU Classpath. * gcj/method.h: Add missing #includes. * java/io/ObjectInputStream.java (readClassDescriptor): Check for primitive class IDs on the stream here... (resolveClass): ...not here. * java/io/ObjectStreamField.java: Use VMObjectStream class calls to set fields. * java/io/VMObjectStreamClass.java (setDoubleNative, setFloatNative, setLongNative, setIntNative, setShortNative, setCharNative, setByteNative, setBooleanNative, setObjectNative): New native methods. * java/io/natVMObjectStreamClass.java (setDoubleNative, setFloatNative, setLongNative, setIntNative, setShortNative, setCharNative, setByteNative, setBooleanNative, setObjectNative): Implement them. * java/io/natObjectInputStream.cc (allocateObject): Add new parameters from Classpath's version. Use _Jv_FromReflectedConstructor(). Call the constructor here. (callConstructor): Removed. (getCallersClassLoader): Removed. * java/lang/reflect/Field.java (setByte, setShort, setInt, setLong, setFloat, setDouble, setChar, setBoolean): Add 'checkFinal' parameter to control whether setting final field values is permitted. Call getAddr() with checkFinal parameter instead of setAddr(). * java/lang/reflect/natField.cc (getType): Lookup and resolve field only if not done already. (getAddr): Add checkFinal parameter. Do the final field check only if checkFinal is set. (setAddr): Removed. 2005-02-21 Mark Wielaard # Fixes bug #11957 * java/io/ObjectInputStream.java (resolveClass): Don't check "void" twice. 2005-02-21 Mark Wielaard Fixes bug #11618. * java/io/ObjectInputStream.java (readClassDescriptor): Handle classes without a super class and us ObjectStreamClass.lookupForClassObject(). (resolveClass): Check for primitive types. (lookupClass): Return null when argument is null. 2005-02-21 Jeroen Frijters * java/io/ObjectInputStream.java (readObject): Fix to consume TC_ENDBLOCKDATA after readExternal. 2005-02-21 Jeroen Frijters * java/io/ObjectOutputStream.java (writeObject, callWriteMethod): Replaced reflection with accessing cached info in ObjectStreamClass. (getMethod): Removed. * java/io/ObjectStreamClass.java (findMethod): Added check to make sure the method found has the right modifiers. (cacheMethods): Added writeReplace and writeObject methods. (setFlags): Look at new writeObjectMethod field instead of doing reflection again. (writeReplaceMethod): New field. (writeObjectMethod): New field. 2005-02-21 Guilhem Lavaux Jeroen Frijters * java/io/ObjectInputStream.java (newObject): Changed prototype. Get a constructor reflect object directly. (callConstructor): Removed. (allocateObject): Changed prototype. (readClassDescriptor): Build the constructor reflection directly. (readObject): Invoke newObject using the new prototype. * java/io/ObjectStreamClass.java (firstNonSerializableParent): Removed. (firstNonSerializableParentConstructor): Added. From-SVN: r95378 --- libjava/java/io/ObjectInputStream.java | 127 ++++++++++++++++++++++++--------- 1 file changed, 93 insertions(+), 34 deletions(-) (limited to 'libjava/java/io/ObjectInputStream.java') diff --git a/libjava/java/io/ObjectInputStream.java b/libjava/java/io/ObjectInputStream.java index 6f4faf8..2cfe4c9 100644 --- a/libjava/java/io/ObjectInputStream.java +++ b/libjava/java/io/ObjectInputStream.java @@ -43,6 +43,7 @@ import gnu.classpath.Configuration; import gnu.java.io.ObjectIdentityWrapper; import java.lang.reflect.Array; +import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -122,15 +123,6 @@ public class ObjectInputStream extends InputStream */ public final Object readObject() throws ClassNotFoundException, IOException { - if (callersClassLoader == null) - { - callersClassLoader = getCallersClassLoader (); - if (Configuration.DEBUG && dump) - { - dumpElementln ("CallersClassLoader = " + callersClassLoader); - } - } - if (this.useSubclassMethod) return readObjectOverride(); @@ -272,7 +264,7 @@ public class ObjectInputStream extends InputStream readArrayElements(array, componentType); if(dump) for (int i = 0, len = Array.getLength(array); i < len; i++) - dumpElementln(" ELEMENT[" + i + "]=" + Array.get(array, i)); + dumpElementln(" ELEMENT[" + i + "]=" + Array.get(array, i)); ret_val = processResolution(null, array, handle); break; } @@ -302,13 +294,18 @@ public class ObjectInputStream extends InputStream obj.readExternal(this); if (read_from_blocks) - setBlockDataMode(oldmode); + { + setBlockDataMode(oldmode); + if (!oldmode) + if (this.realInputStream.readByte() != TC_ENDBLOCKDATA) + throw new IOException("No end of block data seen for class with readExternal (ObjectInputStream) method."); + } ret_val = processResolution(osc, obj, handle); break; } // end if (osc.realClassIsExternalizable) - Object obj = newObject(clazz, osc.firstNonSerializableParent); + Object obj = newObject(clazz, osc.firstNonSerializableParentConstructor); int handle = assignNewHandle(obj); Object prevObject = this.currentObject; @@ -399,8 +396,6 @@ public class ObjectInputStream extends InputStream setBlockDataMode(old_mode); this.isDeserializing = was_deserializing; - - depth -= 2; depth -= 2; @@ -506,7 +501,8 @@ public class ObjectInputStream extends InputStream flags, fields); assignNewHandle(osc); - ClassLoader currentLoader = currentLoader(); + if (callersClassLoader == null) + callersClassLoader = currentLoader(); for (int i = 0; i < field_count; i++) { @@ -527,12 +523,40 @@ public class ObjectInputStream extends InputStream class_name = String.valueOf(type_code); fields[i] = - new ObjectStreamField(field_name, class_name, currentLoader); + new ObjectStreamField(field_name, class_name, callersClassLoader); } /* Now that fields have been read we may resolve the class * (and read annotation if needed). */ - Class clazz = resolveClass(osc); + Class clazz; + try + { + clazz = resolveClass(osc); + } + catch (ClassNotFoundException cnfe) + { + // Maybe it was an primitive class? + if (name.equals("void")) + clazz = Void.TYPE; + else if (name.equals("boolean")) + clazz = Boolean.TYPE; + else if (name.equals("byte")) + clazz = Byte.TYPE; + else if (name.equals("short")) + clazz = Short.TYPE; + else if (name.equals("char")) + clazz = Character.TYPE; + else if (name.equals("int")) + clazz = Integer.TYPE; + else if (name.equals("long")) + clazz = Long.TYPE; + else if (name.equals("float")) + clazz = Float.TYPE; + else if (name.equals("double")) + clazz = Double.TYPE; + else + throw cnfe; + } boolean oldmode = setBlockDataMode(true); osc.setClass(clazz, lookupClass(clazz.getSuperclass())); @@ -542,16 +566,45 @@ public class ObjectInputStream extends InputStream // find the first non-serializable, non-abstract // class in clazz's inheritance hierarchy Class first_nonserial = clazz.getSuperclass(); - while (Serializable.class.isAssignableFrom(first_nonserial) - || Modifier.isAbstract(first_nonserial.getModifiers())) + // Maybe it is a primitive class, those don't have a super class, + // or Object itself. Otherwise we can keep getting the superclass + // till we hit the Object class, or some other non-serializable class. + + if (first_nonserial == null) + first_nonserial = clazz; + else + while (Serializable.class.isAssignableFrom(first_nonserial) + || Modifier.isAbstract(first_nonserial.getModifiers())) first_nonserial = first_nonserial.getSuperclass(); - osc.firstNonSerializableParent = first_nonserial; + final Class local_constructor_class = first_nonserial; + + osc.firstNonSerializableParentConstructor = + (Constructor)AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + try + { + Constructor c = local_constructor_class. + getDeclaredConstructor(new Class[0]); + if (Modifier.isPrivate(c.getModifiers())) + return null; + return c; + } + catch (NoSuchMethodException e) + { + // error will be reported later, in newObject() + return null; + } + } + }); + osc.realClassIsSerializable = Serializable.class.isAssignableFrom(clazz); osc.realClassIsExternalizable = Externalizable.class.isAssignableFrom(clazz); ObjectStreamField[] stream_fields = osc.fields; - ObjectStreamField[] real_fields = ObjectStreamClass.lookup(clazz).fields; + ObjectStreamField[] real_fields = ObjectStreamClass.lookupForClassObject(clazz).fields; ObjectStreamField[] fieldmapping = new ObjectStreamField[2 * Math.max(stream_fields.length, real_fields.length)]; int stream_idx = 0; @@ -717,6 +770,15 @@ public class ObjectInputStream extends InputStream protected Class resolveClass(ObjectStreamClass osc) throws ClassNotFoundException, IOException { + if (callersClassLoader == null) + { + callersClassLoader = currentLoader (); + if (Configuration.DEBUG && dump) + { + dumpElementln ("CallersClassLoader = " + callersClassLoader); + } + } + return Class.forName(osc.getName(), true, callersClassLoader); } @@ -750,8 +812,10 @@ public class ObjectInputStream extends InputStream */ private ObjectStreamClass lookupClass(Class clazz) { - ObjectStreamClass oclazz; + if (clazz == null) + return null; + ObjectStreamClass oclazz; oclazz = (ObjectStreamClass)classLookupTable.get(clazz); if (oclazz == null) return ObjectStreamClass.lookup(clazz); @@ -1767,14 +1831,14 @@ public class ObjectInputStream extends InputStream // returns a new instance of REAL_CLASS that has been constructed // only to the level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS) - private Object newObject (Class real_class, Class constructor_class) - throws ClassNotFoundException + private Object newObject (Class real_class, Constructor constructor) + throws ClassNotFoundException, IOException { + if (constructor == null) + throw new InvalidClassException("Missing accessible no-arg base class constructor for " + real_class.getName()); try { - Object obj = allocateObject (real_class); - callConstructor (constructor_class, obj); - return obj; + return allocateObject(real_class, constructor.getDeclaringClass(), constructor); } catch (InstantiationException e) { @@ -1810,8 +1874,6 @@ public class ObjectInputStream extends InputStream * @return The current class loader in the calling stack. */ private static native ClassLoader currentClassLoader (SecurityManager sm); - - private native ClassLoader getCallersClassLoader(); private void callReadMethod (Method readObject, Class klass, Object obj) throws ClassNotFoundException, IOException @@ -1844,11 +1906,9 @@ public class ObjectInputStream extends InputStream prereadFields = null; } - private native Object allocateObject (Class clazz) + private native Object allocateObject(Class clazz, Class constr_clazz, Constructor constructor) throws InstantiationException; - private native void callConstructor (Class clazz, Object obj); - private static final int BUFFER_SIZE = 1024; private DataInputStream realInputStream; @@ -1870,9 +1930,8 @@ public class ObjectInputStream extends InputStream private Hashtable classLookupTable; private GetField prereadFields; - private static boolean dump = false && Configuration.DEBUG; - private ClassLoader callersClassLoader; + private static boolean dump; // The nesting depth for debugging output private int depth = 0; -- cgit v1.1