En introduksjon til Java Debug Interface (JDI)

1. Oversikt

Vi kan lure på hvor anerkjente IDEer som IntelliJ IDEA og Eclipse implementerer feilsøkingsfunksjoner. Disse verktøyene er avhengige av Java Platform Debugger Architecture (JPDA).

I denne innledende artikkelen vil vi diskutere Java Debug Interface API (JDI) tilgjengelig under JPDA.

Samtidig, vi skriver et tilpasset feilsøkingsprogram trinn for trinn og gjøre oss kjent med praktiske JDI-grensesnitt.

2. Introduksjon til JPDA

Java Platform Debugger Architecture (JPDA) er et sett med veldesignede grensesnitt og protokoller som brukes til å feilsøke Java.

Den gir tre spesialdesignede grensesnitt for å implementere tilpassede feilsøkere for et utviklingsmiljø i stasjonære systemer.

Til å begynne med hjelper Java Virtual Machine Tool Interface (JVMTI) oss med å samhandle og kontrollere kjøringen av applikasjoner som kjører i JVM.

Deretter er det Java Debug Wire Protocol (JDWP) som definerer protokollen som brukes mellom applikasjonen som testes (feilsøking) og feilsøkingsprogrammet.

Til slutt brukes Java Debug Interface (JDI) til å implementere feilsøkingsprogrammet.

3. Hva er? JDI?

Java Debug Interface API er et sett med grensesnitt levert av Java, for å implementere frontend av feilsøkingsprogrammet. JDI er det høyeste laget av JPDA.

En feilsøking bygget med JDI kan feilsøke applikasjoner som kjører i hvilken som helst JVM som støtter JPDA. Samtidig kan vi koble den til ethvert lag med feilsøking.

Det gir muligheten til å få tilgang til VM og dens tilstand sammen med tilgang til variabler i feilsøking. Samtidig tillater det å stille inn brytepunkter, tråkk, overvåkningspunkter og håndtere tråder.

4. Oppsett

Vi trenger to separate programmer - en feilsøking og en feilsøking - for å forstå JDIs implementeringer.

Først skriver vi et eksempelprogram som feilsøking.

La oss lage en JDIEeksempelDebuggee klasse med noen få String variabler og utskrift uttalelser:

offentlig klasse JDIExampleDebuggee {public static void main (String [] args) {String jpda = "Java Platform Debugger Architecture"; System.out.println ("Hei alle sammen, velkommen til" + jpda); // legg til et bruddpunkt her String jdi = "Java Debug Interface"; // legg til et bruddpunkt her og også gå inn her String text = "I dag skal vi dykke ned i" + jdi; System.out.println (tekst); }}

Deretter skriver vi et feilsøkingsprogram.

La oss lage en JDIEeksempelDebugger klasse med egenskaper for å holde feilsøkingsprogrammet (debugClass) og linjenumre for brytepunkter (breakPointLines):

offentlig klasse JDIExampleDebugger {private Class debugClass; private int [] breakPointLines; // getters og setters}

4.1. LaunchingConnector

Først krever en feilsøkingsprogram en kobling for å opprette en forbindelse med målet Virtual Machine (VM).

Deretter må vi angi feilsøkingsprogrammet som kontakten hoved- argument. Til slutt skal kontakten starte VM for feilsøking.

For å gjøre det, gir JDI en Støvelhempe klasse som gir en forekomst av LaunchingConnector. De LaunchingConnector gir et kart over standardargumentene, der vi kan stille inn hoved- argument.

La oss derfor legge til connectAndLaunchVM metoden til JDIDebuggerExample klasse:

offentlig VirtualMachine connectAndLaunchVM () kaster Unntak {LaunchingConnector launchingConnector = Bootstrap.virtualMachineManager (). standardConnector (); Kartargumenter = launchingConnector.defaultArguments (); argumenter.get ("hoved"). setValue (debugClass.getName ()); return launchingConnector.launch (argumenter); }

Nå skal vi legge til hoved- metoden til JDIDebuggerExample klasse for å feilsøke JDIEeksempelDebuggee:

offentlig statisk ugyldig hoved (String [] args) kaster Unntak {JDIExampleDebugger debuggerInstance = new JDIExampleDebugger (); debuggerInstance.setDebugClass (JDIExampleDebuggee.class); int [] breakPoints = {6, 9}; debuggerInstance.setBreakPointLines (breakPoints); VirtualMachine vm = null; prøv {vm = debuggerInstance.connectAndLaunchVM (); vm.resume (); } fange (Unntak e) {e.printStackTrace (); }}

La oss lage begge klassene våre, JDIEeksempelDebuggee (debuggee) og JDIEeksempelDebugger (feilsøkingsprogram):

javac -g -cp "/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/lib/tools.jar" com / baeldung / jdi / *. java

La oss diskutere javac kommandoen som brukes her, i detalj.

De -g alternativet genererer all feilsøkingsinformasjonen uten hvilken, kan vi se AbsentInformationException.

Og -cp vil legge til tools.jar i klassestien for å kompilere klassene.

Alle JDI-biblioteker er tilgjengelige under tools.jar av JDK. Sørg derfor for å legge til tools.jar i klassestien til både kompilering og utførelse.

Det er det, nå er vi klare til å utføre vår tilpassede feilsøkingsprogram JDIEeksempelDebugger:

java -cp "/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/lib/tools.jar :." JDIEeksempelDebugger

Legg merke til “:.” med tools.jar. Dette vil føyes til tools.jar til klassestien for gjeldende kjøretid (bruk “;.” på windows).

4.2. Støvelhempe og ClassPrepareRequest

Å utføre feilsøkingsprogrammet her vil ikke gi noen resultater siden vi ikke har forberedt klassen for feilsøking og satt brytepunktene.

De Virtuell maskin klassen har eventRequestManager metode for å lage forskjellige forespørsler som ClassPrepareRequest, BreakpointRequest, og StepEventRequest.

Så la oss legge til enableClassPrepareRequest metoden til JDIEeksempelDebugger klasse.

Dette vil filtrere JDIEeksempelDebuggee klasse og muliggjør ClassPrepareRequest:

public void enableClassPrepareRequest (VirtualMachine vm) {ClassPrepareRequest classPrepareRequest = vm.eventRequestManager (). createClassPrepareRequest (); classPrepareRequest.addClassFilter (debugClass.getName ()); classPrepareRequest.enable (); }

4.3. ClassPrepareEvent og BreakpointRequest

En gang, ClassPrepareRequest for JDIEeksempelDebuggee klasse er aktivert, vil hendelseskøen til VM begynne å ha forekomster av ClassPrepareEvent.

Ved hjelp av ClassPrepareEvent, vi kan få stedet til å sette et bruddpunkt og skaper et BreakPointRequest.

For å gjøre det, la oss legge til setBreakPoints metoden til JDIEeksempelDebugger klasse:

public void setBreakPoints (VirtualMachine vm, ClassPrepareEvent event) kaster AbsentInformationException {ClassType classType = (ClassType) event.referenceType (); for (int lineNumber: breakPointLines) {Location location = classType.locationsOfLine (lineNumber) .get (0); BreakpointRequest bpReq = vm.eventRequestManager (). CreateBreakpointRequest (plassering); bpReq.enable (); }}

4.4. BreakPointEvent og StackFrame

Så langt har vi forberedt klassen for feilsøking og satt brytepunktene. Nå må vi fange BreakPointEvent og vise variablene.

JDI sørger for StackFrame klasse, for å få listen over alle synlige variabler til feilsøking.

La oss derfor legge til displayVariables metoden til JDIEeksempelDebugger klasse:

public void displayVariables (LocatableEvent event) kaster IncompatibleThreadStateException, AbsentInformationException {StackFrame stackFrame = event.thread (). frame (0); hvis (stackFrame.location (). toString (). inneholder (debugClass.getName ())) {Map visibleVariables = stackFrame .getValues ​​(stackFrame.visibleVariables ()); System.out.println ("Variabler ved" + stackFrame.location (). ToString () + ">"); for (Map.Entry entry: visibleVariables.entrySet ()) {System.out.println (entry.getKey (). name () + "=" + entry.getValue ()); }}}

5. Feilsøk mål

På dette trinnet er alt vi trenger å oppdatere hoved- metoden for JDIEeksempelDebugger for å starte feilsøking.

Derfor vil vi bruke de allerede diskuterte metodene som enableClassPrepareRequest, setBreakPoints, og displayVariables:

prøv {vm = debuggerInstance.connectAndLaunchVM (); debuggerInstance.enableClassPrepareRequest (vm); EventSet eventSet = null; while ((eventSet = vm.eventQueue (). remove ())! = null) {for (Event event: eventSet) {if (event instance of ClassPrepareEvent) {debuggerInstance.setBreakPoints (vm, (ClassPrepareEvent) event); } if (event instanceof BreakpointEvent) {debuggerInstance.displayVariables ((BreakpointEvent) event); } vm.resume (); }}} fangst (VMDisconnectedException e) {System.out.println ("Virtual Machine is disconnected."); } fange (Unntak e) {e.printStackTrace (); }

La oss først kompilere JDIDebuggerExample klasse igjen med det allerede diskuterte javac kommando.

Og til slutt vil vi utføre feilsøkingsprogrammet sammen med alle endringene for å se utdataene:

Variabler ved com.baeldung.jdi.JDIExampleDebuggee: 6> args = forekomst av java.lang.String [0] (id = 93) Variabler ved com.baeldung.jdi.JDIExampleDebuggee: 9> jpda = "Java Platform Debugger Architecture" args = forekomst av java.lang.String [0] (id = 93) Den virtuelle maskinen er koblet fra.

Hurra! Vi har feilsøkt feilsøking JDIEeksempelDebuggee klasse. Samtidig har vi vist verdiene til variablene på brytpunktstedene (linje nummer 6 og 9).

Derfor er vår tilpassede feilsøkingsprogram klar.

5.1. StepRequest

Feilsøking krever også å gå gjennom koden og kontrollere tilstanden til variablene i påfølgende trinn. Derfor oppretter vi en trinnforespørsel ved brytpunktet.

Mens du oppretter forekomsten av StepRequest, vi må oppgi størrelsen og dybden på trinnet. Vi definerer STEP_LINE og TRÅKKE OVER henholdsvis.

La oss skrive en metode for å aktivere trinnforespørselen.

For enkelhets skyld begynner vi å gå til det siste brytpunktet (linje nummer 9):

public void enableStepRequest (VirtualMachine vm, BreakpointEvent event) {// aktiver trinnforespørsel for siste brytpunkt hvis (event.location (). toString (). inneholder (debugClass.getName () + ":" + breakPointLines [breakPointLines.length- 1])) {StepRequest stepRequest = vm.eventRequestManager () .createStepRequest (event.thread (), StepRequest.STEP_LINE, StepRequest.STEP_OVER); stepRequest.enable (); }}

Nå kan vi oppdatere hoved- metoden for JDIEeksempelDebugger, for å aktivere trinnforespørselen når den er en BreakPointEvent:

if (event instanceof BreakpointEvent) {debuggerInstance.enableStepRequest (vm, (BreakpointEvent) event); }

5.2. StepEvent

I likhet med BreakPointEvent, kan vi også vise variablene på StepEvent.

La oss oppdatere hoved- metoden deretter:

if (event instanceof StepEvent) {debuggerInstance.displayVariables ((StepEvent) event); }

Til slutt vil vi utføre feilsøkingsprogrammet for å se tilstanden til variablene mens vi går gjennom koden:

Variabler ved com.baeldung.jdi.JDIEeksempelDebuggee: 6> args = forekomst av java.lang.String [0] (id = 93) Variabler ved com.baeldung.jdi.JDIExampleDebuggee: 9> args = forekomst av java.lang.String [0] (id = 93) jpda = "Java Platform Debugger Architecture" Variabler på com.baeldung.jdi.JDIExampleDebuggee: 10> args = forekomst av java.lang.String [0] (id = 93) jpda = "Java Platform Feilsøkingsarkitektur "jdi =" Java Debug Interface "Variabler på com.baeldung.jdi.JDIExampleDebuggee: 11> args = forekomst av java.lang.String [0] (id = 93) jpda =" Java Platform Debugger Architecture "jdi =" Java Debug Interface "text =" I dag dykker vi inn i Java Debug Interface "-variabler på com.baeldung.jdi.JDIEeksempelDebuggee: 12> args = forekomst av java.lang.String [0] (id = 93) jpda =" Java Platform Debugger Architecture "jdi =" Java Debug Interface "text =" I dag dykker vi ned i Java Debug Interface "Virtual Machine er koblet fra.

Hvis vi sammenligner produksjonen, vil vi innse at feilsøkingsprogrammet gikk inn fra linje nummer 9 og viser variablene i alle påfølgende trinn.

6. Les utførelsesutdata

Vi vil kanskje legge merke til det utskrift uttalelser fra JDIEeksempelDebuggee klasse har ikke vært en del av feilsøkingsutgangen.

I henhold til JDI-dokumentasjonen, hvis vi starter VM gjennom LaunchingConnector, dens utgangs- og feilstrømmer må leses av Prosess gjenstand.

La oss derfor legge det til endelig klausul om vår hoved- metode:

til slutt {InputStreamReader reader = new InputStreamReader (vm.process (). getInputStream ()); OutputStreamWriter-forfatter = ny OutputStreamWriter (System.out); røye [] buf = ny røye [512]; reader.read (buf); writer.write (buf); writer.flush (); }

Nå vil kjøring av feilsøkingsprogrammet også legge til utskrift uttalelser fra JDIEeksempelDebuggee klasse til feilsøkingsutgangen:

Hei alle sammen, Velkommen til Java Platform Debugger Architecture I dag vil vi dykke ned i Java Debug Interface

7. Konklusjon

I denne artikkelen har vi utforsket Java Debug Interface (JDI) API tilgjengelig under Java Platform Debugger Architecture (JPDA).

Underveis har vi bygget en tilpasset feilsøkingsprogram ved hjelp av de praktiske grensesnittene som tilbys av JDI. Samtidig har vi også lagt til stegefunksjon i feilsøkingsprogrammet.

Siden dette bare var en introduksjon til JDI, anbefales det å se på implementeringene av andre grensesnitt som er tilgjengelige under JDI API.

Som vanlig er alle kodeimplementeringene tilgjengelige på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found