1 package org.springframework.roo.classpath.javaparser.details;
2
3 import japa.parser.ast.expr.AnnotationExpr;
4 import japa.parser.ast.expr.ArrayInitializerExpr;
5 import japa.parser.ast.expr.BinaryExpr;
6 import japa.parser.ast.expr.BooleanLiteralExpr;
7 import japa.parser.ast.expr.CharLiteralExpr;
8 import japa.parser.ast.expr.ClassExpr;
9 import japa.parser.ast.expr.DoubleLiteralExpr;
10 import japa.parser.ast.expr.Expression;
11 import japa.parser.ast.expr.FieldAccessExpr;
12 import japa.parser.ast.expr.IntegerLiteralExpr;
13 import japa.parser.ast.expr.LongLiteralExpr;
14 import japa.parser.ast.expr.MarkerAnnotationExpr;
15 import japa.parser.ast.expr.MemberValuePair;
16 import japa.parser.ast.expr.NameExpr;
17 import japa.parser.ast.expr.NormalAnnotationExpr;
18 import japa.parser.ast.expr.SingleMemberAnnotationExpr;
19 import japa.parser.ast.expr.StringLiteralExpr;
20 import japa.parser.ast.type.Type;
21
22 import java.util.ArrayList;
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Map;
26
27 import org.springframework.roo.classpath.details.annotations.AnnotationAttributeValue;
28 import org.springframework.roo.classpath.details.annotations.AnnotationMetadata;
29 import org.springframework.roo.classpath.details.annotations.ArrayAttributeValue;
30 import org.springframework.roo.classpath.details.annotations.BooleanAttributeValue;
31 import org.springframework.roo.classpath.details.annotations.CharAttributeValue;
32 import org.springframework.roo.classpath.details.annotations.ClassAttributeValue;
33 import org.springframework.roo.classpath.details.annotations.DoubleAttributeValue;
34 import org.springframework.roo.classpath.details.annotations.EnumAttributeValue;
35 import org.springframework.roo.classpath.details.annotations.IntegerAttributeValue;
36 import org.springframework.roo.classpath.details.annotations.LongAttributeValue;
37 import org.springframework.roo.classpath.details.annotations.NestedAnnotationAttributeValue;
38 import org.springframework.roo.classpath.details.annotations.StringAttributeValue;
39 import org.springframework.roo.classpath.javaparser.CompilationUnitServices;
40 import org.springframework.roo.classpath.javaparser.JavaParserUtils;
41 import org.springframework.roo.model.EnumDetails;
42 import org.springframework.roo.model.JavaSymbolName;
43 import org.springframework.roo.model.JavaType;
44 import org.springframework.roo.support.style.ToStringCreator;
45 import org.springframework.roo.support.util.Assert;
46
47
48
49
50
51
52
53
54 public final class JavaParserAnnotationMetadata implements AnnotationMetadata {
55
56 private AnnotationExpr annotationExpr;
57 private CompilationUnitServices compilationUnitServices;
58
59
60 private JavaType annotationType;
61 private List<AnnotationAttributeValue<?>> attributes = new ArrayList<AnnotationAttributeValue<?>>();
62 private Map<JavaSymbolName, AnnotationAttributeValue<?>> attributeMap = new HashMap<JavaSymbolName, AnnotationAttributeValue<?>>();
63
64 public JavaParserAnnotationMetadata(AnnotationExpr annotationExpr, CompilationUnitServices compilationUnitServices) {
65 Assert.notNull(annotationExpr, "Annotation expression required");
66 Assert.notNull(compilationUnitServices, "Compilation unit services required");
67
68
69 this.annotationExpr = annotationExpr;
70 this.compilationUnitServices = compilationUnitServices;
71
72
73 NameExpr nameToFind = JavaParserUtils.getNameExpr(annotationExpr);
74
75
76 annotationType = JavaParserUtils.getJavaType(compilationUnitServices, nameToFind, null);
77
78
79 List<MemberValuePair> annotationPairs = new ArrayList<MemberValuePair>();
80 if (annotationExpr instanceof MarkerAnnotationExpr) {
81
82 } else if (annotationExpr instanceof SingleMemberAnnotationExpr) {
83 SingleMemberAnnotationExpr a = (SingleMemberAnnotationExpr) annotationExpr;
84
85 if (a.getMemberValue() != null) {
86 annotationPairs.add(new MemberValuePair("value", a.getMemberValue()));
87 }
88 } else if (annotationExpr instanceof NormalAnnotationExpr) {
89 NormalAnnotationExpr a = (NormalAnnotationExpr) annotationExpr;
90
91 if (a.getPairs() != null) {
92 annotationPairs = a.getPairs();
93 }
94 }
95
96
97 for (MemberValuePair p : annotationPairs) {
98 JavaSymbolName annotationName = new JavaSymbolName(p.getName());
99 AnnotationAttributeValue<?> value = convert(annotationName, p.getValue());
100 attributes.add(value);
101 attributeMap.put(value.getName(), value);
102 }
103 }
104
105 private AnnotationAttributeValue<?> convert(JavaSymbolName annotationName, Expression expression) {
106 if (annotationName == null) {
107 annotationName = new JavaSymbolName("__ARRAY_ELEMENT__");
108 }
109
110 if (expression instanceof AnnotationExpr) {
111 AnnotationExpr annotationExpr = (AnnotationExpr) expression;
112 AnnotationMetadata value = new JavaParserAnnotationMetadata(annotationExpr, compilationUnitServices);
113 return new NestedAnnotationAttributeValue(annotationName, value);
114 }
115
116 if (expression instanceof BooleanLiteralExpr) {
117 boolean value = ((BooleanLiteralExpr)expression).getValue();
118 return new BooleanAttributeValue(annotationName, value);
119 }
120
121 if (expression instanceof CharLiteralExpr) {
122 String value = ((CharLiteralExpr)expression).getValue();
123 Assert.isTrue(value.length() == 1, "Expected a char expression, but instead received '" + value + "' for attribute '" + annotationName + "'");
124 char c = value.charAt(0);
125 return new CharAttributeValue(annotationName, c);
126 }
127
128 if (expression instanceof LongLiteralExpr) {
129 String value = ((LongLiteralExpr)expression).getValue();
130 Assert.isTrue(value.toUpperCase().endsWith("L"), "Expected long literal expression '" + value + "' to end in 'l' or 'L'");
131 value = value.substring(0, value.length()-1);
132 long l = new Long(value);
133 return new LongAttributeValue(annotationName, l);
134 }
135
136 if (expression instanceof IntegerLiteralExpr) {
137 String value = ((IntegerLiteralExpr)expression).getValue();
138 int i = new Integer(value);
139 return new IntegerAttributeValue(annotationName, i);
140 }
141
142 if (expression instanceof DoubleLiteralExpr) {
143 String value = ((DoubleLiteralExpr)expression).getValue();
144 boolean floatingPrecisionOnly = false;
145 if (value.toUpperCase().endsWith("F")) {
146 value = value.substring(0, value.length()-1);
147 floatingPrecisionOnly = true;
148 }
149 if (value.toUpperCase().endsWith("D")) {
150 value = value.substring(0, value.length()-1);
151 }
152 double d = new Double(value);
153 return new DoubleAttributeValue(annotationName, d, floatingPrecisionOnly);
154 }
155
156 if (expression instanceof BinaryExpr) {
157 String result = "";
158 BinaryExpr current = (BinaryExpr) expression;
159 while (current instanceof BinaryExpr) {
160 Assert.isInstanceOf(StringLiteralExpr.class, current.getRight());
161 String right = ((StringLiteralExpr)current.getRight()).getValue();
162 result = right + result;
163 if (current.getLeft() instanceof StringLiteralExpr) {
164 String left = ((StringLiteralExpr)current.getLeft()).getValue();
165 result = left + result;
166 }
167 if (current.getLeft() instanceof BinaryExpr) {
168 current = (BinaryExpr) current.getLeft();
169 } else {
170 current = null;
171 }
172 }
173 return new StringAttributeValue(annotationName, result);
174 }
175
176 if (expression instanceof StringLiteralExpr) {
177 String value = ((StringLiteralExpr)expression).getValue();
178 return new StringAttributeValue(annotationName, value);
179 }
180
181 if (expression instanceof FieldAccessExpr) {
182 FieldAccessExpr field = (FieldAccessExpr) expression;
183 String fieldName = field.getField();
184
185
186 Expression scope = field.getScope();
187 NameExpr nameToFind = null;
188 if (scope instanceof FieldAccessExpr) {
189 FieldAccessExpr fScope = (FieldAccessExpr) scope;
190 nameToFind = JavaParserUtils.getNameExpr(fScope.toString());
191 } else if (scope instanceof NameExpr) {
192 nameToFind = (NameExpr) scope;
193 } else {
194 throw new UnsupportedOperationException("A FieldAccessExpr for '" + field.getScope() + "' should return a NameExpr or FieldAccessExpr (was " + field.getScope().getClass().getName() + ")");
195 }
196 JavaType fieldType = JavaParserUtils.getJavaType(compilationUnitServices, nameToFind, null);
197
198 EnumDetails enumDetails = new EnumDetails(fieldType, new JavaSymbolName(fieldName));
199 return new EnumAttributeValue(annotationName, enumDetails);
200 }
201
202 if (expression instanceof ClassExpr) {
203 ClassExpr clazz = (ClassExpr) expression;
204 Type nameToFind = clazz.getType();
205 JavaType javaType = JavaParserUtils.getJavaType(compilationUnitServices, nameToFind, null);
206 return new ClassAttributeValue(annotationName, javaType);
207 }
208
209 if (expression instanceof ArrayInitializerExpr) {
210 ArrayInitializerExpr castExp = (ArrayInitializerExpr) expression;
211 List<AnnotationAttributeValue<?>> arrayElements = new ArrayList<AnnotationAttributeValue<?>>();
212 for (Expression e : castExp.getValues()) {
213 arrayElements.add(convert(null, e));
214 }
215 return new ArrayAttributeValue<AnnotationAttributeValue<?>>(annotationName, arrayElements);
216 }
217
218 throw new UnsupportedOperationException("Unable to parse annotation attribute '" + annotationName + "' due to unsupported annotation expression '" + expression.getClass().getName() + "'");
219 }
220
221 public JavaType getAnnotationType() {
222 return annotationType;
223 }
224
225 public AnnotationAttributeValue<?> getAttribute(JavaSymbolName attributeName) {
226 Assert.notNull(attributeName, "Attribute name required");
227 return attributeMap.get(attributeName);
228 }
229
230 public List<JavaSymbolName> getAttributeNames() {
231 List<JavaSymbolName> result = new ArrayList<JavaSymbolName>();
232 for (AnnotationAttributeValue<?> value : attributes) {
233 result.add(value.getName());
234 }
235 return result;
236 }
237
238
239
240
241
242
243
244
245 public static void addAnnotationToList(CompilationUnitServices compilationUnitServices, List<AnnotationExpr> annotations, AnnotationMetadata annotation, boolean permitFlush) {
246 Assert.notNull(compilationUnitServices, "Compilation unit services required");
247 Assert.notNull(annotations, "Annotations required");
248 Assert.notNull(annotation, "Annotation metadata required");
249
250
251 boolean foundExisting = false;
252
253
254 for (AnnotationExpr candidate : annotations) {
255 NameExpr existingName = null;
256 if (candidate instanceof NormalAnnotationExpr) {
257 existingName = ((NormalAnnotationExpr) candidate).getName();
258 } else if (candidate instanceof MarkerAnnotationExpr) {
259 existingName = ((MarkerAnnotationExpr) candidate).getName();
260 } else if (candidate instanceof SingleMemberAnnotationExpr) {
261 existingName = ((SingleMemberAnnotationExpr) candidate).getName();
262 }
263
264
265 JavaType javaType = JavaParserUtils.getJavaType(compilationUnitServices, existingName, null);
266 if (annotation.getAnnotationType().equals(javaType)) {
267 foundExisting = true;
268 break;
269 }
270 }
271 Assert.isTrue(!foundExisting, "Found an existing annotation for type '" + annotation.getAnnotationType() + "'");
272
273
274 NameExpr nameToUse = JavaParserUtils.importTypeIfRequired(compilationUnitServices.getEnclosingTypeName(), compilationUnitServices.getImports(), annotation.getAnnotationType());
275
276
277 List<MemberValuePair> memberValuePairs = new ArrayList<MemberValuePair>();
278 for (JavaSymbolName attributeName : annotation.getAttributeNames()) {
279 AnnotationAttributeValue<?> value = annotation.getAttribute(attributeName);
280 Assert.notNull(value, "Unable to acquire value '" + attributeName + "' from annotation");
281 MemberValuePair memberValuePair = convert(value);
282 Assert.notNull(memberValuePair, "Member value pair should have been set");
283 memberValuePairs.add(memberValuePair);
284 }
285
286
287 AnnotationExpr annotationExpression = null;
288 if (memberValuePairs.size() == 0) {
289 annotationExpression = new MarkerAnnotationExpr(nameToUse);
290 } else if (memberValuePairs.size() == 1 && (memberValuePairs.get(0).getName() == null || "value".equals(memberValuePairs.get(0).getName()))) {
291 Expression toUse = JavaParserUtils.importExpressionIfRequired(compilationUnitServices.getEnclosingTypeName(), compilationUnitServices.getImports(), memberValuePairs.get(0).getValue());
292 annotationExpression = new SingleMemberAnnotationExpr(nameToUse, toUse);
293 } else {
294
295 annotationExpression = new NormalAnnotationExpr(nameToUse, new ArrayList<MemberValuePair>());
296 }
297
298
299 annotations.add(annotationExpression);
300
301
302 if (memberValuePairs != null && memberValuePairs.size() > 0) {
303
304
305 if (annotationExpression instanceof MarkerAnnotationExpr) {
306 MarkerAnnotationExpr mae = (MarkerAnnotationExpr) annotationExpression;
307
308 annotations.remove(mae);
309
310 if (memberValuePairs != null && memberValuePairs.size() == 1 && (memberValuePairs.get(0).getName() == null || "value".equals(memberValuePairs.get(0).getName()))) {
311 Expression toUse = JavaParserUtils.importExpressionIfRequired(compilationUnitServices.getEnclosingTypeName(), compilationUnitServices.getImports(), memberValuePairs.get(0).getValue());
312 annotationExpression = new SingleMemberAnnotationExpr(nameToUse, toUse);
313 annotations.add(annotationExpression);
314 } else {
315
316 annotationExpression = new NormalAnnotationExpr(nameToUse, new ArrayList<MemberValuePair>());
317 annotations.add(annotationExpression);
318 }
319 }
320 if (annotationExpression instanceof SingleMemberAnnotationExpr) {
321
322 SingleMemberAnnotationExpr smae = (SingleMemberAnnotationExpr) annotationExpression;
323 if (memberValuePairs.size() == 1 && memberValuePairs.get(0).getName() == null || memberValuePairs.get(0).getName().equals("value") || memberValuePairs.get(0).getName().equals("")) {
324
325 Expression toUse = JavaParserUtils.importExpressionIfRequired(compilationUnitServices.getEnclosingTypeName(), compilationUnitServices.getImports(), memberValuePairs.get(0).getValue());
326 smae.setMemberValue(toUse);
327 if (permitFlush) {
328 compilationUnitServices.flush();
329 }
330 return;
331 } else {
332
333
334 Expression existingValue = smae.getMemberValue();
335 annotationExpression = new NormalAnnotationExpr(smae.getName(), new ArrayList<MemberValuePair>());
336 ((NormalAnnotationExpr)annotationExpression).getPairs().add(new MemberValuePair("value", existingValue));
337 }
338 }
339 Assert.isInstanceOf(NormalAnnotationExpr.class, annotationExpression, "Attempting to add >1 annotation member-value pair requires an existing normal annotation expression");
340 List<MemberValuePair> annotationPairs = ((NormalAnnotationExpr)annotationExpression).getPairs();
341 annotationPairs.clear();
342 for (MemberValuePair pair : memberValuePairs) {
343 Expression toUse = JavaParserUtils.importExpressionIfRequired(compilationUnitServices.getEnclosingTypeName(), compilationUnitServices.getImports(), pair.getValue());
344 pair.setValue(toUse);
345 annotationPairs.add(pair);
346 }
347 }
348
349 if (permitFlush) {
350 compilationUnitServices.flush();
351 }
352 }
353
354
355
356
357
358
359
360
361 public static void removeAnnotationFromList(CompilationUnitServices compilationUnitServices, List<AnnotationExpr> annotations, JavaType annotation, boolean permitFlush) {
362 Assert.notNull(compilationUnitServices, "Compilation unit services required");
363 Assert.notNull(annotations, "Annotations required");
364 Assert.notNull(annotation, "Annotation metadata required");
365
366 AnnotationExpr toRemove = null;
367 for (AnnotationExpr candidate : annotations) {
368 NameExpr existingName = null;
369 if (candidate instanceof NormalAnnotationExpr) {
370 existingName = ((NormalAnnotationExpr) candidate).getName();
371 } else if (candidate instanceof MarkerAnnotationExpr) {
372 existingName = ((MarkerAnnotationExpr) candidate).getName();
373 } else if (candidate instanceof SingleMemberAnnotationExpr) {
374 existingName = ((SingleMemberAnnotationExpr) candidate).getName();
375 }
376
377 JavaType javaType = JavaParserUtils.getJavaType(compilationUnitServices, existingName, null);
378 if (annotation.equals(javaType)) {
379 toRemove = candidate;
380 break;
381 }
382 }
383
384 Assert.notNull(toRemove, "Could not find annotation for type '" + annotation.getFullyQualifiedTypeName() + "' to remove");
385
386 annotations.remove(toRemove);
387
388 if (permitFlush) {
389 compilationUnitServices.flush();
390 }
391 }
392
393 @SuppressWarnings("unchecked")
394 private static MemberValuePair convert(AnnotationAttributeValue<?> value) {
395
396 if (value instanceof NestedAnnotationAttributeValue) {
397 NestedAnnotationAttributeValue castValue = (NestedAnnotationAttributeValue) value;
398 Assert.isInstanceOf(JavaParserAnnotationMetadata.class, castValue.getValue(), "Cannot presented nested annotations unless created by this class");
399 JavaParserAnnotationMetadata javaParserMutableAnnotationMetadata = (JavaParserAnnotationMetadata) castValue.getValue();
400
401
402 return new MemberValuePair(value.getName().getSymbolName(), javaParserMutableAnnotationMetadata.annotationExpr);
403 }
404
405 if (value instanceof BooleanAttributeValue) {
406 boolean castValue = ((BooleanAttributeValue)value).getValue();
407 BooleanLiteralExpr convertedValue = new BooleanLiteralExpr(castValue);
408 return new MemberValuePair(value.getName().getSymbolName(), convertedValue);
409 }
410
411 if (value instanceof CharAttributeValue) {
412 char castValue = ((CharAttributeValue)value).getValue();
413 CharLiteralExpr convertedValue = new CharLiteralExpr(new String(new char[] {castValue}));
414 return new MemberValuePair(value.getName().getSymbolName(), convertedValue);
415 }
416
417 if (value instanceof LongAttributeValue) {
418 Long castValue = ((LongAttributeValue)value).getValue();
419 LongLiteralExpr convertedValue = new LongLiteralExpr(castValue.toString() + "L");
420 return new MemberValuePair(value.getName().getSymbolName(), convertedValue);
421 }
422
423 if (value instanceof IntegerAttributeValue) {
424 Integer castValue = ((IntegerAttributeValue)value).getValue();
425 IntegerLiteralExpr convertedValue = new IntegerLiteralExpr(castValue.toString());
426 return new MemberValuePair(value.getName().getSymbolName(), convertedValue);
427 }
428
429 if (value instanceof DoubleAttributeValue) {
430 DoubleAttributeValue doubleAttributeValue = (DoubleAttributeValue) value;
431 Double castValue = doubleAttributeValue.getValue();
432 DoubleLiteralExpr convertedValue;
433 if (doubleAttributeValue.isFloatingPrecisionOnly()) {
434 convertedValue = new DoubleLiteralExpr(castValue.toString() + "F");
435 } else {
436 convertedValue = new DoubleLiteralExpr(castValue.toString() + "D");
437 }
438 return new MemberValuePair(value.getName().getSymbolName(), convertedValue);
439 }
440
441 if (value instanceof StringAttributeValue) {
442 String castValue = ((StringAttributeValue)value).getValue();
443 StringLiteralExpr convertedValue = new StringLiteralExpr(castValue.toString());
444 return new MemberValuePair(value.getName().getSymbolName(), convertedValue);
445 }
446
447 if (value instanceof EnumAttributeValue) {
448 EnumDetails castValue = ((EnumAttributeValue)value).getValue();
449
450 FieldAccessExpr convertedValue = new FieldAccessExpr(JavaParserUtils.getNameExpr(castValue.getType().getFullyQualifiedTypeName()), castValue.getField().getSymbolName());
451 return new MemberValuePair(value.getName().getSymbolName(), convertedValue);
452 }
453
454 if (value instanceof ClassAttributeValue) {
455 JavaType castValue = ((ClassAttributeValue)value).getValue();
456
457 NameExpr nameExpr = JavaParserUtils.getNameExpr(castValue.getFullyQualifiedTypeName());
458 ClassExpr convertedValue = new ClassExpr(JavaParserUtils.getReferenceType(nameExpr));
459 return new MemberValuePair(value.getName().getSymbolName(), convertedValue);
460 }
461
462 if (value instanceof ArrayAttributeValue) {
463 ArrayAttributeValue<AnnotationAttributeValue<?>> castValue = (ArrayAttributeValue<AnnotationAttributeValue<?>>) value;
464
465 List<Expression> arrayElements = new ArrayList<Expression>();
466 for (AnnotationAttributeValue<?> v : castValue.getValue()) {
467 arrayElements.add(convert(v).getValue());
468 }
469 return new MemberValuePair(value.getName().getSymbolName(), new ArrayInitializerExpr(arrayElements));
470 }
471
472 throw new UnsupportedOperationException("Unsupported attribute value '" + value.getName() + "' of type '" + value.getClass().getName() + "'");
473 }
474
475 public String toString() {
476 ToStringCreator tsc = new ToStringCreator(this);
477 tsc.append("annotationType", annotationType);
478 tsc.append("attributes", attributes);
479 return tsc.toString();
480 }
481
482 }