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

javac does not emit SYNTHETIC and MANDATED flags for parameters by default

XMLWordPrintable

    • b21
    • generic
    • generic

      A DESCRIPTION OF THE PROBLEM :
      Chapter 13.1 in the JLS mentions:
      11. A construct emitted by a Java compiler must be marked as synthetic if it does not correspond to a construct declared explicitly or implicitly in source code, unless the emitted construct is a class initialization method
      and
      12. A construct emitted by a Java compiler must be marked as mandated if it corresponds to a formal parameter declared implicitly in source code

      For parameters, this information is stored in the MethodParameters attribute. However, this attribute is only emitted when compiling with the -parameters flag or if the method is a canonical record constructor.

      This behavior can be observed by either looking at the produced class files using javap, or by using the Parameter#isImplicit()/isSynthetic() methods.

      Additional context: https://mail.openjdk.org/pipermail/compiler-dev/2022-May/019783.html and https://mail.openjdk.org/pipermail/compiler-dev/2022-June/019924.html

      I'm able to provide a fix for this.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Compile the code below with javac without -parameters flag.
      Run the code with java A.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      ----------
      Executable: A$Inner
      Parameter at position 0
      parameter.getType() = class A
      parameter.isImplicit() = true
      ----------
      ----------
      Executable: A$1
      Parameter at position 0
      parameter.getType() = class A
      parameter.isImplicit() = true
      ----------
      ----------
      Executable: valueOf
      Parameter at position 0
      parameter.getType() = class java.lang.String
      parameter.isImplicit() = true
      ----------
      ----------
      Executable: A$R
      Parameter at position 0
      parameter.getType() = int
      parameter.isImplicit() = true
      Parameter at position 1
      parameter.getType() = float
      parameter.isImplicit() = true
      ----------
      ----------
      Executable: A$E
      Parameter at position 0
      parameter.getType() = class java.lang.String
      parameter.isSynthetic() = true
      Parameter at position 1
      parameter.getType() = int
      parameter.isSynthetic() = true
      ----------
      ACTUAL -
      ----------
      Executable: A$Inner
      Parameter at position 0
      parameter.getType() = class A
      parameter.isImplicit() = false
      ----------
      ----------
      Executable: A$1
      Parameter at position 0
      parameter.getType() = class A
      parameter.isImplicit() = false
      ----------
      ----------
      Executable: valueOf
      Parameter at position 0
      parameter.getType() = class java.lang.String
      parameter.isImplicit() = false
      ----------
      ----------
      Executable: A$R
      Parameter at position 0
      parameter.getType() = int
      parameter.isImplicit() = false
      Parameter at position 1
      parameter.getType() = float
      parameter.isImplicit() = false
      ----------
      ----------
      Executable: A$E
      Parameter at position 0
      parameter.getType() = class java.lang.String
      parameter.isSynthetic() = false
      Parameter at position 1
      parameter.getType() = int
      parameter.isSynthetic() = false
      ----------

      ---------- BEGIN SOURCE ----------
      import java.lang.reflect.Executable;
      import java.lang.reflect.Parameter;

      public class A {
        public static void main(String[] args) throws Exception {
          // implicit
          print(Inner.class.getDeclaredConstructors()[0], true);
          print(A.class.getDeclaredField("anon").get(new A()).getClass().getDeclaredConstructors()[0], true);
          print(E.class.getDeclaredMethod("valueOf", String.class), true);
          print(R.class.getDeclaredConstructors()[0], true);
          // synthetic
          print(E.class.getDeclaredConstructors()[0], false);
        }
        static void print(Executable executable, boolean implicit) {
          System.out.println("----------");
          System.out.println("Executable: " + executable.getName());
          Parameter[] parameters = executable.getParameters();
          for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            System.out.println("Parameter at position " + i);
            System.out.println("parameter.getType() = " + parameter.getType());
            if (implicit) {
              System.out.println("parameter.isImplicit() = " + parameter.isImplicit());
            } else {
              System.out.println("parameter.isSynthetic() = " + parameter.isSynthetic());
            }
          }
          System.out.println("----------");
        }
        class Inner {
          Inner() {}
        }
        Inner anon = new Inner() {};
        enum E {}
        record R(int a, float b) {
          public R {}
        }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Use the -parameters flag for compilation (does not work for the record ctor).

      FREQUENCY : always


            jwaters Julian Waters
            webbuggrp Webbug Group
            Votes:
            1 Vote for this issue
            Watchers:
            8 Start watching this issue

              Created:
              Updated:
              Resolved: