Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8251554 JEP 401: Value Classes and Objects (Preview)
  3. JDK-8317279

Standard library implementation of value classes and objects

XMLWordPrintable

    • Icon: Sub-task Sub-task
    • Resolution: Unresolved
    • Icon: P4 P4
    • None
    • None
    • core-libs
    • None

      This task summarizes the standard library changes introduced by JEP 401.

      ### Object methods

      Most of the methods of java.lang.Object are fine as is, but their documentation may need to be updated.

      'equals', 'hashCode', and 'System.identityHashCode' rely on a revised definition of "the same object" and "distinct objects", where two value objects are "the same" if they belong to the same class and have the same field values. (The implementation is supported by java.lang.runtime.ValueObjectMethods.)

      'clone' is useful for value objects if they store an identity object in a field. If not, the result should generally be == to the original. In either case, the implementation of 'Object.clone' will either throw CNSE or simply return 'this'.

      'toString' works out of the box, but the printed hash code reflects the lack of identity (as noted above).

      'wait'/'notify'/etc. work out of the box; they always throw IMSE, because it's impossible (per language/VM rules) to 'synchronize' on a value object.

      'finalize': will never be called on value objects, but nothing prevents overriding it


      ### Core reflection

      New preview API methods in `java.util.Objects`: `hasIdentity` and `requireIdentity`. These test/assert whether an object is an identity object. Arrays and direct instances of the class `Object` are always considered identity objects. (We may consider a similar method as a member of class `Object`.)

      A new `IdentityException` class is declared to indicate that an operation fails because an object does not have identity.

      `java.lang.reflect.Modifier` and `java.lang.reflect.AccessFlag` add support for the `value`/`ACC_IDENTITY` and `ACC_STRICT` flags. This is also exposed via new `isValue` and `isIdentity` methods in `java.lang.Class`.

      (Arguably, `obj.getClass().isIdentity()` is a good enough way to express `hasIdentity(obj)`, and the latter is redundant. But identity is so meaningful for the object itself, nevermind its class, that a more direct query seems justified.)


      ### java.lang.invoke

      VarHandles and MethodHandles that access flattened storage must interpret it properly. This is supported through new Unsafe methods that interact with flattened storage.

      (There is no expectation that these APIs will support scalarized or null-restricted entry points. We leave those sorts of optimizations to inlining.)


      ### Serialization

      ObjectInputStream.readObject generally throws an InvalidClassException if the object being deserialized is an instance of a value class, whether concrete or abstract.

      There are four exceptions:
      - Value records are deserialized following the normal record deserialization process.
      - A non-Serializable abstract value class can act as a superclass if, as usual, it can be instantiated via a no-arg constructor call.
      - The primitive wrapper classes get special treatment and are deserialized via a constructor or 'valueOf' call.
      - The class Number gets special treatment—it has no fields and no constructor logic, so deserialization can simply skip it.

      ObjectOutputStream.writeObject should detect this problem and throw an InvalidClassException when writing an object that implements a value class and isn't one of the allowed special cases.

      (Users declaring non-record, Serializable value classes can work around this restriction by using the 'writeReplace' mechanism. In this release, there is no other support for migrating a Serializable identity class to be a value class.)


      ### java.lang.ref and WeakHashMap

      Instances of java.lang.ref.Reference throw an exception if created for a value object. Similarly, WeakHashMap rejects value objects as keys. (In a future release we may provide some mechanism for GC management of the identity objects referenced by a value object.)


      ### java.lang.classfile

      The class file changes, as described in JDK-8317278, should be supported by the java.lang.classfile API. Specifically:
      - Support modifiers `ACC_IDENTITY` and `ACC_STRICT` in the appropriate contexts
      - Recognize the `LoadableDescriptors` attribute


      ### Migrated value-based classes

      The following classes should be capable of being treated as value classes by adding a 'value' keyword:
      - java.lang.Number
      - java.lang.Record
      - All 8 primitive wrapper classes
      - All 4 java.util.Optional* classes
      - 12 java.time classes: Duration, Instant, LocalTime, Year, YearMonth, MonthDay, Period, LocalDate, LocalDateTime, OffsetTime, OffsetDateTime, ZonedDateTime
      - 5 java.time.chrono classes: ChronoLocalDateImpl, MinguoDate, HijrahDate, JapaneseDate, and ThaiBuddhistDate

      Specifically, their constructors should be compatible with strict fields, with an implicit 'super()' call being placed at the end of a constructor body.

      The 'month' and 'day' fields of YearMonth, MonthDay, LocalDate, HijrahDate, and JapaneseDate should be refactored to have type 'byte' instead of 'int'.

      In JDK builds, alternative sources of these classes are generated, inserting the 'value' modifier, and then recompiled and made available at run time whenever '--enable-preview' is set.

            rriggs Roger Riggs
            dlsmith Dan Smith
            Votes:
            1 Vote for this issue
            Watchers:
            6 Start watching this issue

              Created:
              Updated: