[code-reflection] RFR: Make @Reflect a use-site annotation

Maurizio Cimadamore mcimadamore at openjdk.org
Thu Dec 4 13:43:47 UTC 2025


In the current iteration of compiler support there are two ways to make a lambda reflectable:
1. cast the lambda to a type that is annotated with the `@Reflect` annotation (use-site)
2. pass the lambda to a functional interface whose declaration is annotated with `@Reflect` (decl-site)

While (2) is handy in cases where the library wants to control reflectability of the lambdas it receives, this model is too weak and insecure, as it might lead to unknowing clients exposing private impl details with frameworks using code reflection.

For this reason, we have revamped the `@Reflect` annotation to control, at the use-site, which program elements should support code reflection:

* If a method is annotated with `@Reflect`, the method itself is reflectable, and all the lambdas it contains are reflectable;
* If a field/local variable is annotated with `@Reflect`, all the lambdas that occur inside the initializer (if present), are reflectable;
* If a cast type is annotated with `@Reflect` and the cast is applied to a lambda expression, that lambda expression is reflectable (this is the same as (1) above).

This means it's no longer possible for a library to create a reflectable functional interface, like:


@Reflect
interface ReflectableRunnable extends Runnable { }


And unilaterally decide, for _all_ clients whether their lambdas should be reflectable.

To be clear, this is **not** how things will work longer term, but it's an interim step which provides the desired level of safety w/o requiring the additional language features.

I've fixed all tests. I've tried to simplify both javac and JDK tests by dropping redundant functional interface declarations.

I also fixed all the samples; for ONNX some tweaks were done, and I've decided to drop the OnnxFunction -- and to use a supplier instead. But if that's not desirable I can change back (or it can be changed back later).

I also fixed HAT tests -- in that case it was a bit trickier, as there's lots of tests that end up passing reflectable lambdas to the HAT's compute method. Luckily, all these tests are annotated with `@HatTest`, so I've simply added an extra `@Reflect` to any such test method. Since `@Reflect` now propagates to the body, this guarantees that all the lambdas inside these test methods are treated as reflectable.

Of course these HAT change end up enabling reflection for a lot more than it's required. I'll leave it to people more expert with HAT to clean that up, if needed.
In the meantime, it was useful to run in this mode, as that uncovered 2 separate issues in the compiler support, one in this PR (default methods were no longer being treated as reflectable) and another pre-existing (compiler crashed when encountering package names in qualified names).

-------------

Commit messages:
 - Fix diags
 - Fix hat tests
 - Fix tests
 - Merge branch 'code-reflection' into better_annos
 - Initial push
 - Initial push

Changes: https://git.openjdk.org/babylon/pull/726/files
  Webrev: https://webrevs.openjdk.org/?repo=babylon&pr=726&range=00
  Stats: 981 lines in 52 files changed: 281 ins; 575 del; 125 mod
  Patch: https://git.openjdk.org/babylon/pull/726.diff
  Fetch: git fetch https://git.openjdk.org/babylon.git pull/726/head:pull/726

PR: https://git.openjdk.org/babylon/pull/726


More information about the babylon-dev mailing list