¿Qué es un seguimiento de pila y cómo puedo usarlo para depurar los errores de mi aplicación?

643

A veces, cuando ejecuto mi aplicación, aparece un error similar al siguiente:

Exception in thread "main" java.lang.NullPointerException
        at com.example.myproject.Book.getTitle(Book.java:16)
        at com.example.myproject.Author.getBookTitles(Author.java:25)
        at com.example.myproject.Bootstrap.main(Bootstrap.java:14)

La gente se ha referido a esto como un "rastro de pila". ¿Qué es un seguimiento de pila? ¿Qué puede decirme sobre el error que está ocurriendo en mi programa?


Acerca de esta pregunta: con bastante frecuencia veo que surge una pregunta en la que un programador novato está "recibiendo un error", y simplemente pegan su seguimiento de la pila y algún bloque de código aleatorio sin comprender qué es el seguimiento de la pila o cómo pueden usarlo. Esta pregunta pretende ser una referencia para programadores novatos que puedan necesitar ayuda para comprender el valor de un seguimiento de pila.

Rob Hruska
fuente
25
Además, si una línea de stacktrace no contiene el nombre de archivo y un número de línea, la clase para esa línea no se compiló con información de depuración.
Thorbjørn Ravn Andersen

Respuestas:

590

En términos simples, un seguimiento de pila es una lista de las llamadas a métodos que la aplicación estaba en el medio de cuando se lanzó una Excepción.

Ejemplo simple

Con el ejemplo dado en la pregunta, podemos determinar exactamente dónde se produjo la excepción en la aplicación. Echemos un vistazo al seguimiento de la pila:

Exception in thread "main" java.lang.NullPointerException
        at com.example.myproject.Book.getTitle(Book.java:16)
        at com.example.myproject.Author.getBookTitles(Author.java:25)
        at com.example.myproject.Bootstrap.main(Bootstrap.java:14)

Este es un seguimiento de pila muy simple. Si comenzamos al principio de la lista de "en ...", podemos saber dónde ocurrió nuestro error. Lo que estamos buscando es la llamada al método más importante que es parte de nuestra aplicación. En este caso, es:

at com.example.myproject.Book.getTitle(Book.java:16)

Para depurar esto, podemos abrir Book.javay mirar la línea 16, que es:

15   public String getTitle() {
16      System.out.println(title.toString());
17      return title;
18   }

Esto indicaría que algo (probablemente title) esnull en el código anterior.

Ejemplo con una cadena de excepciones

Algunas veces las aplicaciones detectarán una Excepción y la volverán a lanzar como la causa de otra Excepción. Esto normalmente se parece a:

34   public void getBookIds(int id) {
35      try {
36         book.getId(id);    // this method it throws a NullPointerException on line 22
37      } catch (NullPointerException e) {
38         throw new IllegalStateException("A book has a null property", e)
39      }
40   }

Esto podría darle un seguimiento de la pila que se parece a:

Exception in thread "main" java.lang.IllegalStateException: A book has a null property
        at com.example.myproject.Author.getBookIds(Author.java:38)
        at com.example.myproject.Bootstrap.main(Bootstrap.java:14)
Caused by: java.lang.NullPointerException
        at com.example.myproject.Book.getId(Book.java:22)
        at com.example.myproject.Author.getBookIds(Author.java:36)
        ... 1 more

Lo diferente de este es el "Causado por". A veces las excepciones tendrán múltiples secciones "Causado por". Para estos, normalmente desea encontrar la "causa raíz", que será una de las secciones "Causadas por" más bajas en el seguimiento de la pila. En nuestro caso, es:

Caused by: java.lang.NullPointerException <-- root cause
        at com.example.myproject.Book.getId(Book.java:22) <-- important line

Una vez más, con esta excepción que nos gustaría mirar a la línea 22de Book.javaver lo que podría hacer que el NullPointerExceptionaquí.

Ejemplo más desalentador con código de biblioteca

Por lo general, las trazas de pila son mucho más complejas que los dos ejemplos anteriores. Aquí hay un ejemplo (es largo, pero demuestra varios niveles de excepciones encadenadas):

javax.servlet.ServletException: Something bad happened
    at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.java:60)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.example.myproject.ExceptionHandlerFilter.doFilter(ExceptionHandlerFilter.java:28)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.example.myproject.OutputBufferFilter.doFilter(OutputBufferFilter.java:33)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
    at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
    at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
    at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
    at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
    at org.mortbay.jetty.Server.handle(Server.java:326)
    at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
    at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:943)
    at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:756)
    at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
    at org.mortbay.jetty.bio.SocketConnector$Connection.run(SocketConnector.java:228)
    at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
Caused by: com.example.myproject.MyProjectServletException
    at com.example.myproject.MyServlet.doPost(MyServlet.java:169)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
    at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
    at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.java:30)
    ... 27 more
Caused by: org.hibernate.exception.ConstraintViolationException: could not insert: [com.example.myproject.MyEntity]
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
    at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:64)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2329)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2822)
    at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:71)
    at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:268)
    at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:321)
    at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
    at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
    at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
    at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
    at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:705)
    at org.hibernate.impl.SessionImpl.save(SessionImpl.java:693)
    at org.hibernate.impl.SessionImpl.save(SessionImpl.java:689)
    at sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:344)
    at $Proxy19.save(Unknown Source)
    at com.example.myproject.MyEntityService.save(MyEntityService.java:59) <-- relevant call (see notes below)
    at com.example.myproject.MyServlet.doPost(MyServlet.java:164)
    ... 32 more
Caused by: java.sql.SQLException: Violation of unique constraint MY_ENTITY_UK_1: duplicate value(s) for column(s) MY_COLUMN in statement [...]
    at org.hsqldb.jdbc.Util.throwError(Unknown Source)
    at org.hsqldb.jdbc.jdbcPreparedStatement.executeUpdate(Unknown Source)
    at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:105)
    at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:57)
    ... 54 more

En este ejemplo, hay mucho más. Lo que más nos preocupa es buscar métodos que provienen de nuestro código , que serían cualquier cosa en el com.example.myprojectpaquete. Del segundo ejemplo (arriba), primero queremos buscar la causa raíz, que es:

Caused by: java.sql.SQLException

Sin embargo, todas las llamadas a métodos que se encuentran debajo son código de biblioteca. Así que pasaremos al "Causado por" que se encuentra arriba y buscaremos la primera llamada al método que se origina en nuestro código, que es:

at com.example.myproject.MyEntityService.save(MyEntityService.java:59)

Al igual que en los ejemplos anteriores, deberíamos mirar en MyEntityService.javalínea 59, porque ahí es donde se originó este error (esto es un poco obvio de lo que salió mal, ya que la SQLException indica el error, pero el procedimiento de depuración es lo que estamos buscando).

Rob Hruska
fuente
3
@RobHruska - Muy bien explicado. +1. ¿Conoces algún analizador que tome el rastreo de excepción como una cadena y proporcione métodos útiles para analizar stacktrace? - como getLastCausedBy () o getCausedByForMyAppCode ("com.example.myproject")
Andy Dufresne
1
@AndyDufresne: no he encontrado ninguno, pero tampoco he mirado realmente.
Rob Hruska
1
Mejora sugerida: explique la primera línea de un seguimiento de pila que comienza Exception in thread "main"en su primer ejemplo. Creo que sería especialmente útil explicar que esta línea suele ir acompañada de un mensaje, como el valor de una variable, que puede ayudar a diagnosticar el problema. Intenté hacer una edición yo mismo, pero estoy luchando por adaptar estas ideas a la estructura existente de su respuesta.
Code-Apprentice
55
También Java 1.7 agregó "Suprimido:" - que enumera las trazas de pila de excepciones suprimidas antes de mostrar "Causado por:" para esta excepción. La construcción try-with-resource lo usa automáticamente: docs.oracle.com/javase/specs/jls/se8/html/… y contiene excepciones, si las hubo, durante el cierre de los recursos.
dhblah 01 de
Hay un JEP openjdk.java.net/jeps/8220715 que tiene como objetivo mejorar aún más la comprensión de los NPE especialmente proporcionando detalles como "No se puede escribir el campo 'nullInstanceField' porque 'this.nullInstanceField' es nulo".
Mahatma_Fatal_Error
80

Estoy publicando esta respuesta para que la respuesta más alta (cuando se ordena por actividad) no sea una que simplemente esté equivocada.

¿Qué es un Stacktrace?

Un stacktrace es una herramienta de depuración muy útil. Muestra la pila de llamadas (es decir, la pila de funciones que se llamaron hasta ese punto) en el momento en que se lanzó una excepción no detectada (o en el momento en que se generó manualmente el seguimiento de la pila). Esto es muy útil porque no solo muestra dónde ocurrió el error, sino también cómo el programa terminó en ese lugar del código. Esto lleva a la siguiente pregunta:

¿Qué es una excepción?

Una excepción es lo que utiliza el entorno de tiempo de ejecución para indicarle que se produjo un error. Ejemplos populares son NullPointerException, IndexOutOfBoundsException o ArithmeticException. Cada uno de estos se produce cuando intentas hacer algo que no es posible. Por ejemplo, se lanzará una NullPointerException cuando intente desreferenciar un objeto Nulo:

Object a = null;
a.toString();                 //this line throws a NullPointerException

Object[] b = new Object[5];
System.out.println(b[10]);    //this line throws an IndexOutOfBoundsException,
                              //because b is only 5 elements long
int ia = 5;
int ib = 0;
ia = ia/ib;                   //this line throws an  ArithmeticException with the 
                              //message "/ by 0", because you are trying to
                              //divide by 0, which is not possible.

¿Cómo debo tratar con Stacktraces / Exceptions?

Al principio, averigüe qué está causando la excepción. Intente googlear el nombre de la excepción para averiguar cuál es la causa de esa excepción. La mayoría de las veces será causado por un código incorrecto. En los ejemplos anteriores, todas las excepciones son causadas por un código incorrecto. Entonces, para el ejemplo NullPointerException, puede asegurarse de que anunca sea nulo en ese momento. Podría, por ejemplo, inicializar ao incluir un cheque como este:

if (a!=null) {
    a.toString();
}

De esta manera, la línea ofensiva no se ejecuta si a==null. Lo mismo ocurre con los otros ejemplos.

A veces no puedes asegurarte de no obtener una excepción. Por ejemplo, si está utilizando una conexión de red en su programa, no puede evitar que la computadora pierda su conexión a Internet (por ejemplo, no puede evitar que el usuario desconecte la conexión de red de la computadora). En este caso, la biblioteca de red probablemente arrojará una excepción. Ahora deberías atrapar la excepción y manejarla . Esto significa que, en el ejemplo con la conexión de red, debe intentar volver a abrir la conexión o notificar al usuario o algo así. Además, siempre que use catch, siempre capture solo la excepción que desea capturar, no use declaraciones de captura amplias comocatch (Exception e)eso atraparía todas las excepciones. Esto es muy importante, porque de lo contrario podría detectar accidentalmente la excepción incorrecta y reaccionar de la manera incorrecta.

try {
    Socket x = new Socket("1.1.1.1", 6789);
    x.getInputStream().read()
} catch (IOException e) {
    System.err.println("Connection could not be established, please try again later!")
}

¿Por qué no debería usar catch (Exception e) ?

Usemos un pequeño ejemplo para mostrar por qué no debe capturar todas las excepciones:

int mult(Integer a,Integer b) {
    try {
        int result = a/b
        return result;
    } catch (Exception e) {
        System.err.println("Error: Division by zero!");
        return 0;
    }
}

Lo que este código está tratando de hacer es atrapar lo ArithmeticExceptioncausado por una posible división por 0. Pero también atrapa un posible NullPointerExceptionque se lanza si es ao bes null. Esto significa que puede obtener unNullPointerException pero lo tratará como una Excepción Aritmética y probablemente hará lo incorrecto. En el mejor de los casos, aún echa de menos que haya una NullPointerException. Cosas así hacen que la depuración sea mucho más difícil, así que no hagas eso.

TLDR

  1. Averigua cuál es la causa de la excepción y arréglalo para que no arroje la excepción en absoluto.
  2. Si 1. no es posible, tome la excepción específica y manejela.

    • ¡Nunca agregue un try / catch y luego simplemente ignore la excepción! ¡No hagas eso!
    • Nunca use catch (Exception e), siempre tome excepciones específicas. Eso te ahorrará muchos dolores de cabeza.
Dakkaron
fuente
1
buena explicación de por qué deberíamos evitar el enmascaramiento de errores
Sudip Bhandari
2
Estoy publicando esta respuesta, por lo que la respuesta más importante (cuando está ordenada por actividad) no es simplemente incorrecta, no tengo idea de cuál está hablando, ya que probablemente esto ya haya cambiado. Pero la respuesta aceptada es definitivamente más interesante;)
AxelH
1
El que quise decir ha sido eliminado por ahora, por lo que sé. Básicamente decía "solo prueba {} catch (Exception e) {} e ignora todos los errores". La respuesta aceptada es mucho más antigua que mi respuesta, así que tenía el objetivo de dar una visión un poco diferente sobre el asunto. No creo que ayude a nadie simplemente copiar la respuesta de otra persona o cubrir lo que otras personas ya cubrieron bien.
Dakkaron
Es engañoso decir "No atrapar excepciones", ese es solo un caso de uso. Su ejemplo es excelente, pero ¿qué tal si se encuentra en la parte superior del bucle de hilo (ejecución interna)? SIEMPRE debe capturar una excepción (o tal vez Throwable) allí y registrarla para que no desaparezca de manera invisible (las excepciones generadas por la ejecución generalmente no se registran correctamente a menos que haya configurado su hilo / registrador para hacerlo).
Bill K
1
No incluí este caso especial ya que solo importa con subprocesos múltiples. En un solo subproceso, una excepción filtrada mata el programa y se registra visiblemente. Si alguien no sabe cómo manejar las excepciones correctamente, generalmente tampoco sabe cómo usar el subprocesamiento múltiple.
Dakkaron
21

Para agregar a lo que Rob ha mencionado. Establecer puntos de interrupción en su aplicación permite el procesamiento paso a paso de la pila. Esto permite al desarrollador usar el depurador para ver en qué punto exacto el método está haciendo algo que no se había previsto.

Como Rob ha utilizado el NullPointerException(NPE) para ilustrar algo común, podemos ayudar a eliminar este problema de la siguiente manera:

si tenemos un método que toma parámetros como: void (String firstName)

En nuestro código nos gustaría evaluar que firstNamecontiene un valor, lo haríamos así:if(firstName == null || firstName.equals("")) return;

Lo anterior nos impide usarlo firstNamecomo un parámetro inseguro. Por lo tanto, al hacer comprobaciones nulas antes del procesamiento, podemos ayudar a garantizar que nuestro código se ejecute correctamente. Para ampliar un ejemplo que utiliza un objeto con métodos, podemos mirar aquí:

if(dog == null || dog.firstName == null) return;

Lo anterior es el orden correcto para verificar los nulos, comenzamos con el objeto base, perro en este caso, y luego comenzamos a caminar por el árbol de posibilidades para asegurarnos de que todo sea válido antes del procesamiento. Si se invirtiera la orden, se podría lanzar un NPE y nuestro programa se bloquearía.

Woot4Moo
fuente
Convenido. Este enfoque podría usarse para averiguar qué referencia en una declaración es nullcuando NullPointerExceptionse está examinando un, por ejemplo.
Rob Hruska
16
Cuando se trata de String, si desea usar el método igual, creo que es mejor usar la constante en el lado izquierdo de la comparación, así: En lugar de: if (firstName == null || firstName.equals ("" )) regreso; Siempre uso: if ((""). Equals (firstName)) Esto previene la excepción Nullpointer
Torres
15

Hay una característica más de stacktrace que ofrece la familia Throwable: la posibilidad de manipular la información de seguimiento de pila.

Comportamiento estándar:

package test.stack.trace;

public class SomeClass {

    public void methodA() {
        methodB();
    }

    public void methodB() {
        methodC();
    }

    public void methodC() {
        throw new RuntimeException();
    }

    public static void main(String[] args) {
        new SomeClass().methodA();
    }
}

Seguimiento de pila:

Exception in thread "main" java.lang.RuntimeException
    at test.stack.trace.SomeClass.methodC(SomeClass.java:18)
    at test.stack.trace.SomeClass.methodB(SomeClass.java:13)
    at test.stack.trace.SomeClass.methodA(SomeClass.java:9)
    at test.stack.trace.SomeClass.main(SomeClass.java:27)

Seguimiento de pila manipulada:

package test.stack.trace;

public class SomeClass {

    ...

    public void methodC() {
        RuntimeException e = new RuntimeException();
        e.setStackTrace(new StackTraceElement[]{
                new StackTraceElement("OtherClass", "methodX", "String.java", 99),
                new StackTraceElement("OtherClass", "methodY", "String.java", 55)
        });
        throw e;
    }

    public static void main(String[] args) {
        new SomeClass().methodA();
    }
}

Seguimiento de pila:

Exception in thread "main" java.lang.RuntimeException
    at OtherClass.methodX(String.java:99)
    at OtherClass.methodY(String.java:55)
Przemek Hertel
fuente
2
No sé cómo me siento acerca de esto ... con la naturaleza del hilo, recomendaría a los nuevos desarrolladores que no definan su propio rastro de pila.
PeonProgrammer
15

Para comprender el nombre : Un seguimiento de pila es una lista de Excepciones (o puede decir una lista de "Causa por"), desde la Excepción más superficial (por ejemplo, Excepción de capa de servicio) hasta la más profunda (por ejemplo, Excepción de base de datos). Al igual que la razón por la que lo llamamos 'stack' es porque stack es First in Last out (FILO), la excepción más profunda sucedió desde el principio, luego se generó una cadena de excepción, una serie de consecuencias, la excepción de superficie fue la última uno sucedió a tiempo, pero lo vemos en primer lugar.

Clave 1 : Una cosa difícil e importante aquí que hay que entender es: la causa más profunda puede no ser la "causa raíz", porque si escribe algún "código incorrecto", puede causar alguna excepción debajo que es más profunda que su capa. Por ejemplo, una consulta sql incorrecta puede provocar el restablecimiento de la conexión SQLServerException en el bottem en lugar del error de sincronización, que puede estar justo en el medio de la pila.

-> Localizar la causa raíz en el medio es su trabajo. ingrese la descripción de la imagen aquí

Clave 2 : Otra cosa difícil pero importante está dentro de cada bloque "Causa por", la primera línea fue la capa más profunda y sucedió en primer lugar para este bloque. Por ejemplo,

Exception in thread "main" java.lang.NullPointerException
        at com.example.myproject.Book.getTitle(Book.java:16)
           at com.example.myproject.Author.getBookTitles(Author.java:25)
               at com.example.myproject.Bootstrap.main(Bootstrap.java:14)

Book.java:16 fue llamado por Auther.java:25 que fue llamado por Bootstrap.java:14, Book.java:16 fue la causa raíz. Aquí adjunte un diagrama, clasifique la pila de rastreo en orden cronológico. ingrese la descripción de la imagen aquí

Kevin Li
fuente
8

Solo para agregar a los otros ejemplos, hay clases internas (anidadas) que aparecen con el $signo. Por ejemplo:

public class Test {

    private static void privateMethod() {
        throw new RuntimeException();
    }

    public static void main(String[] args) throws Exception {
        Runnable runnable = new Runnable() {
            @Override public void run() {
                privateMethod();
            }
        };
        runnable.run();
    }
}

Resultará en este seguimiento de pila:

Exception in thread "main" java.lang.RuntimeException
        at Test.privateMethod(Test.java:4)
        at Test.access$000(Test.java:1)
        at Test$1.run(Test.java:10)
        at Test.main(Test.java:13)
Eugene S
fuente
5

Las otras publicaciones describen qué es un seguimiento de pila, pero aún puede ser difícil trabajar con él.

Si obtiene un seguimiento de la pila y desea rastrear la causa de la excepción, un buen punto de partida para comprenderlo es utilizar la Consola de seguimiento de pila de Java en Eclipse . Si usa otro IDE, puede haber una característica similar, pero esta respuesta es sobre Eclipse.

Primero, asegúrese de tener todas sus fuentes Java accesibles en un proyecto Eclipse.

Luego, en la perspectiva de Java , haga clic en la pestaña Consola (generalmente en la parte inferior). Si la vista de la consola no está visible, vaya a la opción de menú Ventana -> Mostrar vista y seleccione Consola .

Luego, en la ventana de la consola, haga clic en el siguiente botón (a la derecha)

Botón de consolas

y luego seleccione Java Stack Trace Console de la lista desplegable.

Pegue su rastro de pila en la consola. Luego proporcionará una lista de enlaces a su código fuente y cualquier otro código fuente disponible.

Esto es lo que puede ver (imagen de la documentación de Eclipse):

Diagrama de la documentación de Eclipse

La llamada al método más reciente realizada será la parte superior de la pila, que es la línea superior (excluyendo el texto del mensaje). Bajar por la pila retrocede en el tiempo. La segunda línea es el método que llama a la primera línea, etc.

Si está utilizando software de código abierto, es posible que deba descargar y adjuntar a su proyecto las fuentes si desea examinarlas. Descargue los archivos jar de origen, en su proyecto, abra la carpeta Bibliotecas referenciadas para encontrar su jar para su módulo de código abierto (el que tiene los archivos de clase), luego haga clic derecho, seleccione Propiedades y adjunte el jar de origen.

rghome
fuente