|
CSR :
|
Summary
-------
Add API notes about `Method.invoke` and `Constructor.newInstance` wrapping all `Error` in `InvocationTargetException`, recommending users to unwrap and handle those errors or the consequences.
Problem
-------
`Method.invoke` and `Constructor.newInstance` wraps `Error` instances in `InvocationTargetException`, which could be dangerous if `OutOfMemoryError` or `StackOverflowError` are wrapped; even further wrapping the InvocationTargetException into other throwables can lead to more errors from the VM, hiding the original error.
Meanwhile, the specifcations already require `Error` instances to be wrapped in `InvocationTargetException`, but the wording is not clear; it's easy for users to mishandle these APIs' `InvocationTargetException`.
Solution
--------
1. Specify that `InvocationTargetException` wraps any throwable, explicitly.
2. Add a note section about this wrapping of `Error` and the risk associated to mishandling/ignoring `Error`.
Specification
-------------
diff --git a/src/java.base/share/classes/java/lang/reflect/Constructor.java b/src/java.base/share/classes/java/lang/reflect/Constructor.java
index 99f14d01536..e3656df0a4c 100644
--- a/src/java.base/share/classes/java/lang/reflect/Constructor.java
+++ b/src/java.base/share/classes/java/lang/reflect/Constructor.java
@@ -450,6 +450,15 @@ void specificToGenericStringHeader(StringBuilder sb) {
* <p>If the constructor completes normally, returns the newly
* created and initialized instance.
*
+ * @apiNote
+ * {@link Throwable}s thrown by the constructor, including {@link
+ * Error}s, are wrapped in {@link InvocationTargetException}s.
+ * The wrapped throwable should be handled; ignoring the wrapped
+ * throwable, such as passing the {@link InvocationTargetException}
+ * as the cause to construct a new throwable, may fail in cases
+ * like {@link OutOfMemoryError} or {@link StackOverflowError}.
+ * The JVM may throw new errors that hide the original ones.
+ *
* @param initargs array of objects to be passed as arguments to
* the constructor call; values of primitive types are wrapped in
* a wrapper object of the appropriate type (e.g. a {@code float}
@@ -471,7 +480,7 @@ void specificToGenericStringHeader(StringBuilder sb) {
* @throws InstantiationException if the class that declares the
* underlying constructor represents an abstract class.
* @throws InvocationTargetException if the underlying constructor
- * throws an exception.
+ * throws any {@link Throwable}.
* @throws ExceptionInInitializerError if the initialization provoked
* by this method fails.
*/
diff --git a/src/java.base/share/classes/java/lang/reflect/Method.java b/src/java.base/share/classes/java/lang/reflect/Method.java
index b6ccbaa8294..33711f9953d 100644
--- a/src/java.base/share/classes/java/lang/reflect/Method.java
+++ b/src/java.base/share/classes/java/lang/reflect/Method.java
@@ -526,6 +526,16 @@ void specificToGenericStringHeader(StringBuilder sb) {
* underlying method return type is void, the invocation returns
* null.
*
+ * @apiNote
+ * {@link Throwable}s thrown by the underlying method, including
+ * {@link Error}s like {@link AbstractMethodError}, are wrapped
+ * in {@link InvocationTargetException}s.
+ * The wrapped throwable should be handled; ignoring the wrapped
+ * throwable, such as passing the {@link InvocationTargetException}
+ * as the cause to construct a new throwable, may fail in cases
+ * like {@link OutOfMemoryError} or {@link StackOverflowError}.
+ * The JVM may throw new errors that hide the original ones.
+ *
* @param obj the object the underlying method is invoked from
* @param args the arguments used for the method call
* @return the result of dispatching the method represented by
@@ -546,7 +556,7 @@ void specificToGenericStringHeader(StringBuilder sb) {
* cannot be converted to the corresponding formal
* parameter type by a method invocation conversion.
* @throws InvocationTargetException if the underlying method
- * throws an exception.
+ * throws any {@link Throwable}.
* @throws NullPointerException if the specified object is null
* and the method is an instance method.
* @throws ExceptionInInitializerError if the initialization