-
Bug
-
Resolution: Fixed
-
P4
-
18
-
b21
-
generic
-
generic
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
- csr for
-
JDK-8292467 javac does not emit SYNTHETIC and MANDATED flags for parameters by default
- Closed
- duplicates
-
JDK-5087240 (reflect) Constructor.getGenericParameterTypes for nested class w/ generics fail
- Closed
-
JDK-6520205 (enum) Enum constructor has wrong generic parameter types
- Closed
-
JDK-8284333 Constructor.getAnnotatedParameterTypes returns wrong value for Enums
- Closed
- is blocked by
-
JDK-8304837 Classfile API throws IOOBE for MethodParameters attribute without parameter names
- Closed
- relates to
-
JDK-8213329 Normalize inclusion of non-explicit parameters in JVM attributes
- Open
-
JDK-8322040 Missing array bounds check in ClassReader.parameter
- Resolved
-
JDK-8162501 getAnnotatedReceiverType of a local class constructor returns null
- In Progress
-
JDK-5087240 (reflect) Constructor.getGenericParameterTypes for nested class w/ generics fail
- Closed
-
JDK-8308050 Renaissance dotty fails after JDK-8292275
- Closed
-
JDK-8320575 generic type information lost on mandated parameters of record's compact constructors
- Closed
-
JDK-8341145 MalformedParametersException when using reflection on an inner class constructor
- Closed
-
JDK-8317731 When -parameters are not used, the inner class carries unexpected information
- Closed
-
JDK-8250919 Mark compiler-generated elements as mandated
- Open