Skip to content

Commit 7e9be4a

Browse files
committed
feat: Implement SampleProcessor to generate md files
Implemented a sample processor to scan all samples and write the tldr/description to a md file Moved Sample.java to the annotation package
1 parent 8b6f7db commit 7e9be4a

File tree

2 files changed

+97
-1
lines changed

2 files changed

+97
-1
lines changed

operator-annotations/src/main/java/io/javaoperatorsdk/Sample.java renamed to operator-annotations/src/main/java/io/javaoperatorsdk/annotation/Sample.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package io.javaoperatorsdk;
1+
package io.javaoperatorsdk.annotation;
22

33
import java.lang.annotation.*;
44

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package io.javaoperatorsdk.processor;
2+
3+
import javax.annotation.processing.AbstractProcessor;
4+
import javax.annotation.processing.RoundEnvironment;
5+
import javax.annotation.processing.SupportedAnnotationTypes;
6+
import javax.lang.model.element.*;
7+
import javax.lang.model.util.Types;
8+
import javax.tools.FileObject;
9+
import javax.tools.StandardLocation;
10+
import java.io.IOException;
11+
import java.io.Writer;
12+
import java.util.*;
13+
14+
/**
15+
* Annotation processor that generates a markdown file listing all classes annotated with @Sample.
16+
*/
17+
@SupportedAnnotationTypes("io.javaoperatorsdk.annotation.Sample")
18+
public class SampleProcessor extends AbstractProcessor {
19+
20+
private record SampleInfo(String tldr, String description) {}
21+
private final List<SampleInfo> samples = new ArrayList<>();
22+
23+
@Override
24+
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
25+
26+
Types types = processingEnv.getTypeUtils();
27+
for (TypeElement annotation: annotations) {
28+
// element has details about the class being annotated, but not the values
29+
// ex: String tldr = ..., it knows it has a field called tldr but not what's assigned
30+
for (Element element : roundEnv.getElementsAnnotatedWith(annotation)) {
31+
// a mirror gives access to the values assigned to the fields of the annotation
32+
// element.getAnnotation does not work since the retention is SOURCE
33+
AnnotationMirror annotationMirror = element.getAnnotationMirrors().stream()
34+
.filter(am -> types.isSameType(am.getAnnotationType(), annotation.asType()))
35+
.findFirst()
36+
.orElse(null);
37+
38+
if (annotationMirror != null) {
39+
String tldr = getString(annotationMirror.getElementValues(), "tldr");
40+
String description = getString(annotationMirror.getElementValues(), "description");
41+
42+
samples.add(new SampleInfo(tldr, description) );
43+
}
44+
}
45+
}
46+
47+
if (roundEnv.processingOver()) {
48+
// sort to keep the order stable
49+
samples.sort(Comparator.comparing(SampleInfo::tldr, String.CASE_INSENSITIVE_ORDER));
50+
writeSampleMDFile(samples);
51+
}
52+
return false;
53+
}
54+
55+
/**
56+
*
57+
*/
58+
private void writeSampleMDFile(List<SampleInfo> samples) {
59+
try {
60+
FileObject fileObject = processingEnv.getFiler()
61+
.createResource(StandardLocation.CLASS_OUTPUT, "", "samples.md");
62+
63+
try(Writer writer = fileObject.openWriter();) {
64+
writer.write("# Integration Test Samples \n");
65+
66+
for (SampleInfo sample : samples) {
67+
writer.write("## " + sample.tldr() + "\n");
68+
writer.write(sample.description() + "\n\n");
69+
}
70+
} catch (IOException e) {
71+
throw new RuntimeException(e);
72+
}
73+
74+
} catch (Exception e) {
75+
throw new RuntimeException(e);
76+
}
77+
}
78+
79+
/**
80+
* Extracts a string value from the annotation values map.
81+
* @param vals the map of annotation values
82+
* @param name the name of the field to extract
83+
* @return the string value, or empty string if not found
84+
*/
85+
private String getString(
86+
Map<? extends ExecutableElement, ? extends AnnotationValue> vals, String name) {
87+
for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> ev : vals.entrySet()) {
88+
if (ev.getKey().getSimpleName().contentEquals(name)) {
89+
Object value = ev.getValue().getValue();
90+
return value == null ? "" : value.toString();
91+
}
92+
}
93+
// should not happen since tldr and description are mandatory
94+
return "";
95+
}
96+
}

0 commit comments

Comments
 (0)