After some experimentation, I have realized that while I can access all the classes in any package, regardless of whether they are private or package-private using reflection, I cannot do that using regular calls. There doesn’t seem to be a central feature that disables that check all together.
Now, I wanted to write a purely reflection-based checker anyway, but I also wanted to get the bytecode-based version to work. Now I have to think hard what to do. One option, of course, would be to detect the use of a predicate method that cannot be called from the call site. Whether that is possible or not can only be found out once I examine the call site, so in the case of on-the-fly instrumentation, that would boil down to an exception, just like now.
A second approach would be to stipulate that the predicate method must be in a class that’s accessible from anywhere, i.e. either in a public top-level class, or in a public static nested class. The classes containing the predicates cannot be private, protected, package-private or non-static inner classes. Assuming this stance would allow me to do a robust analysis at the time I’m checking the annotations, and I can reject annotations that might lead to problems at call sites later.
The third and most complicated way is to add relay methods in a place that has access to and can call the original predicate method that should be called. These relay methods must then satisfy the criteria from the second approach. Where exactly I would put these methods, I don’t know… I think I’ll try to sleep over it, even though I just got up again at 2 AM to work on this…