changeset 38567:6d4c5a278fff

8133977: add specification for serialized forms Reviewed-by: chegar, plevart, scolebourne
author smarks
date Wed, 25 May 2016 13:38:35 -0700
parents 6a1386b76fdd
children f992c34c85b3
files jdk/src/java.base/share/classes/java/util/ImmutableCollections.java jdk/src/java.base/share/classes/java/util/List.java jdk/src/java.base/share/classes/java/util/Map.java jdk/src/java.base/share/classes/java/util/Set.java
diffstat 4 files changed, 124 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/jdk/src/java.base/share/classes/java/util/ImmutableCollections.java	Wed May 25 20:26:43 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/util/ImmutableCollections.java	Wed May 25 13:38:35 2016 -0700
@@ -28,6 +28,7 @@
 import java.io.IOException;
 import java.io.InvalidObjectException;
 import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.io.ObjectStreamException;
 import java.io.Serializable;
 
@@ -607,7 +608,10 @@
 // ---------- Serialization Proxy ----------
 
 /**
- * Serialization proxy class for immutable collections.
+ * A unified serialization proxy class for the immutable collections.
+ *
+ * @serial
+ * @since 9
  */
 final class CollSer implements Serializable {
     private static final long serialVersionUID = 6309168927139932177L;
@@ -616,14 +620,114 @@
     static final int IMM_SET = 2;
     static final int IMM_MAP = 3;
 
-    private final int flags;
-    private final Object[] array;
+    /**
+     * Indicates the type of collection that is serialized.
+     * The low order 8 bits have the value 1 for an immutable
+     * {@code List}, 2 for an immutable {@code Set}, and 3 for
+     * an immutable {@code Map}. Any other value causes an
+     * {@link InvalidObjectException} to be thrown. The high
+     * order 24 bits are zero when an instance is serialized,
+     * and they are ignored when an instance is deserialized.
+     * They can thus be used by future implementations without
+     * causing compatibility issues.
+     *
+     * <p>The tag value also determines the interpretation of the
+     * transient {@code Object[] array} field.
+     * For {@code List} and {@code Set}, the array's length is the size
+     * of the collection, and the array contains the elements of the collection.
+     * Null elements are not allowed. For {@code Set}, duplicate elements
+     * are not allowed.
+     *
+     * <p>For {@code Map}, the array's length is twice the number of mappings
+     * present in the map. The array length is necessarily even.
+     * The array contains a succession of key and value pairs:
+     * {@code k1, v1, k2, v2, ..., kN, vN.} Nulls are not allowed,
+     * and duplicate keys are not allowed.
+     *
+     * @serial
+     * @since 9
+     */
+    private final int tag;
 
-    CollSer(int f, Object... a) {
-        flags = f;
+    /**
+     * @serial
+     * @since 9
+     */
+    private transient Object[] array;
+
+    CollSer(int t, Object... a) {
+        tag = t;
         array = a;
     }
 
+    /**
+     * Reads objects from the stream and stores them
+     * in the transient {@code Object[] array} field.
+     *
+     * @serialData
+     * A nonnegative int, indicating the count of objects,
+     * followed by that many objects.
+     *
+     * @param ois the ObjectInputStream from which data is read
+     * @throws IOException if an I/O error occurs
+     * @throws ClassNotFoundException if a serialized class cannot be loaded
+     * @throws InvalidObjectException if the count is negative
+     * @since 9
+     */
+    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+        ois.defaultReadObject();
+        int len = ois.readInt();
+
+        if (len < 0) {
+            throw new InvalidObjectException("negative length " + len);
+        }
+
+        Object[] a = new Object[len];
+        for (int i = 0; i < len; i++) {
+            a[i] = ois.readObject();
+        }
+
+        array = a;
+    }
+
+    /**
+     * Writes objects to the stream from
+     * the transient {@code Object[] array} field.
+     *
+     * @serialData
+     * A nonnegative int, indicating the count of objects,
+     * followed by that many objects.
+     *
+     * @param oos the ObjectOutputStream to which data is written
+     * @throws IOException if an I/O error occurs
+     * @since 9
+     */
+    private void writeObject(ObjectOutputStream oos) throws IOException {
+        oos.defaultWriteObject();
+        oos.writeInt(array.length);
+        for (int i = 0; i < array.length; i++) {
+            oos.writeObject(array[i]);
+        }
+    }
+
+    /**
+     * Creates and returns an immutable collection from this proxy class.
+     * The instance returned is created as if by calling one of the
+     * static factory methods for
+     * <a href="List.html#immutable">List</a>,
+     * <a href="Map.html#immutable">Map</a>, or
+     * <a href="Set.html#immutable">Set</a>.
+     * This proxy class is the serial form for all immutable collection instances,
+     * regardless of implementation type. This is necessary to ensure that the
+     * existence of any particular implementation type is kept out of the
+     * serialized form.
+     *
+     * @return a collection created from this proxy object
+     * @throws InvalidObjectException if the tag value is illegal or if an exception
+     *         is thrown during creation of the collection
+     * @throws ObjectStreamException if another serialization error has occurred
+     * @since 9
+     */
     private Object readResolve() throws ObjectStreamException {
         try {
             if (array == null) {
@@ -631,8 +735,8 @@
             }
 
             // use low order 8 bits to indicate "kind"
-            // ignore high order bits
-            switch (flags & 0xff) {
+            // ignore high order 24 bits
+            switch (tag & 0xff) {
                 case IMM_LIST:
                     return List.of(array);
                 case IMM_SET:
@@ -646,7 +750,7 @@
                         return new ImmutableCollections.MapN<>(array);
                     }
                 default:
-                    throw new InvalidObjectException(String.format("invalid flags 0x%x", flags));
+                    throw new InvalidObjectException(String.format("invalid flags 0x%x", tag));
             }
         } catch (NullPointerException|IllegalArgumentException ex) {
             InvalidObjectException ioe = new InvalidObjectException("invalid object");
--- a/jdk/src/java.base/share/classes/java/util/List.java	Wed May 25 20:26:43 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/util/List.java	Wed May 25 13:38:35 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -107,6 +107,9 @@
  * Factories are free to create new instances or reuse existing ones. Therefore,
  * identity-sensitive operations on these instances (reference equality ({@code ==}),
  * identity hash code, and synchronization) are unreliable and should be avoided.
+ * <li>They are serialized as specified on the
+ * <a href="{@docRoot}/serialized-form.html#java.util.CollSer">Serialized Form</a>
+ * page.
  * </ul>
  *
  * <p>This interface is a member of the
--- a/jdk/src/java.base/share/classes/java/util/Map.java	Wed May 25 20:26:43 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/util/Map.java	Wed May 25 13:38:35 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -133,6 +133,9 @@
  * Factories are free to create new instances or reuse existing ones. Therefore,
  * identity-sensitive operations on these instances (reference equality ({@code ==}),
  * identity hash code, and synchronization) are unreliable and should be avoided.
+ * <li>They are serialized as specified on the
+ * <a href="{@docRoot}/serialized-form.html#java.util.CollSer">Serialized Form</a>
+ * page.
  * </ul>
  *
  * <p>This interface is a member of the
--- a/jdk/src/java.base/share/classes/java/util/Set.java	Wed May 25 20:26:43 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/util/Set.java	Wed May 25 13:38:35 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -84,6 +84,9 @@
  * Factories are free to create new instances or reuse existing ones. Therefore,
  * identity-sensitive operations on these instances (reference equality ({@code ==}),
  * identity hash code, and synchronization) are unreliable and should be avoided.
+ * <li>They are serialized as specified on the
+ * <a href="{@docRoot}/serialized-form.html#java.util.CollSer">Serialized Form</a>
+ * page.
  * </ul>
  *
  * <p>This interface is a member of the