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.