[code-reflection] RFR: Add sample annotation processor using code models

Maurizio Cimadamore mcimadamore at openjdk.org
Wed Sep 10 11:13:07 UTC 2025


On Mon, 8 Sep 2025 16:47:49 GMT, Maurizio Cimadamore <mcimadamore at openjdk.org> wrote:

>> This change adds a new sample of an annotation processor that uses code models to:
>> * reject unsupported methods (e.g. `System.gc`, `System.exit`)
>> * reject unsupported language construct (e.g. `try`, `throw`)
>> 
>> The annotation processor is somewhat configurable, and can be used by developers as an initial sketch upon which to build more custom compile-time checks.
>> 
>> When using the annotation processor to compile this:
>> 
>> 
>> class Foo {
>>    @CodeReflection
>>    void test1() {
>>       System.exit(1);
>>    }
>> 
>>     @CodeReflection
>>     void test2() {
>>         System.gc();
>>     }
>> 
>>     @CodeReflection
>>     void test3() {
>> 
>>        try {
>>            test2();
>>        } finally {
>>            test3();
>>        }
>> 
>>     }
>> }
>> 
>> 
>> The following error messages are generated:
>> 
>> 
>> Foo.java:5: error: System.exit not supported in reflectable methods
>>    void test1() {
>>         ^
>> Foo.java:10: error: System.gc not supported in reflectable methods
>>     void test2() {
>>          ^
>> Foo.java:15: error: try/catch statement not supported in reflectable methods
>>     void test3() {
>>          ^
>> 
>> 
>> When putting this together, I noted some issues, reported below:
>> 
>> * javac was failing to execute annotation processors that depended on `jdk.incubator.code` module
>> * obtaining the model from a method that contains attribution errors crashed the annotation processor
>> * some packages (e.g. the ones in java.base) are not exported to the dynamic module layer's `jdk.incubator.code`
>> * it is not possible to report the message at a more accurate location because the `Messager` API does not allow for this
>> 
>> Many thanks to @lahodaj for the invaluable help when fighting with module layers :-)
>
> src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java line 1766:
> 
>> 1764:                 // But we need to do so by calling a method in java.base reflectively
>> 1765:                 try {
>> 1766:                     Class<?> codeModuleLayerInit = Class.forName("jdk.internal.access.code.CodeModuleLayerInit");
> 
> If the babylon module is not in the module graph when running javac, then we need to explicitly export all java.base packages to that module, to make sure it runs correctly (this might be too broad).

Note - we have to call through reflection, otherwise javac might fail to compile against a bootstrap JDK

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

PR Review Comment: https://git.openjdk.org/babylon/pull/554#discussion_r2330805953


More information about the babylon-dev mailing list