-
Bug
-
Resolution: Fixed
-
P3
-
8, 11, 12
-
b21
-
x86_64
-
generic
ADDITIONAL SYSTEM INFORMATION :
Any OpenJDK version 1.8 onward, any platform. Tested and verified on 1.8.0_60-b27 and 18.9 (build 11+28) on Windows 7.
A DESCRIPTION OF THE PROBLEM :
If an anonymous or local inner class is declared inside of a lambda, the `EnclosingMethod` attribute on that class refers to the compiler-generated "lambda$" method rather than the method that enclosed the original declaration.
This is a violation of JVMS §4.7.7 ("The EnclosingMethod Attribute"):
> It is the responsibility of a Java compiler to ensure that the method identified via the `method_index` is indeed the closest **lexically enclosing** method of the class that contains this `EnclosingMethod` attribute.
Emphasis mine. Currently, if the class containing an `EnclosingMethod` attribute was declared within a lambda expression, the attribute refers to a method that never existed in the lexical scope.
A particularly vexing side effect of this occurs when the generic signature of a lambda-embedded inner type contains type variables declared by the lexically enclosing method. Those type variables will be out of scope from the perspective of the method identified by the `EnclosingMethod` attribute. Consequently, the `java.lang.reflect` APIs cannot resolve them.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run attached "source code for an executable test case". Note the output.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Output should be:
[class LambdaBug$1] EnclosingClass=class LambdaBug; EnclosingMethod=static void LambdaBug.immediateScope()
[class LambdaBug$1ExplicitToken] EnclosingClass=class LambdaBug; EnclosingMethod=static void LambdaBug.immediateScope()
[class LambdaBug$2] EnclosingClass=class LambdaBug; EnclosingMethod=static void LambdaBug.lambdaScope()
[class LambdaBug$2ExplicitToken] EnclosingClass=class LambdaBug; EnclosingMethod=static void LambdaBug.lambdaScope()
ACTUAL -
Output is actually:
[class LambdaBug$1] EnclosingClass=class LambdaBug; EnclosingMethod=static void LambdaBug.immediateScope()
[class LambdaBug$1ExplicitToken] EnclosingClass=class LambdaBug; EnclosingMethod=static void LambdaBug.immediateScope()
[class LambdaBug$2] EnclosingClass=class LambdaBug; EnclosingMethod=private static void LambdaBug.lambda$lambdaScope$0()
[class LambdaBug$2ExplicitToken] EnclosingClass=class LambdaBug; EnclosingMethod=private static void LambdaBug.lambda$lambdaScope$0()
---------- BEGIN SOURCE ----------
class LambdaBug<T> {
protected LambdaBug() {
System.out.printf("[%s] EnclosingClass=%s; EnclosingMethod=%s%n",
getClass(),
getClass().getEnclosingClass(),
getClass().getEnclosingMethod());
}
static <X> void immediateScope() {
class ExplicitToken extends LambdaBug<X> {}
new LambdaBug<X>() {};
new ExplicitToken();
}
static <X> void lambdaScope() {
Runnable r = () -> {
class ExplicitToken extends LambdaBug<X> {}
new LambdaBug<X>() {};
new ExplicitToken();
};
r.run();
}
public static void main(final String[] args) {
immediateScope();
lambdaScope();
}
}
---------- END SOURCE ----------
FREQUENCY : always
Any OpenJDK version 1.8 onward, any platform. Tested and verified on 1.8.0_60-b27 and 18.9 (build 11+28) on Windows 7.
A DESCRIPTION OF THE PROBLEM :
If an anonymous or local inner class is declared inside of a lambda, the `EnclosingMethod` attribute on that class refers to the compiler-generated "lambda$" method rather than the method that enclosed the original declaration.
This is a violation of JVMS §4.7.7 ("The EnclosingMethod Attribute"):
> It is the responsibility of a Java compiler to ensure that the method identified via the `method_index` is indeed the closest **lexically enclosing** method of the class that contains this `EnclosingMethod` attribute.
Emphasis mine. Currently, if the class containing an `EnclosingMethod` attribute was declared within a lambda expression, the attribute refers to a method that never existed in the lexical scope.
A particularly vexing side effect of this occurs when the generic signature of a lambda-embedded inner type contains type variables declared by the lexically enclosing method. Those type variables will be out of scope from the perspective of the method identified by the `EnclosingMethod` attribute. Consequently, the `java.lang.reflect` APIs cannot resolve them.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run attached "source code for an executable test case". Note the output.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Output should be:
[class LambdaBug$1] EnclosingClass=class LambdaBug; EnclosingMethod=static void LambdaBug.immediateScope()
[class LambdaBug$1ExplicitToken] EnclosingClass=class LambdaBug; EnclosingMethod=static void LambdaBug.immediateScope()
[class LambdaBug$2] EnclosingClass=class LambdaBug; EnclosingMethod=static void LambdaBug.lambdaScope()
[class LambdaBug$2ExplicitToken] EnclosingClass=class LambdaBug; EnclosingMethod=static void LambdaBug.lambdaScope()
ACTUAL -
Output is actually:
[class LambdaBug$1] EnclosingClass=class LambdaBug; EnclosingMethod=static void LambdaBug.immediateScope()
[class LambdaBug$1ExplicitToken] EnclosingClass=class LambdaBug; EnclosingMethod=static void LambdaBug.immediateScope()
[class LambdaBug$2] EnclosingClass=class LambdaBug; EnclosingMethod=private static void LambdaBug.lambda$lambdaScope$0()
[class LambdaBug$2ExplicitToken] EnclosingClass=class LambdaBug; EnclosingMethod=private static void LambdaBug.lambda$lambdaScope$0()
---------- BEGIN SOURCE ----------
class LambdaBug<T> {
protected LambdaBug() {
System.out.printf("[%s] EnclosingClass=%s; EnclosingMethod=%s%n",
getClass(),
getClass().getEnclosingClass(),
getClass().getEnclosingMethod());
}
static <X> void immediateScope() {
class ExplicitToken extends LambdaBug<X> {}
new LambdaBug<X>() {};
new ExplicitToken();
}
static <X> void lambdaScope() {
Runnable r = () -> {
class ExplicitToken extends LambdaBug<X> {}
new LambdaBug<X>() {};
new ExplicitToken();
};
r.run();
}
public static void main(final String[] args) {
immediateScope();
lambdaScope();
}
}
---------- END SOURCE ----------
FREQUENCY : always
- csr for
-
JDK-8217272 Bad EnclosingMethod attribute on classes declared in lambdas
-
- Closed
-
- duplicates
-
JDK-8215328 NullPointerException thrown by default type implementations from lambda on calling #toString
-
- Closed
-
- relates to
-
JDK-8257078 getActualTypeArguments returns array with null values for older Java versions
-
- Closed
-
There are no Sub-Tasks for this issue.