That approach (passing the `target` dir as agent argument
through `-javaagent`) might cause problems for concurrent builds,
e.g. a Gradle build which concurrently runs tests with different JDK
versions.
In that case the agent cannot use a static file name for the
bootstrap JAR since the concurrent runs might overwrite each others
files. So it would again have to create unique / temp files in that
directory. Creating temp files in `target` might be somewhat better
than creating them in the OS temp dir, but it is also not so great.
Especially if the user does not run `mvn clean ...` / `gradle clean
...` that often, for better build performance.
Have you tried giving each test run its own temp directory?
I assume that would be possible, but it would be even more cumbersome
for users of those agent libraries then, and the build config setup
needed for this would start getting non-trivial.
So if an agent was able to delete the file passed to
`appendToBootstrapClassLoaderSearch`, that might really be the
easiest solution for agent implementations.
This amounts to deleting a JAR file on bootstrap class path while the
VM is running.
Note that opening the JAR file with FILE_SHARE_DELETE won't address
the on Windows. While the delete may appear to work, the semantics are
not the same as Unix and there will be an error somewhere else if
something attempts to create a new JAR file with the same name.
To clarify and to avoid any misunderstandings: I am not asking for being
able to delete the file immediately; instead I am looking for a way to
delete the file eventually when the JVM terminates.
My understanding is that the order of actions is currently:
1. Library calls `appendToBootstrapClassLoaderSearch`
2. At some point JVM shutdown begins
3. Shutdown hooks / `File#deleteOnExit` runs
4. JVM closes bootstrap JAR file handle in native code
So if something like DELETE_ON_CLOSE was possible (which in JVM native
code acted as if the JarFile was opened with ZipFile.OPEN_DELETE), then
when the JVM closes the JAR the file is deleted. From my testing with a
dummy JarFile on Windows 11, it seems the file is even deleted if the
JVM terminates abnormally, e.g. being killed by the Task Manager (as
desired).
I think the case that something else tries to create a JAR with the same
file path is also not an issue. This DELETE_ON_CLOSE use case would be
opt-in and the agent libraries already create unique temp files (after
all the problem is that they cannot get rid of these temp files again),
so an accidental collision is quite unlikely.
Actually, maybe part of the problem is that
`appendToBootstrapClassLoaderSearch` takes a JarFile in the first
place. I guess from a theoretical perspective something like a
`Function<String, byte[]>` (but probably as dedicated interface with
`throws IOException`) or a JarInputStream would suffice? Though maybe
supporting that within the JVM implementation would be difficult?
It would be feasible to have the VM upcall to invoke this function.
The lower level JVMTI AddToBootstrapClassLoaderSearch (Java agents are
implemented as a JVMTI agent) is more flexible in that it allows
directories to be added too. It might not be terrible to add overloads
of the Instrumentation.appendToXXX methods to take a directory. It
wouldn't be hard to try that and see if any issues come up.
Adding support for directories might be useful for other use cases, but
here it would not help much I think. It would only shift the problem
from "how to delete a temp JAR" to "how to delete a temp directory".
Maybe deleting the directory would be possible on Windows then, but I
suspect then you really run into problems when the JVM code tries to
access it (and possibly has accessed it before) and suddenly the
directory is gone, e.g. because it was deleted by a shutdown hook.
So some kind of lowest possible abstraction (e.g. an interface similar
to `Function<String, byte[]>`, or a `Map<String, byte[]>` if all entries
need to be known) would be ideal. Then the user can decide whether they
serve the entries from a JarFile, a directory or possibly a different
location (e.g. a subset of the enclosing JAR file) or even create them
on demand.
Kind regards