Scala Programming Language
  1. Scala Programming Language
  2. SI-2214

Enumeration not "resolved" when de-serialised

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: Scala 2.8.0
    • Component/s: Enumeration
    • Labels:
      None
    • Environment:

      enumeration serialization serialize

      Description

      I'm not quite sure of the intended behaviour here. I've been trying to serialise an Enumeration (in 2.7 and 2.8), but it doesn't seem to work as I expected.

      Welcome to Scala version 2.8.0.r18405-b20090730020155 (Java HotSpot(TM) Client VM, Java 1.6.0_13).
      Type in expressions to have them evaluated.
      Type :help for more information.
      
      scala> def serialise[T](t: T): T = {
           |   val buf = new java.io.ByteArrayOutputStream
           |   val out = new java.io.ObjectOutputStream(buf)
           |   out.writeObject(t)
           |   out.close
           |   val is = new java.io.ByteArrayInputStream(buf.toByteArray)
           |   val in = new java.io.ObjectInputStream(is)
           |   in.readObject.asInstanceOf[T]
           | }
      serialise: [T](t: T)T
      
      scala> object MyEnum extends Enumeration {
           |   val ONE = Value("1")
           |   val TWO = Value("2")
           | }
      defined module MyEnum
      
      scala> val a = MyEnum.ONE
      a: MyEnum.Value = 1
      
      scala> val b = serialise(a)
      b: MyEnum.Value = 1
      
      scala> println(a == b)
      false
      
      scala> println(System.identityHashCode(a))
      1510253
      
      scala> println(System.identityHashCode(b))
      21353508
      
      scala> println(System.identityHashCode(MyEnum))
      15675004
      
      scala> println(System.identityHashCode(serialise(MyEnum)))
      8713829
      

      After poking around in the (2.7) source a little, it seems that Value is being "resolved", but the actual Enumeration "MyEnum" object isn't (and why values end up non-equal too). I have a work-around - inserting def readResolve(): AnyRef = MyEnum method in MyEnum fixes it.

      Should it be necessary that I provide my own readResolve method on each of my Enumeration objects? It's not really an issue, I just have quite a few in my object model, and I want to serialise the whole thing.

      I just thought this was slightly unexpected behaviour, especially if you are used to Enum serialisation in Java. It is also something easily forgotten, and then enum values just end up unequal when you would probably expect they should be.

        Issue Links

          Activity

          Hide
          Paul Phillips added a comment -

          Replying to [comment:10 harrah]:
          > While looking into SI-3616, I noticed that the fix for this bug (in r21235) maintains a strong reference to every user-defined Enumeration. This is quite bad because as long as there are strong references to Scala library classes, user classes will not be garbage collected.

          How do you think we should address this? Would it be enough to use weak references and recreate the enum values if they're collected? It's not entirely clear to me how everything fits together.

          Show
          Paul Phillips added a comment - Replying to [comment:10 harrah] : > While looking into SI-3616 , I noticed that the fix for this bug (in r21235) maintains a strong reference to every user-defined Enumeration. This is quite bad because as long as there are strong references to Scala library classes, user classes will not be garbage collected. How do you think we should address this? Would it be enough to use weak references and recreate the enum values if they're collected? It's not entirely clear to me how everything fits together.
          Hide
          Paul Phillips added a comment -

          Actually: can't I treat this like another Symbol interning cache? Look, I wrote it to be reused:

          /** This is private so it won't appear in the library API, but
            * abstracted to offer some hope of reusability.  */
          private[scala] abstract class UniquenessCache[K, V >: Null]
          

          IS THIS MY BIG CHANCE FOR REUSE?

          Show
          Paul Phillips added a comment - Actually: can't I treat this like another Symbol interning cache? Look, I wrote it to be reused: /** This is private so it won't appear in the library API, but * abstracted to offer some hope of reusability. */ private[scala] abstract class UniquenessCache[K, V >: Null] IS THIS MY BIG CHANCE FOR REUSE?
          Hide
          Mark Harrah added a comment -

          Weak references for keys and values should work:

          private val emap = new WeakHashMap[Class[_], Reference[Enumeration]]
          

          I'm not sure why the singleton isn't obtained with reflection, though:

          val enum = getClass.getField("MODULE$$").get(null)
          
          Show
          Mark Harrah added a comment - Weak references for keys and values should work: private val emap = new WeakHashMap[Class[_], Reference[Enumeration]] I'm not sure why the singleton isn't obtained with reflection, though: val enum = getClass.getField("MODULE$$").get(null)
          Hide
          Paul Phillips added a comment -

          (In r22463) Took a cue from mharrah that we don't need to build global static
          data to keep track of something when we know where it's kept.
          Altered the Enumeration deserialization scheme to use reflection, preserving
          the singleton property by delivering the MODULE$$ singleton. This solves
          the GC issue and lets us drop synchronization to boot. Also added
          some graceful failure for malformed Enumerations. All tests look good
          but a second opinion is in order: closes SI-2214, review by phaller.

          Show
          Paul Phillips added a comment - (In r22463) Took a cue from mharrah that we don't need to build global static data to keep track of something when we know where it's kept. Altered the Enumeration deserialization scheme to use reflection, preserving the singleton property by delivering the MODULE$$ singleton. This solves the GC issue and lets us drop synchronization to boot. Also added some graceful failure for malformed Enumerations. All tests look good but a second opinion is in order: closes SI-2214 , review by phaller.
          Hide
          Mark Harrah added a comment -

          Thanks. I appreciate the fast response.

          Show
          Mark Harrah added a comment - Thanks. I appreciate the fast response.

            People

            • Assignee:
              Paul Phillips
              Reporter:
              Kieron Wilkinson
              TracCC:
              Mark Harrah, Paul Phillips
            • Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development