< prev index next >

jdk/src/java.base/share/classes/java/lang/StackTraceElement.java

Print this page

        

*** 28,38 **** import jdk.internal.loader.BuiltinClassLoader; import jdk.internal.misc.SharedSecrets; import jdk.internal.misc.VM; import jdk.internal.module.ModuleHashes; - import java.lang.module.ModuleDescriptor.Version; import java.lang.reflect.Layer; import java.lang.reflect.Module; import java.util.HashSet; import java.util.Objects; import java.util.Optional; --- 28,37 ----
*** 49,73 **** * * @since 1.4 * @author Josh Bloch */ public final class StackTraceElement implements java.io.Serializable { ! // This field is set to the compacted String representation used ! // by StackTraceElement::toString and stored in serial form. // ! // This field is of Object type. VM initially sets this field to ! // the Class object of the declaring class to build the compacted string. ! private Object classOrLoaderModuleClassName; // Normally initialized by VM private String classLoaderName; private String moduleName; private String moduleVersion; private String declaringClass; private String methodName; private String fileName; private int lineNumber; /** * Creates a stack trace element representing the specified execution * point. The {@link #getModuleName module name} and {@link * #getModuleVersion module version} of the stack trace element will --- 48,74 ---- * * @since 1.4 * @author Josh Bloch */ public final class StackTraceElement implements java.io.Serializable { ! ! // For Throwables and StackWalker, the VM initially sets this field to a ! // reference to the declaring Class. The Class reference is used to ! // construct the 'format' bitmap, and then is cleared. // ! // For STEs constructed using the public constructors, this field is not used. ! private transient Class<?> declaringClassObject; // Normally initialized by VM private String classLoaderName; private String moduleName; private String moduleVersion; private String declaringClass; private String methodName; private String fileName; private int lineNumber; + private byte format = 0; // Default to show all /** * Creates a stack trace element representing the specified execution * point. The {@link #getModuleName module name} and {@link * #getModuleVersion module version} of the stack trace element will
*** 254,266 **** public boolean isNativeMethod() { return lineNumber == -2; } /** ! * Returns a string representation of this stack trace element. The ! * format of this string depends on the implementation, but the following ! * examples may be regarded as typical: * <ul> * <li> * "{@code com.foo.loader/foo@9.0/com.foo.Main.run(Main.java:101)}" * - See the description below. * </li> --- 255,268 ---- public boolean isNativeMethod() { return lineNumber == -2; } /** ! * Returns a string representation of this stack trace element. ! * ! * @apiNote The format of this string depends on the implementation, but the ! * following examples may be regarded as typical: * <ul> * <li> * "{@code com.foo.loader/foo@9.0/com.foo.Main.run(Main.java:101)}" * - See the description below. * </li>
*** 307,343 **** * * <p> If a class is defined in an <em>unnamed module</em> * then the second element is omitted as shown in * "{@code com.foo.loader//com.foo.bar.App.run(App.java:12)}". * ! * If the class loader is a <a href="ClassLoader.html#builtinLoaders"> * built-in class loader</a> or is not named then the first element * and its following {@code "/"} are omitted as shown in * "{@code acme@2.1/org.acme.Lib.test(Lib.java:80)}". * If the first element is omitted and the module is an unnamed module, * the second element and its following {@code "/"} are also omitted * as shown in "{@code MyClass.mash(MyClass.java:9)}". * * @see Throwable#printStackTrace() */ public String toString() { ! String s = buildLoaderModuleClassName(); ! if (s == null) { ! // all elements will be included ! s = ""; ! if (classLoaderName != null && !classLoaderName.isEmpty()) { s += classLoaderName + "/"; } if (moduleName != null && !moduleName.isEmpty()) { s += moduleName; ! if (moduleVersion != null && !moduleVersion.isEmpty()) { s += "@" + moduleVersion; } } s = s.isEmpty() ? declaringClass : s + "/" + declaringClass; - } return s + "." + methodName + "(" + (isNativeMethod() ? "Native Method)" : (fileName != null && lineNumber >= 0 ? fileName + ":" + lineNumber + ")" : --- 309,350 ---- * * <p> If a class is defined in an <em>unnamed module</em> * then the second element is omitted as shown in * "{@code com.foo.loader//com.foo.bar.App.run(App.java:12)}". * ! * <p> If the class loader is a <a href="ClassLoader.html#builtinLoaders"> * built-in class loader</a> or is not named then the first element * and its following {@code "/"} are omitted as shown in * "{@code acme@2.1/org.acme.Lib.test(Lib.java:80)}". * If the first element is omitted and the module is an unnamed module, * the second element and its following {@code "/"} are also omitted * as shown in "{@code MyClass.mash(MyClass.java:9)}". * + * <p> The {@code toString} method may return two different values on two + * {@code StackTraceElement} instances that are + * {@linkplain #equals(Object) equal}, for example one created via the + * constructor, and one obtained from {@link java.lang.Throwable} or + * {@link java.lang.StackWalker.StackFrame}, where an implementation may + * choose to omit some element in the returned string. + * * @see Throwable#printStackTrace() */ public String toString() { ! String s = ""; ! if (!dropClassLoaderName() && classLoaderName != null && ! !classLoaderName.isEmpty()) { s += classLoaderName + "/"; } if (moduleName != null && !moduleName.isEmpty()) { s += moduleName; ! if (!dropModuleVersion() && moduleVersion != null && ! !moduleVersion.isEmpty()) { s += "@" + moduleVersion; } } s = s.isEmpty() ? declaringClass : s + "/" + declaringClass; return s + "." + methodName + "(" + (isNativeMethod() ? "Native Method)" : (fileName != null && lineNumber >= 0 ? fileName + ":" + lineNumber + ")" :
*** 395,465 **** return result; } /** ! * Build the compacted String representation to be returned by ! * toString method from the declaring Class object. ! */ ! synchronized String buildLoaderModuleClassName() { ! if (classOrLoaderModuleClassName == null) ! return null; ! ! if (classOrLoaderModuleClassName instanceof Class) { ! Class<?> cls = (Class<?>)classOrLoaderModuleClassName; ! classOrLoaderModuleClassName = toLoaderModuleClassName(cls); ! } ! return (String)classOrLoaderModuleClassName; ! } ! ! /** ! * Returns <loader>/<module>/<fully-qualified-classname> string ! * representation of the given class. ! * <p> ! * If the module is a non-upgradeable JDK module then omit ! * its version string. ! * <p> ! * If the loader has no name, or if the loader is one of the built-in ! * loaders (`boot`, `platform`, or `app`) then drop the first element ! * (`<loader>/`). * <p> ! * If the first element has been dropped and the module is unnamed ! * then drop the second element (`<module>/`). * <p> ! * If the first element is not dropped and the module is unnamed ! * then drop `<module>`. */ ! private static String toLoaderModuleClassName(Class<?> cls) { ClassLoader loader = cls.getClassLoader0(); Module m = cls.getModule(); // First element - class loader name // Call package-private ClassLoader::name method ! String s = ""; ! if (loader != null && loader.name() != null && ! !(loader instanceof BuiltinClassLoader)) { ! s = loader.name() + "/"; } // Second element - module name and version ! if (m != null && m.isNamed()) { ! s += m.getName(); ! // Include version if it is a user module or upgradeable module ! // ! // If it is JDK non-upgradeable module which is recorded ! // in the hashes in java.base, omit the version. ! if (!isHashedInJavaBase(m)) { ! Optional<Version> ov = m.getDescriptor().version(); ! if (ov.isPresent()) { ! String version = "@" + ov.get().toString(); ! s += version; } } } ! // fully-qualified class name ! return s.isEmpty() ? cls.getName() : s + "/" + cls.getName(); } /** * Returns true if the module is hashed with java.base. * <p> --- 402,458 ---- return result; } /** ! * Called from of() methods to set the 'format' bitmap using the Class ! * reference stored in declaringClassObject, and then clear the reference. ! * * <p> ! * If the module is a non-upgradeable JDK module, then set ! * JDK_NON_UPGRADEABLE_MODULE to omit its version string. * <p> ! * If the loader is one of the built-in loaders (`boot`, `platform`, or `app`) ! * then set BUILTIN_CLASS_LOADER to omit the first element (`<loader>/`). */ ! private synchronized void computeFormat() { ! try { ! Class<?> cls = (Class<?>) declaringClassObject; ClassLoader loader = cls.getClassLoader0(); Module m = cls.getModule(); + byte bits = 0; // First element - class loader name // Call package-private ClassLoader::name method ! ! if (loader instanceof BuiltinClassLoader) { ! bits |= BUILTIN_CLASS_LOADER; } // Second element - module name and version ! ! // Omit if is a JDK non-upgradeable module (recorded in the hashes ! // in java.base) ! if (isHashedInJavaBase(m)) { ! bits |= JDK_NON_UPGRADEABLE_MODULE; ! } ! format = bits; ! } finally { ! // Class reference no longer needed, clear it ! declaringClassObject = null; } } + + private static final byte BUILTIN_CLASS_LOADER = 0x1; + private static final byte JDK_NON_UPGRADEABLE_MODULE = 0x2; + + private boolean dropClassLoaderName() { + return (format & BUILTIN_CLASS_LOADER) == BUILTIN_CLASS_LOADER; } ! private boolean dropModuleVersion() { ! return (format & JDK_NON_UPGRADEABLE_MODULE) == JDK_NON_UPGRADEABLE_MODULE; } /** * Returns true if the module is hashed with java.base. * <p>
*** 517,527 **** // VM to fill in StackTraceElement initStackTraceElements(stackTrace, x); // ensure the proper StackTraceElement initialization for (StackTraceElement ste : stackTrace) { ! ste.buildLoaderModuleClassName(); } return stackTrace; } /* --- 510,520 ---- // VM to fill in StackTraceElement initStackTraceElements(stackTrace, x); // ensure the proper StackTraceElement initialization for (StackTraceElement ste : stackTrace) { ! ste.computeFormat(); } return stackTrace; } /*
*** 529,539 **** */ static StackTraceElement of(StackFrameInfo sfi) { StackTraceElement ste = new StackTraceElement(); initStackTraceElement(ste, sfi); ! ste.buildLoaderModuleClassName(); return ste; } /* * Sets the given stack trace elements with the backtrace --- 522,532 ---- */ static StackTraceElement of(StackFrameInfo sfi) { StackTraceElement ste = new StackTraceElement(); initStackTraceElement(ste, sfi); ! ste.computeFormat(); return ste; } /* * Sets the given stack trace elements with the backtrace
< prev index next >