Skip to content

Commit 2b97cc1

Browse files
authored
Initial Commit (thombergs#142)
* Initial Commit Added Maven Annotation Processor Demo project. Initial commit. * Test - checking * Delete test.rtf * Initial commits Initial commits for sample code * Update SuppressWarningsDemo.java * Code changes till SafeVarargs Code changes till SafeVarargs * Completed source code Completed source code * Final draft Final draft version. Grammarly check done. * Deleted java docs Deleted java docs
1 parent 9d6f34d commit 2b97cc1

91 files changed

Lines changed: 996 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Binary file not shown.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<artifactId>AnnotationProcessorDemo</artifactId>
7+
<groupId>com.reflectoring.annotation.processor</groupId>
8+
<version>1.0</version>
9+
</parent>
10+
11+
<modelVersion>4.0.0</modelVersion>
12+
<groupId>com.reflectoring.annotation.processor</groupId>
13+
<artifactId>annotation-processor</artifactId>
14+
<version>1.0</version>
15+
16+
<properties>
17+
<maven.compiler.source>11</maven.compiler.source>
18+
<maven.compiler.target>11</maven.compiler.target>
19+
</properties>
20+
21+
<dependencies>
22+
<dependency>
23+
<groupId>com.google.auto.service</groupId>
24+
<artifactId>auto-service</artifactId>
25+
<version>1.0.1</version>
26+
<scope>provided</scope>
27+
</dependency>
28+
<!-- https://mvnrepository.com/artifact/com.squareup/javapoet -->
29+
<dependency>
30+
<groupId>com.squareup</groupId>
31+
<artifactId>javapoet</artifactId>
32+
<version>1.9.0</version>
33+
</dependency>
34+
<dependency>
35+
<groupId>org.apache.commons</groupId>
36+
<artifactId>commons-text</artifactId>
37+
<version>1.9</version>
38+
</dependency>
39+
40+
</dependencies>
41+
42+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.reflectoring.annotation.processor;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
@Target({ElementType.TYPE})
9+
@Retention(RetentionPolicy.SOURCE)
10+
public @interface Builder {
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
package com.reflectoring.annotation.processor;
2+
3+
import com.google.auto.service.AutoService;
4+
import com.squareup.javapoet.*;
5+
import org.apache.commons.text.CaseUtils;
6+
7+
import javax.annotation.processing.*;
8+
import javax.lang.model.SourceVersion;
9+
import javax.lang.model.element.Element;
10+
import javax.lang.model.element.ElementKind;
11+
import javax.lang.model.element.Modifier;
12+
import javax.lang.model.element.TypeElement;
13+
import javax.lang.model.type.TypeMirror;
14+
import javax.lang.model.util.Elements;
15+
import javax.tools.Diagnostic;
16+
import javax.tools.JavaFileObject;
17+
import java.io.IOException;
18+
import java.io.PrintWriter;
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
import java.util.Set;
22+
import java.util.stream.Collectors;
23+
24+
@SupportedAnnotationTypes("com.reflectoring.annotation.processor.Builder")
25+
@SupportedSourceVersion(SourceVersion.RELEASE_11)
26+
@AutoService(Processor.class)
27+
public class BuilderProcessor extends AbstractProcessor {
28+
29+
private Filer filer;
30+
private Messager messager;
31+
private Elements elementUtils;
32+
33+
@Override
34+
public synchronized void init(ProcessingEnvironment processingEnv) {
35+
36+
super.init(processingEnv);
37+
filer = processingEnv.getFiler();
38+
messager = processingEnv.getMessager();
39+
elementUtils = processingEnv.getElementUtils();
40+
}
41+
42+
@Override
43+
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
44+
45+
for (Element typeElement : roundEnv.getElementsAnnotatedWith(Builder.class)) {
46+
47+
List<Element> fieldElements = typeElement.getEnclosedElements().stream().filter(e -> ElementKind.FIELD.equals(e.getKind())).collect(
48+
Collectors.toList());
49+
50+
String packageName = elementUtils.getPackageOf(typeElement).getQualifiedName().toString();
51+
String className = typeElement.getSimpleName().toString();
52+
String builderName = String.format("%sBuilder", typeElement.getSimpleName().toString());
53+
String classVariableName = CaseUtils.toCamelCase(typeElement.getSimpleName().toString(), false, '_');
54+
55+
try {
56+
//writeBuilderClass(packageName, className, classVariableName, builderName, fieldElements);
57+
58+
writeJavaPoetBuilderClass(packageName, className, classVariableName, builderName, fieldElements, typeElement);
59+
} catch (IOException e) {
60+
messager.printMessage(Diagnostic.Kind.ERROR, "Failed to write file for element", typeElement);
61+
}
62+
}
63+
64+
return true;
65+
}
66+
67+
private String getBaseName(String name) {
68+
69+
int lastPeriodIndex = name.lastIndexOf('.');
70+
if (lastPeriodIndex > 0) {
71+
name = name.substring(lastPeriodIndex + 1);
72+
}
73+
74+
return name;
75+
}
76+
77+
private void writeBuilderClass(String packageName, String className, String classVariableName, String builderName,
78+
List<Element> fieldElements) throws IOException {
79+
80+
JavaFileObject builder = processingEnv.getFiler().createSourceFile(builderName);
81+
82+
try (PrintWriter out = new PrintWriter(builder.openWriter())) {
83+
84+
// Write the Package name
85+
out.print("package ");
86+
out.print(packageName);
87+
out.println(";");
88+
out.println();
89+
90+
// Write the Class name
91+
out.print("public final class ");
92+
out.print(builderName);
93+
out.println(" {");
94+
out.println();
95+
96+
// Write the Field names
97+
for (Element fieldElement : fieldElements) {
98+
99+
TypeMirror typeMirror = fieldElement.asType();
100+
101+
String fieldTypeName = getBaseName(typeMirror.toString());
102+
String fieldName = getBaseName(fieldElement.getSimpleName().toString());
103+
104+
out.print("private ");
105+
out.print(fieldTypeName);
106+
out.print(" ");
107+
out.print(fieldName);
108+
out.print(";");
109+
out.println();
110+
}
111+
112+
out.println();
113+
114+
// Write the Setters
115+
for (Element fieldElement : fieldElements) {
116+
117+
TypeMirror typeMirror = fieldElement.asType();
118+
119+
String fieldTypeName = getBaseName(typeMirror.toString());
120+
String fieldName = getBaseName(fieldElement.getSimpleName().toString());
121+
122+
out.print("public ");
123+
out.print(" ");
124+
out.print(builderName);
125+
out.print(" ");
126+
out.print(fieldName);
127+
out.print("(");
128+
out.print(fieldTypeName);
129+
out.print(" ");
130+
out.print(fieldName);
131+
out.print(") {");
132+
out.println();
133+
out.print(" this.");
134+
out.print(fieldName);
135+
out.print(" = ");
136+
out.print(fieldName);
137+
out.print(";");
138+
out.println();
139+
out.print(" return this;");
140+
out.println();
141+
out.print("}");
142+
out.println();
143+
out.println();
144+
}
145+
146+
// Write the build function
147+
out.print("public ");
148+
out.print(" ");
149+
out.print(className);
150+
out.print(" build() {");
151+
out.println();
152+
out.print(" ");
153+
out.print(className);
154+
out.print(" ");
155+
out.print(classVariableName);
156+
out.print(" = new ");
157+
out.print(className);
158+
out.print("();");
159+
out.println();
160+
161+
for (Element fieldElement : fieldElements) {
162+
163+
TypeMirror typeMirror = fieldElement.asType();
164+
165+
String fieldTypeName = getBaseName(typeMirror.toString());
166+
String fieldName = getBaseName(fieldElement.getSimpleName().toString());
167+
168+
out.print(" ");
169+
out.print(classVariableName);
170+
out.print(".set");
171+
out.print(CaseUtils.toCamelCase(fieldName, true, '_'));
172+
out.print("(this.");
173+
out.print(fieldName);
174+
out.println(");");
175+
}
176+
177+
out.println();
178+
out.print(" return ");
179+
out.print(classVariableName);
180+
out.print(";");
181+
out.println();
182+
out.println(" }");
183+
out.println("}");
184+
}
185+
}
186+
187+
private void writeJavaPoetBuilderClass(String packageName, String className, String classVariableName, String builderName,
188+
List<Element> fieldElements, Element typeElement) throws IOException {
189+
190+
ClassName builderType = ClassName.get(packageName, builderName);
191+
192+
List<FieldSpec> fields = new ArrayList<>(fieldElements.size());
193+
List<MethodSpec> fieldSetters = new ArrayList<>(fieldElements.size());
194+
195+
// Generate the fields and field setters
196+
generateFieldsAndSetters(fields, fieldSetters, fieldElements, builderType);
197+
198+
TypeName targetType = TypeName.get(typeElement.asType());
199+
200+
// Generate the build method
201+
MethodSpec buildMethod = generateBuildMethod(targetType, classVariableName, fields);
202+
203+
TypeSpec builder = TypeSpec.classBuilder(builderType)
204+
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
205+
.addFields(fields)
206+
.addMethods(fieldSetters)
207+
.addMethod(buildMethod).build();
208+
209+
JavaFile file = JavaFile.builder(builderType.packageName(), builder.toBuilder().build()).build();
210+
211+
file.writeTo(filer);
212+
}
213+
214+
private void generateFieldsAndSetters(List<FieldSpec> fields, List<MethodSpec> fieldSetters, List<Element> fieldElements, ClassName builderType){
215+
216+
for (Element fieldElement : fieldElements) {
217+
218+
TypeName typeName = TypeName.get(fieldElement.asType());
219+
String fieldName = getBaseName(fieldElement.getSimpleName().toString());
220+
221+
fields.add(FieldSpec.builder(typeName, fieldName, Modifier.PRIVATE).build());
222+
223+
fieldSetters.add(
224+
MethodSpec.methodBuilder(fieldName)
225+
.addModifiers(Modifier.PUBLIC)
226+
.returns(builderType)
227+
.addParameter(typeName, fieldName)
228+
.addStatement("this.$N = $N", fieldName, fieldName)
229+
.addStatement("return this").build());
230+
}
231+
}
232+
233+
private MethodSpec generateBuildMethod(TypeName targetType, String variableName, List<FieldSpec> fields) {
234+
235+
MethodSpec.Builder buildMethodBuilder = MethodSpec.methodBuilder("build")
236+
.addModifiers(Modifier.PUBLIC)
237+
.returns(targetType)
238+
.addStatement("$1T $2N = new $1T()", targetType, variableName);
239+
240+
for (FieldSpec field : fields) {
241+
242+
buildMethodBuilder.addStatement("$1N.set$2N(this.$3N)", variableName, CaseUtils.toCamelCase(field.name, true, '_'), field.name);
243+
}
244+
245+
buildMethodBuilder.addStatement("return $N", variableName);
246+
247+
return buildMethodBuilder.build();
248+
}
249+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
com.reflectoring.annotation.processor.BuilderProcessor
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#Generated by Maven
2+
#Wed Jan 26 14:56:24 EST 2022
3+
groupId=com.reflectoring.annotation.processor
4+
artifactId=annotation-processor
5+
version=1.0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
META-INF\services\javax.annotation.processing.Processor
2+
com\reflectoring\annotation\processor\Builder.class
3+
com\reflectoring\annotation\processor\BuilderProcessor.class

0 commit comments

Comments
 (0)