Java Debug Interface API (JDI) – Hello World Example | Programmatic debugging for beginners

In this article we will go through very simple Hello World example for Java Debug Interface API i.e. JDI. This can help for getting started with JDI. We will also try to understand how JDI works in very basic manner.

Objective: We will debug Hello world program using JDI & read its variable & print. In the process, we will try to understand how basic JDI works.

JDI Terminologies:

  • Debugger program – Code/program which will be debugging other code/program.
  • Debug target program – Code/program which is being debugged.
  • Virtual Machine (VM) – JVM which is running debug target program.
  • Connector – This connects debugger program to JVM of debug target. In this example we will use LaunchingConnector which will launch a JVM & connect to it. There are also AttachingConnector which connect to existing running JVM.
  • Events – When VM runs debug target program in debug mode, it triggers several events so that debugger program can take action as needed. Debugger program can also request VM to trigger certain special events which are not triggered by default.

Steps:

  1. Create Virtual Machine using launching connector which has ability to launch a VM & connect to it.
  2. Request VM to let program know when class (debug target) is prepared. VM will trigger ClassPrepareEvent when class is prepared so that program knows.
  3. When ClassPrepareEvent is triggered, request VM to set a breakpoint at expected line number. When code execution reached that line number, VM will trigger BreakpointEvent.
  4. Keep looping till VM reaches to the breakpoint line & triggers BreakpointEvent
  5. When BreakpointEvent received, disable breakpoint, read local variables & resume VM.

Code:

This is the debug target class which we will debug pragmatically using JDI.  We will be putting debug breakpoint at line denoted by a comment.




This is the Debugger program which will debug above program.

Compilation:

Please take below precautions to avoid any issues in execution of example.

  • Make sure to use -g option during compilation. This option generates all debugging information, including local variables. If you miss this, you might see AbsentInformationException as below.  Oracle Reference
  • Make sure to have jdk\lib\tools.jar in classpath as it has all JDI Library. Without this you might get  java.lang.ClassNotFoundException: com.sun.jdi.Bootstrap



Execution:

  • Make sure to have jdk\lib\tools.jar in classpath as it has all JDI Library.
  • Note “.;” in classpath. If you miss that you might see  Error: Could not find or load main class com.itsallbinary.java.jdi.HelloWorldJDIExample
  • If you run this program as part of maven project, then classes will be compiled in target directory. So you might need below additional env argument in code of HelloWorldJDIExample.

As you can see in execution output, HelloWorld.java program has been executed & all local variable names & their values are printed in the logs.

Where is System.out.println from HelloWorld.java?

As you might have noticed in execution output, that the output of  System.out.println("Hi Everyone, " + greeting);// Put a break point at this line. is not printed in console even though program has been executed correctly. Why is so?

If you check the API javadoc of LaunchingConnector.html#launch, it has below documentation.

Important note: If a target VM is launched through this functions, its output and error streams must be read as it executes. These streams are available through the Process object returned byVirtualMachine.process(). If the streams are not periodically read, the target VM will stop executing when the buffers for these streams are filled.

So we have to get the streams from process & connect it to System.out of debugger program. Ideally this mush be done in a separate parallel thread which can be spun from debugger program & continuously keep reading streams. This way we can meet the requirement from above documentation of reading streams periodically.

For our example, since we have just one small statement printed, we won’t run into situation of buffer filling up & VM getting stopped. So we will just read & print stream at the end of program in finally block.




Complete code

Now you can see statement from HelloWorld.java being printed in console.

Further Reading:

Go through below articles for further understanding of Java Debug Interface in depth.

Java Debug Interface API (JDI) – Hello World Example | Programmatic stepping through the code lines



Leave a Reply

Your email address will not be published. Required fields are marked *