RFR: JDK-8276892: Provide a way to emulate exceptional situations in FileManager when using JavadocTester
Jonathan Gibbons
jjg at openjdk.java.net
Tue Nov 16 18:27:44 UTC 2021
On Tue, 16 Nov 2021 17:43:42 GMT, Pavel Rappo <prappo at openjdk.org> wrote:
> After having looked at this change, I think I might have fallen prey to the famous "XY problem". Instead of asking on how to emulate error conditions in a black-box fashion first, I asked to provide white-box support for those through JavadocTester.
I didn't see the question this way, and I thought the JBS issue was well stated.
Setting aside `JavadocTester` for a moment, there were two ways to solve the general problem of triggering exceptions to emulate weird conditions.
1. Build back doors into the main system `JavaFileManager` ... i..e. `JavacFileManager` (note `Javac`), such that the code can be triggered by backdoor access, either reflective, or breaking abstraction or system properties.
2. Provide a new file manager to do the job.
I prefer not to do the first ... I prefer not to build those backdoors into the main file manager that is routinely used everywhere. So that means to do the second.
Providing a new file manager to do the job means either using `javax.tools.DocumentationTool` directly, or else updating `JavadocTester`. The latter seems more desirable because of all the extra code in `JavadocTester.javadoc(...)` surrounding the actual tool invocation. And it comes at the cost of tweaking the tool invocation. It would be possible to have `JavadocTester` invoke `Start` directly without modification, but that would have required modifying _all_ existing tests, because of the need to use `com.sun.tools.javac.util.Context`. Stepping away from that means modifying either `Main` or `Start` to accept a file manager directly, and of the two, it seemed more future-proof to adapt `Main` into a builder-style API, without otherwise changing any existing code paths.
The one surprise/disappointment was the "sort-of technical debt" I discovered in `Start` ... that file-manager options in the "command-line" args were ignored if a non-standard file manager was used. That seemed like a worthwhile issue to address here.
In terms of providing a custom file manager, the question is, "which file objects" and "which methods". I went through a series of iterations before deciding on using `Predicate<JavaFileObject>` to filter the file objects. For a while, the API used regular expressions applied to the name of the file object, but that runs into issues with platform-specific file separators. Yeah, we could use the URI, but equally, it's nicer to have access to the file object itself, for filtering directly on properties of the file object, including the possibility of `.equals()`. As for "which methods", yeah, you suggested the two methods used to _read_ objects, but what if we want to write tests where the exceptions are thrown when _writing_ the object.
That all being said, I accept that the API as presented at this point may seem to be a sledgehammer, and it may be convenient to provide a coat of paint. I like the general underlying architecture of the solution, but maybe we can come up with a method on the builder along the following lines:
static StandardJavaFileManager throwExceptionWhenReading(StandardJavaFileManager fm, JavaFileObject jfo)
We can bike-shed on the name, and maybe there's a 3rd argument `Function<JavaFileObject, Throwable>` to create the exception to supply the exception that will be thrown. And, there's clearly a family of possible overloads, such as replacing the `JavaFileObject` parameter with a `Predicate<JavaFileObject>` to make it easier to specify the behavior for more than one file object, if that should be useful, or `Predicate<String>` to specify a predicate on the file name, or last component of the filename.
To summarize, I don't think the change is as scary as it might appear at first, although it may be somewhat lacking in ease-of-use for common cases. While the code of the builder may seem complicated, with its use of reflection and proxies, the entire class, the file is only 240 lines, including the legal header block and documentation comments.
> Just to make sure we're on the same page and aren't trying to solve a more complex problem than is required. Is there an easy way to make these methods throw: javax.tools.JavaFileManager#getFileForInput and javax.tools.FileObject#getCharContent?
TL;DR: Yes. But I didn't know about the `getFileForInput` use case. I'll look to make that possible.
-------------
PR: https://git.openjdk.java.net/jdk/pull/6404
More information about the javadoc-dev
mailing list