record-builder icon indicating copy to clipboard operation
record-builder copied to clipboard

Make @Generated optional on generated classes

Open bmarwell opened this issue 2 months ago • 3 comments

Hi!

The @Generated annotation causes some troubles with JPMS.

History on @Generated

Originally, it was designed to show static code analyzers which classes to ignore. Nowadays, they will usually look for .gitignored files or something line target/generated-* or any @*Generated annotation. So that's that.

Why it is a problem with JPMS

I do not want code which uses my record builders to require the java.compiler module -- it is not needed, because none of that code would read the @Generated annotation. So, instead of using requires java.compiler;, the correct approach is requires static java.compiler -- which translates to "only use this module for compiling".

However, the compiler is a bit dumb, sees the @Generated annotation and complains that it will be there on the .class file -- which it will be not, because it does not know about annotations and their @RetentionPolicy, so it assumes it will be there.

This will yield the following compiler warning:

[WARNING] /path/to/my/target/generated-sources/annotations/MyRecordBuilder.java:[217,6]  class javax.annotation.processing.Generated in module java.compiler is not indirectly exported using 'requires transitive'

Alternatives

1.: Do not generate @Generated at all

An option with all its drawbacks

2.: Only add @Generated if it is in the classpath

mapstruct uses this approach

3.: let the user decide (boolean)

Booleans are meh. Use an enum.

4. let the user decide (enum)

-AgeneratedAnnotation = enum AddGeneratedAnnotation { ON, OFF, USER_SUPPLIED, IF_ON_CLASSPATH }

Default: IF_ON_CLASSPATH

When USER_SUPPLIED is set, the user would also need to specify -AgeneratedUserAnnotation=com.my.project.MyProjectGenerated or so.

names are not meant to be final. Let some native speaker pick something better :)

bmarwell avatar Oct 21 '25 07:10 bmarwell

Given the existence of addClassRetainedGenerated a new boolean will be easier to add.

Randgalt avatar Oct 22 '25 06:10 Randgalt

Given the existence of addClassRetainedGenerated a new boolean will be easier to add.

IIRC, this is only an ADDITIONAL annotation, no? If so, I would treat them as unrelated. In fact, I would add -AaddClassRetainedGenerated=true after disabling @Generated because of the reason stated below.

        /**
         * If true, generated classes are annotated with {@code RecordBuilderGenerated} which has a retention policy of
         * {@code CLASS}. This ensures that analyzers such as Jacoco will ignore the generated class.
         */
        boolean addClassRetainedGenerated() default false;

So, I would still vote for an enum, but ultimately, the choice is yours.

bmarwell avatar Oct 22 '25 08:10 bmarwell

@Randgalt you can review my draft PR. If that is okay for you, I will continue with the Interface Processor.

bmarwell avatar Oct 24 '25 10:10 bmarwell