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