< prev index next >
jdk/src/java.base/share/classes/java/lang/StackTraceElement.java
Print this page
@@ -28,11 +28,10 @@
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;
@@ -49,25 +48,27 @@
*
* @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.
+
+ // 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.
//
- // 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;
+ // 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,13 +255,14 @@
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:
+ * 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,37 +309,42 @@
*
* <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">
+ * <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 = buildLoaderModuleClassName();
- if (s == null) {
- // all elements will be included
- s = "";
- if (classLoaderName != null && !classLoaderName.isEmpty()) {
+ String s = "";
+ if (!dropClassLoaderName() && classLoaderName != null &&
+ !classLoaderName.isEmpty()) {
s += classLoaderName + "/";
}
if (moduleName != null && !moduleName.isEmpty()) {
s += moduleName;
- if (moduleVersion != null && !moduleVersion.isEmpty()) {
+ 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,71 +402,57 @@
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>/`).
+ * Called from of() methods to set the 'format' bitmap using the Class
+ * reference stored in declaringClassObject, and then clear the reference.
+ *
* <p>
- * If the first element has been dropped and the module is unnamed
- * then drop the second element (`<module>/`).
+ * If the module is a non-upgradeable JDK module, then set
+ * JDK_NON_UPGRADEABLE_MODULE to omit its version string.
* <p>
- * If the first element is not dropped and the module is unnamed
- * then drop `<module>`.
+ * 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 static String toLoaderModuleClassName(Class<?> cls) {
+ 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
- String s = "";
- if (loader != null && loader.name() != null &&
- !(loader instanceof BuiltinClassLoader)) {
- s = loader.name() + "/";
+
+ if (loader instanceof BuiltinClassLoader) {
+ bits |= BUILTIN_CLASS_LOADER;
}
// 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;
+
+ // 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;
}
- // fully-qualified class name
- return s.isEmpty() ? cls.getName() : s + "/" + cls.getName();
+ 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,11 +510,11 @@
// VM to fill in StackTraceElement
initStackTraceElements(stackTrace, x);
// ensure the proper StackTraceElement initialization
for (StackTraceElement ste : stackTrace) {
- ste.buildLoaderModuleClassName();
+ ste.computeFormat();
}
return stackTrace;
}
/*
@@ -529,11 +522,11 @@
*/
static StackTraceElement of(StackFrameInfo sfi) {
StackTraceElement ste = new StackTraceElement();
initStackTraceElement(ste, sfi);
- ste.buildLoaderModuleClassName();
+ ste.computeFormat();
return ste;
}
/*
* Sets the given stack trace elements with the backtrace
< prev index next >