/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package java.lang;
import java.io.Serializable;
/**
* A representation of a single stack frame. Arrays of {@code StackTraceElement}
* are stored in {@link Throwable} objects to represent the whole state of the
* call stack at the time a {@code Throwable} gets thrown.
*
* @see Throwable#getStackTrace()
*/
public final class StackTraceElement implements Serializable {
private static final long serialVersionUID = 6992337162326171013L;
private static final int NATIVE_LINE_NUMBER = -2;
String declaringClass;
String methodName;
String fileName;
int lineNumber;
/**
* Constructs a new {@code StackTraceElement} for a specified execution
* point.
*
* @param cls
* the fully qualified name of the class where execution is at.
* @param method
* the name of the method where execution is at.
* @param file
* The name of the file where execution is at or {@code null}.
* @param line
* the line of the file where execution is at, a negative number
* if unknown or {@code -2} if the execution is in a native
* method.
* @throws NullPointerException
* if {@code cls} or {@code method} is {@code null}.
*/
public StackTraceElement(String cls, String method, String file, int line) {
if (cls == null) {
throw new NullPointerException("cls == null");
} else if (method == null) {
throw new NullPointerException("method == null");
}
declaringClass = cls;
methodName = method;
fileName = file;
lineNumber = line;
}
/**
* <p>
* Private, nullary constructor for VM use only.
* </p>
*/
private StackTraceElement() {
}
/**
* Compares this instance with the specified object and indicates if they
* are equal. In order to be equal, the following conditions must be
* fulfilled:
* <ul>
* <li>{@code obj} must be a stack trace element,</li>
* <li>the method names of this stack trace element and of {@code obj} must
* not be {@code null},</li>
* <li>the class, method and file names as well as the line number of this
* stack trace element and of {@code obj} must be equal.</li>
* </ul>
*
* @param obj
* the object to compare this instance with.
* @return {@code true} if the specified object is equal to this
* {@code StackTraceElement}; {@code false} otherwise.
* @see #hashCode
*/
@Override
public boolean equals(Object obj) {
if (!(obj instanceof StackTraceElement)) {
return false;
}
StackTraceElement castObj = (StackTraceElement) obj;
/*
* Unknown methods are never equal to anything (not strictly to spec,
* but spec does not allow null method/class names)
*/
if ((methodName == null) || (castObj.methodName == null)) {
return false;
}
if (!getMethodName().equals(castObj.getMethodName())) {
return false;
}
if (!getClassName().equals(castObj.getClassName())) {
return false;
}
String localFileName = getFileName();
if (localFileName == null) {
if (castObj.getFileName() != null) {
return false;
}
} else {
if (!localFileName.equals(castObj.getFileName())) {
return false;
}
}
if (getLineNumber() != castObj.getLineNumber()) {
return false;
}
return true;
}
/**
* Returns the fully qualified name of the class belonging to this
* {@code StackTraceElement}.
*
* @return the fully qualified type name of the class
*/
public String getClassName() {
return (declaringClass == null) ? "<unknown class>" : declaringClass;
}
/**
* Returns the name of the Java source file containing class belonging to
* this {@code StackTraceElement}.
*
* @return the name of the file, or {@code null} if this information is not
* available.
*/
public String getFileName() {
return fileName;
}
/**
* Returns the line number in the source for the class belonging to this
* {@code StackTraceElement}.
*
* @return the line number, or a negative number if this information is not
* available.
*/
public int getLineNumber() {
return lineNumber;
}
/**
* Returns the name of the method belonging to this {@code
* StackTraceElement}.
*
* @return the name of the method, or "<unknown method>" if this information
* is not available.
*/
public String getMethodName() {
return (methodName == null) ? "<unknown method>" : methodName;
}
@Override
public int hashCode() {
/*
* Either both methodName and declaringClass are null, or neither are
* null.
*/
if (methodName == null) {
// all unknown methods hash the same
return 0;
}
// declaringClass never null if methodName is non-null
return methodName.hashCode() ^ declaringClass.hashCode();
}
/**
* Indicates if the method name returned by {@link #getMethodName()} is
* implemented as a native method.
*
* @return {@code true} if the method in which this stack trace element is
* executing is a native method; {@code false} otherwise.
*/
public boolean isNativeMethod() {
return lineNumber == NATIVE_LINE_NUMBER;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder(80);
buf.append(getClassName());
buf.append('.');
buf.append(getMethodName());
if (isNativeMethod()) {
buf.append("(Native Method)");
} else {
String fName = getFileName();
if (fName == null) {
buf.append("(Unknown Source)");
} else {
int lineNum = getLineNumber();
buf.append('(');
buf.append(fName);
if (lineNum >= 0) {
buf.append(':');
buf.append(lineNum);
}
buf.append(')');
}
}
return buf.toString();
}
}