title: EnumSet serialization
body: <p>I've just lost a couple of hours debugging my app, and I believe I've stumbled upon a (another one o_O) Java bug... sniff... I hope it is not, because this would be sad :(</p>
  
  <p>I'm doing the following: </p>
  
  <ol>
  <li>Creating an EnumSet <code>mask</code> with some flags</li>
  <li>Serializing it (with <code>ObjectOutputStream.writeObject(mask)</code>)</li>
  <li>Clearing and setting some other flags in the <code>mask</code></li>
  <li>Serializing it again</li>
  </ol>
  
  <p><strong>Expected result:</strong> the second serialized object is different from the first one (reflects the changes in the instance)</p>
  
  <p><strong>Obtained result:</strong> the second serialized object is the exact copy of the first one</p>
  
  <p>The code:</p>
  
  <pre><code>enum MyEnum {
      ONE, TWO
  }
  
  @Test
  public void testEnumSetSerialize() throws Exception {           
      ByteArrayOutputStream bos = new ByteArrayOutputStream();
      ObjectOutputStream stream = new ObjectOutputStream(bos);
  
      EnumSet&lt;MyEnum&gt; mask = EnumSet.noneOf(MyEnum.class);
      mask.add(MyEnum.ONE);
      mask.add(MyEnum.TWO);
      System.out.println("First serialization: " + mask);
      stream.writeObject(mask);
  
      mask.clear();
      System.out.println("Second serialization: " + mask);
      stream.writeObject(mask);
      stream.close();
  
      ObjectInputStream istream = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
  
      System.out.println("First deserialized " + istream.readObject());
      System.out.println("Second deserialized " + istream.readObject());
  }
  </code></pre>
  
  <p>It prints:</p>
  
  <blockquote>
  <pre><code>First serialization: [ONE, TWO]
  Second serialization: []
  First deserialized [ONE, TWO]
  Second deserialized [ONE, TWO]  &lt;&lt;&lt;&lt;&lt;&lt; Expecting [] here!!!!
  </code></pre>
  </blockquote>
  
  <p>Am I using <code>EnumSet</code> incorrectly? Do I have to create a new instance each time instead of clearing it?</p>
  
  <p>Thanks for your input!</p>
  
  <p>**** UPDATE **** </p>
  
  <p>My initial idea was to use an <code>EnumSet</code> as a mask to indicate which fields will be present or absent in the message that follows, so a sort of bandwidth and cpu usage optimization. It was very wrong!!! An <code>EnumSet</code> takes ages to serialize, and each instance takes 30 (!!!) bytes! So much for the space economy :) </p>
  
  <p>In a nutshell, while <code>ObjectOutputStream</code> is very fast for primitive types (as I figured out already in a small test here: <a href="https://stackoverflow.com/a/33753694">https://stackoverflow.com/a/33753694</a>), it is painfully slooooow and inefficient with (especially small) objects...</p>
  
  <p>So I worked around it by making my own EnumSet backed by an int, and serializing/deserializing the int directly (not the object).</p>
  
  <pre><code>static class MyEnumSet&lt;T extends Enum&lt;T&gt;&gt; {
      private int mask = 0;
  
      @Override
      public boolean equals(Object o) {
          if (o == null || getClass() != o.getClass()) return false;
          return mask == ((MyEnumSet&lt;?&gt;) o).mask;
      }
  
      @Override
      public int hashCode() {
          return mask;
      }
  
      private MyEnumSet(int mask) {
          this.mask = mask;
      }
  
      public static &lt;T extends Enum&lt;T&gt;&gt; MyEnumSet&lt;T&gt; noneOf(Class&lt;T&gt; clz) {
          return new MyEnumSet&lt;T&gt;(0);
      }
  
      public static &lt;T extends Enum&lt;T&gt;&gt; MyEnumSet&lt;T&gt; fromMask(Class&lt;T&gt; clz, int mask) {
          return new MyEnumSet&lt;T&gt;(mask);
      }
  
      public int mask() {
          return mask;
      }
  
      public MyEnumSet&lt;T&gt; add(T flag) {
          mask = mask | (1 &lt;&lt; flag.ordinal());
          return this;
      }
  
      public void clear() {
          mask = 0;
      }
  }
  
  private final int N = 1000000;
  
  @Test
  public void testSerializeMyEnumSet() throws Exception {
  
      ByteArrayOutputStream bos = new ByteArrayOutputStream(N * 100);
      ObjectOutputStream out = new ObjectOutputStream(bos);
  
      List&lt;MyEnumSet&lt;TestEnum&gt;&gt; masks = Lists.newArrayList();
  
      Random r = new Random(132477584521L);
      for (int i = 0; i &lt; N; i++) {
          MyEnumSet&lt;TestEnum&gt; mask = MyEnumSet.noneOf(TestEnum.class);
          for (TestEnum f : TestEnum.values()) {
              if (r.nextBoolean()) {
                  mask.add(f);
              }
          }
          masks.add(mask);
      }
  
      logger.info("Serializing " + N + " myEnumSets");
      long tic = TicToc.tic();
      for (MyEnumSet&lt;TestEnum&gt; mask : masks) {
          out.writeInt(mask.mask());
      }
      TicToc.toc(tic);
      out.close();
      logger.info("Size: " + bos.size() + " (" + (bos.size() / N) + "b per object)");
  
      logger.info("Deserializing " + N + " myEnumSets");
      MyEnumSet&lt;TestEnum&gt;[] deserialized = new MyEnumSet[masks.size()];
  
      ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
      tic = TicToc.tic();
      for (int i = 0; i &lt; deserialized.length; i++) {
          deserialized[i] = MyEnumSet.fromMask(TestEnum.class, in.readInt());
      }
      TicToc.toc(tic);
  
      Assert.assertArrayEquals(masks.toArray(), deserialized);
  
  }
  </code></pre>
  
  <p>It's about 130x times faster during serialization and 25x times faster during deserialization...</p>
  
  <p>MyEnumSets:</p>
  
  <blockquote>
  <pre><code>17/12/15 11:59:31 INFO - Serializing 1000000 myEnumSets
  17/12/15 11:59:31 INFO - Elapsed time is 0.019 s
  17/12/15 11:59:31 INFO - Size: 4019539 (4b per object)
  17/12/15 11:59:31 INFO - Deserializing 1000000 myEnumSets
  17/12/15 11:59:31 INFO - Elapsed time is 0.021 s
  </code></pre>
  </blockquote>
  
  <p>Regular EnumSets:</p>
  
  <blockquote>
  <pre><code>17/12/15 11:59:48 INFO - Serializing 1000000 enumSets
  17/12/15 11:59:51 INFO - Elapsed time is 2.506 s
  17/12/15 11:59:51 INFO - Size: 30691553 (30b per object)
  17/12/15 11:59:51 INFO - Deserializing 1000000 enumSets
  17/12/15 11:59:51 INFO - Elapsed time is 0.489 s
  </code></pre>
  </blockquote>
  
  <p>It's not as safe though. For example, it will not work for enums with more than 32 entries. </p>
  
  <p>How can I ensure that the enum has less than 32 values on MyEnumSet creation?</p>