OSDN Git Service

Merge with Classpath:
[pf3gnuchains/gcc-fork.git] / libjava / java / io / ObjectStreamClass.java
index ecdd91d..5d4c102 100644 (file)
@@ -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)
@@ -260,22 +274,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 +349,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 +401,7 @@ public class ObjectStreamClass implements Serializable
     {
       Field serialPersistentFields
        = cl.getDeclaredField ("serialPersistentFields");
+      serialPersistentFields.setAccessible(true);
       int modifiers = serialPersistentFields.getModifiers ();
 
       if (Modifier.isStatic (modifiers)
@@ -427,26 +452,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 +485,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 +525,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 (hasClassInitializer (cl))
       {
        data_out.writeUTF ("<clinit>");
        data_out.writeInt (Modifier.STATIC);
@@ -564,11 +582,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 +600,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)
@@ -597,21 +616,23 @@ public class ObjectStreamClass implements Serializable
 
   // 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
       {
+       /*
+        * There exists a problem here, according to the spec
+        * clazz.getDeclaredMethod ("<clinit>", classArgs);
+        * will always throw NoSuchMethodException, even if the static 
+        * intializer does exist.
+        */
        Class classArgs[] = {};
        m = clazz.getDeclaredMethod ("<clinit>", classArgs);
       }
     catch (java.lang.NoSuchMethodException e)
       {
-       throw new java.lang.NoSuchMethodError ();
       }
 
     return m != null;
@@ -640,9 +661,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;
+
 }