-
Bug
-
Resolution: Unresolved
-
P4
-
21, 24
-
generic
-
generic
A DESCRIPTION OF THE PROBLEM :
The java.lang.invoke.ConstantBootstraps.explicitCast method does not behave as documented when converting a null value to a primitive type. Instead of throwing a ClassCastException as its specification mandates, it silently returns the primitive's default zero value (e.g., 0 for int).
The core of this issue lies in a conflict between the high-level contract of explicitCast and the behavior of the lower-level mechanism it uses for its implementation.
The explicitCast Contract
The Javadoc for java.lang.invoke.ConstantBootstraps.explicitCast provides a clear specification for this case. It states:
"If dstType is a primitive type, then, if the runtime type of value is a primitive wrapper type (such as Integer), a Java unboxing conversion is applied ... If the runtime type of value is not a primitive wrapper type a ClassCastException is thrown."
The input value in the test case is null. The runtime type of null is not a primitive wrapper type. Therefore, according to this contract, a ClassCastException is required.
The Underlying Implementation's Behavior
The observed behavior (returning 0) stems from explicitCast delegating the conversion to java.lang.invoke.MethodHandles.explicitCastArguments. The documentation for MethodHandles.explicitCastArguments describes a different handling for null:
"If T0 is a reference and T1 a primitive, and if the reference is null at runtime, a zero value is introduced."
This perfectly explains why 0 is returned. The explicitCast method's implementation relies on explicitCastArguments, which has a specific, documented rule to convert a null reference to a primitive's default value. The problem is that explicitCast uses this mechanism without adding the check required to fulfill its own, more stringent, documented contract.
Maybe clarify JavaDoc is helpful
---------- BEGIN SOURCE ----------
import java.lang.invoke.ConstantBootstraps;
public class ExplicitCastBug {
public static void main(String[] args) {
System.out.println("Attempting to cast null to int via ConstantBootstraps.explicitCast...");
try {
// This call should throw ClassCastException according to the documentation.
Object result = ConstantBootstraps.explicitCast(null, null, int.class, null);
// This line is reached, which is incorrect.
System.out.println("BUG: The call succeeded and returned: " + result);
System.out.println("Expected a ClassCastException, but none was thrown.");
} catch (ClassCastException e) {
// This block is never reached.
System.out.println("SUCCESS: Correctly caught the expected ClassCastException.");
e.printStackTrace();
}
}
}
---------- END SOURCE ----------
The java.lang.invoke.ConstantBootstraps.explicitCast method does not behave as documented when converting a null value to a primitive type. Instead of throwing a ClassCastException as its specification mandates, it silently returns the primitive's default zero value (e.g., 0 for int).
The core of this issue lies in a conflict between the high-level contract of explicitCast and the behavior of the lower-level mechanism it uses for its implementation.
The explicitCast Contract
The Javadoc for java.lang.invoke.ConstantBootstraps.explicitCast provides a clear specification for this case. It states:
"If dstType is a primitive type, then, if the runtime type of value is a primitive wrapper type (such as Integer), a Java unboxing conversion is applied ... If the runtime type of value is not a primitive wrapper type a ClassCastException is thrown."
The input value in the test case is null. The runtime type of null is not a primitive wrapper type. Therefore, according to this contract, a ClassCastException is required.
The Underlying Implementation's Behavior
The observed behavior (returning 0) stems from explicitCast delegating the conversion to java.lang.invoke.MethodHandles.explicitCastArguments. The documentation for MethodHandles.explicitCastArguments describes a different handling for null:
"If T0 is a reference and T1 a primitive, and if the reference is null at runtime, a zero value is introduced."
This perfectly explains why 0 is returned. The explicitCast method's implementation relies on explicitCastArguments, which has a specific, documented rule to convert a null reference to a primitive's default value. The problem is that explicitCast uses this mechanism without adding the check required to fulfill its own, more stringent, documented contract.
Maybe clarify JavaDoc is helpful
---------- BEGIN SOURCE ----------
import java.lang.invoke.ConstantBootstraps;
public class ExplicitCastBug {
public static void main(String[] args) {
System.out.println("Attempting to cast null to int via ConstantBootstraps.explicitCast...");
try {
// This call should throw ClassCastException according to the documentation.
Object result = ConstantBootstraps.explicitCast(null, null, int.class, null);
// This line is reached, which is incorrect.
System.out.println("BUG: The call succeeded and returned: " + result);
System.out.println("Expected a ClassCastException, but none was thrown.");
} catch (ClassCastException e) {
// This block is never reached.
System.out.println("SUCCESS: Correctly caught the expected ClassCastException.");
e.printStackTrace();
}
}
}
---------- END SOURCE ----------
- csr for
-
JDK-8365193 ConstantBootstraps.explicitCast contradictory specification for null-to-primitive
-
- Draft
-
- links to
-
Review(master) openjdk/jdk/26714