1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.sw4j.tool.annotation.jpa.processor;
18
19 import java.beans.Introspector;
20 import java.util.LinkedHashMap;
21 import java.util.List;
22 import java.util.Map;
23 import javax.annotation.Nonnull;
24 import javax.annotation.processing.ProcessingEnvironment;
25 import javax.lang.model.element.Element;
26 import javax.lang.model.element.ElementKind;
27 import javax.lang.model.element.ExecutableElement;
28 import javax.lang.model.element.TypeElement;
29 import javax.lang.model.type.TypeKind;
30 import javax.lang.model.type.TypeMirror;
31 import javax.persistence.AccessType;
32 import javax.persistence.Id;
33 import javax.tools.Diagnostic;
34 import org.sw4j.tool.annotation.jpa.generator.model.Attribute;
35 import org.sw4j.tool.annotation.jpa.generator.model.Entity;
36
37
38
39
40
41
42 public class AttributeProcessor {
43
44
45 private static final String PROPERTY_PREFIX = "get";
46
47
48 private static final int PROPERTY_PREFIX_LENGTH = "get".length();
49
50
51 private static final String BOOLEAN_PROPERTY_PREFIX = "is";
52
53
54 private static final int BOOLEAN_PROPERTY_PREFIX_LENGTH = "is".length();
55
56
57 private ProcessingEnvironment processingEnv;
58
59
60
61
62
63 public AttributeProcessor() {
64 }
65
66
67
68
69
70
71 @SuppressWarnings("checkstyle:HiddenField")
72 public void init(@Nonnull final ProcessingEnvironment processingEnv) {
73 this.processingEnv = processingEnv;
74 }
75
76
77
78
79
80
81
82 public void process(@Nonnull final Entity entity, @Nonnull final List<? extends Element> possibleAttributes) {
83 AccessType accessType = null;
84 Map<String, Element> possibleFields = new LinkedHashMap<>();
85 Map<String, Element> possibleProperties = new LinkedHashMap<>();
86 Map<String, Element> possibleIds = new LinkedHashMap<>();
87 for (Element possibleAttribute: possibleAttributes) {
88 String attributeName = null;
89 if (isField(possibleAttribute)) {
90 attributeName = possibleAttribute.getSimpleName().toString();
91 possibleFields.put(attributeName, possibleAttribute);
92 } else if (isProperty(possibleAttribute)) {
93 attributeName = getAttributeNameFromProperty(possibleAttribute);
94 possibleProperties.put(attributeName, possibleAttribute);
95 }
96 if (attributeName != null && isPossibleIdAttribute(possibleAttribute)) {
97 if (possibleIds.put(attributeName, possibleAttribute) != null) {
98 this.processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
99 new StringBuilder("The entity \"")
100 .append(entity.getName())
101 .append("\" (with class name \"")
102 .append(entity.getClassName())
103 .append("\") has the same attribute annotated with @Id twice."));
104 }
105 }
106 }
107
108 if (possibleIds.size() == 1) {
109 Map.Entry<String, Element> id = possibleIds.entrySet().iterator().next();
110 if (isField(id.getValue())) {
111 accessType = AccessType.FIELD;
112 } else {
113 accessType = AccessType.PROPERTY;
114 }
115 if (accessType == AccessType.FIELD) {
116 for (Map.Entry<String, Element> possibleField: possibleFields.entrySet()) {
117 processField(entity, possibleField.getValue());
118 }
119 } else {
120 for (Map.Entry<String, Element> possibleProperty: possibleProperties.entrySet()) {
121 processProperty(entity, possibleProperty.getValue());
122 }
123 }
124 } else if (possibleIds.isEmpty()) {
125 this.processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, new StringBuilder(
126 "This annotation processor does not support entities without @Id annotations. The entity \"")
127 .append(entity.getName())
128 .append("\" (with class name \"")
129 .append(entity.getClassName())
130 .append("\") has no @Id attributes."));
131 } else {
132 this.processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, new StringBuilder(
133 "This annotation processor does not support entities with multiple @Id annotations. The entity \"")
134 .append(entity.getName())
135 .append("\" (with class name \"")
136 .append(entity.getClassName())
137 .append("\") has more than 1 @Id attribute."));
138 }
139 }
140
141
142
143
144
145
146
147 private void processField(@Nonnull final Entity entity, @Nonnull final Element fieldElement) {
148 Attribute attribute = new Attribute(fieldElement.getSimpleName().toString(),
149 isPossibleIdAttribute(fieldElement), getDataTypeFromType(fieldElement.asType()));
150 entity.addAttribute(attribute);
151 }
152
153
154
155
156
157
158
159 private void processProperty(@Nonnull final Entity entity, @Nonnull final Element propertyElement) {
160 TypeMirror returnType = ((ExecutableElement)propertyElement).getReturnType();
161 Attribute attribute = new Attribute(getAttributeNameFromProperty(propertyElement),
162 isPossibleIdAttribute(propertyElement), getDataTypeFromType(returnType));
163 entity.addAttribute(attribute);
164 }
165
166
167
168
169
170
171
172 private String getDataTypeFromType(TypeMirror type) {
173 String dataType = "";
174 if (type.getKind().isPrimitive()) {
175
176 dataType = type.toString();
177 } else {
178
179 Element dataTypeElement = this.processingEnv.getTypeUtils().asElement(type);
180 if (dataTypeElement != null) {
181 ElementKind dataTypeKind = dataTypeElement.getKind();
182 if (dataTypeKind.isClass() || dataTypeKind.isInterface()) {
183 dataType = ((TypeElement)dataTypeElement).getQualifiedName().toString();
184 }
185 }
186 }
187 return dataType;
188 }
189
190
191
192
193
194
195
196 private boolean isPossibleIdAttribute(@Nonnull final Element element) {
197 Id idAnnotation = element.getAnnotation(Id.class);
198 return idAnnotation != null;
199 }
200
201
202
203
204
205
206
207 private boolean isField(@Nonnull final Element element) {
208 return ElementKind.FIELD.equals(element.getKind());
209 }
210
211
212
213
214
215
216
217 private boolean isProperty(@Nonnull final Element element) {
218 boolean isProperty = false;
219 if (ElementKind.METHOD.equals(element.getKind())) {
220 isProperty = !"".equals(getAttributeNameFromProperty(element));
221 }
222 return isProperty;
223 }
224
225
226
227
228
229
230
231
232
233 private String getAttributeNameFromProperty(@Nonnull final Element element) {
234 StringBuilder result = new StringBuilder();
235 String elementName = element.getSimpleName().toString();
236 if (elementName.startsWith(PROPERTY_PREFIX)) {
237 result.append(Introspector.decapitalize(elementName.substring(PROPERTY_PREFIX_LENGTH)));
238 } else if (elementName.startsWith(BOOLEAN_PROPERTY_PREFIX)) {
239 TypeMirror returnType = ((ExecutableElement)element).getReturnType();
240 if (TypeKind.BOOLEAN.equals(returnType.getKind())) {
241 result.append(Introspector.decapitalize(elementName.substring(BOOLEAN_PROPERTY_PREFIX_LENGTH)));
242 } else {
243 Element returnElement = this.processingEnv.getTypeUtils().asElement(returnType);
244 if (returnElement != null && ElementKind.CLASS.equals(returnElement.getKind())) {
245 if (Boolean.class.getName().equals(((TypeElement)returnElement).getQualifiedName().toString())) {
246 result.append(Introspector.decapitalize(elementName.substring(2)));
247 }
248 }
249 }
250 }
251 return result.toString();
252 }
253
254 }