BAEL-2846- Intro to the Java Debug Interface (#7606)

This commit is contained in:
Anshul Bansal 2019-08-21 09:27:31 +03:00 committed by Grzegorz Piwowarek
parent 5bc7d85eee
commit b5272dedb5
4 changed files with 317 additions and 0 deletions

130
java-jdi/pom.xml Normal file
View File

@ -0,0 +1,130 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>java-jdi</artifactId>
<version>0.1.0-SNAPSHOT</version>
<name>java-jdi</name>
<packaging>jar</packaging>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-java</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../parent-java</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>${jmh-core.version}</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh-generator.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>${tools.version}</version>
<scope>system</scope>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
</dependencies>
<build>
<finalName>java-jdi</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>${maven-javadoc-plugin.version}</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>integration</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<includes>
<include>**/*IntegrationTest.java</include>
</includes>
</configuration>
</execution>
</executions>
<configuration>
<systemPropertyVariables>
<test.mime>json</test.mime>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<properties>
<commons-lang3.version>3.5</commons-lang3.version>
<assertj.version>3.6.1</assertj.version>
<tool.version>1.8</tool.version>
<org.slf4j.version>1.7.21</org.slf4j.version>
<logback.version>1.1.7</logback.version>
<tools.version>1.8</tools.version>
<maven-surefire-plugin.version>2.21.0</maven-surefire-plugin.version>
<maven-javadoc-plugin.version>3.0.0-M1</maven-javadoc-plugin.version>
<maven-jar-plugin.version>3.0.2</maven-jar-plugin.version>
</properties>
</project>

View File

@ -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);
}
}

View File

@ -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<String, Connector.Argument> 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<LocalVariable, Value> visibleVariables = stackFrame.getValues(stackFrame.visibleVariables());
System.out.println("Variables at " +stackFrame.location().toString() + " > ");
for (Map.Entry<LocalVariable, Value> 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();
}
}
}

View File

@ -457,6 +457,7 @@
<module>java-collections-conversions</module>
<module>java-collections-maps</module>
<module>java-collections-maps-2</module>
<module>java-jdi</module>
<!-- <module>java-dates</module> --> <!-- We haven't upgraded to java 9. Fixing in BAEL-10841 -->
<!-- <module>java-dates-2</module> --> <!-- We haven't upgraded to java 9. Fixing in BAEL-10841 -->
<!-- <module>java-ee-8-security-api</module> --> <!-- long running -->
@ -1156,6 +1157,7 @@
<module>java-collections-conversions</module>
<module>java-collections-maps</module>
<module>java-collections-maps-2</module>
<module>java-jdi</module>
<!-- <module>java-dates</module> --> <!-- We haven't upgraded to java 9. Fixing in BAEL-10841 -->
<module>java-ee-8-security-api</module>
<module>java-lite</module>