8002212: adding read/writeObject to additional SerialXXX classes
authorlancea
Tue, 06 Nov 2012 14:59:22 -0500
changeset 14409 d879c92507ec
parent 14408 db08012d1d6f
child 14410 4d59642be50d
8002212: adding read/writeObject to additional SerialXXX classes Reviewed-by: naoto, forax
jdk/src/share/classes/javax/sql/rowset/serial/SerialArray.java
jdk/src/share/classes/javax/sql/rowset/serial/SerialDatalink.java
jdk/src/share/classes/javax/sql/rowset/serial/SerialJavaObject.java
jdk/src/share/classes/javax/sql/rowset/serial/SerialRef.java
jdk/src/share/classes/javax/sql/rowset/serial/SerialStruct.java
--- a/jdk/src/share/classes/javax/sql/rowset/serial/SerialArray.java	Mon Nov 05 12:51:14 2012 -0500
+++ b/jdk/src/share/classes/javax/sql/rowset/serial/SerialArray.java	Tue Nov 06 14:59:22 2012 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,7 @@
 import java.io.*;
 import java.util.Map;
 import java.net.URL;
-
+import java.util.Arrays;
 
 /**
  * A serialized version of an <code>Array</code>
@@ -525,6 +525,97 @@
     }
 
     /**
+     * Compares this SerialArray to the specified object.  The result is {@code
+     * true} if and only if the argument is not {@code null} and is a {@code
+     * SerialArray} object whose elements are identical to this object's elements
+     *
+     * @param  obj The object to compare this {@code SerialArray} against
+     *
+     * @return  {@code true} if the given object represents a {@code SerialArray}
+     *          equivalent to this SerialArray, {@code false} otherwise
+     *
+     */
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj instanceof SerialArray) {
+            SerialArray sa = (SerialArray)obj;
+            return baseType == sa.baseType &&
+                    baseTypeName.equals(sa.baseTypeName) &&
+                    Arrays.equals(elements, sa.elements);
+        }
+        return false;
+    }
+
+    /**
+     * Returns a hash code for this SerialArray. The hash code for a
+     * {@code SerialArray} object is computed using the hash codes
+     * of the elements of the  {@code SerialArray} object
+     *
+     * @return  a hash code value for this object.
+     */
+    public int hashCode() {
+        return (((31 + Arrays.hashCode(elements)) * 31 + len)  * 31 +
+                baseType) * 31 + baseTypeName.hashCode();
+    }
+
+    /**
+     * Returns a clone of this {@code SerialArray}. The copy will contain a
+     * reference to a clone of the underlying objects array, not a reference
+     * to the original underlying object array of this {@code SerialArray} object.
+     *
+     * @return  a clone of this SerialArray
+     */
+    public Object clone() {
+        try {
+            SerialArray sa = (SerialArray) super.clone();
+            sa.elements = Arrays.copyOf(elements, len);
+            return sa;
+        } catch (CloneNotSupportedException ex) {
+            // this shouldn't happen, since we are Cloneable
+            throw new InternalError();
+        }
+
+    }
+
+    /**
+     * readObject is called to restore the state of the {@code SerialArray} from
+     * a stream.
+     */
+    private void readObject(ObjectInputStream s)
+            throws IOException, ClassNotFoundException {
+
+       ObjectInputStream.GetField fields = s.readFields();
+       Object[] tmp = (Object[])fields.get("elements", null);
+       if (tmp == null)
+           throw new InvalidObjectException("elements is null and should not be!");
+       elements = tmp.clone();
+       len = fields.get("len", 0);
+       if(elements.length != len)
+           throw new InvalidObjectException("elements is not the expected size");
+
+       baseType = fields.get("baseType", 0);
+       baseTypeName = (String)fields.get("baseTypeName", null);
+    }
+
+    /**
+     * writeObject is called to save the state of the {@code SerialArray}
+     * to a stream.
+     */
+    private void writeObject(ObjectOutputStream s)
+            throws IOException, ClassNotFoundException {
+
+        ObjectOutputStream.PutField fields = s.putFields();
+        fields.put("elements", elements);
+        fields.put("len", len);
+        fields.put("baseType", baseType);
+        fields.put("baseTypeName", baseTypeName);
+        s.writeFields();
+    }
+
+    /**
      * The identifier that assists in the serialization of this <code>SerialArray</code>
      * object.
      */
--- a/jdk/src/share/classes/javax/sql/rowset/serial/SerialDatalink.java	Mon Nov 05 12:51:14 2012 -0500
+++ b/jdk/src/share/classes/javax/sql/rowset/serial/SerialDatalink.java	Tue Nov 06 14:59:22 2012 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -100,10 +100,64 @@
         return aURL;
     }
 
+    /**
+     * Compares this {@code SerialDatalink} to the specified object.
+     * The result is {@code true} if and only if the argument is not
+     * {@code null} and is a {@code SerialDatalink} object whose URL is
+     * identical to this object's URL
+     *
+     * @param  obj The object to compare this {@code SerialDatalink} against
+     *
+     * @return  {@code true} if the given object represents a {@code SerialDatalink}
+     *          equivalent to this SerialDatalink, {@code false} otherwise
+     *
+     */
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof SerialDatalink) {
+            SerialDatalink sdl = (SerialDatalink) obj;
+            return url.equals(sdl.url);
+        }
+        return false;
+    }
 
     /**
-         * The identifier that assists in the serialization of this <code>SerialDatalink</code>
-     * object.
+     * Returns a hash code for this {@code SerialDatalink}. The hash code for a
+     * {@code SerialDatalink} object is taken as the hash code of
+     * the {@code URL} it stores
+     *
+     * @return  a hash code value for this object.
+     */
+    public int hashCode() {
+        return 31 + url.hashCode();
+    }
+
+    /**
+     * Returns a clone of this {@code SerialDatalink}.
+     *
+     * @return  a clone of this SerialDatalink
+     */
+    public Object clone() {
+        try {
+            SerialDatalink sdl = (SerialDatalink) super.clone();
+            return sdl;
+        } catch (CloneNotSupportedException ex) {
+            // this shouldn't happen, since we are Cloneable
+            throw new InternalError();
+        }
+    }
+
+    /**
+     * readObject and writeObject are called to restore the state
+     * of the {@code SerialDatalink}
+     * from a stream. Note: we leverage the default Serialized form
+     */
+
+    /**
+     * The identifier that assists in the serialization of this
+     *  {@code SerialDatalink} object.
      */
     static final long serialVersionUID = 2826907821828733626L;
 }
--- a/jdk/src/share/classes/javax/sql/rowset/serial/SerialJavaObject.java	Mon Nov 05 12:51:14 2012 -0500
+++ b/jdk/src/share/classes/javax/sql/rowset/serial/SerialJavaObject.java	Tue Nov 06 14:59:22 2012 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,8 @@
 
 import java.io.*;
 import java.lang.reflect.*;
+import java.util.Arrays;
+import java.util.Vector;
 import javax.sql.rowset.RowSetWarning;
 
 /**
@@ -49,7 +51,7 @@
     /**
      * Placeholder for object to be serialized.
      */
-    private final Object obj;
+    private Object obj;
 
 
    /**
@@ -82,18 +84,9 @@
         // any of these are static, this should invalidate
         // the action of attempting to persist these fields
         // in a serialized form
-
-        boolean anyStaticFields = false;
         fields = c.getFields();
 
-        for (int i = 0; i < fields.length; i++ ) {
-            if ( fields[i].getModifiers() == Modifier.STATIC ) {
-                anyStaticFields = true;
-            }
-        }
-
-
-        if (anyStaticFields) {
+        if (hasStaticFields(fields)) {
             throw new SerialException("Located static fields in " +
                 "object instance. Cannot serialize");
         }
@@ -132,7 +125,7 @@
     }
 
     /**
-         * The identifier that assists in the serialization of this
+     * The identifier that assists in the serialization of this
      * <code>SerialJavaObject</code> object.
      */
     static final long serialVersionUID = -1465795139032831023L;
@@ -142,15 +135,117 @@
      * object. When there are multiple warnings, each warning is chained to the
      * previous warning.
      */
-    java.util.Vector<RowSetWarning> chain;
+    Vector<RowSetWarning> chain;
+
+    /**
+     * Compares this SerialJavaObject to the specified object.
+     * The result is {@code true} if and only if the argument
+     * is not {@code null} and is a {@code SerialJavaObject}
+     * object that is identical to this object
+     *
+     * @param  o The object to compare this {@code SerialJavaObject} against
+     *
+     * @return  {@code true} if the given object represents a {@code SerialJavaObject}
+     *          equivalent to this SerialJavaObject, {@code false} otherwise
+     *
+     */
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o instanceof SerialJavaObject) {
+            SerialJavaObject sjo = (SerialJavaObject) o;
+            return obj.equals(sjo.obj);
+        }
+        return false;
+    }
+
+    /**
+     * Returns a hash code for this SerialJavaObject. The hash code for a
+     * {@code SerialJavaObject} object is taken as the hash code of
+     * the {@code Object} it stores
+     *
+     * @return  a hash code value for this object.
+     */
+    public int hashCode() {
+        return 31 + obj.hashCode();
+    }
+
+    /**
+     * Returns a clone of this {@code SerialJavaObject}.
+     *
+     * @return  a clone of this SerialJavaObject
+     */
+
+    public Object clone() {
+        try {
+            SerialJavaObject sjo = (SerialJavaObject) super.clone();
+            sjo.fields = Arrays.copyOf(fields, fields.length);
+            if (chain != null)
+                sjo.chain = new Vector<>(chain);
+            return sjo;
+        } catch (CloneNotSupportedException ex) {
+            // this shouldn't happen, since we are Cloneable
+            throw new InternalError();
+        }
+    }
 
     /**
      * Registers the given warning.
      */
     private void setWarning(RowSetWarning e) {
         if (chain == null) {
-            chain = new java.util.Vector<>();
+            chain = new Vector<>();
         }
         chain.add(e);
     }
+
+    /**
+     * readObject is called to restore the state of the {@code SerialJavaObject}
+     * from a stream.
+     */
+    private void readObject(ObjectInputStream s)
+            throws IOException, ClassNotFoundException {
+
+        ObjectInputStream.GetField fields1 = s.readFields();
+        @SuppressWarnings("unchecked")
+        Vector<RowSetWarning> tmp = (Vector<RowSetWarning>)fields1.get("chain", null);
+        if (tmp != null)
+            chain = new Vector<>(tmp);
+
+        obj = fields1.get("obj", null);
+        if (obj != null) {
+            fields = obj.getClass().getFields();
+            if(hasStaticFields(fields))
+                throw new IOException("Located static fields in " +
+                "object instance. Cannot serialize");
+        } else {
+            throw new IOException("Object cannot be null!");
+        }
+
+    }
+
+    /**
+     * writeObject is called to save the state of the {@code SerialJavaObject}
+     * to a stream.
+     */
+    private void writeObject(ObjectOutputStream s)
+            throws IOException {
+        ObjectOutputStream.PutField fields = s.putFields();
+        fields.put("obj", obj);
+        fields.put("chain", chain);
+        s.writeFields();
+    }
+
+    /*
+     * Check to see if there are any Static Fields in this object
+     */
+    private static boolean hasStaticFields(Field[] fields) {
+        for (Field field : fields) {
+            if ( field.getModifiers() == Modifier.STATIC) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
--- a/jdk/src/share/classes/javax/sql/rowset/serial/SerialRef.java	Mon Nov 05 12:51:14 2012 -0500
+++ b/jdk/src/share/classes/javax/sql/rowset/serial/SerialRef.java	Tue Nov 06 14:59:22 2012 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -163,7 +163,85 @@
     }
 
     /**
-         * The identifier that assists in the serialization of this <code>SerialRef</code>
+     * Compares this SerialRef to the specified object.  The result is {@code
+     * true} if and only if the argument is not {@code null} and is a {@code
+     * SerialRef} object that represents the same object as this
+     * object.
+     *
+     * @param  obj The object to compare this {@code SerialRef} against
+     *
+     * @return  {@code true} if the given object represents a {@code SerialRef}
+     *          equivalent to this SerialRef, {@code false} otherwise
+     *
+     */
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if(obj instanceof SerialRef) {
+            SerialRef ref = (SerialRef)obj;
+            return baseTypeName.equals(ref.baseTypeName) &&
+                    object.equals(ref.object);
+        }
+        return false;
+    }
+
+    /**
+     * Returns a hash code for this {@code SerialRef}.
+     * @return  a hash code value for this object.
+     */
+    public int hashCode() {
+        return (31 + object.hashCode()) * 31 + baseTypeName.hashCode();
+    }
+
+    /**
+     * Returns a clone of this {@code SerialRef}. .
+     * The underlying {@code Ref} object will be set to null.
+     *
+     * @return  a clone of this SerialRef
+     */
+    public Object clone() {
+        try {
+            SerialRef ref = (SerialRef) super.clone();
+            ref.reference = null;
+            return ref;
+        } catch (CloneNotSupportedException ex) {
+            // this shouldn't happen, since we are Cloneable
+            throw new InternalError();
+        }
+
+    }
+
+    /**
+     * readObject is called to restore the state of the SerialRef from
+     * a stream.
+     */
+    private void readObject(ObjectInputStream s)
+            throws IOException, ClassNotFoundException {
+        ObjectInputStream.GetField fields = s.readFields();
+        object = fields.get("object", null);
+        baseTypeName = (String) fields.get("baseTypeName", null);
+        reference = (Ref) fields.get("reference", null);
+    }
+
+    /**
+     * writeObject is called to save the state of the SerialRef
+     * to a stream.
+     */
+    private void writeObject(ObjectOutputStream s)
+            throws IOException, ClassNotFoundException {
+
+        ObjectOutputStream.PutField fields = s.putFields();
+        fields.put("baseTypeName", baseTypeName);
+        fields.put("object", object);
+        // Note: this check to see if it is an instance of Serializable
+        // is for backwards compatibiity
+        fields.put("reference", reference instanceof Serializable ? reference : null);
+        s.writeFields();
+    }
+
+    /**
+     * The identifier that assists in the serialization of this <code>SerialRef</code>
      * object.
      */
     static final long serialVersionUID = -4727123500609662274L;
--- a/jdk/src/share/classes/javax/sql/rowset/serial/SerialStruct.java	Mon Nov 05 12:51:14 2012 -0500
+++ b/jdk/src/share/classes/javax/sql/rowset/serial/SerialStruct.java	Tue Nov 06 14:59:22 2012 -0500
@@ -250,6 +250,88 @@
     }
 
     /**
+     * Compares this SerialStruct to the specified object.  The result is
+     * {@code true} if and only if the argument is not {@code null} and is a
+     * {@code SerialStruct} object whose attributes are identical to this
+     * object's attributes
+     *
+     * @param  obj The object to compare this {@code SerialStruct} against
+     *
+     * @return {@code true} if the given object represents a {@code SerialStruct}
+     *          equivalent to this SerialStruct, {@code false} otherwise
+     *
+     */
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof SerialStruct) {
+            SerialStruct ss = (SerialStruct)obj;
+            return SQLTypeName.equals(ss.SQLTypeName) &&
+                    Arrays.equals(attribs, ss.attribs);
+        }
+        return false;
+    }
+
+    /**
+     * Returns a hash code for this {@code SerialStruct}. The hash code for a
+     * {@code SerialStruct} object is computed using the hash codes
+     * of the attributes of the {@code SerialStruct} object and its
+     * {@code SQLTypeName}
+     *
+     * @return  a hash code value for this object.
+     */
+    public int hashCode() {
+        return ((31 + Arrays.hashCode(attribs)) * 31) * 31
+                + SQLTypeName.hashCode();
+    }
+
+    /**
+     * Returns a clone of this {@code SerialStruct}. The copy will contain a
+     * reference to a clone of the underlying attribs array, not a reference
+     * to the original underlying attribs array of this {@code SerialStruct} object.
+     *
+     * @return  a clone of this SerialStruct
+     */
+    public Object clone() {
+        try {
+            SerialStruct ss = (SerialStruct) super.clone();
+            ss.attribs = Arrays.copyOf(attribs, attribs.length);
+            return ss;
+        } catch (CloneNotSupportedException ex) {
+            // this shouldn't happen, since we are Cloneable
+            throw new InternalError();
+        }
+
+    }
+
+    /**
+     * readObject is called to restore the state of the {@code SerialStruct} from
+     * a stream.
+     */
+    private void readObject(ObjectInputStream s)
+            throws IOException, ClassNotFoundException {
+
+       ObjectInputStream.GetField fields = s.readFields();
+       Object[] tmp = (Object[])fields.get("attribs", null);
+       attribs = tmp == null ? null : tmp.clone();
+       SQLTypeName = (String)fields.get("SQLTypeName", null);
+    }
+
+    /**
+     * writeObject is called to save the state of the {@code SerialStruct}
+     * to a stream.
+     */
+    private void writeObject(ObjectOutputStream s)
+            throws IOException, ClassNotFoundException {
+
+        ObjectOutputStream.PutField fields = s.putFields();
+        fields.put("attribs", attribs);
+        fields.put("SQLTypeName", SQLTypeName);
+        s.writeFields();
+    }
+
+    /**
      * The identifier that assists in the serialization of this
      * <code>SerialStruct</code> object.
      */