--- old/src/java.base/share/classes/java/lang/ClassNotFoundException.java 2018-09-13 13:47:44.000000000 -0700 +++ new/src/java.base/share/classes/java/lang/ClassNotFoundException.java 2018-09-13 13:47:43.000000000 -0700 @@ -25,6 +25,11 @@ package java.lang; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamField; + /** * Thrown when an application tries to load in a class through its * string name using: @@ -57,15 +62,6 @@ private static final long serialVersionUID = 9176873029745254542L; /** - * This field holds the exception ex if the - * ClassNotFoundException(String s, Throwable ex) constructor was - * used to instantiate the object - * @serial - * @since 1.2 - */ - private Throwable ex; - - /** * Constructs a ClassNotFoundException with no detail message. */ public ClassNotFoundException() { @@ -92,8 +88,7 @@ * @since 1.2 */ public ClassNotFoundException(String s, Throwable ex) { - super(s, null); // Disallow initCause - this.ex = ex; + super(s, ex); // Disallow initCause } /** @@ -108,18 +103,42 @@ * @since 1.2 */ public Throwable getException() { - return ex; + return super.getCause(); } /** - * Returns the cause of this exception (the exception that was raised - * if an error occurred while attempting to load the class; otherwise - * {@code null}). + * Serializable fields for ClassNotFoundException. * - * @return the cause of this exception. - * @since 1.4 + * @serialField ex Throwable */ - public Throwable getCause() { - return ex; + private static final ObjectStreamField[] serialPersistentFields = { + new ObjectStreamField("ex", Throwable.class) + }; + + /* + * Reconstitutes the ClassNotFoundException instance from a stream + * and initialize the cause properly when deserializing from an older + * version. + * + * The getException and getCause method returns the private "ex" field + * in the older implementation and ClassNotFoundException::cause + * was set to null. + */ + private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { + ObjectInputStream.GetField fields = s.readFields(); + Throwable exception = (Throwable) fields.get("ex", null); + if (exception != null) { + setCause(exception); + } + } + + /* + * To maintain compatibility with older implementation, write a serial + * "ex" field with the cause as the value. + */ + private void writeObject(ObjectOutputStream out) throws IOException { + ObjectOutputStream.PutField fields = out.putFields(); + fields.put("ex", super.getCause()); + out.writeFields(); } } --- old/src/java.base/share/classes/java/lang/ExceptionInInitializerError.java 2018-09-13 13:47:46.000000000 -0700 +++ new/src/java.base/share/classes/java/lang/ExceptionInInitializerError.java 2018-09-13 13:47:45.000000000 -0700 @@ -25,6 +25,11 @@ package java.lang; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamField; + /** * Signals that an unexpected exception has occurred in a static initializer. * An ExceptionInInitializerError is thrown to indicate that an @@ -48,23 +53,13 @@ private static final long serialVersionUID = 1521711792217232256L; /** - * This field holds the exception if the - * ExceptionInInitializerError(Throwable thrown) constructor was - * used to instantiate the object - * - * @serial - * - */ - private Throwable exception; - - /** * Constructs an ExceptionInInitializerError with * null as its detail message string and with no saved * throwable object. * A detail message is a String that describes this particular exception. */ public ExceptionInInitializerError() { - initCause(null); // Disallow subsequent initCause + initCause(null); // Disallow subsequent initCause } /** @@ -76,23 +71,20 @@ * @param thrown The exception thrown */ public ExceptionInInitializerError(Throwable thrown) { - initCause(null); // Disallow subsequent initCause - this.exception = thrown; + super(null, thrown); // Disallow subsequent initCause } /** - * Constructs an ExceptionInInitializerError with the specified detail + * Constructs an {@code ExceptionInInitializerError} with the specified detail * message string. A detail message is a String that describes this * particular exception. The detail message string is saved for later * retrieval by the {@link Throwable#getMessage()} method. There is no * saved throwable object. * - * * @param s the detail message */ public ExceptionInInitializerError(String s) { - super(s); - initCause(null); // Disallow subsequent initCause + super(s, null); // Disallow subsequent initCause } /** @@ -109,18 +101,43 @@ * throwable object. */ public Throwable getException() { - return exception; + return super.getCause(); } /** - * Returns the cause of this error (the exception that occurred - * during a static initialization that caused this error to be created). + * Serializable fields for ExceptionInInitializerError. * - * @return the cause of this error or null if the - * cause is nonexistent or unknown. - * @since 1.4 + * @serialField exception Throwable */ - public Throwable getCause() { - return exception; + private static final ObjectStreamField[] serialPersistentFields = { + new ObjectStreamField("exception", Throwable.class) + }; + + /* + * Reconstitutes the ExceptionInInitializerError instance from a stream + * and initialize the cause properly when deserializing from an older + * version. + * + * The getException and getCause method returns the private "exception" + * field in the older implementation and ExceptionInInitializerError::cause + * was set to null. + */ + private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { + ObjectInputStream.GetField fields = s.readFields(); + Throwable exception = (Throwable) fields.get("exception", null); + if (exception != null) { + setCause(exception); + } } + + /* + * To maintain compatibility with older implementation, write a serial + * "exception" field with the cause as the value. + */ + private void writeObject(ObjectOutputStream out) throws IOException { + ObjectOutputStream.PutField fields = out.putFields(); + fields.put("exception", super.getCause()); + out.writeFields(); + } + } --- old/src/java.base/share/classes/java/lang/System.java 2018-09-13 13:47:47.000000000 -0700 +++ new/src/java.base/share/classes/java/lang/System.java 2018-09-13 13:47:47.000000000 -0700 @@ -2201,6 +2201,9 @@ return StringCoding.getBytesUTF8NoRepl(s); } + public void setCause(Throwable t, Throwable cause) { + t.setCause(cause); + } }); } } --- old/src/java.base/share/classes/java/lang/Throwable.java 2018-09-13 13:47:49.000000000 -0700 +++ new/src/java.base/share/classes/java/lang/Throwable.java 2018-09-13 13:47:49.000000000 -0700 @@ -466,6 +466,16 @@ return this; } + /* + * This is called by readObject of a few exceptions such as + * ClassNotFoundException and ExceptionInInitializerError to deserialize + * a stream output from an older runtime version where the cause may + * have set to null. + */ + final void setCause(Throwable t) { + this.cause = t; + } + /** * Returns a short description of this throwable. * The result is the concatenation of: --- old/src/java.base/share/classes/java/lang/reflect/InvocationTargetException.java 2018-09-13 13:47:51.000000000 -0700 +++ new/src/java.base/share/classes/java/lang/reflect/InvocationTargetException.java 2018-09-13 13:47:50.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; + /** * InvocationTargetException is a checked exception that wraps * an exception thrown by an invoked method or constructor. @@ -46,16 +53,6 @@ */ private static final long serialVersionUID = 4085088731926701167L; - /** - * This field holds the target if the - * InvocationTargetException(Throwable target) constructor was - * used to instantiate the object - * - * @serial - * - */ - private Throwable target; - /** * Constructs an {@code InvocationTargetException} with * {@code null} as the target exception. @@ -70,8 +67,7 @@ * @param target the target exception */ public InvocationTargetException(Throwable target) { - super((Throwable)null); // Disallow initCause - this.target = target; + super(null, target); // Disallow initCause } /** @@ -82,8 +78,7 @@ * @param s the detail message */ public InvocationTargetException(Throwable target, String s) { - super(s, null); // Disallow initCause - this.target = target; + super(s, target); // Disallow initCause } /** @@ -96,17 +91,42 @@ * @return the thrown target exception (cause of this exception). */ public Throwable getTargetException() { - return target; + return super.getCause(); } /** - * Returns the cause of this exception (the thrown target exception, - * which may be {@code null}). + * Serializable fields for UndeclaredThrowableException. * - * @return the cause of this exception. - * @since 1.4 + * @serialField target Throwable */ - public Throwable getCause() { - return target; + private static final ObjectStreamField[] serialPersistentFields = { + new ObjectStreamField("target", Throwable.class) + }; + + /* + * Reconstitutes the InvocationTargetException instance from a stream + * and initialize the cause properly when deserializing from an older + * version. + * + * The getException and getCause method returns the private "target" field + * in the older implementation and InvocationTargetException::cause + * was set to null. + */ + private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { + ObjectInputStream.GetField fields = s.readFields(); + Throwable exception = (Throwable) fields.get("target", null); + if (exception != null) { + SharedSecrets.getJavaLangAccess().setCause(this, exception); + } + } + + /* + * To maintain compatibility with older implementation, write a serial + * "target" field with the cause as the value. + */ + private void writeObject(ObjectOutputStream out) throws IOException { + ObjectOutputStream.PutField fields = out.putFields(); + fields.put("target", super.getCause()); + out.writeFields(); } } --- 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(); } } --- old/src/java.base/share/classes/java/security/PrivilegedActionException.java 2018-09-13 13:47:54.000000000 -0700 +++ new/src/java.base/share/classes/java/security/PrivilegedActionException.java 2018-09-13 13:47:53.000000000 -0700 @@ -25,6 +25,13 @@ package java.security; +import jdk.internal.misc.SharedSecrets; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamField; + /** * This exception is thrown by * {@code doPrivileged(PrivilegedExceptionAction)} and @@ -53,19 +60,13 @@ private static final long serialVersionUID = 4724086851538908602L; /** - * @serial - */ - private Exception exception; - - /** * Constructs a new PrivilegedActionException "wrapping" * the specific Exception. * * @param exception The exception thrown */ public PrivilegedActionException(Exception exception) { - super((Throwable)null); // Disallow initCause - this.exception = exception; + super(null, exception); // Disallow initCause } /** @@ -84,23 +85,49 @@ * AccessControlContext) */ public Exception getException() { - return exception; + return (Exception)super.getCause(); } + public String toString() { + String s = getClass().getName(); + Throwable cause = super.getCause(); + return (cause != null) ? (s + ": " + cause.toString()) : s; + } + + /** - * Returns the cause of this exception (the exception thrown by - * the privileged computation that resulted in this - * {@code PrivilegedActionException}). + * Serializable fields for UndeclaredThrowableException. + * + * @serialField undeclaredThrowable Throwable + */ + private static final ObjectStreamField[] serialPersistentFields = { + new ObjectStreamField("exception", Exception.class) + }; + + /* + * Reconstitutes the PrivilegedActionException instance from a stream + * and initialize the cause properly when deserializing from an older + * version. * - * @return the cause of this exception. - * @since 1.4 + * The getException and getCause method returns the private "exception" + * field in the older implementation and PrivilegedActionException::cause + * was set to null. */ - public Throwable getCause() { - return exception; + private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { + ObjectInputStream.GetField fields = s.readFields(); + Exception exception = (Exception) fields.get("exception", null); + if (exception != null) { + SharedSecrets.getJavaLangAccess().setCause(this, exception); + } } - public String toString() { - String s = getClass().getName(); - return (exception != null) ? (s + ": " + exception.toString()) : s; + /* + * To maintain compatibility with older implementation, write a serial + * "exception" field with the cause as the value. + */ + private void writeObject(ObjectOutputStream out) throws IOException { + ObjectOutputStream.PutField fields = out.putFields(); + fields.put("exception", super.getCause()); + out.writeFields(); } } --- old/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java 2018-09-13 13:47:55.000000000 -0700 +++ new/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java 2018-09-13 13:47:55.000000000 -0700 @@ -305,4 +305,10 @@ * @throws IllegalArgumentException for malformed surrogates */ byte[] getBytesUTF8NoRepl(String s); + + /** + * Set the cause of Throwable + * @param cause set t's cause to new value + */ + void setCause(Throwable t, Throwable cause); } --- old/test/jdk/java/lang/Throwable/LegacyChainedExceptionSerialization.java 2018-09-13 13:47:57.000000000 -0700 +++ new/test/jdk/java/lang/Throwable/LegacyChainedExceptionSerialization.java 2018-09-13 13:47:56.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,10 +22,15 @@ */ import java.io.*; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.UndeclaredThrowableException; +import java.security.PrivilegedActionException; +import java.util.Base64; +import java.util.Map; /** * @test - * @bug 4385429 8004928 + * @bug 4385429 8004928 8210721 * @summary Certain legacy chained exceptions throw IllegalArgumentException * upon deserialization if "causative exception" is null. * @author Josh Bloch @@ -33,18 +38,31 @@ public class LegacyChainedExceptionSerialization { private static Throwable[] broken = { new ClassNotFoundException(), + new ClassNotFoundException("bar", new IOException("reading class file")), new ExceptionInInitializerError(), + new ExceptionInInitializerError(new NullPointerException("foo")), new java.lang.reflect.UndeclaredThrowableException(null), + new java.lang.reflect.UndeclaredThrowableException(new IllegalArgumentException("foo")), new java.lang.reflect.InvocationTargetException(null), - new java.security.PrivilegedActionException(null) + new java.lang.reflect.InvocationTargetException(new Error("goo")), + new java.security.PrivilegedActionException(null), + new java.security.PrivilegedActionException(new IOException("foo")), }; + public static void main(String[] args) throws Exception { for (int i=0; i e : SERIALIZED_DATA.entrySet()) { + Throwable t = deserialize(e.getKey()); + verify(t, e.getValue()); + } + + testOverriddenGetCause(); } - private static void test(Throwable e) throws Exception { + private static Throwable test(Throwable e) throws Exception { ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(bout); out.writeObject(e); @@ -54,5 +72,247 @@ new ByteArrayInputStream(bout.toByteArray()); ObjectInputStream in = new ObjectInputStream(bin); Throwable clone = (Throwable) in.readObject(); + return clone; + } + + private static void testOverriddenGetCause() throws Exception { + SubClass sc = new SubClass(new NullPointerException()); + SubClass clone = (SubClass)test(sc); + Throwable cause = clone.getException(); + if (!(cause instanceof NullPointerException) || cause.getMessage() != null) { + throw new RuntimeException("unexpected cause: " + cause); + } + } + + private static Throwable deserialize(String ser) throws Exception { + Base64.Decoder decoder = Base64.getDecoder(); + try (ByteArrayInputStream bin = new ByteArrayInputStream(decoder.decode(ser)); + ObjectInputStream ois = new ObjectInputStream(bin)) { + return (Throwable)ois.readObject(); + } + } + + /* + * Verify the deserialization of the serialized data from an old version. + * See SERIALIZED_DATA. + */ + private static void verify(Throwable t, Throwable expected) { + String msg = expected.getMessage(); + Throwable cause = expected.getCause(); + if (t.getMessage() != msg && msg != null && !msg.equals(t.getMessage())) { + throw new RuntimeException("unexpected message: " + t.getMessage() + + " expected: " + msg); + } + Throwable e = t.getCause(); + if (e.getClass() != cause.getClass()) { + throw new RuntimeException("unexpected cause: " + t.getCause()); + } + String causedBy = cause.getMessage(); + if (e.getMessage() != causedBy) { + if (e.getMessage() == null || causedBy == null || !causedBy.equals(e.getMessage())) { + throw new RuntimeException("unexpected message: " + t.getMessage() + + " expected: " + causedBy); + } + } + Throwable exception = null; + if (t instanceof ExceptionInInitializerError) { + exception = ((ExceptionInInitializerError)t).getException(); + } else if (t instanceof ClassNotFoundException) { + exception = ((ClassNotFoundException)t).getException(); + } else if (t instanceof InvocationTargetException) { + exception = ((InvocationTargetException) t).getTargetException(); + } else if (t instanceof UndeclaredThrowableException) { + exception = ((UndeclaredThrowableException) t).getUndeclaredThrowable(); + } else if (t instanceof PrivilegedActionException) { + exception = ((PrivilegedActionException) t).getException(); + } else { + // skip the cause == exception check below + e = null; + } + if (e != exception) { + throw new RuntimeException("unexpected exception: " + exception); + } + } + + static class SubClass extends ExceptionInInitializerError { + public SubClass(Throwable t) { + super(t); + } + @Override + public Throwable getCause() { + return new Throwable("always new"); + } + } + + /* + * The following strings are base64-encoded serialized data generated + * by running the jdk10SerializeThrowable method with JDK 10 runtime. + * + * private static void jdk10SerializeThrowable(Throwable e) throws Exception { + * Base64.Encoder encoder = Base64.getEncoder(); + * try (ByteArrayOutputStream os = new ByteArrayOutputStream(); + * ObjectOutputStream out = new ObjectOutputStream(os)) { + * out.writeObject(e); + * out.flush(); + * String s = encoder.encodeToString(os.toByteArray()); + * for (int i=0; i < s.length();) { + * int end = Math.min(i+60, s.length()); + * CharSequence seq = s.subSequence(i, end); + * System.out.format("\"%s\" +%n", seq); + * i = end; + * } + * } + * } + */ + + private static final String EIIE_OLD_VERSION = + "rO0ABXNyACVqYXZhLmxhbmcuRXhjZXB0aW9uSW5Jbml0aWFsaXplckVycm9y" + + "FR400Amhk4ACAAFMAAlleGNlcHRpb250ABVMamF2YS9sYW5nL1Rocm93YWJs" + + "ZTt4cgAWamF2YS5sYW5nLkxpbmthZ2VFcnJvcjGtS1U0qEq6AgAAeHIAD2ph" + + "dmEubGFuZy5FcnJvckUdNlaLgg5WAgAAeHIAE2phdmEubGFuZy5UaHJvd2Fi" + + "bGXVxjUnOXe4ywMABEwABWNhdXNlcQB+AAFMAA1kZXRhaWxNZXNzYWdldAAS" + + "TGphdmEvbGFuZy9TdHJpbmc7WwAKc3RhY2tUcmFjZXQAHltMamF2YS9sYW5n" + + "L1N0YWNrVHJhY2VFbGVtZW50O0wAFHN1cHByZXNzZWRFeGNlcHRpb25zdAAQ" + + "TGphdmEvdXRpbC9MaXN0O3hwcHB1cgAeW0xqYXZhLmxhbmcuU3RhY2tUcmFj" + + "ZUVsZW1lbnQ7AkYqPDz9IjkCAAB4cAAAAAFzcgAbamF2YS5sYW5nLlN0YWNr" + + "VHJhY2VFbGVtZW50YQnFmiY23YUCAAhCAAZmb3JtYXRJAApsaW5lTnVtYmVy" + + "TAAPY2xhc3NMb2FkZXJOYW1lcQB+AAVMAA5kZWNsYXJpbmdDbGFzc3EAfgAF" + + "TAAIZmlsZU5hbWVxAH4ABUwACm1ldGhvZE5hbWVxAH4ABUwACm1vZHVsZU5h" + + "bWVxAH4ABUwADW1vZHVsZVZlcnNpb25xAH4ABXhwAQAAAAd0AANhcHB0AARU" + + "ZXN0dAAJVGVzdC5qYXZhdAAEbWFpbnBwc3IAH2phdmEudXRpbC5Db2xsZWN0" + + "aW9ucyRFbXB0eUxpc3R6uBe0PKee3gIAAHhweHNyAB5qYXZhLmxhbmcuTnVs" + + "bFBvaW50ZXJFeGNlcHRpb25HpaGO/zHhuAIAAHhyABpqYXZhLmxhbmcuUnVu" + + "dGltZUV4Y2VwdGlvbp5fBkcKNIPlAgAAeHIAE2phdmEubGFuZy5FeGNlcHRp" + + "b27Q/R8+GjscxAIAAHhxAH4ABHEAfgAWdAADZm9vdXEAfgAJAAAAAXNxAH4A" + + "CwEAAAAHcQB+AA1xAH4ADnEAfgAPcQB+ABBwcHEAfgASeA=="; + + private static final String CNFE_OLD_VERSION = + "rO0ABXNyACBqYXZhLmxhbmcuQ2xhc3NOb3RGb3VuZEV4Y2VwdGlvbn9azWY+" + + "1CCOAgABTAACZXh0ABVMamF2YS9sYW5nL1Rocm93YWJsZTt4cgAmamF2YS5s" + + "YW5nLlJlZmxlY3RpdmVPcGVyYXRpb25FeGNlcHRpb24AAAAAB1vNFQIAAHhy" + + "ABNqYXZhLmxhbmcuRXhjZXB0aW9u0P0fPho7HMQCAAB4cgATamF2YS5sYW5n" + + "LlRocm93YWJsZdXGNSc5d7jLAwAETAAFY2F1c2VxAH4AAUwADWRldGFpbE1l" + + "c3NhZ2V0ABJMamF2YS9sYW5nL1N0cmluZztbAApzdGFja1RyYWNldAAeW0xq" + + "YXZhL2xhbmcvU3RhY2tUcmFjZUVsZW1lbnQ7TAAUc3VwcHJlc3NlZEV4Y2Vw" + + "dGlvbnN0ABBMamF2YS91dGlsL0xpc3Q7eHBwdAADYmFydXIAHltMamF2YS5s" + + "YW5nLlN0YWNrVHJhY2VFbGVtZW50OwJGKjw8/SI5AgAAeHAAAAABc3IAG2ph" + + "dmEubGFuZy5TdGFja1RyYWNlRWxlbWVudGEJxZomNt2FAgAIQgAGZm9ybWF0" + + "SQAKbGluZU51bWJlckwAD2NsYXNzTG9hZGVyTmFtZXEAfgAFTAAOZGVjbGFy" + + "aW5nQ2xhc3NxAH4ABUwACGZpbGVOYW1lcQB+AAVMAAptZXRob2ROYW1lcQB+" + + "AAVMAAptb2R1bGVOYW1lcQB+AAVMAA1tb2R1bGVWZXJzaW9ucQB+AAV4cAEA" + + "AAAMdAADYXBwdAAEVGVzdHQACVRlc3QuamF2YXQABG1haW5wcHNyAB9qYXZh" + + "LnV0aWwuQ29sbGVjdGlvbnMkRW1wdHlMaXN0ergXtDynnt4CAAB4cHhzcgAT" + + "amF2YS5pby5JT0V4Y2VwdGlvbmyAc2RlJfCrAgAAeHEAfgADcQB+ABV0ABJy" + + "ZWFkaW5nIGNsYXNzIGZpbGV1cQB+AAoAAAABc3EAfgAMAQAAAAxxAH4ADnEA" + + "fgAPcQB+ABBxAH4AEXBwcQB+ABN4"; + + private static final String ITE1_OLD_VERSION = + "rO0ABXNyACtqYXZhLmxhbmcucmVmbGVjdC5JbnZvY2F0aW9uVGFyZ2V0RXhj" + + "ZXB0aW9uOLEmjtZxJG8CAAFMAAZ0YXJnZXR0ABVMamF2YS9sYW5nL1Rocm93" + + "YWJsZTt4cgAmamF2YS5sYW5nLlJlZmxlY3RpdmVPcGVyYXRpb25FeGNlcHRp" + + "b24AAAAAB1vNFQIAAHhyABNqYXZhLmxhbmcuRXhjZXB0aW9u0P0fPho7HMQC" + + "AAB4cgATamF2YS5sYW5nLlRocm93YWJsZdXGNSc5d7jLAwAETAAFY2F1c2Vx" + + "AH4AAUwADWRldGFpbE1lc3NhZ2V0ABJMamF2YS9sYW5nL1N0cmluZztbAApz" + + "dGFja1RyYWNldAAeW0xqYXZhL2xhbmcvU3RhY2tUcmFjZUVsZW1lbnQ7TAAU" + + "c3VwcHJlc3NlZEV4Y2VwdGlvbnN0ABBMamF2YS91dGlsL0xpc3Q7eHBwdAAD" + + "YmFydXIAHltMamF2YS5sYW5nLlN0YWNrVHJhY2VFbGVtZW50OwJGKjw8/SI5" + + "AgAAeHAAAAABc3IAG2phdmEubGFuZy5TdGFja1RyYWNlRWxlbWVudGEJxZom" + + "Nt2FAgAIQgAGZm9ybWF0SQAKbGluZU51bWJlckwAD2NsYXNzTG9hZGVyTmFt" + + "ZXEAfgAFTAAOZGVjbGFyaW5nQ2xhc3NxAH4ABUwACGZpbGVOYW1lcQB+AAVM" + + "AAptZXRob2ROYW1lcQB+AAVMAAptb2R1bGVOYW1lcQB+AAVMAA1tb2R1bGVW" + + "ZXJzaW9ucQB+AAV4cAEAAAARdAADYXBwdAAEVGVzdHQACVRlc3QuamF2YXQA" + + "BG1haW5wcHNyAB9qYXZhLnV0aWwuQ29sbGVjdGlvbnMkRW1wdHlMaXN0ergX" + + "tDynnt4CAAB4cHhzcgAPamF2YS5sYW5nLkVycm9yRR02VouCDlYCAAB4cQB+" + + "AARxAH4AFXQAA2Zvb3VxAH4ACgAAAAFzcQB+AAwBAAAAEXEAfgAOcQB+AA9x" + + "AH4AEHEAfgARcHBxAH4AE3g="; + + private static final String ITE2_OLD_VERSION = + "rO0ABXNyACtqYXZhLmxhbmcucmVmbGVjdC5JbnZvY2F0aW9uVGFyZ2V0RXhj" + + "ZXB0aW9uOLEmjtZxJG8CAAFMAAZ0YXJnZXR0ABVMamF2YS9sYW5nL1Rocm93" + + "YWJsZTt4cgAmamF2YS5sYW5nLlJlZmxlY3RpdmVPcGVyYXRpb25FeGNlcHRp" + + "b24AAAAAB1vNFQIAAHhyABNqYXZhLmxhbmcuRXhjZXB0aW9u0P0fPho7HMQC" + + "AAB4cgATamF2YS5sYW5nLlRocm93YWJsZdXGNSc5d7jLAwAETAAFY2F1c2Vx" + + "AH4AAUwADWRldGFpbE1lc3NhZ2V0ABJMamF2YS9sYW5nL1N0cmluZztbAApz" + + "dGFja1RyYWNldAAeW0xqYXZhL2xhbmcvU3RhY2tUcmFjZUVsZW1lbnQ7TAAU" + + "c3VwcHJlc3NlZEV4Y2VwdGlvbnN0ABBMamF2YS91dGlsL0xpc3Q7eHBwcHVy" + + "AB5bTGphdmEubGFuZy5TdGFja1RyYWNlRWxlbWVudDsCRio8PP0iOQIAAHhw" + + "AAAAAXNyABtqYXZhLmxhbmcuU3RhY2tUcmFjZUVsZW1lbnRhCcWaJjbdhQIA" + + "CEIABmZvcm1hdEkACmxpbmVOdW1iZXJMAA9jbGFzc0xvYWRlck5hbWVxAH4A" + + "BUwADmRlY2xhcmluZ0NsYXNzcQB+AAVMAAhmaWxlTmFtZXEAfgAFTAAKbWV0" + + "aG9kTmFtZXEAfgAFTAAKbW9kdWxlTmFtZXEAfgAFTAANbW9kdWxlVmVyc2lv" + + "bnEAfgAFeHABAAAAEnQAA2FwcHQABFRlc3R0AAlUZXN0LmphdmF0AARtYWlu" + + "cHBzcgAfamF2YS51dGlsLkNvbGxlY3Rpb25zJEVtcHR5TGlzdHq4F7Q8p57e" + + "AgAAeHB4c3IAD2phdmEubGFuZy5FcnJvckUdNlaLgg5WAgAAeHEAfgAEcQB+" + + "ABR0AANnb291cQB+AAkAAAABc3EAfgALAQAAABJxAH4ADXEAfgAOcQB+AA9x" + + "AH4AEHBwcQB+ABJ4"; + + private static final String UTE1_OLD_VERSION = + "rO0ABXNyAC5qYXZhLmxhbmcucmVmbGVjdC5VbmRlY2xhcmVkVGhyb3dhYmxl" + + "RXhjZXB0aW9uBJTY3HP5/P8CAAFMABN1bmRlY2xhcmVkVGhyb3dhYmxldAAV" + + "TGphdmEvbGFuZy9UaHJvd2FibGU7eHIAGmphdmEubGFuZy5SdW50aW1lRXhj" + + "ZXB0aW9unl8GRwo0g+UCAAB4cgATamF2YS5sYW5nLkV4Y2VwdGlvbtD9Hz4a" + + "OxzEAgAAeHIAE2phdmEubGFuZy5UaHJvd2FibGXVxjUnOXe4ywMABEwABWNh" + + "dXNlcQB+AAFMAA1kZXRhaWxNZXNzYWdldAASTGphdmEvbGFuZy9TdHJpbmc7" + + "WwAKc3RhY2tUcmFjZXQAHltMamF2YS9sYW5nL1N0YWNrVHJhY2VFbGVtZW50" + + "O0wAFHN1cHByZXNzZWRFeGNlcHRpb25zdAAQTGphdmEvdXRpbC9MaXN0O3hw" + + "cHQAA2JhcnVyAB5bTGphdmEubGFuZy5TdGFja1RyYWNlRWxlbWVudDsCRio8" + + "PP0iOQIAAHhwAAAAAXNyABtqYXZhLmxhbmcuU3RhY2tUcmFjZUVsZW1lbnRh" + + "CcWaJjbdhQIACEIABmZvcm1hdEkACmxpbmVOdW1iZXJMAA9jbGFzc0xvYWRl" + + "ck5hbWVxAH4ABUwADmRlY2xhcmluZ0NsYXNzcQB+AAVMAAhmaWxlTmFtZXEA" + + "fgAFTAAKbWV0aG9kTmFtZXEAfgAFTAAKbW9kdWxlTmFtZXEAfgAFTAANbW9k" + + "dWxlVmVyc2lvbnEAfgAFeHABAAAAE3QAA2FwcHQABFRlc3R0AAlUZXN0Lmph" + + "dmF0AARtYWlucHBzcgAfamF2YS51dGlsLkNvbGxlY3Rpb25zJEVtcHR5TGlz" + + "dHq4F7Q8p57eAgAAeHB4c3IAImphdmEubGFuZy5JbGxlZ2FsQXJndW1lbnRF" + + "eGNlcHRpb261iXPTfWaPvAIAAHhxAH4AAnEAfgAVdAADZm9vdXEAfgAKAAAA" + + "AXNxAH4ADAEAAAATcQB+AA5xAH4AD3EAfgAQcQB+ABFwcHEAfgATeA=="; + + private static final String UTE2_OLD_VERSION = + "rO0ABXNyAC5qYXZhLmxhbmcucmVmbGVjdC5VbmRlY2xhcmVkVGhyb3dhYmxl" + + "RXhjZXB0aW9uBJTY3HP5/P8CAAFMABN1bmRlY2xhcmVkVGhyb3dhYmxldAAV" + + "TGphdmEvbGFuZy9UaHJvd2FibGU7eHIAGmphdmEubGFuZy5SdW50aW1lRXhj" + + "ZXB0aW9unl8GRwo0g+UCAAB4cgATamF2YS5sYW5nLkV4Y2VwdGlvbtD9Hz4a" + + "OxzEAgAAeHIAE2phdmEubGFuZy5UaHJvd2FibGXVxjUnOXe4ywMABEwABWNh" + + "dXNlcQB+AAFMAA1kZXRhaWxNZXNzYWdldAASTGphdmEvbGFuZy9TdHJpbmc7" + + "WwAKc3RhY2tUcmFjZXQAHltMamF2YS9sYW5nL1N0YWNrVHJhY2VFbGVtZW50" + + "O0wAFHN1cHByZXNzZWRFeGNlcHRpb25zdAAQTGphdmEvdXRpbC9MaXN0O3hw" + + "cHB1cgAeW0xqYXZhLmxhbmcuU3RhY2tUcmFjZUVsZW1lbnQ7AkYqPDz9IjkC" + + "AAB4cAAAAAFzcgAbamF2YS5sYW5nLlN0YWNrVHJhY2VFbGVtZW50YQnFmiY2" + + "3YUCAAhCAAZmb3JtYXRJAApsaW5lTnVtYmVyTAAPY2xhc3NMb2FkZXJOYW1l" + + "cQB+AAVMAA5kZWNsYXJpbmdDbGFzc3EAfgAFTAAIZmlsZU5hbWVxAH4ABUwA" + + "Cm1ldGhvZE5hbWVxAH4ABUwACm1vZHVsZU5hbWVxAH4ABUwADW1vZHVsZVZl" + + "cnNpb25xAH4ABXhwAQAAABR0AANhcHB0AARUZXN0dAAJVGVzdC5qYXZhdAAE" + + "bWFpbnBwc3IAH2phdmEudXRpbC5Db2xsZWN0aW9ucyRFbXB0eUxpc3R6uBe0" + + "PKee3gIAAHhweHNyACJqYXZhLmxhbmcuSWxsZWdhbEFyZ3VtZW50RXhjZXB0" + + "aW9utYlz031mj7wCAAB4cQB+AAJxAH4AFHQAA2dvb3VxAH4ACQAAAAFzcQB+" + + "AAsBAAAAFHEAfgANcQB+AA5xAH4AD3EAfgAQcHBxAH4AEng="; + + private static final String PAE_OLD_VERSION = + "rO0ABXNyACdqYXZhLnNlY3VyaXR5LlByaXZpbGVnZWRBY3Rpb25FeGNlcHRp" + + "b25Bj1P2UhH1ugIAAUwACWV4Y2VwdGlvbnQAFUxqYXZhL2xhbmcvRXhjZXB0" + + "aW9uO3hyABNqYXZhLmxhbmcuRXhjZXB0aW9u0P0fPho7HMQCAAB4cgATamF2" + + "YS5sYW5nLlRocm93YWJsZdXGNSc5d7jLAwAETAAFY2F1c2V0ABVMamF2YS9s" + + "YW5nL1Rocm93YWJsZTtMAA1kZXRhaWxNZXNzYWdldAASTGphdmEvbGFuZy9T" + + "dHJpbmc7WwAKc3RhY2tUcmFjZXQAHltMamF2YS9sYW5nL1N0YWNrVHJhY2VF" + + "bGVtZW50O0wAFHN1cHByZXNzZWRFeGNlcHRpb25zdAAQTGphdmEvdXRpbC9M" + + "aXN0O3hwcHB1cgAeW0xqYXZhLmxhbmcuU3RhY2tUcmFjZUVsZW1lbnQ7AkYq" + + "PDz9IjkCAAB4cAAAAAFzcgAbamF2YS5sYW5nLlN0YWNrVHJhY2VFbGVtZW50" + + "YQnFmiY23YUCAAhCAAZmb3JtYXRJAApsaW5lTnVtYmVyTAAPY2xhc3NMb2Fk" + + "ZXJOYW1lcQB+AAVMAA5kZWNsYXJpbmdDbGFzc3EAfgAFTAAIZmlsZU5hbWVx" + + "AH4ABUwACm1ldGhvZE5hbWVxAH4ABUwACm1vZHVsZU5hbWVxAH4ABUwADW1v" + + "ZHVsZVZlcnNpb25xAH4ABXhwAQAAABd0AANhcHB0AARUZXN0dAAJVGVzdC5q" + + "YXZhdAAEbWFpbnBwc3IAH2phdmEudXRpbC5Db2xsZWN0aW9ucyRFbXB0eUxp" + + "c3R6uBe0PKee3gIAAHhweHNyABNqYXZhLmlvLklPRXhjZXB0aW9ubIBzZGUl" + + "8KsCAAB4cQB+AAJxAH4AFHQAA2Zvb3VxAH4ACQAAAAFzcQB+AAsBAAAAF3EA" + + "fgANcQB+AA5xAH4AD3EAfgAQcHBxAH4AEng="; + + private static Map SERIALIZED_DATA = Map.of( + EIIE_OLD_VERSION, new ExceptionInInitializerError(new NullPointerException("foo")), + CNFE_OLD_VERSION, new ClassNotFoundException("bar", new IOException("reading class file")), + ITE1_OLD_VERSION, new InvocationTargetException(new Error("foo"), "bar"), + ITE2_OLD_VERSION, new InvocationTargetException(new Error("goo")), + UTE1_OLD_VERSION, new UndeclaredThrowableException(new IllegalArgumentException("foo"), "bar"), + UTE2_OLD_VERSION, new UndeclaredThrowableException(new IllegalArgumentException("goo")), + PAE_OLD_VERSION, new PrivilegedActionException(new IOException("foo")) + ); }