From b5272dedb5746ee8d28538e078ec416f38576ecf Mon Sep 17 00:00:00 2001 From: Anshul Bansal Date: Wed, 21 Aug 2019 09:27:31 +0300 Subject: [PATCH] BAEL-2846- Intro to the Java Debug Interface (#7606) --- java-jdi/pom.xml | 130 +++++++++++++ .../java/com/baeldung/jdi/JDIExample.java | 14 ++ .../com/baeldung/jdi/JDIExampleDebugger.java | 171 ++++++++++++++++++ pom.xml | 2 + 4 files changed, 317 insertions(+) create mode 100644 java-jdi/pom.xml create mode 100644 java-jdi/src/main/java/com/baeldung/jdi/JDIExample.java create mode 100644 java-jdi/src/main/java/com/baeldung/jdi/JDIExampleDebugger.java diff --git a/java-jdi/pom.xml b/java-jdi/pom.xml new file mode 100644 index 0000000000..3d70461dce --- /dev/null +++ b/java-jdi/pom.xml @@ -0,0 +1,130 @@ + + 4.0.0 + java-jdi + 0.1.0-SNAPSHOT + java-jdi + jar + + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../parent-java + + + + + log4j + log4j + ${log4j.version} + + + org.slf4j + slf4j-api + ${org.slf4j.version} + + + ch.qos.logback + logback-classic + ${logback.version} + + + org.openjdk.jmh + jmh-core + ${jmh-core.version} + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh-generator.version} + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + org.assertj + assertj-core + ${assertj.version} + test + + + com.sun + tools + ${tools.version} + system + ${java.home}/../lib/tools.jar + + + + + java-jdi + + + src/main/resources + true + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven-javadoc-plugin.version} + + 1.8 + 1.8 + + + + + + + + integration + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration-test + + test + + + + **/*IntegrationTest.java + + + + + + + json + + + + + + + + + + 3.5 + + 3.6.1 + 1.8 + 1.7.21 + 1.1.7 + 1.8 + 2.21.0 + 3.0.0-M1 + 3.0.2 + + diff --git a/java-jdi/src/main/java/com/baeldung/jdi/JDIExample.java b/java-jdi/src/main/java/com/baeldung/jdi/JDIExample.java new file mode 100644 index 0000000000..f8f20553b8 --- /dev/null +++ b/java-jdi/src/main/java/com/baeldung/jdi/JDIExample.java @@ -0,0 +1,14 @@ +package com.baeldung.jdi; + +public class JDIExample { + + public static void main(String[] args) { + String jpda = "Java Platform Debugger Architecture"; + System.out.println("Hi Everyone, Welcome to " + jpda); //add a break point here + + String jdi = "Java Debug Interface"; //add a break point here and also stepping in here + String text = "Today, we'll dive into " + jdi; + System.out.println(text); + } + +} diff --git a/java-jdi/src/main/java/com/baeldung/jdi/JDIExampleDebugger.java b/java-jdi/src/main/java/com/baeldung/jdi/JDIExampleDebugger.java new file mode 100644 index 0000000000..1d9de57ddb --- /dev/null +++ b/java-jdi/src/main/java/com/baeldung/jdi/JDIExampleDebugger.java @@ -0,0 +1,171 @@ +package com.baeldung.jdi; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.util.Map; + +import com.sun.jdi.AbsentInformationException; +import com.sun.jdi.Bootstrap; +import com.sun.jdi.ClassType; +import com.sun.jdi.IncompatibleThreadStateException; +import com.sun.jdi.LocalVariable; +import com.sun.jdi.Location; +import com.sun.jdi.StackFrame; +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.Value; +import com.sun.jdi.VirtualMachine; +import com.sun.jdi.connect.Connector; +import com.sun.jdi.connect.IllegalConnectorArgumentsException; +import com.sun.jdi.connect.LaunchingConnector; +import com.sun.jdi.connect.VMStartException; +import com.sun.jdi.event.BreakpointEvent; +import com.sun.jdi.event.ClassPrepareEvent; +import com.sun.jdi.event.Event; +import com.sun.jdi.event.EventSet; +import com.sun.jdi.event.LocatableEvent; +import com.sun.jdi.event.StepEvent; +import com.sun.jdi.request.BreakpointRequest; +import com.sun.jdi.request.ClassPrepareRequest; +import com.sun.jdi.request.StepRequest; + +public class JDIExampleDebugger { + + private Class debugClass; + private int[] breakPointLines; + + public Class getDebugClass() { + return debugClass; + } + + public void setDebugClass(Class debugClass) { + this.debugClass = debugClass; + } + + public int[] getBreakPointLines() { + return breakPointLines; + } + + public void setBreakPointLines(int[] breakPointLines) { + this.breakPointLines = breakPointLines; + } + + /** + * Sets the debug class as the main argument in the connector and launches the VM + * @return VirtualMachine + * @throws IOException + * @throws IllegalConnectorArgumentsException + * @throws VMStartException + */ + public VirtualMachine connectAndLaunchVM() throws IOException, IllegalConnectorArgumentsException, VMStartException { + LaunchingConnector launchingConnector = Bootstrap.virtualMachineManager().defaultConnector(); + Map arguments = launchingConnector.defaultArguments(); + arguments.get("main").setValue(debugClass.getName()); + VirtualMachine vm = launchingConnector.launch(arguments); + return vm; + } + + /** + * Creates a request to prepare the debug class, add filter as the debug class and enables it + * @param vm + */ + public void enableClassPrepareRequest(VirtualMachine vm) { + ClassPrepareRequest classPrepareRequest = vm.eventRequestManager().createClassPrepareRequest(); + classPrepareRequest.addClassFilter(debugClass.getName()); + classPrepareRequest.enable(); + } + + /** + * Sets the break points at the line numbers mentioned in breakPointLines array + * @param vm + * @param event + * @throws AbsentInformationException + */ + public void setBreakPoints(VirtualMachine vm, ClassPrepareEvent event) throws AbsentInformationException { + ClassType classType = (ClassType) event.referenceType(); + for(int lineNumber: breakPointLines) { + Location location = classType.locationsOfLine(lineNumber).get(0); + BreakpointRequest bpReq = vm.eventRequestManager().createBreakpointRequest(location); + bpReq.enable(); + } + } + + /** + * Displays the visible variables + * @param event + * @throws IncompatibleThreadStateException + * @throws AbsentInformationException + */ + public void displayVariables(LocatableEvent event) throws IncompatibleThreadStateException, AbsentInformationException { + StackFrame stackFrame = event.thread().frame(0); + if(stackFrame.location().toString().contains(debugClass.getName())) { + Map visibleVariables = stackFrame.getValues(stackFrame.visibleVariables()); + System.out.println("Variables at " +stackFrame.location().toString() + " > "); + for (Map.Entry entry : visibleVariables.entrySet()) { + System.out.println(entry.getKey().name() + " = " + entry.getValue()); + } + } + } + + /** + * Enables step request for a break point + * @param vm + * @param event + */ + public void enableStepRequest(VirtualMachine vm, BreakpointEvent event) { + //enable step request for last break point + if(event.location().toString().contains(debugClass.getName()+":"+breakPointLines[breakPointLines.length-1])) { + StepRequest stepRequest = vm.eventRequestManager().createStepRequest(event.thread(), StepRequest.STEP_LINE, StepRequest.STEP_OVER); + stepRequest.enable(); + } + } + + public static void main(String[] args) throws Exception { + + JDIExampleDebugger debuggerInstance = new JDIExampleDebugger(); + debuggerInstance.setDebugClass(JDIExample.class); + int[] breakPoints = {6, 9}; + debuggerInstance.setBreakPointLines(breakPoints); + VirtualMachine vm = null; + + try { + vm = debuggerInstance.connectAndLaunchVM(); + debuggerInstance.enableClassPrepareRequest(vm); + + EventSet eventSet = null; + while ((eventSet = vm.eventQueue().remove()) != null) { + for (Event event : eventSet) { + if (event instanceof ClassPrepareEvent) { + debuggerInstance.setBreakPoints(vm, (ClassPrepareEvent)event); + } + + if (event instanceof BreakpointEvent) { + event.request().disable(); + debuggerInstance.displayVariables((BreakpointEvent) event); + debuggerInstance.enableStepRequest(vm, (BreakpointEvent)event); + } + + if (event instanceof StepEvent) { + debuggerInstance.displayVariables((StepEvent) event); + } + vm.resume(); + } + } + } catch (VMDisconnectedException e) { + System.out.println("Virtual Machine is disconnected."); + } catch (Exception e) { + e.printStackTrace(); + } + finally { + InputStreamReader reader = new InputStreamReader(vm.process().getInputStream()); + OutputStreamWriter writer = new OutputStreamWriter(System.out); + char[] buf = new char[512]; + + reader.read(buf); + writer.write(buf); + writer.flush(); + } + + } + +} diff --git a/pom.xml b/pom.xml index fc3567be51..58c5473744 100644 --- a/pom.xml +++ b/pom.xml @@ -457,6 +457,7 @@ java-collections-conversions java-collections-maps java-collections-maps-2 + java-jdi @@ -1156,6 +1157,7 @@ java-collections-conversions java-collections-maps java-collections-maps-2 + java-jdi java-ee-8-security-api java-lite