Java >> Java tutorial >  >> Tag >> Stack

Arbejde med (ukendt kilde) Stack Traces i Java

1. Oversigt

I denne korte artikel vil vi se på, hvorfor vi kan se en ukendt kilde i vores Java-undtagelsesstacksporing, og hvordan kan vi rette det.

2. Klasse Debug Information

En Java-klassefil indeholder valgfri debug-information for at lette debugging. Vi kan i kompileringstiden vælge, om og hvad al fejlretningsinformation skal tilføjes til klassefilerne. Dette vil afgøre, hvilke fejlfindingsoplysninger der er tilgængelige under kørsel.

Lad os undersøge Java-kompilerens hjælpedokumentation for at se de forskellige tilgængelige muligheder:

javac -help

Usage: javac <options> <source files>
where possible options include:
  -g                         Generate all debugging info
  -g:none                    Generate no debugging info
  -g:{lines,vars,source}     Generate only some debugging info

Standardadfærden for Javas compiler er at tilføje linjerne og kildeoplysningerne til klassefilerne, hvilket svarer til -g:lines,source.

2.1. Kompilere med Debug Option

Lad os se, hvad der sker, når vi kompilerer vores Java-klasser med mulighederne ovenfor. Vi har en Main klasse, der med vilje genererer en StringIndexOutOfBoundsException .

Afhængigt af den anvendte kompileringsmekanisme bliver vi nødt til at specificere kompileringsindstillingen i overensstemmelse hermed. Her vil vi bruge Maven og dets compiler-plugin til at tilpasse compiler-indstillingen:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.1</version>
    <configuration>
        <compilerArgs>
            <arg>-g:none</arg>
        </compilerArgs>
    </configuration>
</plugin>

Vi har indstillet -g til ingen hvilket betyder, at der ikke vil blive genereret fejlfindingsoplysninger for vores kompilerede klasser. Kører vores buggy Main klasse genererer staksporet, hvor vi ser ukendte kilder i stedet for linjenummeret, hvor undtagelsen opstod.

Exception in thread "main" java.lang.StringIndexOutOfBoundsException: begin 0, end 10, length 5
  at java.base/java.lang.String.checkBoundsBeginEnd(String.java:3751)
  at java.base/java.lang.String.substring(String.java:1907)
  at com.baeldung.unknownsourcestacktrace.Main.getShortenedName(Unknown Source)
  at com.baeldung.unknownsourcestacktrace.Main.getGreetingMessage(Unknown Source)
  at com.baeldung.unknownsourcestacktrace.Main.main(Unknown Source)

Lad os se, hvad den genererede klassefil indeholder. Vi bruger javap  som er Java-klassens filopdeling for at gøre dette:

javap -l -p Main.class

public class com.baeldung.unknownsourcestacktrace.Main {
    private static final org.slf4j.Logger logger;
    private static final int SHORT_NAME_LIMIT;
    public com.baeldung.unknownsourcestacktrace.Main();
    public static void main(java.lang.String[]);
    private static java.lang.String getGreetingMessage(java.lang.String);
    private static java.lang.String getShortenedName(java.lang.String);
    static {};
}

Det kan være svært at vide, hvilken fejlretningsinformation vi skal forvente her, så lad os ændre kompileringsindstillingen og se, hvad der sker.

2.3. Rettelsen

Lad os nu ændre kompileringsindstillingen til -g:lines,vars,source som vil indsætte LineNumberTable, LocalVariableTable og Kilde oplysninger i vores klassefiler. Det svarer også til bare at have -g  som sætter alle fejlretningsoplysningerne:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.1</version>
    <configuration>
        <compilerArgs>
            <arg>-g</arg>
        </compilerArgs>
    </configuration>
</plugin>

Kører vores buggy Main klasse igen producerer nu:

Exception in thread "main" java.lang.StringIndexOutOfBoundsException: begin 0, end 10, length 5
  at java.base/java.lang.String.checkBoundsBeginEnd(String.java:3751)
  at java.base/java.lang.String.substring(String.java:1907)
  at com.baeldung.unknownsourcestacktrace.Main.getShortenedName(Main.java:23)
  at com.baeldung.unknownsourcestacktrace.Main.getGreetingMessage(Main.java:19)
  at com.baeldung.unknownsourcestacktrace.Main.main(Main.java:15)

Voila, vi ser linjenummeroplysningerne i vores stakspor. Lad os se, hvad der er ændret i vores klassefil:

javap -l -p Main

Compiled from "Main.java"
public class com.baeldung.unknownsourcestacktrace.Main {
  private static final org.slf4j.Logger logger;

  private static final int SHORT_NAME_LIMIT;

  public com.baeldung.unknownsourcestacktrace.Main();
    LineNumberTable:
      line 7: 0
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0       5     0  this   Lcom/baeldung/unknownsourcestacktrace/Main;

  public static void main(java.lang.String[]);
    LineNumberTable:
      line 12: 0
      line 13: 8
      line 15: 14
      line 16: 29
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0      30     0  args   [Ljava/lang/String;
          8      22     1  user   Lcom/baeldung/unknownsourcestacktrace/dto/User;

  private static java.lang.String getGreetingMessage(java.lang.String);
    LineNumberTable:
      line 19: 0
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0      28     0  name   Ljava/lang/String;

  private static java.lang.String getShortenedName(java.lang.String);
    LineNumberTable:
      line 23: 0
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0       8     0  name   Ljava/lang/String;

  static {};
    LineNumberTable:
      line 8: 0
}

Vores klassefil indeholder nu tre vigtige oplysninger:

  1. Kilde , den øverste overskrift, der angiver .java fil, hvorfra .class fil er blevet genereret. I sammenhæng med en staksporing giver den klassenavnet, hvor undtagelsen opstod.
  2. LineNumberTable kortlægger linjenummeret i den kode, som JVM'en rent faktisk kører, til linjenummeret i vores kildekodefil. I sammenhæng med en staksporing giver den linjenummeret, hvor undtagelsen opstod. Vi har også brug for dette for at kunne bruge breakpoints i vores debuggere.
  3. LocalVariableTable indeholder detaljerne for at få værdien af ​​en lokal variabel. Debuggere kan bruge det til at læse værdien af ​​en lokal variabel. I forbindelse med en staksporing er dette ligegyldigt.

3. Konklusion

Vi er nu bekendt med fejlfindingsoplysningerne, der genereres af Java-kompileren. Måden at manipulere dem på, -g compiler mulighed. Vi så, hvordan vi kan gøre det med Maven compiler plugin.

Så hvis vi finder ukendte kilder i vores stakspor, kan vi undersøge vores klassefiler for at kontrollere, om fejlretningsinformationen er tilgængelig eller ej. Herefter kan vi vælge den rigtige kompileringsmulighed baseret på vores byggeværktøj for at løse dette problem.

Som altid er den komplette kode og Maven-konfigurationer tilgængelige på GitHub.


Java tag