--- old/src/java.base/share/classes/java/lang/reflect/UndeclaredThrowableException.java 2018-09-13 13:47:52.000000000 -0700 +++ new/src/java.base/share/classes/java/lang/reflect/UndeclaredThrowableException.java 2018-09-13 13:47:52.000000000 -0700 @@ -25,6 +25,13 @@ package java.lang.reflect; +import jdk.internal.misc.SharedSecrets; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamField; + /** * Thrown by a method invocation on a proxy instance if its invocation * handler's {@link InvocationHandler#invoke invoke} method throws a @@ -59,12 +66,6 @@ static final long serialVersionUID = 330127114055056639L; /** - * the undeclared checked exception that was thrown - * @serial - */ - private Throwable undeclaredThrowable; - - /** * Constructs an {@code UndeclaredThrowableException} with the * specified {@code Throwable}. * @@ -72,8 +73,7 @@ * that was thrown */ public UndeclaredThrowableException(Throwable undeclaredThrowable) { - super((Throwable) null); // Disallow initCause - this.undeclaredThrowable = undeclaredThrowable; + super(null, undeclaredThrowable); // Disallow initCause } /** @@ -87,8 +87,7 @@ public UndeclaredThrowableException(Throwable undeclaredThrowable, String s) { - super(s, null); // Disallow initCause - this.undeclaredThrowable = undeclaredThrowable; + super(s, undeclaredThrowable); // Disallow initCause } /** @@ -102,18 +101,38 @@ * @return the undeclared checked exception that was thrown */ public Throwable getUndeclaredThrowable() { - return undeclaredThrowable; + return super.getCause(); } /** - * Returns the cause of this exception (the {@code Throwable} - * instance wrapped in this {@code UndeclaredThrowableException}, - * which may be {@code null}). + * Serializable fields for UndeclaredThrowableException. * - * @return the cause of this exception. - * @since 1.4 + * @serialField undeclaredThrowable Throwable + */ + private static final ObjectStreamField[] serialPersistentFields = { + new ObjectStreamField("undeclaredThrowable", Throwable.class) + }; + + /* + * Reconstitutes the UndeclaredThrowableException instance from a stream + * and initialize the cause properly when deserializing from an older + * version. + */ + private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { + ObjectInputStream.GetField fields = s.readFields(); + Throwable exception = (Throwable) fields.get("undeclaredThrowable", null); + if (exception != null) { + SharedSecrets.getJavaLangAccess().setCause(this, exception); + } + } + + /* + * To maintain compatibility with older implementation, write a serial + * "ex" field with the cause as the value. */ - public Throwable getCause() { - return undeclaredThrowable; + private void writeObject(ObjectOutputStream out) throws IOException { + ObjectOutputStream.PutField fields = out.putFields(); + fields.put("undeclaredThrowable", super.getCause()); + out.writeFields(); } }