8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.lang; 27 28 import java.util.Objects; 29 30 /** 31 * An element in a stack trace, as returned by {@link 32 * Throwable#getStackTrace()}. Each element represents a single stack frame. 33 * All stack frames except for the one at the top of the stack represent 34 * a method invocation. The frame at the top of the stack represents the 35 * execution point at which the stack trace was generated. Typically, 36 * this is the point at which the throwable corresponding to the stack trace 37 * was created. 38 * 39 * @since 1.4 40 * @author Josh Bloch 41 */ 42 public final class StackTraceElement implements java.io.Serializable { 43 // Normally initialized by VM (public constructor added in 1.5) 44 private String moduleName; 45 private String moduleVersion; 46 private String declaringClass; 47 private String methodName; 48 private String fileName; 49 private int lineNumber; 50 51 /** 52 * Creates a stack trace element representing the specified execution 53 * point. The {@link #getModuleName module name} and {@link 54 * #getModuleVersion module version} of the stack trace element will 55 * be {@code null}. 56 * 57 * @param declaringClass the fully qualified name of the class containing 58 * the execution point represented by the stack trace element 59 * @param methodName the name of the method containing the execution point 60 * represented by the stack trace element 61 * @param fileName the name of the file containing the execution point 62 * represented by the stack trace element, or {@code null} if 63 * this information is unavailable 64 * @param lineNumber the line number of the source line containing the 65 * execution point represented by this stack trace element, or 66 * a negative number if this information is unavailable. A value 67 * of -2 indicates that the method containing the execution point 68 * is a native method 69 * @throws NullPointerException if {@code declaringClass} or 70 * {@code methodName} is null 71 * @since 1.5 72 */ 73 public StackTraceElement(String declaringClass, String methodName, 74 String fileName, int lineNumber) { 75 this(null, null, declaringClass, methodName, fileName, lineNumber); 76 } 77 78 /** 79 * Creates a stack trace element representing the specified execution 80 * point. 81 * 82 * @param moduleName the module name if the class containing the 83 * execution point represented by the stack trace is in a named 84 * module; can be {@code null} 85 * @param moduleVersion the module version if the class containing the 86 * execution point represented by the stack trace is in a named 87 * module that has a version; can be {@code null} 88 * @param declaringClass the fully qualified name of the class containing 89 * the execution point represented by the stack trace element 90 * @param methodName the name of the method containing the execution point 91 * represented by the stack trace element 92 * @param fileName the name of the file containing the execution point 93 * represented by the stack trace element, or {@code null} if 94 * this information is unavailable 95 * @param lineNumber the line number of the source line containing the 96 * execution point represented by this stack trace element, or 97 * a negative number if this information is unavailable. A value 98 * of -2 indicates that the method containing the execution point 99 * is a native method 100 * @throws NullPointerException if {@code declaringClass} is {@code null} 101 * or {@code methodName} is {@code null} 102 * @since 9 103 */ 104 public StackTraceElement(String moduleName, String moduleVersion, 105 String declaringClass, String methodName, 106 String fileName, int lineNumber) { 107 this.moduleName = moduleName; 108 this.moduleVersion = moduleVersion; 109 this.declaringClass = Objects.requireNonNull(declaringClass, "Declaring class is null"); 110 this.methodName = Objects.requireNonNull(methodName, "Method name is null"); 111 this.fileName = fileName; 112 this.lineNumber = lineNumber; 113 } 114 115 116 /** 117 * Creates an empty stack frame element to be filled in by Throwable. 118 */ 119 StackTraceElement() { } 120 121 /** 122 * Returns the name of the source file containing the execution point 123 * represented by this stack trace element. Generally, this corresponds 124 * to the {@code SourceFile} attribute of the relevant {@code class} 125 * file (as per <i>The Java Virtual Machine Specification</i>, Section 126 * 4.7.7). In some systems, the name may refer to some source code unit 127 * other than a file, such as an entry in source repository. 128 * 129 * @return the name of the file containing the execution point 130 * represented by this stack trace element, or {@code null} if 131 * this information is unavailable. 132 */ 133 public String getFileName() { 134 return fileName; 135 } 136 137 /** 138 * Returns the line number of the source line containing the execution 139 * point represented by this stack trace element. Generally, this is 161 */ 162 public String getModuleName() { 163 return moduleName; 164 } 165 166 /** 167 * Returns the module version of the module containing the execution point 168 * represented by this stack trace element. 169 * 170 * @return the module version of the {@code Module} containing the execution 171 * point represented by this stack trace element; {@code null} 172 * if the module version is not available. 173 * @since 9 174 * @see java.lang.module.ModuleDescriptor.Version 175 */ 176 public String getModuleVersion() { 177 return moduleVersion; 178 } 179 180 /** 181 * Returns the fully qualified name of the class containing the 182 * execution point represented by this stack trace element. 183 * 184 * @return the fully qualified name of the {@code Class} containing 185 * the execution point represented by this stack trace element. 186 */ 187 public String getClassName() { 188 return declaringClass; 189 } 190 191 /** 192 * Returns the name of the method containing the execution point 193 * represented by this stack trace element. If the execution point is 194 * contained in an instance or class initializer, this method will return 195 * the appropriate <i>special method name</i>, {@code <init>} or 196 * {@code <clinit>}, as per Section 3.9 of <i>The Java Virtual 197 * Machine Specification</i>. 198 * 199 * @return the name of the method containing the execution point 200 * represented by this stack trace element. 203 return methodName; 204 } 205 206 /** 207 * Returns true if the method containing the execution point 208 * represented by this stack trace element is a native method. 209 * 210 * @return {@code true} if the method containing the execution point 211 * represented by this stack trace element is a native method. 212 */ 213 public boolean isNativeMethod() { 214 return lineNumber == -2; 215 } 216 217 /** 218 * Returns a string representation of this stack trace element. The 219 * format of this string depends on the implementation, but the following 220 * examples may be regarded as typical: 221 * <ul> 222 * <li> 223 * {@code "MyClass.mash(my.module@9.0/MyClass.java:101)"} - Here, 224 * {@code "MyClass"} is the <i>fully-qualified name</i> of the class 225 * containing the execution point represented by this stack trace element, 226 * {@code "mash"} is the name of the method containing the execution 227 * point, {@code "my.module"} is the module name, {@code "9.0"} is the 228 * module version, and {@code "101"} is the line number of the source 229 * line containing the execution point. 230 * <li> 231 * {@code "MyClass.mash(my.module@9.0/MyClass.java)"} - As above, but the 232 * line number is unavailable. 233 * <li> 234 * {@code "MyClass.mash(my.module@9.0/Unknown Source)"} - As above, but 235 * neither the file name nor the line number are available. 236 * <li> 237 * {@code "MyClass.mash(my.module@9.0/Native Method)"} - As above, but 238 * neither the file name nor the line number are available, and the 239 * method containing the execution point is known to be a native method. 240 * </ul> 241 * If the execution point is not in a named module, {@code "my.module@9.0/"} 242 * will be omitted from the above. 243 * 244 * @see Throwable#printStackTrace() 245 */ 246 public String toString() { 247 String mid = ""; 248 if (moduleName != null) { 249 mid = moduleName; 250 if (moduleVersion != null) 251 mid += "@" + moduleVersion; 252 mid += "/"; 253 } 254 return getClassName() + "." + methodName + "(" + mid + 255 (isNativeMethod() ? "Native Method)" : 256 (fileName != null && lineNumber >= 0 ? 257 fileName + ":" + lineNumber + ")" : 258 (fileName != null ? ""+fileName+")" : "Unknown Source)"))); 259 } 260 261 /** 262 * Returns true if the specified object is another 263 * {@code StackTraceElement} instance representing the same execution 264 * point as this instance. Two stack trace elements {@code a} and 265 * {@code b} are equal if and only if: 266 * <pre>{@code 267 * equals(a.getFileName(), b.getFileName()) && 268 * a.getLineNumber() == b.getLineNumber()) && 269 * equals(a.getModuleName(), b.getModuleName()) && 270 * equals(a.getModuleVersion(), b.getModuleVersion()) && 271 * equals(a.getClassName(), b.getClassName()) && 272 * equals(a.getMethodName(), b.getMethodName()) 273 * }</pre> 274 * where {@code equals} has the semantics of {@link 275 * java.util.Objects#equals(Object, Object) Objects.equals}. 276 * 277 * @param obj the object to be compared with this stack trace element. 278 * @return true if the specified object is another 279 * {@code StackTraceElement} instance representing the same 280 * execution point as this instance. 281 */ 282 public boolean equals(Object obj) { 283 if (obj==this) 284 return true; 285 if (!(obj instanceof StackTraceElement)) 286 return false; 287 StackTraceElement e = (StackTraceElement)obj; 288 return e.declaringClass.equals(declaringClass) && 289 Objects.equals(moduleName, e.moduleName) && 290 Objects.equals(moduleVersion, e.moduleVersion) && 291 e.lineNumber == lineNumber && 292 Objects.equals(methodName, e.methodName) && 293 Objects.equals(fileName, e.fileName); 294 } 295 296 /** 297 * Returns a hash code value for this stack trace element. 298 */ 299 public int hashCode() { 300 int result = 31*declaringClass.hashCode() + methodName.hashCode(); 301 result = 31*result + Objects.hashCode(moduleName); 302 result = 31*result + Objects.hashCode(moduleVersion); 303 result = 31*result + Objects.hashCode(fileName); 304 result = 31*result + lineNumber; 305 return result; 306 } 307 308 private static final long serialVersionUID = 6992337162326171013L; 309 } | 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.lang; 27 28 import jdk.internal.loader.BuiltinClassLoader; 29 import jdk.internal.misc.SharedSecrets; 30 import jdk.internal.misc.VM; 31 import jdk.internal.module.ModuleHashes; 32 33 import java.lang.module.ModuleDescriptor.Version; 34 import java.lang.reflect.Layer; 35 import java.lang.reflect.Module; 36 import java.util.HashSet; 37 import java.util.Objects; 38 import java.util.Optional; 39 import java.util.Set; 40 41 /** 42 * An element in a stack trace, as returned by {@link 43 * Throwable#getStackTrace()}. Each element represents a single stack frame. 44 * All stack frames except for the one at the top of the stack represent 45 * a method invocation. The frame at the top of the stack represents the 46 * execution point at which the stack trace was generated. Typically, 47 * this is the point at which the throwable corresponding to the stack trace 48 * was created. 49 * 50 * @since 1.4 51 * @author Josh Bloch 52 */ 53 public final class StackTraceElement implements java.io.Serializable { 54 // This field is set to the compacted String representation used 55 // by StackTraceElement::toString and stored in serial form. 56 // 57 // This field is of Object type. VM initially sets this field to 58 // the Class object of the declaring class to build the compacted string. 59 private Object classOrLoaderModuleClassName; 60 61 // Normally initialized by VM 62 private String classLoaderName; 63 private String moduleName; 64 private String moduleVersion; 65 private String declaringClass; 66 private String methodName; 67 private String fileName; 68 private int lineNumber; 69 70 /** 71 * Creates a stack trace element representing the specified execution 72 * point. The {@link #getModuleName module name} and {@link 73 * #getModuleVersion module version} of the stack trace element will 74 * be {@code null}. 75 * 76 * @param declaringClass the fully qualified name of the class containing 77 * the execution point represented by the stack trace element 78 * @param methodName the name of the method containing the execution point 79 * represented by the stack trace element 80 * @param fileName the name of the file containing the execution point 81 * represented by the stack trace element, or {@code null} if 82 * this information is unavailable 83 * @param lineNumber the line number of the source line containing the 84 * execution point represented by this stack trace element, or 85 * a negative number if this information is unavailable. A value 86 * of -2 indicates that the method containing the execution point 87 * is a native method 88 * @throws NullPointerException if {@code declaringClass} or 89 * {@code methodName} is null 90 * @since 1.5 91 */ 92 public StackTraceElement(String declaringClass, String methodName, 93 String fileName, int lineNumber) { 94 this(null, null, null, declaringClass, methodName, fileName, lineNumber); 95 } 96 97 /** 98 * Creates a stack trace element representing the specified execution 99 * point. 100 * 101 * @param classLoaderName the class loader name if the class loader of 102 * the class containing the execution point represented by 103 * the stack trace is named; otherwise {@code null} 104 * @param moduleName the module name if the class containing the 105 * execution point represented by the stack trace is in a named 106 * module; otherwise {@code null} 107 * @param moduleVersion the module version if the class containing the 108 * execution point represented by the stack trace is in a named 109 * module that has a version; otherwise {@code null} 110 * @param declaringClass the fully qualified name of the class containing 111 * the execution point represented by the stack trace element 112 * @param methodName the name of the method containing the execution point 113 * represented by the stack trace element 114 * @param fileName the name of the file containing the execution point 115 * represented by the stack trace element, or {@code null} if 116 * this information is unavailable 117 * @param lineNumber the line number of the source line containing the 118 * execution point represented by this stack trace element, or 119 * a negative number if this information is unavailable. A value 120 * of -2 indicates that the method containing the execution point 121 * is a native method 122 * 123 * @throws IllegalArgumentException if {@code classLoaderName}, 124 * {@code moduleName} or {@code moduleVersion} is an empty string 125 * @throws NullPointerException if {@code declaringClass} is {@code null} 126 * or {@code methodName} is {@code null} 127 * 128 * @since 9 129 */ 130 public StackTraceElement(String classLoaderName, 131 String moduleName, String moduleVersion, 132 String declaringClass, String methodName, 133 String fileName, int lineNumber) { 134 this.classLoaderName = requireNonEmpty(classLoaderName, "classLoaderName"); 135 this.moduleName = requireNonEmpty(moduleName, "moduleName"); 136 this.moduleVersion = requireNonEmpty(moduleVersion, "moduleVersion"); 137 this.declaringClass = Objects.requireNonNull(declaringClass, "Declaring class is null"); 138 this.methodName = Objects.requireNonNull(methodName, "Method name is null"); 139 this.fileName = fileName; 140 this.lineNumber = lineNumber; 141 } 142 143 private static String requireNonEmpty(String name, String paramName) { 144 if (name != null && name.isEmpty()) { 145 throw new IllegalArgumentException(paramName + 146 " must be non-empty or null"); 147 } 148 return name; 149 } 150 151 /* 152 * Private constructor for the factory methods to create StackTraceElement 153 * for Throwable and StackFrameInfo 154 */ 155 private StackTraceElement() {} 156 157 /** 158 * Returns the name of the source file containing the execution point 159 * represented by this stack trace element. Generally, this corresponds 160 * to the {@code SourceFile} attribute of the relevant {@code class} 161 * file (as per <i>The Java Virtual Machine Specification</i>, Section 162 * 4.7.7). In some systems, the name may refer to some source code unit 163 * other than a file, such as an entry in source repository. 164 * 165 * @return the name of the file containing the execution point 166 * represented by this stack trace element, or {@code null} if 167 * this information is unavailable. 168 */ 169 public String getFileName() { 170 return fileName; 171 } 172 173 /** 174 * Returns the line number of the source line containing the execution 175 * point represented by this stack trace element. Generally, this is 197 */ 198 public String getModuleName() { 199 return moduleName; 200 } 201 202 /** 203 * Returns the module version of the module containing the execution point 204 * represented by this stack trace element. 205 * 206 * @return the module version of the {@code Module} containing the execution 207 * point represented by this stack trace element; {@code null} 208 * if the module version is not available. 209 * @since 9 210 * @see java.lang.module.ModuleDescriptor.Version 211 */ 212 public String getModuleVersion() { 213 return moduleVersion; 214 } 215 216 /** 217 * Returns the name of the class loader of the class containing the 218 * execution point represented by this stack trace element. 219 * 220 * @return the name of the class loader of the class containing the execution 221 * point represented by this stack trace element; {@code null} 222 * if the class loader is not named. 223 * 224 * @since 9 225 * @see java.lang.ClassLoader#getName() 226 */ 227 public String getClassLoaderName() { 228 return classLoaderName; 229 } 230 231 /** 232 * Returns the fully qualified name of the class containing the 233 * execution point represented by this stack trace element. 234 * 235 * @return the fully qualified name of the {@code Class} containing 236 * the execution point represented by this stack trace element. 237 */ 238 public String getClassName() { 239 return declaringClass; 240 } 241 242 /** 243 * Returns the name of the method containing the execution point 244 * represented by this stack trace element. If the execution point is 245 * contained in an instance or class initializer, this method will return 246 * the appropriate <i>special method name</i>, {@code <init>} or 247 * {@code <clinit>}, as per Section 3.9 of <i>The Java Virtual 248 * Machine Specification</i>. 249 * 250 * @return the name of the method containing the execution point 251 * represented by this stack trace element. 254 return methodName; 255 } 256 257 /** 258 * Returns true if the method containing the execution point 259 * represented by this stack trace element is a native method. 260 * 261 * @return {@code true} if the method containing the execution point 262 * represented by this stack trace element is a native method. 263 */ 264 public boolean isNativeMethod() { 265 return lineNumber == -2; 266 } 267 268 /** 269 * Returns a string representation of this stack trace element. The 270 * format of this string depends on the implementation, but the following 271 * examples may be regarded as typical: 272 * <ul> 273 * <li> 274 * "{@code com.foo.loader/foo@9.0/com.foo.Main.run(Main.java:101)}" 275 * - See the description below. 276 * </li> 277 * <li> 278 * "{@code com.foo.loader/foo@9.0/com.foo.Main.run(Main.java)}" 279 * - The line number is unavailable. 280 * </li> 281 * <li> 282 * "{@code com.foo.loader/foo@9.0/com.foo.Main.run(Unknown Source)}" 283 * - Neither the file name nor the line number is available. 284 * </li> 285 * <li> 286 * "{@code com.foo.loader/foo@9.0/com.foo.Main.run(Native Method)}" 287 * - The method containing the execution point is a native method. 288 * </li> 289 * <li> 290 * "{@code com.foo.loader//com.foo.bar.App.run(App.java:12)}" 291 * - The class of the execution point is defined in the unnamed module of 292 * the class loader named {@code com.foo.loader}. 293 * </li> 294 * <li> 295 * "{@code acme@2.1/org.acme.Lib.test(Lib.java:80)}" 296 * - The class of the execution point is defined in {@code acme} module 297 * loaded by by a built-in class loader such as the application class loader. 298 * </li> 299 * <li> 300 * "{@code MyClass.mash(MyClass.java:9)}" 301 * - {@code MyClass} class is on the application class path. 302 * </li> 303 * </ul> 304 * 305 * <p> The first example shows a stack trace element consisting of 306 * three elements, each separated by {@code "/"} followed with 307 * the source file name and the line number of the source line 308 * containing the execution point. 309 * 310 * The first element "{@code com.foo.loader}" is 311 * the name of the class loader. The second element "{@code foo@9.0}" 312 * is the module name and version. The third element is the method 313 * containing the execution point; "{@code com.foo.Main"}" is the 314 * fully-qualified class name and "{@code run}" is the name of the method. 315 * "{@code Main.java}" is the source file name and "{@code 101}" is 316 * the line number. 317 * 318 * <p> If a class is defined in an <em>unnamed module</em> 319 * then the second element is omitted as shown in 320 * "{@code com.foo.loader//com.foo.bar.App.run(App.java:12)}". 321 * 322 * If the class loader is a <a href="ClassLoader.html#builtinLoaders"> 323 * built-in class loader</a> or is not named then the first element 324 * and its following {@code "/"} are omitted as shown in 325 * "{@code acme@2.1/org.acme.Lib.test(Lib.java:80)}". 326 * If the first element is omitted and the module is an unnamed module, 327 * the second element and its following {@code "/"} are also omitted 328 * as shown in "{@code MyClass.mash(MyClass.java:9)}". 329 * 330 * @see Throwable#printStackTrace() 331 */ 332 public String toString() { 333 String s = buildLoaderModuleClassName(); 334 if (s == null) { 335 // all elements will be included 336 s = ""; 337 if (classLoaderName != null && !classLoaderName.isEmpty()) { 338 s += classLoaderName + "/"; 339 } 340 if (moduleName != null && !moduleName.isEmpty()) { 341 s += moduleName; 342 } 343 if (moduleVersion != null && !moduleVersion.isEmpty()) { 344 s += "@" + moduleVersion; 345 } 346 s = s.isEmpty() ? declaringClass : s + "/" + declaringClass; 347 } 348 349 return s + "." + methodName + "(" + 350 (isNativeMethod() ? "Native Method)" : 351 (fileName != null && lineNumber >= 0 ? 352 fileName + ":" + lineNumber + ")" : 353 (fileName != null ? ""+fileName+")" : "Unknown Source)"))); 354 } 355 356 /** 357 * Returns true if the specified object is another 358 * {@code StackTraceElement} instance representing the same execution 359 * point as this instance. Two stack trace elements {@code a} and 360 * {@code b} are equal if and only if: 361 * <pre>{@code 362 * equals(a.getClassLoaderName(), b.getClassLoaderName()) && 363 * equals(a.getModuleName(), b.getModuleName()) && 364 * equals(a.getModuleVersion(), b.getModuleVersion()) && 365 * equals(a.getClassName(), b.getClassName()) && 366 * equals(a.getMethodName(), b.getMethodName()) 367 * equals(a.getFileName(), b.getFileName()) && 368 * a.getLineNumber() == b.getLineNumber() 369 * 370 * }</pre> 371 * where {@code equals} has the semantics of {@link 372 * java.util.Objects#equals(Object, Object) Objects.equals}. 373 * 374 * @param obj the object to be compared with this stack trace element. 375 * @return true if the specified object is another 376 * {@code StackTraceElement} instance representing the same 377 * execution point as this instance. 378 */ 379 public boolean equals(Object obj) { 380 if (obj==this) 381 return true; 382 if (!(obj instanceof StackTraceElement)) 383 return false; 384 StackTraceElement e = (StackTraceElement)obj; 385 return Objects.equals(classLoaderName, e.classLoaderName) && 386 Objects.equals(moduleName, e.moduleName) && 387 Objects.equals(moduleVersion, e.moduleVersion) && 388 e.declaringClass.equals(declaringClass) && 389 e.lineNumber == lineNumber && 390 Objects.equals(methodName, e.methodName) && 391 Objects.equals(fileName, e.fileName); 392 } 393 394 /** 395 * Returns a hash code value for this stack trace element. 396 */ 397 public int hashCode() { 398 int result = 31*declaringClass.hashCode() + methodName.hashCode(); 399 result = 31*result + Objects.hashCode(classLoaderName); 400 result = 31*result + Objects.hashCode(moduleName); 401 result = 31*result + Objects.hashCode(moduleVersion); 402 result = 31*result + Objects.hashCode(fileName); 403 result = 31*result + lineNumber; 404 return result; 405 } 406 407 408 /** 409 * Build the compacted String representation to be returned by 410 * toString method from the declaring Class object. 411 */ 412 synchronized String buildLoaderModuleClassName() { 413 if (classOrLoaderModuleClassName == null) 414 return null; 415 416 if (classOrLoaderModuleClassName instanceof Class) { 417 Class<?> cls = (Class<?>)classOrLoaderModuleClassName; 418 classOrLoaderModuleClassName = toLoaderModuleClassName(cls); 419 } 420 return (String)classOrLoaderModuleClassName; 421 } 422 423 /** 424 * Returns <loader>/<module>/<fully-qualified-classname> string 425 * representation of the given class. 426 * <p> 427 * If the module is a non-upgradeable JDK module then omit 428 * its version string. 429 * <p> 430 * If the loader has no name, or if the loader is one of the built-in 431 * loaders (`boot`, `platform`, or `app`) then drop the first element 432 * (`<loader>/`). 433 * <p> 434 * If the first element has been dropped and the module is unnamed 435 * then drop the second element (`<module>/`). 436 * <p> 437 * If the first element is not dropped and the module is unnamed 438 * then drop `<module>`. 439 */ 440 private static String toLoaderModuleClassName(Class<?> cls) { 441 ClassLoader loader = cls.getClassLoader0(); 442 Module m = cls.getModule(); 443 444 // First element - class loader name 445 // Call package-private ClassLoader::name method 446 String s = ""; 447 if (loader != null && loader.name() != null && 448 !(loader instanceof BuiltinClassLoader)) { 449 s = loader.name() + "/"; 450 } 451 452 // Second element - module name and version 453 if (m != null && m.isNamed()) { 454 s += m.getName(); 455 // Include version if it is a user module or upgradeable module 456 // 457 // If it is JDK non-upgradeable module which is recorded 458 // in the hashes in java.base, omit the version. 459 if (!isHashedInJavaBase(m)) { 460 Optional<Version> ov = m.getDescriptor().version(); 461 if (ov.isPresent()) { 462 String version = "@" + ov.get().toString(); 463 s += version; 464 } 465 } 466 } 467 468 // fully-qualified class name 469 return s.isEmpty() ? cls.getName() : s + "/" + cls.getName(); 470 } 471 472 /** 473 * Returns true if the module is hashed with java.base. 474 * <p> 475 * This method returns false when running on the exploded image 476 * since JDK modules are not hashed. They have no Version attribute 477 * and so "@<version>" part will be omitted anyway. 478 */ 479 private static boolean isHashedInJavaBase(Module m) { 480 // return true if module system is not initialized as the code 481 // must be in java.base 482 if (!VM.isModuleSystemInited()) 483 return true; 484 485 return Layer.boot() == m.getLayer() && HashedModules.contains(m); 486 } 487 488 /* 489 * Finds JDK non-upgradeable modules, i.e. the modules that are 490 * included in the hashes in java.base. 491 */ 492 private static class HashedModules { 493 static Set<String> HASHED_MODULES = hashedModules(); 494 495 static Set<String> hashedModules() { 496 Module javaBase = Layer.boot().findModule("java.base").get(); 497 Optional<ModuleHashes> ohashes = 498 SharedSecrets.getJavaLangModuleAccess() 499 .hashes(javaBase.getDescriptor()); 500 501 if (ohashes.isPresent()) { 502 Set<String> names = new HashSet<>(ohashes.get().names()); 503 names.add("java.base"); 504 return names; 505 } 506 507 return Set.of(); 508 } 509 510 static boolean contains(Module m) { 511 return HASHED_MODULES.contains(m.getName()); 512 } 513 } 514 515 516 /* 517 * Returns a StackTraceElement from a given StackFrameInfo. 518 */ 519 static StackTraceElement of(StackFrameInfo sfi) { 520 StackTraceElement ste = new StackTraceElement(); 521 ste.fillFromStackFrameInfo(sfi); 522 ste.buildLoaderModuleClassName(); 523 return ste; 524 } 525 526 /* 527 * Returns an array of StackTraceElements of the given depth 528 * filled from the backtrace of a given Throwable. 529 */ 530 static StackTraceElement[] of(Throwable x, int depth) { 531 StackTraceElement[] stackTrace = new StackTraceElement[depth]; 532 for (int i = 0; i < depth; i++) { 533 stackTrace[i] = new StackTraceElement(); 534 } 535 536 // VM to fill in StackTraceElement 537 fillStackTraceFromThrowable(stackTrace, x); 538 539 // ensure the proper StackTraceElement initialization 540 for (StackTraceElement ste : stackTrace) { 541 ste.buildLoaderModuleClassName(); 542 } 543 return stackTrace; 544 } 545 546 /* 547 * Fill in the stack trace elements from a given Throwable. 548 */ 549 private static native void fillStackTraceFromThrowable(StackTraceElement[] elements, 550 Throwable x); 551 /* 552 * Fill in the stack trace elements from a given StackFrameInfo. 553 */ 554 private native void fillFromStackFrameInfo(StackFrameInfo sfi); 555 556 private static final long serialVersionUID = 6992337162326171013L; 557 } |