View Javadoc

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   * Java Parser implementation of {@link AnnotationMetadata}.
49   * 
50   * @author Ben Alex
51   * @since 1.0
52   *
53   */
54  public final class JavaParserAnnotationMetadata implements AnnotationMetadata {
55  	// passed in
56  	private AnnotationExpr annotationExpr;
57  	private CompilationUnitServices compilationUnitServices;
58  
59  	// computed
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  		// Store required source information for subsequent mutability support
69  		this.annotationExpr = annotationExpr;
70  		this.compilationUnitServices = compilationUnitServices;
71  		
72  		// Obtain the annotation type name from the assorted types of annotations we might have received (ie marker annotations, single member annotations, normal annotations etc)
73  		NameExpr nameToFind = JavaParserUtils.getNameExpr(annotationExpr);
74  		
75  		// Compute the actual annotation type, having regard to the compilation unit package and imports
76  		annotationType = JavaParserUtils.getJavaType(compilationUnitServices, nameToFind, null);
77  		
78  		// Generate some member-value pairs for subsequent parsing
79  		List<MemberValuePair> annotationPairs = new ArrayList<MemberValuePair>();
80  		if (annotationExpr instanceof MarkerAnnotationExpr) {
81  			// A marker annotation has no values, so we can have no pairs to add
82  		} else if (annotationExpr instanceof SingleMemberAnnotationExpr) {
83  			SingleMemberAnnotationExpr a = (SingleMemberAnnotationExpr) annotationExpr;
84  			// Add the "value=" member-value pair.
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  			// Must iterate over the expressions
91  			if (a.getPairs() != null) {
92  				annotationPairs = a.getPairs();
93  			}
94  		}
95  		
96  		// Iterate over the annotation attributes, creating our parsed attributes map
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 			// Determine the type
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 	 * Facilitates the addition of the annotation to the presented type.
240 	 * 
241 	 * @param compilationUnitServices to use for flushing (required)
242 	 * @param annotations to add to the end of (required)
243 	 * @param annotation to add (required)
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 		// Create a holder for the annotation we're going to create
251 	    boolean foundExisting = false;
252 
253 	    // Search for an existing annotation of this type
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 			// Convert the candidate annotation type's into a JavaType
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 		// Import the annotation type, if needed
274 		NameExpr nameToUse = JavaParserUtils.importTypeIfRequired(compilationUnitServices.getEnclosingTypeName(), compilationUnitServices.getImports(), annotation.getAnnotationType());
275 
276 		// Create member-value pairs in accordance with Java Parser requirements
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 		// Create the AnnotationExpr; it varies depending on how many member-value pairs we need to present
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 	    	// We have a number of pairs being presented
295 	    	annotationExpression = new NormalAnnotationExpr(nameToUse, new ArrayList<MemberValuePair>());
296     	}
297 		
298 		// Add our AnnotationExpr to the actual annotations that will eventually be flushed through to the compilation unit
299 	    annotations.add(annotationExpression);
300 
301 	    // Add member-value pairs to our AnnotationExpr
302 	    if (memberValuePairs != null && memberValuePairs.size() > 0) {
303 	    	
304 	    	// have to check here for cases where we need to change an existing MarkerAnnotationExpr to a NormalAnnotationExpr or SingleMemberAnnotationExpr
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 			    	// We have a number of pairs being presented
316 			    	annotationExpression = new NormalAnnotationExpr(nameToUse, new ArrayList<MemberValuePair>());
317 			    	annotations.add(annotationExpression);
318 		    	}
319 	    	}
320 	    	if (annotationExpression instanceof SingleMemberAnnotationExpr) {
321 	    		// Potentially upgrade this expression to a NormalAnnotationExpr
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 	    			// they specified only a single member-value pair, and it is the default anyway, so we need not do anything except update the value
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 	    			// there is >1 expression, or they have provided some sort of non-default value, so it's time to upgrade the expression
333 	    			// (whilst retaining any potentially existing expression values)
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 	 * Facilitates the removal of the annotation type indicated.
356 	 * 
357 	 * @param compilationUnitServices to use for flushing (required)
358 	 * @param annotations to remove the annotation from (required)
359 	 * @param annotation to remove (required)
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 			// Rely on the nested instance to know its member value pairs
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 			// this isn't as elegant as it could be (ie loss of type parameters), but it will do for now
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 			// this doesn't preserve type parameters
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 }