1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package java.lang; 19 20 import java.io.Serializable; 21 22 /** 23 * A representation of a single stack frame. Arrays of {@code StackTraceElement} 24 * are stored in {@link Throwable} objects to represent the whole state of the 25 * call stack at the time a {@code Throwable} gets thrown. 26 * 27 * @see Throwable#getStackTrace() 28 */ 29 public final class StackTraceElement implements Serializable { 30 31 private static final long serialVersionUID = 6992337162326171013L; 32 33 private static final int NATIVE_LINE_NUMBER = -2; 34 35 String declaringClass; 36 37 String methodName; 38 39 String fileName; 40 41 int lineNumber; 42 43 /** 44 * Constructs a new {@code StackTraceElement} for a specified execution 45 * point. 46 * 47 * @param cls 48 * the fully qualified name of the class where execution is at. 49 * @param method 50 * the name of the method where execution is at. 51 * @param file 52 * The name of the file where execution is at or {@code null}. 53 * @param line 54 * the line of the file where execution is at, a negative number 55 * if unknown or {@code -2} if the execution is in a native 56 * method. 57 * @throws NullPointerException 58 * if {@code cls} or {@code method} is {@code null}. 59 */ 60 public StackTraceElement(String cls, String method, String file, int line) { 61 if (cls == null || method == null) { 62 throw new NullPointerException(); 63 } 64 declaringClass = cls; 65 methodName = method; 66 fileName = file; 67 lineNumber = line; 68 } 69 70 /** 71 * <p> 72 * Private, nullary constructor for VM use only. 73 * </p> 74 */ 75 private StackTraceElement() { 76 } 77 78 /** 79 * Compares this instance with the specified object and indicates if they 80 * are equal. In order to be equal, the following conditions must be 81 * fulfilled: 82 * <ul> 83 * <li>{@code obj} must be a stack trace element,</li> 84 * <li>the method names of this stack trace element and of {@code obj} must 85 * not be {@code null},</li> 86 * <li>the class, method and file names as well as the line number of this 87 * stack trace element and of {@code obj} must be equal.</li> 88 * </ul> 89 * 90 * @param obj 91 * the object to compare this instance with. 92 * @return {@code true} if the specified object is equal to this 93 * {@code StackTraceElement}; {@code false} otherwise. 94 * @see #hashCode 95 */ 96 @Override 97 public boolean equals(Object obj) { 98 if (!(obj instanceof StackTraceElement)) { 99 return false; 100 } 101 StackTraceElement castObj = (StackTraceElement) obj; 102 103 /* 104 * Unknown methods are never equal to anything (not strictly to spec, 105 * but spec does not allow null method/class names) 106 */ 107 if ((methodName == null) || (castObj.methodName == null)) { 108 return false; 109 } 110 111 if (!getMethodName().equals(castObj.getMethodName())) { 112 return false; 113 } 114 if (!getClassName().equals(castObj.getClassName())) { 115 return false; 116 } 117 String localFileName = getFileName(); 118 if (localFileName == null) { 119 if (castObj.getFileName() != null) { 120 return false; 121 } 122 } else { 123 if (!localFileName.equals(castObj.getFileName())) { 124 return false; 125 } 126 } 127 if (getLineNumber() != castObj.getLineNumber()) { 128 return false; 129 } 130 131 return true; 132 } 133 134 /** 135 * Returns the fully qualified name of the class belonging to this 136 * {@code StackTraceElement}. 137 * 138 * @return the fully qualified type name of the class 139 */ 140 public String getClassName() { 141 return (declaringClass == null) ? "<unknown class>" : declaringClass; 142 } 143 144 /** 145 * Returns the name of the Java source file containing class belonging to 146 * this {@code StackTraceElement}. 147 * 148 * @return the name of the file, or {@code null} if this information is not 149 * available. 150 */ 151 public String getFileName() { 152 return fileName; 153 } 154 155 /** 156 * Returns the line number in the source for the class belonging to this 157 * {@code StackTraceElement}. 158 * 159 * @return the line number, or a negative number if this information is not 160 * available. 161 */ 162 public int getLineNumber() { 163 return lineNumber; 164 } 165 166 /** 167 * Returns the name of the method belonging to this {@code 168 * StackTraceElement}. 169 * 170 * @return the name of the method, or "<unknown method>" if this information 171 * is not available. 172 */ 173 public String getMethodName() { 174 return (methodName == null) ? "<unknown method>" : methodName; 175 } 176 177 @Override 178 public int hashCode() { 179 /* 180 * Either both methodName and declaringClass are null, or neither are 181 * null. 182 */ 183 if (methodName == null) { 184 // all unknown methods hash the same 185 return 0; 186 } 187 // declaringClass never null if methodName is non-null 188 return methodName.hashCode() ^ declaringClass.hashCode(); 189 } 190 191 /** 192 * Indicates if the method name returned by {@link #getMethodName()} is 193 * implemented as a native method. 194 * 195 * @return {@code true} if the method in which this stack trace element is 196 * executing is a native method; {@code false} otherwise. 197 */ 198 public boolean isNativeMethod() { 199 return lineNumber == NATIVE_LINE_NUMBER; 200 } 201 202 @Override 203 public String toString() { 204 StringBuilder buf = new StringBuilder(80); 205 206 buf.append(getClassName()); 207 buf.append('.'); 208 buf.append(getMethodName()); 209 210 if (isNativeMethod()) { 211 buf.append("(Native Method)"); 212 } else { 213 String fName = getFileName(); 214 215 if (fName == null) { 216 buf.append("(Unknown Source)"); 217 } else { 218 int lineNum = getLineNumber(); 219 220 buf.append('('); 221 buf.append(fName); 222 if (lineNum >= 0) { 223 buf.append(':'); 224 buf.append(lineNum); 225 } 226 buf.append(')'); 227 } 228 } 229 return buf.toString(); 230 } 231 } 232