Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8323708

Adjust Classfile API's type arg model to better represent the embodied type

    XMLWordPrintable

Details

    • source, binary, behavioral
    • low
    • Class-File API is in preview and is allowed to have source and binary incompatible changes; users should be already aware of the incompatibility risks.
    • Java API
    • SE

    Description

      Summary

      Remodel the type arguments in Class-File API to make it an algebraic data type, so users can access the bound type more easily and reliably.

      Problem

      Currently, when the wildcard indicator in TypeArg is not UNBOUNDED, users can safely trust the bound, wrapped in optional, is non-null; but users still have to use a "risky" unwrap code.

      Solution

      Remodel the TypeArg to have Bounded and Unbounded subinterfaces; the wildcard indicator and bound will only be present in the Bounded subinterface. This model also more closely aligns with the model from JLS: https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-4.html#jvms-4.7.9.1-300-B.4

      Specification

      --- a/src/java.base/share/classes/java/lang/classfile/Signature.java
      +++ b/src/java.base/share/classes/java/lang/classfile/Signature.java
      @@ -185,80 +185,92 @@ public static ClassTypeSig of(ClassTypeSig outerType, String className, TypeArg.
           /**
            * Models the type argument.
            *
      +     * @sealedGraph
            * @since 22
            */
           @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API)
      -    public sealed interface TypeArg
      -            permits SignaturesImpl.TypeArgImpl {
      +    public sealed interface TypeArg {
      
               /**
      -         * Indicator for whether a wildcard has default bound, no bound,
      -         * an upper bound, or a lower bound
      -         *
      -         * @since 22
      +         * Models an unbounded type argument {@code *}.
      +         * @since 23
                */
               @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API)
      -        public enum WildcardIndicator {
      -
      -            /**
      -             * default bound wildcard (empty)
      -             */
      -            DEFAULT,
      -
      -            /**
      -             * unbounded indicator {@code *}
      -             */
      -            UNBOUNDED,
      +        public sealed interface Unbounded extends TypeArg permits SignaturesImpl.UnboundedTypeArgImpl {
      +        }
      
      -            /**
      -             * upper-bounded indicator {@code +}
      -             */
      -            EXTENDS,
      +        /**
      +         * Models a type argument with an explicit bound type.
      +         * @since 23
      +         */
      +        @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API)
      +        public sealed interface Bounded extends TypeArg permits SignaturesImpl.TypeArgImpl {
      
                   /**
      -             * lower-bounded indicator {@code -}
      +             * Models a type argument's wildcard indicator.
      +             * @since 23
                    */
      -            SUPER;
      +            @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API)
      +            public enum WildcardIndicator {
      +
      +                /**
      +                 * No wildcard (empty), an exact type. Also known as
      +                 * {@index invariant}.
      +                 */
      +                NONE,
      +
      +                /**
      +                 * Upper-bound indicator {@code +}. Also known as
      +                 * {@index covariant}.
      +                 */
      +                EXTENDS,
      +
      +                /**
      +                 * Lower-bound indicator {@code -}. Also known as
      +                 * {@index contravariant}.
      +                 */
      +                SUPER;
      +            }
      +
      +            /** {@return the kind of wildcard} */
      +            WildcardIndicator wildcardIndicator();
      +
      +            /** {@return the signature of the type bound} */
      +            RefTypeSig boundType();
               }
      
      -        /** {@return the wildcard indicator} */
      -        WildcardIndicator wildcardIndicator();
      -
      -        /** {@return the signature of the type bound, if any} */
      -        Optional<RefTypeSig> boundType();
      -
               /**
                * {@return a bounded type arg}
                * @param boundType the bound
                */
      -        public static TypeArg of(RefTypeSig boundType) {
      +        public static TypeArg.Bounded of(RefTypeSig boundType) {
                   requireNonNull(boundType);
      -            return of(WildcardIndicator.DEFAULT, Optional.of(boundType));
      +            return bounded(Bounded.WildcardIndicator.NONE, boundType);
               }
      
               /**
                * {@return an unbounded type arg}
                */
      -        public static TypeArg unbounded() {
      -            return of(WildcardIndicator.UNBOUNDED, Optional.empty());
      +        public static TypeArg.Unbounded unbounded() {
      +            return SignaturesImpl.UnboundedTypeArgImpl.INSTANCE;
               }
      
               /**
                * {@return an upper-bounded type arg}
                * @param boundType the upper bound
                */
      -        public static TypeArg extendsOf(RefTypeSig boundType) {
      +        public static TypeArg.Bounded extendsOf(RefTypeSig boundType) {
                   requireNonNull(boundType);
      -            return of(WildcardIndicator.EXTENDS, Optional.of(boundType));
      +            return bounded(Bounded.WildcardIndicator.EXTENDS, boundType);
               }
      
               /**
                * {@return a lower-bounded type arg}
                * @param boundType the lower bound
                */
      -        public static TypeArg superOf(RefTypeSig boundType) {
      +        public static TypeArg.Bounded superOf(RefTypeSig boundType) {
                   requireNonNull(boundType);
      -            return of(WildcardIndicator.SUPER, Optional.of(boundType));
      +            return bounded(Bounded.WildcardIndicator.SUPER, boundType);
               }
      
               /**
      @@ -266,7 +278,9 @@ public static TypeArg superOf(RefTypeSig boundType) {
                * @param wildcard the wild card
                * @param boundType optional bound type
                */
      -        public static TypeArg of(WildcardIndicator wildcard, Optional<RefTypeSig> boundType) {
      +        public static TypeArg.Bounded bounded(Bounded.WildcardIndicator wildcard, RefTypeSig boundType) {
      +            requireNonNull(wildcard);
      +            requireNonNull(boundType);
                   return new SignaturesImpl.TypeArgImpl(wildcard, boundType);
               }
           }

      Attachments

        Issue Links

          Activity

            People

              liach Chen Liang
              liach Chen Liang
              Adam Sotona
              Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: