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

File tree

91 files changed

+996
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

91 files changed

+996
-0
lines changed
11.7 KB
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>
Lines changed: 11 additions & 0 deletions
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+
}
Lines changed: 249 additions & 0 deletions
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+
}
8.41 KB
Binary file not shown.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
com.reflectoring.annotation.processor.BuilderProcessor
402 Bytes
Binary file not shown.
13.1 KB
Binary file not shown.
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
Lines changed: 3 additions & 0 deletions
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)