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

Paul Sandoz psandoz at openjdk.org
Thu Dec 4 18:48:08 UTC 2025


On Thu, 4 Dec 2025 13:27:57 GMT, Maurizio Cimadamore <mcimadamore at openjdk.org> wrote:

> 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 ...

Very good simplification for the initial mechanism to declare reflectable methods and lambdas. The HAT examples need updating to declare the compute lambda as reflectable. I recommend using a cast for al these, and we can deal with the specialized interface later on if need be.

src/jdk.incubator.code/share/classes/jdk/incubator/code/Reflect.java line 43:

> 41:  * <li>When a method is annotated with this annotation, the method becomes reflectable, and all the lambda expressions
> 42:  * and method references enclosed in it also become reflectable.</li>
> 43:  * <li>When a variable declaration (a field, or a local variable) is annotated with this annotation, all the methods, lambda expressions

What does it mean "all the methods" in the context of an initializer expression?

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

PR Review: https://git.openjdk.org/babylon/pull/726#pullrequestreview-3541427985
PR Review Comment: https://git.openjdk.org/babylon/pull/726#discussion_r2590172871


More information about the babylon-dev mailing list