Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8335482

Add notes for Error handling in Method.invoke and Constructor.newInstance

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Unresolved
    • Icon: P4 P4
    • tbd
    • core-libs
    • None
    • minimal
    • Change to API notes and rewording involves minimal risk.
    • Java API
    • SE

      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

            liach Chen Liang
            liach Chen Liang
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated: