/
BeanMetaInfoProcessor.java
146 lines (120 loc) · 5.87 KB
/
BeanMetaInfoProcessor.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package io.github.mhagnumdw.beaninfogenerator;
import java.io.Writer;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedOptions;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
import javax.tools.JavaFileObject;
import com.squareup.javapoet.JavaFile;
import io.github.mhagnumdw.beaninfogenerator.builder.ClassFactory;
/**
* Annotation processor to generate the metadata information of the classes annotated with {@link GenerateBeanMetaInfo}.
*/
//@formatter:off
@SupportedAnnotationTypes({
"io.github.mhagnumdw.beaninfogenerator.GenerateBeanMetaInfo"
})
@SupportedOptions({
Context.DEBUG,
Context.SUFFIX,
Context.ADD_GENERATION_DATE,
Context.ONLY_NAME
})
//@formatter:on
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class BeanMetaInfoProcessor extends AbstractProcessor {
private static final boolean ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS = false;
private Context context;
// keep track of all classes for which info have been generated
private final Collection<String> generatedBeanMetaInfoClasses = new HashSet<String>();
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
context = new Context(processingEnv);
logNote("Starting annotation processing: {}", getSupportedAnnotationTypes());
logNote("Supported options: {}", getSupportedOptions());
logNote("Supported options summary: {}", context.supportedOptionsSummary());
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (roundEnv.processingOver() || annotations.size() == 0) {
return ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS;
}
logDebug("Annotations will be processed: {}", annotations);
for (TypeElement annotation : annotations) {
Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(GenerateBeanMetaInfo.class);
logNote("The annotation '{}' is present in {} classes", annotation.getQualifiedName(), elements.size());
for (Element classElement : elements) {
final String fcqnOriginalSource = ((TypeElement) classElement).getQualifiedName().toString();
final String className = classElement.getSimpleName().toString();
final String packageName = context.getPackageOf(classElement).getQualifiedName().toString();
if (!generatedBeanMetaInfoClasses.contains(fcqnOriginalSource)) {
logNote("Processing source: {}", fcqnOriginalSource);
} else {
logDebug("Source '{}' already processed, going to the next", fcqnOriginalSource);
continue;
}
if (!fcqnOriginalSource.equals(buildFcqn(packageName, className))) {
logWarning("fcqn '{}' differs from the concatenation of the package '{}' with the class name '{}'", fcqnOriginalSource, packageName, className);
}
final JavaFile javaFile = ClassFactory.createBuilder(context).build(classElement);
final String fcqnGeneratedSource = buildFcqn(javaFile);
try {
logNote("Generating: {}", fcqnGeneratedSource);
createSourceFile(javaFile);
generatedBeanMetaInfoClasses.add(fcqnOriginalSource);
logDebug("Generated: {}", fcqnGeneratedSource);
} catch (Exception e) {
logError("Failed to generate java code: {}: {}", fcqnGeneratedSource, e.getMessage());
throw new RuntimeException("Failed to generate java code: " + fcqnGeneratedSource, e);
}
}
}
return ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS;
}
private void createSourceFile(JavaFile javaFile) throws Exception {
final String fcqnGeneratedSource = buildFcqn(javaFile);
JavaFileObject jfo = context.getFiler().createSourceFile(fcqnGeneratedSource);
Writer writer = null;
try {
writer = jfo.openWriter();
writer.append(javaFile.toString());
} finally {
if (writer != null) {
writer.close();
}
}
}
private void logNote(String format, Object... arguments) {
context.printMessage(Kind.NOTE, GeneralUtils.format("[INFO ] " + format, arguments));
}
private void logDebug(String format, Object... arguments) {
if (context.isDebug()) {
context.printMessage(Kind.NOTE, GeneralUtils.format("[DEBUG] " + format, arguments));
}
}
private void logError(String format, Object... arguments) {
context.printMessage(Kind.ERROR, GeneralUtils.format("[ERROR] " + format, arguments));
}
private void logWarning(String format, Object... arguments) {
context.printMessage(Kind.WARNING, GeneralUtils.format("[WARN ] " + format, arguments));
}
private String buildFcqn(JavaFile javaFile) {
return buildFcqn(javaFile.packageName, javaFile.typeSpec.name);
}
private String buildFcqn(String packageName, String className) {
if (GeneralUtils.isNotBlank(packageName)) {
packageName += ".";
}
return packageName + className;
}
}