< prev index next >

src/java.base/share/classes/java/util/ImmutableCollections.java

Print this page
rev 14420 : 8133977: add specification for serialized forms
Reviewed-by: chegar, plevart, scolebourne


  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.util;
  27 
  28 import java.io.IOException;
  29 import java.io.InvalidObjectException;
  30 import java.io.ObjectInputStream;

  31 import java.io.ObjectStreamException;
  32 import java.io.Serializable;
  33 
  34 /**
  35  * Container class for immutable collections. Not part of the public API.
  36  * Mainly for namespace management and shared infrastructure.
  37  *
  38  * Serial warnings are suppressed throughout because all implementation
  39  * classes use a serial proxy and thus have no need to declare serialVersionUID.
  40  */
  41 @SuppressWarnings("serial")
  42 class ImmutableCollections {
  43     /**
  44      * A "salt" value used for randomizing iteration order. This is initialized once
  45      * and stays constant for the lifetime of the JVM. It need not be truly random, but
  46      * it needs to vary sufficiently from one run to the next so that iteration order
  47      * will vary between JVM runs.
  48      */
  49     static final int SALT;
  50     static {


 590         }
 591 
 592         private Object writeReplace() {
 593             Object[] array = new Object[2 * size];
 594             int len = table.length;
 595             int dest = 0;
 596             for (int i = 0; i < len; i += 2) {
 597                 if (table[i] != null) {
 598                     array[dest++] = table[i];
 599                     array[dest++] = table[i+1];
 600                 }
 601             }
 602             return new CollSer(CollSer.IMM_MAP, array);
 603         }
 604     }
 605 }
 606 
 607 // ---------- Serialization Proxy ----------
 608 
 609 /**
 610  * Serialization proxy class for immutable collections.



 611  */
 612 final class CollSer implements Serializable {
 613     private static final long serialVersionUID = 6309168927139932177L;
 614 
 615     static final int IMM_LIST = 1;
 616     static final int IMM_SET = 2;
 617     static final int IMM_MAP = 3;
 618 
 619     private final int flags;
 620     private final Object[] array;
































 621 
 622     CollSer(int f, Object... a) {
 623         flags = f;
 624         array = a;
 625     }
 626 




































































 627     private Object readResolve() throws ObjectStreamException {
 628         try {
 629             if (array == null) {
 630                 throw new InvalidObjectException("null array");
 631             }
 632 
 633             // use low order 8 bits to indicate "kind"
 634             // ignore high order bits
 635             switch (flags & 0xff) {
 636                 case IMM_LIST:
 637                     return List.of(array);
 638                 case IMM_SET:
 639                     return Set.of(array);
 640                 case IMM_MAP:
 641                     if (array.length == 0) {
 642                         return new ImmutableCollections.Map0<>();
 643                     } else if (array.length == 2) {
 644                         return new ImmutableCollections.Map1<>(array[0], array[1]);
 645                     } else {
 646                         return new ImmutableCollections.MapN<>(array);
 647                     }
 648                 default:
 649                     throw new InvalidObjectException(String.format("invalid flags 0x%x", flags));
 650             }
 651         } catch (NullPointerException|IllegalArgumentException ex) {
 652             InvalidObjectException ioe = new InvalidObjectException("invalid object");
 653             ioe.initCause(ex);
 654             throw ioe;
 655         }
 656     }
 657 }


  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.util;
  27 
  28 import java.io.IOException;
  29 import java.io.InvalidObjectException;
  30 import java.io.ObjectInputStream;
  31 import java.io.ObjectOutputStream;
  32 import java.io.ObjectStreamException;
  33 import java.io.Serializable;
  34 
  35 /**
  36  * Container class for immutable collections. Not part of the public API.
  37  * Mainly for namespace management and shared infrastructure.
  38  *
  39  * Serial warnings are suppressed throughout because all implementation
  40  * classes use a serial proxy and thus have no need to declare serialVersionUID.
  41  */
  42 @SuppressWarnings("serial")
  43 class ImmutableCollections {
  44     /**
  45      * A "salt" value used for randomizing iteration order. This is initialized once
  46      * and stays constant for the lifetime of the JVM. It need not be truly random, but
  47      * it needs to vary sufficiently from one run to the next so that iteration order
  48      * will vary between JVM runs.
  49      */
  50     static final int SALT;
  51     static {


 591         }
 592 
 593         private Object writeReplace() {
 594             Object[] array = new Object[2 * size];
 595             int len = table.length;
 596             int dest = 0;
 597             for (int i = 0; i < len; i += 2) {
 598                 if (table[i] != null) {
 599                     array[dest++] = table[i];
 600                     array[dest++] = table[i+1];
 601                 }
 602             }
 603             return new CollSer(CollSer.IMM_MAP, array);
 604         }
 605     }
 606 }
 607 
 608 // ---------- Serialization Proxy ----------
 609 
 610 /**
 611  * A unified serialization proxy class for the immutable collections.
 612  *
 613  * @serial
 614  * @since 9
 615  */
 616 final class CollSer implements Serializable {
 617     private static final long serialVersionUID = 6309168927139932177L;
 618 
 619     static final int IMM_LIST = 1;
 620     static final int IMM_SET = 2;
 621     static final int IMM_MAP = 3;
 622 
 623     /**
 624      * Indicates the type of collection that is serialized.
 625      * The low order 8 bits have the value 1 for an immutable
 626      * {@code List}, 2 for an immutable {@code Set}, and 3 for
 627      * an immutable {@code Map}. Any other value causes an
 628      * {@link InvalidObjectException} to be thrown. The high
 629      * order 24 bits are zero when an instance is serialized,
 630      * and they are ignored when an instance is deserialized.
 631      * They can thus be used by future implementations without
 632      * causing compatibility issues.
 633      *
 634      * <p>The tag value also determines the interpretation of the
 635      * transient {@code Object[] array} field.
 636      * For {@code List} and {@code Set}, the array's length is the size
 637      * of the collection, and the array contains the elements of the collection.
 638      * Null elements are not allowed. For {@code Set}, duplicate elements
 639      * are not allowed.
 640      *
 641      * <p>For {@code Map}, the array's length is twice the number of mappings
 642      * present in the map. The array length is necessarily even.
 643      * The array contains a succession of key and value pairs:
 644      * {@code k1, v1, k2, v2, ..., kN, vN.} Nulls are not allowed,
 645      * and duplicate keys are not allowed.
 646      *
 647      * @serial
 648      * @since 9
 649      */
 650     private final int tag;
 651 
 652     /**
 653      * @serial
 654      * @since 9
 655      */
 656     private transient Object[] array;
 657 
 658     CollSer(int t, Object... a) {
 659         tag = t;
 660         array = a;
 661     }
 662 
 663     /**
 664      * Reads objects from the stream and stores them
 665      * in the transient {@code Object[] array} field.
 666      *
 667      * @serialData
 668      * A nonnegative int, indicating the count of objects,
 669      * followed by that many objects.
 670      *
 671      * @param ois the ObjectInputStream from which data is read
 672      * @throws IOException if an I/O error occurs
 673      * @throws ClassNotFoundException if a serialized class cannot be loaded
 674      * @throws InvalidObjectException if the count is negative
 675      * @since 9
 676      */
 677     private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
 678         ois.defaultReadObject();
 679         int len = ois.readInt();
 680 
 681         if (len < 0) {
 682             throw new InvalidObjectException("negative length " + len);
 683         }
 684 
 685         Object[] a = new Object[len];
 686         for (int i = 0; i < len; i++) {
 687             a[i] = ois.readObject();
 688         }
 689 
 690         array = a;
 691     }
 692 
 693     /**
 694      * Writes objects to the stream from
 695      * the transient {@code Object[] array} field.
 696      *
 697      * @serialData
 698      * A nonnegative int, indicating the count of objects,
 699      * followed by that many objects.
 700      *
 701      * @param oos the ObjectOutputStream to which data is written
 702      * @throws IOException if an I/O error occurs
 703      * @since 9
 704      */
 705     private void writeObject(ObjectOutputStream oos) throws IOException {
 706         oos.defaultWriteObject();
 707         oos.writeInt(array.length);
 708         for (int i = 0; i < array.length; i++) {
 709             oos.writeObject(array[i]);
 710         }
 711     }
 712 
 713     /**
 714      * Creates and returns an immutable collection from this proxy class.
 715      * The instance returned is created as if by calling one of the
 716      * static factory methods for
 717      * <a href="List.html#immutable">List</a>,
 718      * <a href="Map.html#immutable">Map</a>, or
 719      * <a href="Set.html#immutable">Set</a>.
 720      * This proxy class is the serial form for all immutable collection instances,
 721      * regardless of implementation type. This is necessary to ensure that the
 722      * existence of any particular implementation type is kept out of the
 723      * serialized form.
 724      *
 725      * @return a collection created from this proxy object
 726      * @throws InvalidObjectException if the tag value is illegal or if an exception
 727      *         is thrown during creation of the collection
 728      * @throws ObjectStreamException if another serialization error has occurred
 729      * @since 9
 730      */
 731     private Object readResolve() throws ObjectStreamException {
 732         try {
 733             if (array == null) {
 734                 throw new InvalidObjectException("null array");
 735             }
 736 
 737             // use low order 8 bits to indicate "kind"
 738             // ignore high order 24 bits
 739             switch (tag & 0xff) {
 740                 case IMM_LIST:
 741                     return List.of(array);
 742                 case IMM_SET:
 743                     return Set.of(array);
 744                 case IMM_MAP:
 745                     if (array.length == 0) {
 746                         return new ImmutableCollections.Map0<>();
 747                     } else if (array.length == 2) {
 748                         return new ImmutableCollections.Map1<>(array[0], array[1]);
 749                     } else {
 750                         return new ImmutableCollections.MapN<>(array);
 751                     }
 752                 default:
 753                     throw new InvalidObjectException(String.format("invalid flags 0x%x", tag));
 754             }
 755         } catch (NullPointerException|IllegalArgumentException ex) {
 756             InvalidObjectException ioe = new InvalidObjectException("invalid object");
 757             ioe.initCause(ex);
 758             throw ioe;
 759         }
 760     }
 761 }
< prev index next >