1717import java .io .IOException ;
1818import java .io .PrintWriter ;
1919import java .io .Writer ;
20+ import java .util .List ;
2021import java .util .Map ;
2122import java .util .Set ;
2223import javax .annotation .processing .AbstractProcessor ;
3132import javax .lang .model .element .AnnotationValue ;
3233import javax .lang .model .element .Element ;
3334import javax .lang .model .element .ExecutableElement ;
35+ import javax .lang .model .element .RecordComponentElement ;
3436import javax .lang .model .element .TypeElement ;
3537import javax .lang .model .util .Elements ;
3638import javax .tools .Diagnostic ;
3739import javax .tools .JavaFileObject ;
3840
39- @ SupportedAnnotationTypes ("org.eclipse.jdt.compiler.apt.tests.annotations.GenClass" )
41+ @ SupportedAnnotationTypes ({"org.eclipse.jdt.compiler.apt.tests.annotations.GenClass" ,
42+ "org.eclipse.jdt.compiler.apt.tests.annotations.Value.Immutable" ,
43+ "org.eclipse.jdt.compiler.apt.tests.annotations.Value.Style" ,
44+ "org.eclipse.jdt.compiler.apt.tests.annotations.Generated" ,})
4045@ SupportedSourceVersion (SourceVersion .RELEASE_6 )
4146public class GenClassProc extends AbstractProcessor {
4247
4348 private Messager _messager ;
4449 private Filer _filer ;
4550 private Elements _elementUtil ;
4651 private TypeElement _annoDecl ;
52+ private TypeElement _immutableDecl ;
53+ private TypeElement _styleDecl ;
4754
4855 @ Override
4956 public synchronized void init (ProcessingEnvironment processingEnv ) {
@@ -52,6 +59,8 @@ public synchronized void init(ProcessingEnvironment processingEnv) {
5259 _messager = processingEnv .getMessager ();
5360 _elementUtil = processingEnv .getElementUtils ();
5461 _annoDecl = _elementUtil .getTypeElement ("org.eclipse.jdt.compiler.apt.tests.annotations.GenClass" );
62+ _immutableDecl = _elementUtil .getTypeElement ("org.eclipse.jdt.compiler.apt.tests.annotations.Value.Immutable" );
63+ _styleDecl = _elementUtil .getTypeElement ("org.eclipse.jdt.compiler.apt.tests.annotations.Value.Style" );
5564
5665 //System.out.println("Processor options are: ");
5766 //for (Map.Entry<String, String> option : processingEnv.getOptions().entrySet()) {
@@ -62,10 +71,35 @@ public synchronized void init(ProcessingEnvironment processingEnv) {
6271 @ Override
6372 public boolean process (Set <? extends TypeElement > annotations ,
6473 RoundEnvironment roundEnv ) {
65-
6674 if (annotations == null || annotations .isEmpty ()) {
6775 return true ;
6876 }
77+
78+ if (annotations .contains (_immutableDecl )) {
79+ List <? extends Element > enclosedElements = _styleDecl .getEnclosedElements ();
80+ int size = enclosedElements .size ();
81+ if (size > 0 ) {
82+ processGH4687_1 ();
83+ return true ;
84+ }
85+ return false ;
86+ }
87+ if (annotations .contains (_styleDecl )) {
88+ Set <? extends Element > elementsAnnotatedWith = roundEnv .getElementsAnnotatedWith (_styleDecl );
89+ TypeElement brokenRecord = null ;
90+ for (Element element : elementsAnnotatedWith ) {
91+ if (element instanceof TypeElement te && te .getSimpleName ().toString ().equals ("BrokenRecord" )) {
92+ brokenRecord = te ;
93+ break ;
94+ }
95+ }
96+ if (brokenRecord == null ) {
97+ throw new IllegalArgumentException ("TypeElement not found for targets.gh4687.Container.BrokenRecord" );
98+ }
99+ processGH4687_2 (brokenRecord );
100+ return true ;
101+ }
102+
69103 // sanity check
70104 if (!annotations .contains (_annoDecl )) {
71105 throw new IllegalArgumentException ("process() called on an unexpected set of annotations" );
@@ -116,7 +150,62 @@ public boolean process(Set<? extends TypeElement> annotations,
116150 }
117151 return true ;
118152 }
153+ private void processGH4687_1 () {
154+ createSourceFile1 (null , "foobar.ImmutableComp" , "toString" );
155+ }
156+ private void processGH4687_2 (TypeElement brokenRecord ) {
157+ List <? extends RecordComponentElement > recordComponents = brokenRecord .getRecordComponents ();
158+ RecordComponentElement rce = null ;
159+ for (Element element : recordComponents ) {
160+ if (element instanceof RecordComponentElement ) {
161+ rce = (RecordComponentElement ) element ;
162+ break ;
163+ }
164+ }
165+ if (rce == null ) {
166+ throw new IllegalArgumentException ("RecordComponentElement not found" );
167+ }
168+ ExecutableElement accessor = rce .getAccessor ();
169+ if (accessor == null ) {
170+ throw new IllegalArgumentException ("Accessor not found" );
171+ }
172+ createSourceFile2 (null , "foobar.WorkingRecordBuilder" , "toString" );
173+ }
119174
175+ private void createSourceFile1 (Element parent , String clazz , String method ) {
176+ int lastDot = clazz .lastIndexOf ('.' );
177+ if (lastDot <= 0 || clazz .length () == lastDot )
178+ return ;
179+ try {
180+ JavaFileObject jfo = _filer .createSourceFile (clazz , parent );
181+ String source = """
182+ package foobar;
183+ public final class ImmutableComp {}
184+ """ ;
185+ try (Writer w = jfo .openWriter (); PrintWriter pw = new PrintWriter (w )) {
186+ pw .println (source .toString ());
187+ }
188+ } catch (IOException e ) {
189+ e .printStackTrace ();
190+ }
191+ }
192+ private void createSourceFile2 (Element parent , String clazz , String method ) {
193+ int lastDot = clazz .lastIndexOf ('.' );
194+ if (lastDot <= 0 || clazz .length () == lastDot )
195+ return ;
196+ try {
197+ JavaFileObject jfo = _filer .createSourceFile (clazz , parent );
198+ String source = """
199+ package foobar;
200+ public final class WorkingRecordBuilder {}
201+ """ ;
202+ try (Writer w = jfo .openWriter (); PrintWriter pw = new PrintWriter (w )) {
203+ pw .println (source .toString ());
204+ }
205+ } catch (IOException e ) {
206+ e .printStackTrace ();
207+ }
208+ }
120209 /**
121210 * Create a source file named 'name', with contents
122211 * that reflect 'method' and 'name'.
0 commit comments