1 package spoon.support.reflect.declaration; 2 3 import java.lang.annotation.Annotation ; 4 import java.lang.reflect.Array ; 5 import java.lang.reflect.InvocationHandler ; 6 import java.lang.reflect.Method ; 7 import java.lang.reflect.Proxy ; 8 import java.util.ArrayList ; 9 import java.util.Arrays ; 10 import java.util.Collection ; 11 import java.util.List ; 12 import java.util.Map ; 13 import java.util.TreeMap ; 14 15 import spoon.reflect.code.CtCodeElement; 16 import spoon.reflect.code.CtFieldAccess; 17 import spoon.reflect.code.CtLiteral; 18 import spoon.reflect.declaration.CtAnnotation; 19 import spoon.reflect.declaration.CtAnnotationType; 20 import spoon.reflect.declaration.CtField; 21 import spoon.reflect.declaration.CtSimpleType; 22 import spoon.reflect.eval.PartialEvaluator; 23 import spoon.reflect.reference.CtFieldReference; 24 import spoon.reflect.reference.CtTypeReference; 25 import spoon.reflect.visitor.CtVisitor; 26 27 32 public class CtAnnotationImpl<A extends Annotation > extends CtElementImpl 33 implements CtAnnotation<A> { 34 class AnnotationInvocationHandler implements InvocationHandler { 35 CtAnnotation<? extends Annotation > annotation; 36 37 public AnnotationInvocationHandler( 38 CtAnnotation<? extends Annotation > annotation) { 39 super(); 40 this.annotation = annotation; 41 } 42 43 public Object invoke(Object proxy, Method method, Object [] args) 44 throws Throwable { 45 String fieldname = method.getName(); 46 if (fieldname.equals("toString")) { 47 return CtAnnotationImpl.this.toString(); 48 } else if (fieldname.equals("annotationType")) { 49 return annotation.getAnnotationType().getActualClass(); 50 } 51 return getElementValue(fieldname); 52 } 53 } 54 55 private static final long serialVersionUID = 1L; 56 57 CtTypeReference<A> annotationType; 58 59 Map <String , Object > elementValues = new TreeMap <String , Object >(); 60 61 public CtAnnotationImpl() { 62 super(); 63 } 64 65 public void accept(CtVisitor visitor) { 66 visitor.visitCtAnnotation(this); 67 } 68 69 protected void appendValues(String elementName, Object ... values) { 70 if (!elementValues.containsKey(elementName)) { 71 elementValues.put(elementName, values); 72 } else { 73 Object o = elementValues.get(elementName); 74 if (o.getClass().isArray()) { 75 List <Object > tmp = new ArrayList <Object >(); 76 Object [] old = (Object []) o; 77 for (Object a : old) { 78 tmp.add(a); 79 } 80 for (Object a : values) { 81 tmp.add(a); 82 } 83 elementValues.put(elementName, tmp.toArray()); 84 } else { 85 if (values.length > 1) { 87 throw new RuntimeException ( 88 "Cannot add array to a non-array value"); 89 } else { 90 elementValues.put(elementName, values[0]); 91 } 92 } 93 } 94 } 95 96 @SuppressWarnings ("unchecked") 97 public A getActualAnnotation() { 98 return (A) Proxy.newProxyInstance(annotationType.getActualClass() 99 .getClassLoader(), new Class [] { annotationType 100 .getActualClass() }, new AnnotationInvocationHandler(this)); 101 } 102 103 @SuppressWarnings ("unchecked") 104 private Object convertValue(Object value) { 105 if (value instanceof CtFieldReference) { 106 Class c = ((CtFieldReference) value).getDeclaringType() 107 .getActualClass(); 108 if (((CtFieldReference) value).getSimpleName().equals("class")) { 109 return c; 110 } 111 CtField field = ((CtFieldReference) value).getDeclaration(); 112 if (Enum .class.isAssignableFrom(c)) { 113 return Enum.valueOf(c, ((CtFieldReference) value) 115 .getSimpleName()); 116 } else { 117 return convertValue(field.getDefaultExpression()); 119 } 120 } else if (value instanceof CtFieldAccess) { 121 return convertValue(((CtFieldAccess) value).getVariable()); 123 } else if (value instanceof CtAnnotation) { 124 return ((CtAnnotation) value).getActualAnnotation(); 126 } else if (value instanceof CtLiteral) { 127 return ((CtLiteral) value).getValue(); 129 } else if (value instanceof CtCodeElement) { 130 PartialEvaluator eval = getFactory().Eval() 132 .createPartialEvaluator(); 133 Object ret = eval.evaluate(((CtCodeElement) value).getParent(), 134 (CtCodeElement) value); 135 if (!(ret instanceof CtCodeElement)) 136 return convertValue(ret); 137 else 138 return ret; 139 } else if (value instanceof CtTypeReference) { 140 return ((CtTypeReference) value).getActualClass(); 142 } 143 return value; 144 } 145 146 private Class getElementType(String name) { 147 CtSimpleType t = getAnnotationType().getDeclaration(); 149 if (t != null) { 150 CtField f = t.getField(name); 151 return f.getType().getActualClass(); 152 } 153 Class c = getAnnotationType().getActualClass(); 155 for (Method m : c.getMethods()) { 156 if (m.getName().equals(name)) { 157 return m.getReturnType(); 158 } 159 } 160 return null; 161 } 162 163 public CtTypeReference<A> getAnnotationType() { 164 return annotationType; 165 } 166 167 private Object getDefaultValue(String fieldName) { 168 Object ret = null; 169 CtAnnotationType<?> at = (CtAnnotationType<?>) getAnnotationType() 170 .getDeclaration(); 171 if (at != null) { 172 CtField<?> f = at.getField(fieldName); 173 ret = f.getDefaultExpression(); 174 } 175 return ret; 176 } 177 178 public Object getElementValue(String key) { 179 Object ret = null; 180 ret = elementValues.get(key); 181 if (ret == null) 182 ret = getDefaultValue(key); 183 if (ret == null) 184 ret = getReflectValue(key); 185 186 Class type = getElementType(key); 187 188 if (type.isArray()) { 189 if (!(ret instanceof Collection )) { 190 List <Object > lst = new ArrayList <Object >(); 191 Object [] temp = (Object [])ret; 192 lst.addAll(Arrays.asList(temp)); 193 ret = lst; 194 195 } 196 Collection col = (Collection ) ret; 197 Object [] array = (Object []) Array.newInstance(type 198 .getComponentType(), col.size()); 199 int i = 0; 200 for (Object obj : col) { 201 array[i++] = convertValue(obj); 202 } 203 ret = array; 204 } else { 205 ret = convertValue(ret); 206 } 207 208 if (type.isPrimitive()) { 209 if (type == boolean.class && ret.getClass() != boolean.class) { 210 ret = Boolean.parseBoolean(ret.toString()); 211 } else if (type == byte.class && ret.getClass() != byte.class) { 212 ret = Byte.parseByte(ret.toString()); 213 } else if (type == char.class && ret.getClass() != char.class) { 214 ret = ret.toString().charAt(0); 215 } else if (type == double.class && ret.getClass() != double.class) { 216 ret = Double.parseDouble(ret.toString()); 217 } else if (type == float.class && ret.getClass() != float.class) { 218 ret = Float.parseFloat(ret.toString()); 219 } else if (type == int.class && ret.getClass() != int.class) { 220 ret = Integer.parseInt(ret.toString()); 221 } else if (type == long.class && ret.getClass() != long.class) { 222 ret = Long.parseLong(ret.toString()); 223 } 224 } 225 return ret; 226 } 227 228 public Map <String , Object > getElementValues() { 229 return elementValues; 230 } 231 232 private Object getReflectValue(String fieldname) { 233 try { 234 Class c = getAnnotationType().getActualClass(); 235 Method m = c.getMethod(fieldname); 236 return m.getDefaultValue(); 237 } catch (Exception e) { 238 return null; 239 } 240 } 241 242 @SuppressWarnings ("unchecked") 243 public void setAnnotationType( 244 CtTypeReference<? extends Annotation > annotationType) { 245 this.annotationType = (CtTypeReference<A>) annotationType; 246 } 247 248 public void setElementValues(Map <String , Object > values) { 249 this.elementValues = values; 250 } 251 } 252 | Popular Tags |