You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by nd...@apache.org on 2008/06/09 05:33:56 UTC

svn commit: r664611 - in /harmony/enhanced/classlib/trunk/modules/luni: .classpath src/main/java/java/io/ObjectInputStream.java src/main/java/java/io/ObjectOutputStream.java src/main/java/java/io/ObjectStreamClass.java

Author: ndbeyer
Date: Sun Jun  8 20:33:55 2008
New Revision: 664611

URL: http://svn.apache.org/viewvc?rev=664611&view=rev
Log:
apply patch for HARMONY-5847: ObjectInputStream/ObjectOutputStream cleanup

Modified:
    harmony/enhanced/classlib/trunk/modules/luni/.classpath
    harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/io/ObjectInputStream.java
    harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/io/ObjectOutputStream.java
    harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/io/ObjectStreamClass.java

Modified: harmony/enhanced/classlib/trunk/modules/luni/.classpath
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/luni/.classpath?rev=664611&r1=664610&r2=664611&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/luni/.classpath (original)
+++ harmony/enhanced/classlib/trunk/modules/luni/.classpath Sun Jun  8 20:33:55 2008
@@ -14,5 +14,6 @@
 		</accessrules>
 	</classpathentry>
 	<classpathentry kind="var" path="JUNIT_HOME/junit.jar" sourcepath="JUNIT_SRC_HOME/junitsrc.zip"/>
+	<classpathentry kind="lib" path="C:/dev/harmony/trunk/working_classlib/deploy/jdk/jre/lib/boot/luni-kernel-stubs.jar"/>
 	<classpathentry kind="output" path="bin/main"/>
 </classpath>

Modified: harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/io/ObjectInputStream.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/io/ObjectInputStream.java?rev=664611&r1=664610&r2=664611&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/io/ObjectInputStream.java (original)
+++ harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/io/ObjectInputStream.java Sun Jun  8 20:33:55 2008
@@ -702,8 +702,7 @@
                 ObjectStreamClass streamClass = ObjectStreamClass
                         .lookup(proxyClass);
                 streamClass.setLoadFields(new ObjectStreamField[0]);
-                registerObjectRead(streamClass, Integer.valueOf(nextHandle()),
-                        false);
+                registerObjectRead(streamClass, nextHandle(), false);
                 checkedSetSuperClassDesc(streamClass, readClassDesc());
                 return streamClass;
             case TC_REFERENCE:
@@ -1324,7 +1323,7 @@
                 int index = findStreamSuperclass(superclass, streamClassList,
                         lastIndex);
                 if (index == -1) {
-                    readObjectNoData(object, superclass);
+                    readObjectNoData(object, superclass, ObjectStreamClass.lookupStreamClass(superclass));
                 } else {
                     for (int j = lastIndex; j <= index; j++) {
                         readObjectForClass(object, streamClassList.get(j));
@@ -1358,12 +1357,11 @@
         return -1;
     }
 
-    private void readObjectNoData(Object object, Class<?> cl)
+    private void readObjectNoData(Object object, Class<?> cl, ObjectStreamClass classDesc)
             throws ObjectStreamException {
-        if (!ObjectStreamClass.isSerializable(cl)) {
+        if (!classDesc.isSerializable()) {
             return;
         }
-        ObjectStreamClass classDesc = ObjectStreamClass.lookupStreamClass(cl);
         if (classDesc.hasMethodReadObjectNoData()){
             final Method readMethod = classDesc.getMethodReadObjectNoData();
             try {
@@ -1501,7 +1499,7 @@
             throw new InvalidClassException(Msg.getString("K00d1")); //$NON-NLS-1$
         }
 
-        Integer newHandle = Integer.valueOf(nextHandle());
+        Integer newHandle = nextHandle();
 
         // Array size
         int size = input.readInt();
@@ -1562,6 +1560,10 @@
             // Array of Objects
             Object[] objectArray = (Object[]) result;
             for (int i = 0; i < size; i++) {
+                // TODO: This place is the opportunity for enhancement
+                //      We can implement writing elements through fast-path,
+                //      without setting up the context (see readObject()) for 
+                //      each element with public API
                 objectArray[i] = readObject();
             }
         }
@@ -1590,10 +1592,9 @@
         ObjectStreamClass classDesc = readClassDesc();
 
         if (classDesc != null) {
-            Integer newHandle = Integer.valueOf(nextHandle());
             Class<?> localClass = classDesc.forClass();
             if (localClass != null) {
-                registerObjectRead(localClass, newHandle, unshared);
+                registerObjectRead(localClass, nextHandle(), unshared);
             }
             return localClass;
         }
@@ -1659,7 +1660,7 @@
             ClassNotFoundException, IOException {
         // read classdesc for Enum first
         ObjectStreamClass classDesc = readEnumDesc();
-        Integer newHandle = Integer.valueOf(nextHandle());
+        int newHandle = nextHandle();
         // read name after class desc
         String name;
         byte tc = nextTC();
@@ -1705,7 +1706,7 @@
         // subclasses during readClassDescriptor()
         primitiveData = input;
         Integer oldHandle = descriptorHandle;
-        descriptorHandle = Integer.valueOf(nextHandle());
+        descriptorHandle = nextHandle();
         ObjectStreamClass newClassDesc = readClassDescriptor();
         registerObjectRead(newClassDesc, descriptorHandle, unshared);
         descriptorHandle = oldHandle;
@@ -1795,8 +1796,7 @@
          * descriptors. If called outside of readObject, the descriptorHandle
          * might be null.
          */
-        descriptorHandle = (null == descriptorHandle ? Integer
-                .valueOf(nextHandle()) : descriptorHandle);
+        descriptorHandle = (null == descriptorHandle ? nextHandle() : descriptorHandle);
         registerObjectRead(newClassDesc, descriptorHandle, false);
 
         readFieldDescriptors(newClassDesc);
@@ -1817,6 +1817,9 @@
      */
     protected Class<?> resolveProxyClass(String[] interfaceNames)
             throws IOException, ClassNotFoundException {
+            
+        // TODO: This method is opportunity for performance enhancement
+        //       We can cache the classloader and recently used interfaces.        
         ClassLoader loader = VM.getNonBootstrapClassLoader();
         Class<?>[] interfaces = new Class<?>[interfaceNames.length];
         for (int i = 0; i < interfaceNames.length; i++) {
@@ -1837,8 +1840,8 @@
      * @throws IOException
      *             If an IO exception happened when reading the handle
      */
-    private Integer readNewHandle() throws IOException {
-        return Integer.valueOf(input.readInt());
+    private int readNewHandle() throws IOException {
+        return input.readInt();
     }
 
     private Class<?> resolveConstructorClass(Class<?> objectClass, boolean wasSerializable, boolean wasExternalizable)
@@ -1936,7 +1939,7 @@
             throw new InvalidClassException(Msg.getString("K00d1")); //$NON-NLS-1$
         }
 
-        Integer newHandle = Integer.valueOf(nextHandle());
+        Integer newHandle = nextHandle();
 
         // Note that these values come from the Stream, and in fact it could be
         // that the classes have been changed so that the info below now
@@ -2009,9 +2012,8 @@
 
         if (objectClass != null) {
 
-            ObjectStreamClass desc = ObjectStreamClass.lookupStreamClass(objectClass);
-            if (desc.hasMethodReadResolve()){
-                Method methodReadResolve = desc.getMethodReadResolve();
+            if (classDesc.hasMethodReadResolve()){
+                Method methodReadResolve = classDesc.getMethodReadResolve();
                 try {
                     result = methodReadResolve.invoke(result, (Object[]) null);
                 } catch (IllegalAccessException iae) {
@@ -2059,8 +2061,7 @@
         if (enableResolve) {
             result = resolveObject(result);
         }
-        int newHandle = nextHandle();
-        registerObjectRead(result, Integer.valueOf(newHandle), unshared);
+		registerObjectRead(result, nextHandle(), unshared);
 
         return result;
     }
@@ -2082,8 +2083,7 @@
         if (enableResolve) {
             result = resolveObject(result);
         }
-        int newHandle = nextHandle();
-        registerObjectRead(result, Integer.valueOf(newHandle), unshared);
+        registerObjectRead(result, nextHandle(), unshared);
 
         return result;
     }
@@ -2427,8 +2427,6 @@
                 // Use the first non-null ClassLoader on the stack. If null, use
                 // the system class loader
                 cls = Class.forName(className, true, callerClassLoader);
-                // save the value
-                osClass.setClass(cls);
             }
         }
         return cls;

Modified: harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/io/ObjectOutputStream.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/io/ObjectOutputStream.java?rev=664611&r1=664610&r2=664611&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/io/ObjectOutputStream.java (original)
+++ harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/io/ObjectOutputStream.java Sun Jun  8 20:33:55 2008
@@ -115,6 +115,11 @@
 
     private ObjectAccessor accessor = AccessorFactory.getObjectAccessor();
 
+	/*
+	 * Descriptor for java.lang.reflect.Proxy
+	 */
+    private final ObjectStreamClass proxyClassDesc = ObjectStreamClass.lookup(Proxy.class); 
+  
     /**
      * Inner class to provide access to serializable fields
      */
@@ -468,8 +473,8 @@
      * 
      * @see #nextHandle
      */
-    private Integer registerObjectWritten(Object obj) {
-        Integer handle = Integer.valueOf(nextHandle());
+    private int registerObjectWritten(Object obj) {
+        int handle = nextHandle();
         objectsWritten.put(obj, handle);
         return handle;
     }
@@ -740,9 +745,10 @@
             }
             // If we got here, it is a new (non-null) classDesc that will have
             // to be registered as well
-            handle = registerObjectWritten(classDesc);
+            handle = nextHandle();
+            objectsWritten.put(classDesc, handle);
 
-            if (Proxy.isProxyClass(classToWrite)) {
+            if (classDesc.isProxy()) {
                 output.writeByte(TC_PROXYCLASSDESC);
                 Class<?>[] interfaces = classToWrite.getInterfaces();
                 output.writeInt(interfaces.length);
@@ -751,7 +757,7 @@
                 }
                 annotateProxyClass(classToWrite);
                 output.writeByte(TC_ENDBLOCKDATA);
-                writeClassDescForClass(Proxy.class);
+                writeClassDesc(proxyClassDesc, false);
                 if (unshared) {
                     // remove reference to unshared object
                     removeUnsharedReference(classDesc, previousHandle);
@@ -783,25 +789,6 @@
     }
 
     /**
-     * Writes a class descriptor (an <code>ObjectStreamClass</code>) that
-     * corresponds to the <code>java.lang.Class objClass</code> to the stream.
-     * 
-     * @param objClass
-     *            The class for which a class descriptor (an
-     *            <code>ObjectStreamClass</code>) will be dumped.
-     * @return the handle assigned to the class descriptor
-     * 
-     * @throws IOException
-     *             If an IO exception happened when writing the class
-     *             descriptor.
-     * 
-     */
-    private Integer writeClassDescForClass(Class<?> objClass)
-            throws IOException {
-        return writeClassDesc(ObjectStreamClass.lookup(objClass), false);
-    }
-
-    /**
      * Writes a handle representing a cyclic reference (object previously
      * dumped).
      * 
@@ -1176,19 +1163,15 @@
      * @throws IOException
      *             If an IO exception happened when writing the array.
      */
-    private Integer writeNewArray(Object array, Class<?> arrayClass,
+    private Integer writeNewArray(Object array, Class<?> arrayClass, ObjectStreamClass arrayClDesc,
             Class<?> componentType, boolean unshared) throws IOException {
         output.writeByte(TC_ARRAY);
-        writeClassDescForClass(arrayClass);
+        writeClassDesc(arrayClDesc, false);
 
-        Integer previousHandle = null;
-        if (unshared) {
-            previousHandle = objectsWritten.get(array);
-        }
-        Integer handle = registerObjectWritten(array);
-        if (unshared) {
-            // remove reference to unshared object
-            removeUnsharedReference(array, previousHandle);
+        int handle = nextHandle();
+
+        if (!unshared) {
+            objectsWritten.put(array, handle);
         }
 
         // Now we have code duplication just because Java is typed. We have to
@@ -1253,6 +1236,10 @@
             Object[] objectArray = (Object[]) array;
             output.writeInt(objectArray.length);
             for (int i = 0; i < objectArray.length; i++) {
+                // TODO: This place is the opportunity for enhancement
+                //      We can implement writing elements through fast-path,
+                //      without setting up the context (see writeObject()) for 
+                //      each element with public API
                 writeObject(objectArray[i]);
             }
         }
@@ -1282,24 +1269,20 @@
         // We cannot call lookup because it returns null if the parameter
         // represents instances that cannot be serialized, and that is not what
         // we want.
-
+        ObjectStreamClass clDesc = ObjectStreamClass.lookupStreamClass(object);
+        
         // The handle for the classDesc is NOT the handle for the class object
         // being dumped. We must allocate a new handle and return it.
-        if (object.isEnum()) {
-            writeEnumDesc(object, unshared);
+        if (clDesc.isEnum()) {
+            writeEnumDesc(object, clDesc, unshared);
         } else {
-            writeClassDesc(ObjectStreamClass.lookupStreamClass(object),
-                    unshared);
+            writeClassDesc(clDesc, unshared);
         }
+     
+        int handle = nextHandle();
 
-        Integer previousHandle = null;
-        if (unshared) {
-            previousHandle = objectsWritten.get(object);
-        }
-        Integer handle = registerObjectWritten(object);
-        if (unshared) {
-            // remove reference to unshared object
-            removeUnsharedReference(object, previousHandle);
+        if (!unshared) {
+            objectsWritten.put(object, handle);
         }
 
         return handle;
@@ -1324,9 +1307,8 @@
         output.writeUTF(classDesc.getName());
         output.writeLong(classDesc.getSerialVersionUID());
         byte flags = classDesc.getFlags();
-        boolean externalizable = false;
-        externalizable = ObjectStreamClass.isExternalizable(classDesc
-                .forClass());
+        
+        boolean externalizable = classDesc.isExternalizable();
 
         if (externalizable) {
             if (protocolVersion == PROTOCOL_VERSION_1) {
@@ -1411,7 +1393,7 @@
      * @throws IOException
      *             If an IO exception happened when writing the object.
      */
-    private Integer writeNewObject(Object object, Class<?> theClass,
+    private Integer writeNewObject(Object object, Class<?> theClass, ObjectStreamClass clDesc, 
             boolean unshared) throws IOException {
         // Not String, not null, not array, not cyclic reference
 
@@ -1419,8 +1401,8 @@
         currentPutField = null; // null it, to make sure one will be computed if
         // needed
 
-        boolean externalizable = ObjectStreamClass.isExternalizable(theClass);
-        boolean serializable = ObjectStreamClass.isSerializable(theClass);
+        boolean externalizable = clDesc.isExternalizable();
+        boolean serializable = clDesc.isSerializable();
         if (!externalizable && !serializable) {
             // Object is neither externalizable nor serializable. Error
             throw new NotSerializableException(theClass.getName());
@@ -1428,19 +1410,20 @@
 
         // Either serializable or externalizable, now we can save info
         output.writeByte(TC_OBJECT);
-        writeClassDescForClass(theClass);
+        writeClassDesc(clDesc, false);
         Integer previousHandle = null;
         if (unshared) {
             previousHandle = objectsWritten.get(object);
         }
-        Integer handle = registerObjectWritten(object);
+        int handle = nextHandle();
+        objectsWritten.put(object, handle);
 
         // This is how we know what to do in defaultWriteObject. And it is also
         // used by defaultWriteObject to check if it was called from an invalid
         // place.
         // It allows writeExternal to call defaultWriteObject and have it work.
         currentObject = object;
-        currentClass = ObjectStreamClass.lookup(theClass);
+        currentClass = clDesc;
         try {
             if (externalizable) {
                 boolean noBlockData = protocolVersion == PROTOCOL_VERSION_1;
@@ -1480,6 +1463,24 @@
     }
 
     /**
+     * Updates the references table with new handle
+     * 
+     * @param obj
+     *            Non-null object being updated
+     * @param unshared
+     *            whether the handle is unshared
+     */
+    private int updateReference(Object object, boolean unshared) {
+        int handle = nextHandle();
+
+        if (!unshared) {
+            objectsWritten.put(object, handle);
+        }
+        
+        return handle;
+    }
+    
+    /**
      * Write String <code>object</code> into the receiver. It is assumed the
      * String has not been dumped yet. Return an <code>Integer</code> that
      * represents the handle for this object (String) which is dumped here.
@@ -1503,16 +1504,13 @@
             output.writeLong(count);
         }
         output.writeUTFBytes(object, count);
+     
+        int handle = nextHandle();
 
-        Integer previousHandle = null;
-        if (unshared) {
-            previousHandle = objectsWritten.get(object);
-        }
-        Integer handle = registerObjectWritten(object);
-        if (unshared) {
-            // remove reference to unshared object
-            removeUnsharedReference(object, previousHandle);
+        if (!unshared) {
+            objectsWritten.put(object, handle);
         }
+        
         return handle;
     }
 
@@ -1634,6 +1632,8 @@
 
         // Non-null object, first time seen...
         Class<?> objClass = object.getClass();
+        ObjectStreamClass clDesc = ObjectStreamClass.lookupStreamClass(objClass);        
+        
         nestedLevels++;
         try {
 
@@ -1648,9 +1648,8 @@
                 }
             }
 
-            if (ObjectStreamClass.isSerializable(object.getClass())
+            if (clDesc.isSerializable()
                     && computeClassBasedReplacement) {
-                ObjectStreamClass clDesc = ObjectStreamClass.lookupStreamClass(objClass);
                 if(clDesc.hasMethodWriteReplace()){
                     Method methodWriteReplace = clDesc.getMethodWriteReplace();
                     Object replObj = null; 
@@ -1724,7 +1723,7 @@
 
             // Is it an Array ?
             if (objClass.isArray()) {
-                return writeNewArray(object, objClass, objClass
+                return writeNewArray(object, objClass, clDesc, objClass
                         .getComponentType(), unshared);
             }
 
@@ -1733,17 +1732,17 @@
             }
 
             // Not a String or Class or Array. Default procedure.
-            return writeNewObject(object, objClass, unshared);
+            return writeNewObject(object, objClass, clDesc, unshared);
         } finally {
             nestedLevels--;
         }
     }
 
     // write for Enum Class Desc only, which is different from other classes
-    private ObjectStreamClass writeEnumDesc(Class<?> theClass, boolean unshared)
+    private ObjectStreamClass writeEnumDesc(Class<?> theClass, ObjectStreamClass classDesc, boolean unshared)
             throws IOException {
         // write classDesc, classDesc for enum is different
-        ObjectStreamClass classDesc = ObjectStreamClass.lookup(theClass);
+
         // set flag for enum, the flag is (SC_SERIALIZABLE | SC_ENUM)
         classDesc.setFlags((byte) (SC_SERIALIZABLE | SC_ENUM));
         Integer previousHandle = null;
@@ -1758,7 +1757,7 @@
             Class<?> classToWrite = classDesc.forClass();
             // If we got here, it is a new (non-null) classDesc that will have
             // to be registered as well
-            registerObjectWritten(classDesc);
+            objectsWritten.put(classDesc, nextHandle());
 
             output.writeByte(TC_CLASSDESC);
             if (protocolVersion == PROTOCOL_VERSION_1) {
@@ -1775,11 +1774,11 @@
             drain(); // flush primitive types in the annotation
             output.writeByte(TC_ENDBLOCKDATA);
             // write super class
-            ObjectStreamClass superClass = classDesc.getSuperclass();
-            if (null != superClass) {
+            ObjectStreamClass superClassDesc = classDesc.getSuperclass();
+            if (null != superClassDesc) {
                 // super class is also enum
-                superClass.setFlags((byte) (SC_SERIALIZABLE | SC_ENUM));
-                writeEnumDesc(superClass.forClass(), unshared);
+                superClassDesc.setFlags((byte) (SC_SERIALIZABLE | SC_ENUM));
+                writeEnumDesc(superClassDesc.forClass(), superClassDesc, unshared);
             } else {
                 output.writeByte(TC_NULL);
             }
@@ -1803,13 +1802,15 @@
             // write enum only
             theClass = theClass.getSuperclass();
         }
-        ObjectStreamClass classDesc = writeEnumDesc(theClass, unshared);
+        ObjectStreamClass classDesc = ObjectStreamClass.lookup(theClass);
+        writeEnumDesc(theClass, classDesc, unshared);
 
         Integer previousHandle = null;
         if (unshared) {
             previousHandle = objectsWritten.get(object);
         }
-        Integer handle = registerObjectWritten(object);
+        int handle = nextHandle();
+        objectsWritten.put(object, handle);
 
         ObjectStreamField[] fields = classDesc.getSuperclass().fields();
         Class<?> declaringClass = classDesc.getSuperclass().forClass();

Modified: harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/io/ObjectStreamClass.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/io/ObjectStreamClass.java?rev=664611&r1=664610&r2=664611&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/io/ObjectStreamClass.java (original)
+++ harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/io/ObjectStreamClass.java Sun Jun  8 20:33:55 2008
@@ -148,6 +148,27 @@
 
     private transient Method methodReadObjectNoData;
 
+    /**
+     * Indicates whether the class properties resolved
+     * 
+     * @see #resolveProperties()
+     */
+    private transient boolean arePropertiesResolved;
+    
+    /**
+     * Cached class properties
+     * 
+     * @see #resolveProperties()
+     * @see #isSerializable()
+     * @see #isExternalizable() 
+     * @see #isProxy()
+     * @see #isEnum()
+     */
+    private transient boolean isSerializable;
+    private transient boolean isExternalizable;      
+    private transient boolean isProxy;
+    private transient boolean isEnum;   
+    
     // ClassDesc //
 
     // Name of the class this descriptor represents
@@ -203,26 +224,24 @@
     }
 
     /**
-     * Compute class descriptor for a given class <code>cl</code>. If
-     * <code>computeSUID</code> is true, this method will compute the SUID for
-     * this class.
+     * Compute class descriptor for a given class <code>cl</code>. 
      * 
      * @param cl
      *            a java.langClass for which to compute the corresponding
-     *            descriptor
-     * @param computeSUID
-     *            a boolean indicating if SUID should be computed or not.
+     *            descriptor 
      * @return the computer class descriptor
      */
-    private static ObjectStreamClass createClassDesc(Class<?> cl,
-            boolean computeSUID) {
+    private static ObjectStreamClass createClassDesc(Class<?> cl) {
 
         ObjectStreamClass result = new ObjectStreamClass();
 
-        boolean isProxy = Proxy.isProxyClass(cl);
-        boolean isEnum = Enum.class.isAssignableFrom(cl);
         boolean isArray = cl.isArray();
+        boolean serializable = isSerializable(cl);
+        boolean externalizable = isExternalizable(cl);          
 
+        result.isSerializable = serializable;
+        result.isExternalizable = externalizable;
+        
         // Now we fill in the values
         result.setName(cl.getName());
         result.setClass(cl);
@@ -232,9 +251,10 @@
         }
 
         Field[] declaredFields = null;
-        if (computeSUID) {
-            // Lazy computation, to save speed & space
-            if (isEnum || isProxy) {
+        
+        // Compute the SUID
+        if(serializable || externalizable) {
+            if (result.isEnum() || result.isProxy()) {
                 result.setSerialVersionUID(0L);
             } else {
                 declaredFields = cl.getDeclaredFields();
@@ -243,7 +263,6 @@
             }
         }
 
-        boolean serializable = isSerializable(cl);
         // Serializables need field descriptors
         if (serializable && !isArray) {
             if (declaredFields == null) {
@@ -274,7 +293,6 @@
         }
 
         byte flags = 0;
-        boolean externalizable = isExternalizable(cl);
         if (externalizable) {
             flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
             flags |= ObjectStreamConstants.SC_BLOCK_DATA; // use protocol version 2 by default
@@ -688,7 +706,7 @@
     ObjectStreamField[] fields() {
         if (fields == null) {
             Class<?> forCl = forClass();
-            if (forCl != null && isSerializable(forCl) && !forCl.isArray()) {
+            if (forCl != null && isSerializable() && !forCl.isArray()) {
                 buildFieldDescriptors(forCl.getDeclaredFields());
             } else {
                 // Externalizables or arrays do not need FieldDesc info
@@ -869,6 +887,63 @@
     }
 
     /**
+     * Resolves the class properties, if they weren't already
+     */
+    private void resolveProperties() {       
+        if (arePropertiesResolved) {
+            return;
+        }
+           
+        Class<?> cl = forClass();
+        isProxy = Proxy.isProxyClass(cl);
+        isEnum = Enum.class.isAssignableFrom(cl);
+        isSerializable = isSerializable(cl);
+        isExternalizable = isExternalizable(cl);
+        
+        arePropertiesResolved = true;
+    }
+
+    /**
+     * Answers whether the class for this descriptor is serializable
+     * 
+     * @return true if class implements Serializable
+     */
+    boolean isSerializable() {
+        resolveProperties();
+        return isSerializable;    
+    }
+
+    /**
+     * Answers whether the class for this descriptor is serializable
+     * 
+     * @return true if class implements Serializable
+     */
+    boolean isExternalizable() {
+        resolveProperties();        
+        return isExternalizable;
+    }
+     
+    /**
+     * Answers whether the class for this descriptor is proxied class
+     * 
+     * @return true if class is proxied
+     */
+    boolean isProxy() {    
+        resolveProperties();
+        return isProxy;
+    }
+
+    /**
+     * Answers whether the class for this descriptor is subclass of Enum
+     * 
+     * @return true if class is subclass of Enum
+     */
+    boolean isEnum() {     
+        resolveProperties();
+        return isEnum;
+    }
+    
+    /**
      * Return a little endian long stored in a given position of the buffer
      * 
      * @param buffer
@@ -899,29 +974,13 @@
      *         the class <code>cl</code> is Serializable or Externalizable
      */
     public static ObjectStreamClass lookup(Class<?> cl) {
-        boolean serializable = isSerializable(cl);
-        boolean externalizable = isExternalizable(cl);
-
-        // Has to be either Serializable or Externalizable
-        if (!serializable && !externalizable) {
-            return null;
+        ObjectStreamClass osc = lookupStreamClass(cl);
+        
+        if (osc.isSerializable() || osc.isExternalizable()) {
+            return osc;
         }
-
-        return lookupStreamClass(cl, true);
-    }
-
-    /**
-     * Return the descriptor (ObjectStreamClass) corresponding to the class
-     * <code>cl</code>. Returns an ObjectStreamClass even if instances of the
-     * class cannot be serialized
-     * 
-     * @param cl
-     *            a java.langClass for which to obtain the corresponding
-     *            descriptor
-     * @return the corresponding descriptor
-     */
-    static ObjectStreamClass lookupStreamClass(Class<?> cl) {
-        return lookupStreamClass(cl, isSerializable(cl) || isExternalizable(cl));
+        
+        return null;
     }
 
     /**
@@ -936,14 +995,13 @@
      *            a boolean indicating if SUID should be computed or not.
      * @return the corresponding descriptor
      */
-    private static ObjectStreamClass lookupStreamClass(Class<?> cl,
-            boolean computeSUID) {
+    static ObjectStreamClass lookupStreamClass(Class<?> cl) {
 
         WeakHashMap<Class<?>,ObjectStreamClass> tlc = OSCThreadLocalCache.oscWeakHashMap.get();
 
         ObjectStreamClass cachedValue = tlc.get(cl);
         if (cachedValue == null) {
-            cachedValue = createClassDesc(cl, computeSUID);
+            cachedValue = createClassDesc(cl);
             tlc.put(cl, cachedValue);
         }
         return cachedValue;