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 }
|