Sometimes one needs to get diagnostic information from code buried in the JDK in a situation where the code can’t easily be run in a debugger, e.g., when a non-technical user has a reproducible problem that no one else can reproduce. In this situation, it can be useful to replace a JDK class with a class of our own. The technique is not difficult once you know how, but examples of doing it are hard to find. Here is a minimal example:
Suppose we would like to print something whenever java.util.Arrays.sort(Object[]) is called. To do that, we get the source code for java.util.Arrays, put it in a directory named java/util and edit the relevant method:
public static void sort(Object[] a) {
// Added by me
System.out.println("HEY HEY HEY");
// Preexisting code
...
}
We compile our modified Arrays.java:
javac --patch-module java.base=. java/util/Arrays.java
The --patch-module option tells javac that we want classes from . to be merged into the java.base module, which is where Arrays lives.
Here is our test program, Test.java, from which we will call Arrays.sort():
import java.util.Arrays;
class Test {
public static void main(String[] args) {
Arrays.sort(new Object[0]);
}
}
Compile the test program as usual:
javac Test.java
Now we run the test program, first using unmodified JDK classes:
$ java Test
$
There is no output, as expected.
Next, we run the test program using the modified Arrays class:
$ java --patch-module java.base=. Test
HEY HEY HEY
$
We can see from the output that our modified method was run.