1 /* 2 * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 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 NullPointerException if {@code declaringClass} is {@code null} 124 * or {@code methodName} is {@code null} 125 * 126 * @since 9 127 */ 128 public StackTraceElement(String classLoaderName, 129 String moduleName, String moduleVersion, 130 String declaringClass, String methodName, 131 String fileName, int lineNumber) { 132 this.classLoaderName = classLoaderName; 133 this.moduleName = moduleName; 134 this.moduleVersion = moduleVersion; 135 this.declaringClass = Objects.requireNonNull(declaringClass, "Declaring class is null"); 136 this.methodName = Objects.requireNonNull(methodName, "Method name is null"); 137 this.fileName = fileName; 138 this.lineNumber = lineNumber; 139 } 140 141 /* 142 * Private constructor for the factory methods to create StackTraceElement 143 * for Throwable and StackFrameInfo 144 */ 145 private StackTraceElement() {} 146 147 /** 148 * Returns the name of the source file containing the execution point 149 * represented by this stack trace element. Generally, this corresponds 150 * to the {@code SourceFile} attribute of the relevant {@code class} 151 * file (as per <i>The Java Virtual Machine Specification</i>, Section 152 * 4.7.7). In some systems, the name may refer to some source code unit 153 * other than a file, such as an entry in source repository. 154 * 155 * @return the name of the file containing the execution point 156 * represented by this stack trace element, or {@code null} if 157 * this information is unavailable. 158 */ 159 public String getFileName() { 160 return fileName; 161 } 162 163 /** 164 * Returns the line number of the source line containing the execution 165 * point represented by this stack trace element. Generally, this is 166 * derived from the {@code LineNumberTable} attribute of the relevant 167 * {@code class} file (as per <i>The Java Virtual Machine 168 * Specification</i>, Section 4.7.8). 169 * 170 * @return the line number of the source line containing the execution 171 * point represented by this stack trace element, or a negative 172 * number if this information is unavailable. 173 */ 174 public int getLineNumber() { 175 return lineNumber; 176 } 177 178 /** 179 * Returns the module name of the module containing the execution point 180 * represented by this stack trace element. 181 * 182 * @return the module name of the {@code Module} containing the execution 183 * point represented by this stack trace element; {@code null} 184 * if the module name is not available. 185 * @since 9 186 * @see java.lang.reflect.Module#getName() 187 */ 188 public String getModuleName() { 189 return moduleName; 190 } 191 192 /** 193 * Returns the module version of the module containing the execution point 194 * represented by this stack trace element. 195 * 196 * @return the module version of the {@code Module} containing the execution 197 * point represented by this stack trace element; {@code null} 198 * if the module version is not available. 199 * @since 9 200 * @see java.lang.module.ModuleDescriptor.Version 201 */ 202 public String getModuleVersion() { 203 return moduleVersion; 204 } 205 206 /** 207 * Returns the name of the class loader of the class containing the 208 * execution point represented by this stack trace element. 209 * 210 * @return the name of the class loader of the class containing the execution 211 * point represented by this stack trace element; {@code null} 212 * if the class loader is not named. 213 * 214 * @since 9 215 * @see java.lang.ClassLoader#getName() 216 */ 217 public String getClassLoaderName() { 218 return classLoaderName; 219 } 220 221 /** 222 * Returns the fully qualified name of the class containing the 223 * execution point represented by this stack trace element. 224 * 225 * @return the fully qualified name of the {@code Class} containing 226 * the execution point represented by this stack trace element. 227 */ 228 public String getClassName() { 229 return declaringClass; 230 } 231 232 /** 233 * Returns the name of the method containing the execution point 234 * represented by this stack trace element. If the execution point is 235 * contained in an instance or class initializer, this method will return 236 * the appropriate <i>special method name</i>, {@code <init>} or 237 * {@code <clinit>}, as per Section 3.9 of <i>The Java Virtual 238 * Machine Specification</i>. 239 * 240 * @return the name of the method containing the execution point 241 * represented by this stack trace element. 242 */ 243 public String getMethodName() { 244 return methodName; 245 } 246 247 /** 248 * Returns true if the method containing the execution point 249 * represented by this stack trace element is a native method. 250 * 251 * @return {@code true} if the method containing the execution point 252 * represented by this stack trace element is a native method. 253 */ 254 public boolean isNativeMethod() { 255 return lineNumber == -2; 256 } 257 258 /** 259 * Returns a string representation of this stack trace element. The 260 * format of this string depends on the implementation, but the following 261 * examples may be regarded as typical: 262 * <ul> 263 * <li> 264 * "{@code com.foo.loader/foo@9.0/com.foo.Main.run(Main.java:101)}" 265 * - See the description below. 266 * </li> 267 * <li> 268 * "{@code com.foo.loader/foo@9.0/com.foo.Main.run(Main.java)}" 269 * - The line number is unavailable. 270 * </li> 271 * <li> 272 * "{@code com.foo.loader/foo@9.0/com.foo.Main.run(Unknown Source)}" 273 * - Neither the file name nor the line number is available. 274 * </li> 275 * <li> 276 * "{@code com.foo.loader/foo@9.0/com.foo.Main.run(Native Method)}" 277 * - The method containing the execution point is a native method. 278 * </li> 279 * <li> 280 * "{@code com.foo.loader//com.foo.bar.App.run(App.java:12)}" 281 * - The class of the execution point is defined in the unnamed module of 282 * the class loader named {@code com.foo.loader}. 283 * </li> 284 * <li> 285 * "{@code acme@2.1/org.acme.Lib.test(Lib.java:80)}" 286 * - The class of the execution point is defined in {@code acme} module 287 * loaded by by a built-in class loader such as the application class loader. 288 * </li> 289 * <li> 290 * "{@code MyClass.mash(MyClass.java:9)}" 291 * - {@code MyClass} class is on the application class path. 292 * </li> 293 * </ul> 294 * 295 * <p> The first example shows a stack trace element consisting of 296 * three elements, each separated by {@code "/"} followed with 297 * the source file name and the line number of the source line 298 * containing the execution point. 299 * 300 * The first element "{@code com.foo.loader}" is 301 * the name of the class loader. The second element "{@code foo@9.0}" 302 * is the module name and version. The third element is the method 303 * containing the execution point; "{@code com.foo.Main"}" is the 304 * fully-qualified class name and "{@code run}" is the name of the method. 305 * "{@code Main.java}" is the source file name and "{@code 101}" is 306 * the line number. 307 * 308 * <p> If a class is defined in an <em>unnamed module</em> 309 * then the second element is omitted as shown in 310 * "{@code com.foo.loader//com.foo.bar.App.run(App.java:12)}". 311 * 312 * If the class loader is a <a href="ClassLoader.html#builtinLoaders"> 313 * built-in class loader</a> or is not named then the first element 314 * and its following {@code "/"} are omitted as shown in 315 * "{@code acme@2.1/org.acme.Lib.test(Lib.java:80)}". 316 * If the first element is omitted and the module is an unnamed module, 317 * the second element and its following {@code "/"} are also omitted 318 * as shown in "{@code MyClass.mash(MyClass.java:9)}". 319 * 320 * @see Throwable#printStackTrace() 321 */ 322 public String toString() { 323 String s = buildLoaderModuleClassName(); 324 if (s == null) { 325 // all elements will be included 326 s = ""; 327 if (classLoaderName != null && !classLoaderName.isEmpty()) { 328 s += classLoaderName + "/"; 329 } 330 if (moduleName != null && !moduleName.isEmpty()) { 331 s += moduleName; 332 333 if (moduleVersion != null && !moduleVersion.isEmpty()) { 334 s += "@" + moduleVersion; 335 } 336 } 337 s = s.isEmpty() ? declaringClass : s + "/" + declaringClass; 338 } 339 340 return s + "." + methodName + "(" + 341 (isNativeMethod() ? "Native Method)" : 342 (fileName != null && lineNumber >= 0 ? 343 fileName + ":" + lineNumber + ")" : 344 (fileName != null ? ""+fileName+")" : "Unknown Source)"))); 345 } 346 347 /** 348 * Returns true if the specified object is another 349 * {@code StackTraceElement} instance representing the same execution 350 * point as this instance. Two stack trace elements {@code a} and 351 * {@code b} are equal if and only if: 352 * <pre>{@code 353 * equals(a.getClassLoaderName(), b.getClassLoaderName()) && 354 * equals(a.getModuleName(), b.getModuleName()) && 355 * equals(a.getModuleVersion(), b.getModuleVersion()) && 356 * equals(a.getClassName(), b.getClassName()) && 357 * equals(a.getMethodName(), b.getMethodName()) 358 * equals(a.getFileName(), b.getFileName()) && 359 * a.getLineNumber() == b.getLineNumber() 360 * 361 * }</pre> 362 * where {@code equals} has the semantics of {@link 363 * java.util.Objects#equals(Object, Object) Objects.equals}. 364 * 365 * @param obj the object to be compared with this stack trace element. 366 * @return true if the specified object is another 367 * {@code StackTraceElement} instance representing the same 368 * execution point as this instance. 369 */ 370 public boolean equals(Object obj) { 371 if (obj==this) 372 return true; 373 if (!(obj instanceof StackTraceElement)) 374 return false; 375 StackTraceElement e = (StackTraceElement)obj; 376 return Objects.equals(classLoaderName, e.classLoaderName) && 377 Objects.equals(moduleName, e.moduleName) && 378 Objects.equals(moduleVersion, e.moduleVersion) && 379 e.declaringClass.equals(declaringClass) && 380 e.lineNumber == lineNumber && 381 Objects.equals(methodName, e.methodName) && 382 Objects.equals(fileName, e.fileName); 383 } 384 385 /** 386 * Returns a hash code value for this stack trace element. 387 */ 388 public int hashCode() { 389 int result = 31*declaringClass.hashCode() + methodName.hashCode(); 390 result = 31*result + Objects.hashCode(classLoaderName); 391 result = 31*result + Objects.hashCode(moduleName); 392 result = 31*result + Objects.hashCode(moduleVersion); 393 result = 31*result + Objects.hashCode(fileName); 394 result = 31*result + lineNumber; 395 return result; 396 } 397 398 399 /** 400 * Build the compacted String representation to be returned by 401 * toString method from the declaring Class object. 402 */ 403 synchronized String buildLoaderModuleClassName() { 404 if (classOrLoaderModuleClassName == null) 405 return null; 406 407 if (classOrLoaderModuleClassName instanceof Class) { 408 Class<?> cls = (Class<?>)classOrLoaderModuleClassName; 409 classOrLoaderModuleClassName = toLoaderModuleClassName(cls); 410 } 411 return (String)classOrLoaderModuleClassName; 412 } 413 414 /** 415 * Returns <loader>/<module>/<fully-qualified-classname> string 416 * representation of the given class. 417 * <p> 418 * If the module is a non-upgradeable JDK module then omit 419 * its version string. 420 * <p> 421 * If the loader has no name, or if the loader is one of the built-in 422 * loaders (`boot`, `platform`, or `app`) then drop the first element 423 * (`<loader>/`). 424 * <p> 425 * If the first element has been dropped and the module is unnamed 426 * then drop the second element (`<module>/`). 427 * <p> 428 * If the first element is not dropped and the module is unnamed 429 * then drop `<module>`. 430 */ 431 private static String toLoaderModuleClassName(Class<?> cls) { 432 ClassLoader loader = cls.getClassLoader0(); 433 Module m = cls.getModule(); 434 435 // First element - class loader name 436 // Call package-private ClassLoader::name method 437 String s = ""; 438 if (loader != null && loader.name() != null && 439 !(loader instanceof BuiltinClassLoader)) { 440 s = loader.name() + "/"; 441 } 442 443 // Second element - module name and version 444 if (m != null && m.isNamed()) { 445 s += m.getName(); 446 // Include version if it is a user module or upgradeable module 447 // 448 // If it is JDK non-upgradeable module which is recorded 449 // in the hashes in java.base, omit the version. 450 if (!isHashedInJavaBase(m)) { 451 Optional<Version> ov = m.getDescriptor().version(); 452 if (ov.isPresent()) { 453 String version = "@" + ov.get().toString(); 454 s += version; 455 } 456 } 457 } 458 459 // fully-qualified class name 460 return s.isEmpty() ? cls.getName() : s + "/" + cls.getName(); 461 } 462 463 /** 464 * Returns true if the module is hashed with java.base. 465 * <p> 466 * This method returns false when running on the exploded image 467 * since JDK modules are not hashed. They have no Version attribute 468 * and so "@<version>" part will be omitted anyway. 469 */ 470 private static boolean isHashedInJavaBase(Module m) { 471 // return true if module system is not initialized as the code 472 // must be in java.base 473 if (!VM.isModuleSystemInited()) 474 return true; 475 476 return Layer.boot() == m.getLayer() && HashedModules.contains(m); 477 } 478 479 /* 480 * Finds JDK non-upgradeable modules, i.e. the modules that are 481 * included in the hashes in java.base. 482 */ 483 private static class HashedModules { 484 static Set<String> HASHED_MODULES = hashedModules(); 485 486 static Set<String> hashedModules() { 487 Module javaBase = Layer.boot().findModule("java.base").get(); 488 Optional<ModuleHashes> ohashes = 489 SharedSecrets.getJavaLangModuleAccess() 490 .hashes(javaBase.getDescriptor()); 491 492 if (ohashes.isPresent()) { 493 Set<String> names = new HashSet<>(ohashes.get().names()); 494 names.add("java.base"); 495 return names; 496 } 497 498 return Set.of(); 499 } 500 501 static boolean contains(Module m) { 502 return HASHED_MODULES.contains(m.getName()); 503 } 504 } 505 506 507 /* 508 * Returns an array of StackTraceElements of the given depth 509 * filled from the backtrace of a given Throwable. 510 */ 511 static StackTraceElement[] of(Throwable x, int depth) { 512 StackTraceElement[] stackTrace = new StackTraceElement[depth]; 513 for (int i = 0; i < depth; i++) { 514 stackTrace[i] = new StackTraceElement(); 515 } 516 517 // VM to fill in StackTraceElement 518 initStackTraceElements(stackTrace, x); 519 520 // ensure the proper StackTraceElement initialization 521 for (StackTraceElement ste : stackTrace) { 522 ste.buildLoaderModuleClassName(); 523 } 524 return stackTrace; 525 } 526 527 /* 528 * Returns a StackTraceElement from a given StackFrameInfo. 529 */ 530 static StackTraceElement of(StackFrameInfo sfi) { 531 StackTraceElement ste = new StackTraceElement(); 532 initStackTraceElement(ste, sfi); 533 534 ste.buildLoaderModuleClassName(); 535 return ste; 536 } 537 538 /* 539 * Sets the given stack trace elements with the backtrace 540 * of the given Throwable. 541 */ 542 private static native void initStackTraceElements(StackTraceElement[] elements, 543 Throwable x); 544 /* 545 * Sets the given stack trace element with the given StackFrameInfo 546 */ 547 private static native void initStackTraceElement(StackTraceElement element, 548 StackFrameInfo sfi); 549 550 private static final long serialVersionUID = 6992337162326171013L; 551 } --- EOF ---