RFR (XS): 8148044: Remove Enum[0] constants from EnumSet and EnumMap

Stuart Marks stuart.marks at oracle.com
Fri Jan 22 18:43:54 UTC 2016

On 1/22/16 7:44 AM, Claes Redestad wrote:
>>> It would seem the assessment that serialVersionUID is not needed when
>>> using the serial proxy pattern might be misguided (or is this a bug in
>>> ObjectInputStream)?
>> It is debate-able whether this is a test bug or not. But I think
>> we should not change the serialVersionUID for this class, whether
>> truly Serializable or not. Even though in practice it is not all
>> that useful.
>> Can you please revert the serialization parts of the change, and
>> rerun the test? To see if still passes or fails.
> I backed out the serial version UID change and reran the test, same thing.
> I dug deeper, as this is a bit vexxing...
> While a static field does not in and of itself cause the generated UID to change,
> the private ZERO_LENGTH_ENUM_ARRAY is being accessed from SerializationProxy
> class, thus javac generates a package-private synthetic method (access$000) which
> will be accounted for when generating serialVersionUID. That's unfortunate.
> I ran a few experiments to confirm this:
> - Adding a package-private static method to EnumSet makes the test fail
> - Adding any static field and the test keep passing
> So it seems our options here are limited.

I think this is a bug in the test (BogusEnumSet.java).

EnumSet, a class in the runtime, should never appear in a serialized stream, 
thus it shouldn't have to declare a serialVersionUID in order to remain 
compatible with anything.

The test deliberately attempts to create a serialized stream that should never 
occur in actual use, so the test should be responsible for constructing that 
stream properly. Unfortunately, the test doesn't actually construct that stream; 
instead it's a bunch of hex constants.

It's tedious but not difficult to patch the constants with the modified value. 
I've appended a patch below that does this, along with removing EnumSet's 
serialVersionUID and restoring the @SuppressWarnings.

I can post a webrev if this doesn't come through properly.


diff -r c421a3928efc -r 6de800698cf7 
--- a/src/java.base/share/classes/java/util/EnumMap.java	Mon Jan 11 10:13:29 
2016 -0800
+++ b/src/java.base/share/classes/java/util/EnumMap.java	Fri Jan 22 10:42:24 
2016 -0800
@@ -25,7 +25,6 @@

  package java.util;

-import java.util.Map.Entry;
  import jdk.internal.misc.SharedSecrets;

@@ -125,8 +124,6 @@
          return (V)(value == NULL ? null : value);

-    private static final Enum<?>[] ZERO_LENGTH_ENUM_ARRAY = new Enum<?>[0];
       * Creates an empty enum map with the specified key type.
diff -r c421a3928efc -r 6de800698cf7 
--- a/src/java.base/share/classes/java/util/EnumSet.java	Mon Jan 11 10:13:29 
2016 -0800
+++ b/src/java.base/share/classes/java/util/EnumSet.java	Fri Jan 22 10:42:24 
2016 -0800
@@ -92,8 +92,6 @@
      final Enum<?>[] universe;

-    private static Enum<?>[] ZERO_LENGTH_ENUM_ARRAY = new Enum<?>[0];
      EnumSet(Class<E>elementType, Enum<?>[] universe) {
          this.elementType = elementType;
          this.universe    = universe;
@@ -421,6 +419,9 @@
      private static class SerializationProxy <E extends Enum<E>>
          implements java.io.Serializable
+        private static final Enum<?>[] ZERO_LENGTH_ENUM_ARRAY = new Enum<?>[0];
           * The element type of this enum set.
diff -r c421a3928efc -r 6de800698cf7 test/java/util/EnumMap/EnumMapBash.java
--- a/test/java/util/EnumMap/EnumMapBash.java	Mon Jan 11 10:13:29 2016 -0800
+++ b/test/java/util/EnumMap/EnumMapBash.java	Fri Jan 22 10:42:24 2016 -0800
@@ -48,8 +48,6 @@

-    private static Enum[] ZERO_LENGTH_ENUM_ARRAY = new Enum[0];
      static <T extends Enum<T>> void bash(Class<T> enumClass) {
          Enum[] universe = enumClass.getEnumConstants();

diff -r c421a3928efc -r 6de800698cf7 test/java/util/EnumSet/BogusEnumSet.java
--- a/test/java/util/EnumSet/BogusEnumSet.java	Mon Jan 11 10:13:29 2016 -0800
+++ b/test/java/util/EnumSet/BogusEnumSet.java	Fri Jan 22 10:42:24 2016 -0800
@@ -32,6 +32,11 @@

  public class BogusEnumSet {
      public static void main(String[] args) throws Throwable {
+        // This test depends on the current serialVersionUID of EnumSet,
+        // which may change if the EnumSet class is modified.
+        // The current value is 4168005130090799668L = 0x39D7BA9531116234L
+        // If the value changes, it will have to be patched into the
+        // serialized byte stream below at the location noted.
          byte[] serializedForm  = {
              (byte)0xac, (byte)0xed, 0x0, 0x5, 0x73, 0x72, 0x0, 0x18,
              0x6a,  0x61,  0x76,  0x61, 0x2e,  0x75,  0x74,  0x69,
@@ -40,9 +45,10 @@
              0x7e, (byte)0xb0, (byte)0xd0, 0x7e, 0x2, 0x0, 0x1, 0x4a, 0x0, 0x8,
              0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x78, 0x72, 0x0,
              0x11, 0x6a,  0x61,  0x76,  0x61, 0x2e,  0x75,  0x74,  0x69,
-            0x6c,  0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x53, 0x65, 0x74, 0xe,
-            0x3, 0x21, 0x6a, (byte)0xcd, (byte)0x8c, 0x29, (byte)0xdd, 0x2,
-            0x0, 0x2, 0x4c, 0x0, 0xb, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74,
+            0x6c,  0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x53, 0x65, 0x74,
+            // EnumSet's serialVersionUID is the following eight bytes (big-endian)
+            0x39, (byte)0xd7, (byte)0xba, (byte)0x95, 0x31, 0x11, 0x62, 0x34,
+            0x2, 0x0, 0x2, 0x4c, 0x0, 0xb, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 
              0x54, 0x79, 0x70, 0x65, 0x74, 0x0, 0x11, 0x4c, 0x6a, 0x61, 0x76,
              0x61, 0x2f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x43, 0x6c, 0x61, 0x73,
              0x73, 0x3b, 0x5b, 0x0, 0x8, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72,

More information about the core-libs-dev mailing list