aboutsummaryrefslogtreecommitdiff
path: root/libjava/java/io/ObjectStreamClass.java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/java/io/ObjectStreamClass.java')
-rw-r--r--libjava/java/io/ObjectStreamClass.java145
1 files changed, 83 insertions, 62 deletions
diff --git a/libjava/java/io/ObjectStreamClass.java b/libjava/java/io/ObjectStreamClass.java
index ecdd91d00c6..19a69ec47bc 100644
--- a/libjava/java/io/ObjectStreamClass.java
+++ b/libjava/java/io/ObjectStreamClass.java
@@ -1,6 +1,6 @@
/* ObjectStreamClass.java -- Class used to write class information
about serialized objects.
- Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -44,6 +44,7 @@ import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
import java.security.DigestOutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@@ -76,6 +77,19 @@ public class ObjectStreamClass implements Serializable
if (! (Serializable.class).isAssignableFrom (cl))
return null;
+ return lookupForClassObject (cl);
+ }
+
+ /**
+ * This lookup for internal use by ObjectOutputStream. Suppose
+ * we have a java.lang.Class object C for class A, though A is not
+ * serializable, but it's okay to serialize C.
+ */
+ static ObjectStreamClass lookupForClassObject (Class cl)
+ {
+ if (cl == null)
+ return null;
+
ObjectStreamClass osc = (ObjectStreamClass)classLookupTable.get (cl);
if (osc != null)
@@ -180,6 +194,28 @@ public class ObjectStreamClass implements Serializable
// Returns true iff the class that this ObjectStreamClass represents
+ // has the following method:
+ //
+ // private void readObject (ObjectOutputStream)
+ //
+ // This method is used by the class to override default
+ // serialization behavior.
+ boolean hasReadMethod ()
+ {
+ try
+ {
+ Class[] readObjectParams = { ObjectInputStream.class };
+ forClass ().getDeclaredMethod ("readObject", readObjectParams);
+ return true;
+ }
+ catch (NoSuchMethodException e)
+ {
+ return false;
+ }
+ }
+
+
+ // Returns true iff the class that this ObjectStreamClass represents
// implements Serializable but does *not* implement Externalizable.
boolean isSerializable ()
{
@@ -260,22 +296,29 @@ public class ObjectStreamClass implements Serializable
void setClass (Class cl) throws InvalidClassException
{
this.clazz = cl;
+
long class_uid = getClassUID (cl);
if (uid == 0)
+ uid = class_uid;
+ else
{
- uid = class_uid;
- return;
- }
-
- // Check that the actual UID of the resolved class matches the UID from
- // the stream.
- if (uid != class_uid)
- {
- String msg = cl +
- ": Local class not compatible: stream serialVersionUID="
- + uid + ", local serialVersionUID=" + class_uid;
- throw new InvalidClassException (msg);
+ // Check that the actual UID of the resolved class matches the UID from
+ // the stream.
+ if (uid != class_uid)
+ {
+ String msg = cl +
+ ": Local class not compatible: stream serialVersionUID="
+ + uid + ", local serialVersionUID=" + class_uid;
+ throw new InvalidClassException (msg);
+ }
}
+
+ isProxyClass = clazz != null && Proxy.isProxyClass (clazz);
+ ObjectStreamClass osc = (ObjectStreamClass)classLookupTable.get (clazz);
+ if (osc == null)
+ classLookupTable.put (clazz, this);
+ superClass = lookupForClassObject (clazz.getSuperclass ());
+ calculateOffsets ();
}
void setSuperclass (ObjectStreamClass osc)
@@ -328,12 +371,15 @@ public class ObjectStreamClass implements Serializable
{
uid = 0;
flags = 0;
+ isProxyClass = Proxy.isProxyClass (cl);
clazz = cl;
name = cl.getName ();
setFlags (cl);
setFields (cl);
- uid = getClassUID (cl);
+ // to those class nonserializable, its uid field is 0
+ if ( (Serializable.class).isAssignableFrom (cl) && !isProxyClass)
+ uid = getClassUID (cl);
superClass = lookup (cl.getSuperclass ());
}
@@ -377,6 +423,7 @@ public class ObjectStreamClass implements Serializable
{
Field serialPersistentFields
= cl.getDeclaredField ("serialPersistentFields");
+ serialPersistentFields.setAccessible(true);
int modifiers = serialPersistentFields.getModifiers ();
if (Modifier.isStatic (modifiers)
@@ -427,26 +474,27 @@ public class ObjectStreamClass implements Serializable
{
try
{
+ // Use getDeclaredField rather than getField, since serialVersionUID
+ // may not be public AND we only want the serialVersionUID of this
+ // class, not a superclass or interface.
Field suid = cl.getDeclaredField ("serialVersionUID");
+ suid.setAccessible(true);
int modifiers = suid.getModifiers ();
- if (Modifier.isStatic (modifiers) && Modifier.isFinal (modifiers))
- return suid.getLong (null);
+ if (Modifier.isStatic (modifiers)
+ && Modifier.isFinal (modifiers)
+ && suid.getType() == Long.TYPE)
+ return suid.getLong (null);
}
catch (NoSuchFieldException ignore)
- {
- }
+ {}
catch (IllegalAccessException ignore)
- {
- }
+ {}
// cl didn't define serialVersionUID, so we have to compute it
try
{
- MessageDigest md = null;
- DigestOutputStream digest_out = null;
- DataOutputStream data_out = null;
-
+ MessageDigest md;
try
{
md = MessageDigest.getInstance ("SHA");
@@ -459,8 +507,10 @@ public class ObjectStreamClass implements Serializable
md = MessageDigest.getInstance ("SHA");
}
- digest_out = new DigestOutputStream (nullOutputStream, md);
- data_out = new DataOutputStream (digest_out);
+ DigestOutputStream digest_out =
+ new DigestOutputStream (nullOutputStream, md);
+ DataOutputStream data_out = new DataOutputStream (digest_out);
+
data_out.writeUTF (cl.getName ());
int modifiers = cl.getModifiers ();
@@ -497,17 +547,7 @@ public class ObjectStreamClass implements Serializable
}
// write class initializer method if present
- boolean has_init;
- try
- {
- has_init = hasClassInitializer (cl);
- }
- catch (NoSuchMethodError e)
- {
- has_init = false;
- }
-
- if (has_init)
+ if (VMObjectStreamClass.hasClassInitializer (cl))
{
data_out.writeUTF ("<clinit>");
data_out.writeInt (Modifier.STATIC);
@@ -564,11 +604,11 @@ public class ObjectStreamClass implements Serializable
catch (NoSuchAlgorithmException e)
{
throw new RuntimeException ("The SHA algorithm was not found to use in computing the Serial Version UID for class "
- + cl.getName ());
+ + cl.getName (), e);
}
catch (IOException ioe)
{
- throw new RuntimeException (ioe.getMessage ());
+ throw new RuntimeException (ioe);
}
}
@@ -582,6 +622,7 @@ public class ObjectStreamClass implements Serializable
// Use getDeclaredField rather than getField for the same reason
// as above in getDefinedSUID.
Field f = clazz.getDeclaredField ("getSerialPersistentFields");
+ f.setAccessible(true);
o = (ObjectStreamField[])f.get (null);
}
catch (java.lang.NoSuchFieldException e)
@@ -594,29 +635,6 @@ public class ObjectStreamClass implements Serializable
return o;
}
-
- // Returns true if CLAZZ has a static class initializer
- // (a.k.a. <clinit>).
- //
- // A NoSuchMethodError is raised if CLAZZ has no such method.
- private static boolean hasClassInitializer (Class clazz)
- throws java.lang.NoSuchMethodError
- {
- Method m = null;
-
- try
- {
- Class classArgs[] = {};
- m = clazz.getDeclaredMethod ("<clinit>", classArgs);
- }
- catch (java.lang.NoSuchMethodException e)
- {
- throw new java.lang.NoSuchMethodError ();
- }
-
- return m != null;
- }
-
public static final ObjectStreamField[] NO_FIELDS = {};
private static Hashtable classLookupTable = new Hashtable ();
@@ -640,9 +658,12 @@ public class ObjectStreamClass implements Serializable
int primFieldSize = -1; // -1 if not yet calculated
int objectFieldCount;
+ boolean isProxyClass = false;
+
// This is probably not necessary because this class is special cased already
// but it will avoid showing up as a discrepancy when comparing SUIDs.
private static final long serialVersionUID = -6120832682080437368L;
+
}