Skip to content

Commit b5272de

Browse files
SmartyAnshpivovarit
authored andcommitted
BAEL-2846- Intro to the Java Debug Interface (eugenp#7606)
1 parent 5bc7d85 commit b5272de

4 files changed

Lines changed: 317 additions & 0 deletions

File tree

java-jdi/pom.xml

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0"
2+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
<artifactId>java-jdi</artifactId>
6+
<version>0.1.0-SNAPSHOT</version>
7+
<name>java-jdi</name>
8+
<packaging>jar</packaging>
9+
10+
<parent>
11+
<groupId>com.baeldung</groupId>
12+
<artifactId>parent-java</artifactId>
13+
<version>0.0.1-SNAPSHOT</version>
14+
<relativePath>../parent-java</relativePath>
15+
</parent>
16+
17+
<dependencies>
18+
<dependency>
19+
<groupId>log4j</groupId>
20+
<artifactId>log4j</artifactId>
21+
<version>${log4j.version}</version>
22+
</dependency>
23+
<dependency>
24+
<groupId>org.slf4j</groupId>
25+
<artifactId>slf4j-api</artifactId>
26+
<version>${org.slf4j.version}</version>
27+
</dependency>
28+
<dependency>
29+
<groupId>ch.qos.logback</groupId>
30+
<artifactId>logback-classic</artifactId>
31+
<version>${logback.version}</version>
32+
</dependency>
33+
<dependency>
34+
<groupId>org.openjdk.jmh</groupId>
35+
<artifactId>jmh-core</artifactId>
36+
<version>${jmh-core.version}</version>
37+
</dependency>
38+
<dependency>
39+
<groupId>org.openjdk.jmh</groupId>
40+
<artifactId>jmh-generator-annprocess</artifactId>
41+
<version>${jmh-generator.version}</version>
42+
</dependency>
43+
<dependency>
44+
<groupId>org.apache.commons</groupId>
45+
<artifactId>commons-lang3</artifactId>
46+
<version>${commons-lang3.version}</version>
47+
</dependency>
48+
<dependency>
49+
<groupId>org.assertj</groupId>
50+
<artifactId>assertj-core</artifactId>
51+
<version>${assertj.version}</version>
52+
<scope>test</scope>
53+
</dependency>
54+
<dependency>
55+
<groupId>com.sun</groupId>
56+
<artifactId>tools</artifactId>
57+
<version>${tools.version}</version>
58+
<scope>system</scope>
59+
<systemPath>${java.home}/../lib/tools.jar</systemPath>
60+
</dependency>
61+
</dependencies>
62+
63+
<build>
64+
<finalName>java-jdi</finalName>
65+
<resources>
66+
<resource>
67+
<directory>src/main/resources</directory>
68+
<filtering>true</filtering>
69+
</resource>
70+
</resources>
71+
72+
<plugins>
73+
74+
<plugin>
75+
<groupId>org.apache.maven.plugins</groupId>
76+
<artifactId>maven-javadoc-plugin</artifactId>
77+
<version>${maven-javadoc-plugin.version}</version>
78+
<configuration>
79+
<source>1.8</source>
80+
<target>1.8</target>
81+
</configuration>
82+
</plugin>
83+
</plugins>
84+
</build>
85+
86+
<profiles>
87+
<profile>
88+
<id>integration</id>
89+
<build>
90+
<plugins>
91+
<plugin>
92+
<groupId>org.apache.maven.plugins</groupId>
93+
<artifactId>maven-surefire-plugin</artifactId>
94+
<executions>
95+
<execution>
96+
<phase>integration-test</phase>
97+
<goals>
98+
<goal>test</goal>
99+
</goals>
100+
<configuration>
101+
<includes>
102+
<include>**/*IntegrationTest.java</include>
103+
</includes>
104+
</configuration>
105+
</execution>
106+
</executions>
107+
<configuration>
108+
<systemPropertyVariables>
109+
<test.mime>json</test.mime>
110+
</systemPropertyVariables>
111+
</configuration>
112+
</plugin>
113+
</plugins>
114+
</build>
115+
</profile>
116+
</profiles>
117+
118+
<properties>
119+
<commons-lang3.version>3.5</commons-lang3.version>
120+
121+
<assertj.version>3.6.1</assertj.version>
122+
<tool.version>1.8</tool.version>
123+
<org.slf4j.version>1.7.21</org.slf4j.version>
124+
<logback.version>1.1.7</logback.version>
125+
<tools.version>1.8</tools.version>
126+
<maven-surefire-plugin.version>2.21.0</maven-surefire-plugin.version>
127+
<maven-javadoc-plugin.version>3.0.0-M1</maven-javadoc-plugin.version>
128+
<maven-jar-plugin.version>3.0.2</maven-jar-plugin.version>
129+
</properties>
130+
</project>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.baeldung.jdi;
2+
3+
public class JDIExample {
4+
5+
public static void main(String[] args) {
6+
String jpda = "Java Platform Debugger Architecture";
7+
System.out.println("Hi Everyone, Welcome to " + jpda); //add a break point here
8+
9+
String jdi = "Java Debug Interface"; //add a break point here and also stepping in here
10+
String text = "Today, we'll dive into " + jdi;
11+
System.out.println(text);
12+
}
13+
14+
}
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
package com.baeldung.jdi;
2+
3+
import java.io.IOException;
4+
import java.io.InputStreamReader;
5+
import java.io.OutputStreamWriter;
6+
import java.util.Map;
7+
8+
import com.sun.jdi.AbsentInformationException;
9+
import com.sun.jdi.Bootstrap;
10+
import com.sun.jdi.ClassType;
11+
import com.sun.jdi.IncompatibleThreadStateException;
12+
import com.sun.jdi.LocalVariable;
13+
import com.sun.jdi.Location;
14+
import com.sun.jdi.StackFrame;
15+
import com.sun.jdi.VMDisconnectedException;
16+
import com.sun.jdi.Value;
17+
import com.sun.jdi.VirtualMachine;
18+
import com.sun.jdi.connect.Connector;
19+
import com.sun.jdi.connect.IllegalConnectorArgumentsException;
20+
import com.sun.jdi.connect.LaunchingConnector;
21+
import com.sun.jdi.connect.VMStartException;
22+
import com.sun.jdi.event.BreakpointEvent;
23+
import com.sun.jdi.event.ClassPrepareEvent;
24+
import com.sun.jdi.event.Event;
25+
import com.sun.jdi.event.EventSet;
26+
import com.sun.jdi.event.LocatableEvent;
27+
import com.sun.jdi.event.StepEvent;
28+
import com.sun.jdi.request.BreakpointRequest;
29+
import com.sun.jdi.request.ClassPrepareRequest;
30+
import com.sun.jdi.request.StepRequest;
31+
32+
public class JDIExampleDebugger {
33+
34+
private Class debugClass;
35+
private int[] breakPointLines;
36+
37+
public Class getDebugClass() {
38+
return debugClass;
39+
}
40+
41+
public void setDebugClass(Class debugClass) {
42+
this.debugClass = debugClass;
43+
}
44+
45+
public int[] getBreakPointLines() {
46+
return breakPointLines;
47+
}
48+
49+
public void setBreakPointLines(int[] breakPointLines) {
50+
this.breakPointLines = breakPointLines;
51+
}
52+
53+
/**
54+
* Sets the debug class as the main argument in the connector and launches the VM
55+
* @return VirtualMachine
56+
* @throws IOException
57+
* @throws IllegalConnectorArgumentsException
58+
* @throws VMStartException
59+
*/
60+
public VirtualMachine connectAndLaunchVM() throws IOException, IllegalConnectorArgumentsException, VMStartException {
61+
LaunchingConnector launchingConnector = Bootstrap.virtualMachineManager().defaultConnector();
62+
Map<String, Connector.Argument> arguments = launchingConnector.defaultArguments();
63+
arguments.get("main").setValue(debugClass.getName());
64+
VirtualMachine vm = launchingConnector.launch(arguments);
65+
return vm;
66+
}
67+
68+
/**
69+
* Creates a request to prepare the debug class, add filter as the debug class and enables it
70+
* @param vm
71+
*/
72+
public void enableClassPrepareRequest(VirtualMachine vm) {
73+
ClassPrepareRequest classPrepareRequest = vm.eventRequestManager().createClassPrepareRequest();
74+
classPrepareRequest.addClassFilter(debugClass.getName());
75+
classPrepareRequest.enable();
76+
}
77+
78+
/**
79+
* Sets the break points at the line numbers mentioned in breakPointLines array
80+
* @param vm
81+
* @param event
82+
* @throws AbsentInformationException
83+
*/
84+
public void setBreakPoints(VirtualMachine vm, ClassPrepareEvent event) throws AbsentInformationException {
85+
ClassType classType = (ClassType) event.referenceType();
86+
for(int lineNumber: breakPointLines) {
87+
Location location = classType.locationsOfLine(lineNumber).get(0);
88+
BreakpointRequest bpReq = vm.eventRequestManager().createBreakpointRequest(location);
89+
bpReq.enable();
90+
}
91+
}
92+
93+
/**
94+
* Displays the visible variables
95+
* @param event
96+
* @throws IncompatibleThreadStateException
97+
* @throws AbsentInformationException
98+
*/
99+
public void displayVariables(LocatableEvent event) throws IncompatibleThreadStateException, AbsentInformationException {
100+
StackFrame stackFrame = event.thread().frame(0);
101+
if(stackFrame.location().toString().contains(debugClass.getName())) {
102+
Map<LocalVariable, Value> visibleVariables = stackFrame.getValues(stackFrame.visibleVariables());
103+
System.out.println("Variables at " +stackFrame.location().toString() + " > ");
104+
for (Map.Entry<LocalVariable, Value> entry : visibleVariables.entrySet()) {
105+
System.out.println(entry.getKey().name() + " = " + entry.getValue());
106+
}
107+
}
108+
}
109+
110+
/**
111+
* Enables step request for a break point
112+
* @param vm
113+
* @param event
114+
*/
115+
public void enableStepRequest(VirtualMachine vm, BreakpointEvent event) {
116+
//enable step request for last break point
117+
if(event.location().toString().contains(debugClass.getName()+":"+breakPointLines[breakPointLines.length-1])) {
118+
StepRequest stepRequest = vm.eventRequestManager().createStepRequest(event.thread(), StepRequest.STEP_LINE, StepRequest.STEP_OVER);
119+
stepRequest.enable();
120+
}
121+
}
122+
123+
public static void main(String[] args) throws Exception {
124+
125+
JDIExampleDebugger debuggerInstance = new JDIExampleDebugger();
126+
debuggerInstance.setDebugClass(JDIExample.class);
127+
int[] breakPoints = {6, 9};
128+
debuggerInstance.setBreakPointLines(breakPoints);
129+
VirtualMachine vm = null;
130+
131+
try {
132+
vm = debuggerInstance.connectAndLaunchVM();
133+
debuggerInstance.enableClassPrepareRequest(vm);
134+
135+
EventSet eventSet = null;
136+
while ((eventSet = vm.eventQueue().remove()) != null) {
137+
for (Event event : eventSet) {
138+
if (event instanceof ClassPrepareEvent) {
139+
debuggerInstance.setBreakPoints(vm, (ClassPrepareEvent)event);
140+
}
141+
142+
if (event instanceof BreakpointEvent) {
143+
event.request().disable();
144+
debuggerInstance.displayVariables((BreakpointEvent) event);
145+
debuggerInstance.enableStepRequest(vm, (BreakpointEvent)event);
146+
}
147+
148+
if (event instanceof StepEvent) {
149+
debuggerInstance.displayVariables((StepEvent) event);
150+
}
151+
vm.resume();
152+
}
153+
}
154+
} catch (VMDisconnectedException e) {
155+
System.out.println("Virtual Machine is disconnected.");
156+
} catch (Exception e) {
157+
e.printStackTrace();
158+
}
159+
finally {
160+
InputStreamReader reader = new InputStreamReader(vm.process().getInputStream());
161+
OutputStreamWriter writer = new OutputStreamWriter(System.out);
162+
char[] buf = new char[512];
163+
164+
reader.read(buf);
165+
writer.write(buf);
166+
writer.flush();
167+
}
168+
169+
}
170+
171+
}

pom.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,7 @@
457457
<module>java-collections-conversions</module>
458458
<module>java-collections-maps</module>
459459
<module>java-collections-maps-2</module>
460+
<module>java-jdi</module>
460461
<!-- <module>java-dates</module> --> <!-- We haven't upgraded to java 9. Fixing in BAEL-10841 -->
461462
<!-- <module>java-dates-2</module> --> <!-- We haven't upgraded to java 9. Fixing in BAEL-10841 -->
462463
<!-- <module>java-ee-8-security-api</module> --> <!-- long running -->
@@ -1156,6 +1157,7 @@
11561157
<module>java-collections-conversions</module>
11571158
<module>java-collections-maps</module>
11581159
<module>java-collections-maps-2</module>
1160+
<module>java-jdi</module>
11591161
<!-- <module>java-dates</module> --> <!-- We haven't upgraded to java 9. Fixing in BAEL-10841 -->
11601162
<module>java-ee-8-security-api</module>
11611163
<module>java-lite</module>

0 commit comments

Comments
 (0)