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