< 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 >