< prev index next >

src/java.base/share/classes/java/lang/ClassLoader.java

Print this page

        

*** 58,67 **** --- 58,68 ---- import java.util.function.Supplier; import java.util.stream.Stream; import java.util.stream.StreamSupport; import jdk.internal.loader.BuiltinClassLoader; + import jdk.internal.loader.ClassLoaderValue; import jdk.internal.perf.PerfCounter; import jdk.internal.loader.BootLoader; import jdk.internal.loader.ClassLoaders; import jdk.internal.misc.Unsafe; import jdk.internal.misc.VM;
*** 2968,2977 **** --- 2969,3065 ---- // Retrieves the assertion directives from the VM. private static native AssertionStatusDirectives retrieveDirectives(); + // A RuntimeException that acts as a substitute for the original exception + // (checked or unchecked) and mimics the original exception in every aspect + // except it's type. + private static class InitExceptionSubst extends RuntimeException { + static final ClassLoaderValue<InitExceptionSubst> INIT_EXCEPTIONS = + new ClassLoaderValue<>(); + + private static final long serialVersionUID = 1; + + private final String threadName; + private final long time; + private final String originalExceptionClassName; + private final String localizedMessage; + + InitExceptionSubst(Throwable originalException, boolean top) { + super(originalException.getMessage()); + + this.threadName = top ? Thread.currentThread().getName() : null; + this.time = top ? System.currentTimeMillis() : 0L; + this.originalExceptionClassName = originalException.getClass().getName(); + this.localizedMessage = originalException.getLocalizedMessage(); + + // substitute originalException's cause + Throwable cause = originalException.getCause(); + initCause(cause == null ? null : new InitExceptionSubst(cause, false)); + + // substitute originalException's suppressed exceptions if any + for (Throwable suppressed : originalException.getSuppressed()) { + addSuppressed(new InitExceptionSubst(suppressed, false)); + } + + // inherit stack trace elements from originalException + setStackTrace(originalException.getStackTrace()); + } + + @Override + public Throwable fillInStackTrace() { + // don't need our backtrace - + // will inherit stack trace elements from originalException + return this; + } + + @Override + public String getLocalizedMessage() { + return localizedMessage; + } + + @Override + public String toString() { + // Emulate toString() method as if called upon originalException + String message = getLocalizedMessage(); + return time == 0L + ? (message != null + ? originalExceptionClassName + ": " + message + : originalExceptionClassName + ) + : (message != null + ? originalExceptionClassName + ": " + + (System.currentTimeMillis() - time) + " ms ago in thread " + + threadName + ": " + message + : originalExceptionClassName + ": " + + (System.currentTimeMillis() - time) + " ms ago in thread " + + threadName + ); + } + } + + // Called by the VM as notification just before exception + // (typically ExceptionInInitializerError) is thrown after unsuccessful + // attempt to initialize the class for the 1st time + private static void recordInitException(Class<?> clazz, Throwable exc) { + InitExceptionSubst.INIT_EXCEPTIONS + .sub(clazz) + .putIfAbsent(clazz.getClassLoader0(), new InitExceptionSubst(exc, true)); + } + + // Called by the vm to throw NoClassDefFoundError as a consequence of + // class re-initialization attempt after the 1st class initialization + // attempt failed + private static void throwReinitException(Class<?> clazz) { + InitExceptionSubst cause = InitExceptionSubst.INIT_EXCEPTIONS + .sub(clazz) + .get(clazz.getClassLoader0()); + throw (Error) new NoClassDefFoundError( + "Could not initialize " + clazz).initCause(cause); + } + // -- Misc -- /** * Returns the ConcurrentHashMap used as a storage for ClassLoaderValue(s) * associated with this ClassLoader, creating it if it doesn't already exist.
< prev index next >