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 // BEGIN android-added 34 private static final int NATIVE_LINE_NUMBER = -2; 35 // END android-added 36 37 String declaringClass; 38 39 String methodName; 40 41 String fileName; 42 43 int lineNumber; 44 45 /** 46 * Constructs a new {@code StackTraceElement} for a specified execution 47 * point. 48 * 49 * @param cls 50 * the fully qualified name of the class where execution is at. 51 * @param method 52 * the name of the method where execution is at. 53 * @param file 54 * The name of the file where execution is at or {@code null}. 55 * @param line 56 * the line of the file where execution is at, a negative number 57 * if unknown or {@code -2} if the execution is in a native 58 * method. 59 * @throws NullPointerException 60 * if {@code cls} or {@code method} is {@code null}. 61 */ StackTraceElement(String cls, String method, String file, int line)62 public StackTraceElement(String cls, String method, String file, int line) { 63 super(); 64 if (cls == null || method == null) { 65 throw new NullPointerException(); 66 } 67 declaringClass = cls; 68 methodName = method; 69 fileName = file; 70 lineNumber = line; 71 } 72 73 /** 74 * <p> 75 * Private, nullary constructor for VM use only. 76 * </p> 77 */ StackTraceElement()78 private StackTraceElement() { 79 super(); 80 } 81 82 /** 83 * Compares this instance with the specified object and indicates if they 84 * are equal. In order to be equal, the following conditions must be 85 * fulfilled: 86 * <ul> 87 * <li>{@code obj} must be a stack trace element,</li> 88 * <li>the method names of this stack trace element and of {@code obj} must 89 * not be {@code null},</li> 90 * <li>the class, method and file names as well as the line number of this 91 * stack trace element and of {@code obj} must be equal.</li> 92 * </ul> 93 * 94 * @param obj 95 * the object to compare this instance with. 96 * @return {@code true} if the specified object is equal to this 97 * {@code StackTraceElement}; {@code false} otherwise. 98 * @see #hashCode 99 */ 100 @Override equals(Object obj)101 public boolean equals(Object obj) { 102 if (!(obj instanceof StackTraceElement)) { 103 return false; 104 } 105 StackTraceElement castObj = (StackTraceElement) obj; 106 107 /* 108 * Unknown methods are never equal to anything (not strictly to spec, 109 * but spec does not allow null method/class names) 110 */ 111 if ((methodName == null) || (castObj.methodName == null)) { 112 return false; 113 } 114 115 if (!getMethodName().equals(castObj.getMethodName())) { 116 return false; 117 } 118 if (!getClassName().equals(castObj.getClassName())) { 119 return false; 120 } 121 String localFileName = getFileName(); 122 if (localFileName == null) { 123 if (castObj.getFileName() != null) { 124 return false; 125 } 126 } else { 127 if (!localFileName.equals(castObj.getFileName())) { 128 return false; 129 } 130 } 131 if (getLineNumber() != castObj.getLineNumber()) { 132 return false; 133 } 134 135 return true; 136 } 137 138 /** 139 * Returns the fully qualified name of the class belonging to this 140 * {@code StackTraceElement}. 141 * 142 * @return the fully qualified type name of the class 143 */ getClassName()144 public String getClassName() { 145 return (declaringClass == null) ? "<unknown class>" : declaringClass; 146 } 147 148 /** 149 * Returns the name of the Java source file containing class belonging to 150 * this {@code StackTraceElement}. 151 * 152 * @return the name of the file, or {@code null} if this information is not 153 * available. 154 */ getFileName()155 public String getFileName() { 156 return fileName; 157 } 158 159 /** 160 * Returns the line number in the source for the class belonging to this 161 * {@code StackTraceElement}. 162 * 163 * @return the line number, or a negative number if this information is not 164 * available. 165 */ getLineNumber()166 public int getLineNumber() { 167 return lineNumber; 168 } 169 170 /** 171 * Returns the name of the method belonging to this {@code 172 * StackTraceElement}. 173 * 174 * @return the name of the method, or "<unknown method>" if this information 175 * is not available. 176 */ getMethodName()177 public String getMethodName() { 178 return (methodName == null) ? "<unknown method>" : methodName; 179 } 180 181 @Override hashCode()182 public int hashCode() { 183 /* 184 * Either both methodName and declaringClass are null, or neither are 185 * null. 186 */ 187 if (methodName == null) { 188 // all unknown methods hash the same 189 return 0; 190 } 191 // declaringClass never null if methodName is non-null 192 return methodName.hashCode() ^ declaringClass.hashCode(); 193 } 194 195 /** 196 * Indicates if the method name returned by {@link #getMethodName()} is 197 * implemented as a native method. 198 * 199 * @return {@code true} if the method in which this stack trace element is 200 * executing is a native method; {@code false} otherwise. 201 */ isNativeMethod()202 public boolean isNativeMethod() { 203 // BEGIN android-changed 204 return lineNumber == NATIVE_LINE_NUMBER; 205 // END android-changed 206 } 207 208 @Override toString()209 public String toString() { 210 StringBuilder buf = new StringBuilder(80); 211 212 buf.append(getClassName()); 213 buf.append('.'); 214 buf.append(getMethodName()); 215 216 if (isNativeMethod()) { 217 buf.append("(Native Method)"); 218 } else { 219 String fName = getFileName(); 220 221 if (fName == null) { 222 buf.append("(Unknown Source)"); 223 } else { 224 int lineNum = getLineNumber(); 225 226 buf.append('('); 227 buf.append(fName); 228 if (lineNum >= 0) { 229 buf.append(':'); 230 buf.append(lineNum); 231 } 232 buf.append(')'); 233 } 234 } 235 return buf.toString(); 236 } 237 } 238