1 /* 2 * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Sun designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Sun in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22 * CA 95054 USA or visit www.sun.com if you need additional information or 23 * have any questions. 24 */ 25 26 package com.sun.tools.javac.model; 27 28 import com.sun.tools.javac.util.*; 29 import java.lang.annotation.*; 30 import java.lang.reflect.Array; 31 import java.lang.reflect.Method; 32 import java.util.LinkedHashMap; 33 import java.util.Map; 34 import sun.reflect.annotation.*; 35 36 import javax.lang.model.type.TypeMirror; 37 import javax.lang.model.type.MirroredTypeException; 38 import javax.lang.model.type.MirroredTypesException; 39 import com.sun.tools.javac.code.*; 40 import com.sun.tools.javac.code.Symbol.*; 41 import com.sun.tools.javac.code.Type.ArrayType; 42 43 44 /** 45 * A generator of dynamic proxy implementations of 46 * java.lang.annotation.Annotation. 47 * 48 * <p> The "dynamic proxy return form" of an annotation element value is 49 * the form used by sun.reflect.annotation.AnnotationInvocationHandler. 50 * 51 * <p><b>This is NOT part of any API supported by Sun Microsystems. If 52 * you write code that depends on this, you do so at your own risk. 53 * This code and its internal interfaces are subject to change or 54 * deletion without notice.</b> 55 */ 56 57 public class AnnotationProxyMaker { 58 59 private final Attribute.Compound anno; 60 private final Class<? extends Annotation> annoType; 61 62 63 private AnnotationProxyMaker(Attribute.Compound anno, 64 Class<? extends Annotation> annoType) { 65 this.anno = anno; 66 this.annoType = annoType; 67 } 68 69 70 /** 71 * Returns a dynamic proxy for an annotation mirror. 72 */ 73 public static <A extends Annotation> A generateAnnotation( 74 Attribute.Compound anno, Class<A> annoType) { 75 AnnotationProxyMaker apm = new AnnotationProxyMaker(anno, annoType); 76 return annoType.cast(apm.generateAnnotation()); 77 } 78 79 80 /** 81 * Returns a dynamic proxy for an annotation mirror. 82 */ 83 private Annotation generateAnnotation() { 84 return AnnotationParser.annotationForMap(annoType, 85 getAllReflectedValues()); 86 } 87 88 /** 89 * Returns a map from element names to their values in "dynamic 90 * proxy return form". Includes all elements, whether explicit or 91 * defaulted. 92 */ 93 private Map<String, Object> getAllReflectedValues() { 94 Map<String, Object> res = new LinkedHashMap<String, Object>(); 95 96 for (Map.Entry<MethodSymbol, Attribute> entry : 97 getAllValues().entrySet()) { 98 MethodSymbol meth = entry.getKey(); 99 Object value = generateValue(meth, entry.getValue()); 100 if (value != null) { 101 res.put(meth.name.toString(), value); 102 } else { 103 // Ignore this element. May (properly) lead to 104 // IncompleteAnnotationException somewhere down the line. 105 } 106 } 107 return res; 108 } 109 110 /** 111 * Returns a map from element symbols to their values. 112 * Includes all elements, whether explicit or defaulted. 113 */ 114 private Map<MethodSymbol, Attribute> getAllValues() { 115 Map<MethodSymbol, Attribute> res = 116 new LinkedHashMap<MethodSymbol, Attribute>(); 117 118 // First find the default values. 119 ClassSymbol sym = (ClassSymbol) anno.type.tsym; 120 for (Scope.Entry e = sym.members().elems; e != null; e = e.sibling) { 121 if (e.sym.kind == Kinds.MTH) { 122 MethodSymbol m = (MethodSymbol) e.sym; 123 Attribute def = m.getDefaultValue(); 124 if (def != null) 125 res.put(m, def); 126 } 127 } 128 // Next find the explicit values, possibly overriding defaults. 129 for (Pair<MethodSymbol, Attribute> p : anno.values) 130 res.put(p.fst, p.snd); 131 return res; 132 } 133 134 /** 135 * Converts an element value to its "dynamic proxy return form". 136 * Returns an exception proxy on some errors, but may return null if 137 * a useful exception cannot or should not be generated at this point. 138 */ 139 private Object generateValue(MethodSymbol meth, Attribute attr) { 140 ValueVisitor vv = new ValueVisitor(meth); 141 return vv.getValue(attr); 142 } 143 144 145 private class ValueVisitor implements Attribute.Visitor { 146 147 private MethodSymbol meth; // annotation element being visited 148 private Class<?> returnClass; // return type of annotation element 149 private Object value; // value in "dynamic proxy return form" 150 151 ValueVisitor(MethodSymbol meth) { 152 this.meth = meth; 153 } 154 155 Object getValue(Attribute attr) { 156 Method method; // runtime method of annotation element 157 try { 158 method = annoType.getMethod(meth.name.toString()); 159 } catch (NoSuchMethodException e) { 160 return null; 161 } 162 returnClass = method.getReturnType(); 163 attr.accept(this); 164 if (!(value instanceof ExceptionProxy) && 165 !AnnotationType.invocationHandlerReturnType(returnClass) 166 .isInstance(value)) { 167 typeMismatch(method, attr); 168 } 169 return value; 170 } 171 172 173 public void visitConstant(Attribute.Constant c) { 174 value = c.getValue(); 175 } 176 177 public void visitClass(Attribute.Class c) { 178 value = new MirroredTypeExceptionProxy(c.type); 179 } 180 181 public void visitArray(Attribute.Array a) { 182 Name elemName = ((ArrayType) a.type).elemtype.tsym.name; 183 184 if (elemName == elemName.table.names.java_lang_Class) { // Class[] 185 // Construct a proxy for a MirroredTypesException 186 List<TypeMirror> elems = List.nil(); 187 for (Attribute value : a.values) { 188 Type elem = ((Attribute.Class) value).type; 189 elems.add(elem); 190 } 191 value = new MirroredTypesExceptionProxy(elems); 192 193 } else { 194 int len = a.values.length; 195 Class<?> returnClassSaved = returnClass; 196 returnClass = returnClass.getComponentType(); 197 try { 198 Object res = Array.newInstance(returnClass, len); 199 for (int i = 0; i < len; i++) { 200 a.values[i].accept(this); 201 if (value == null || value instanceof ExceptionProxy) { 202 return; 203 } 204 try { 205 Array.set(res, i, value); 206 } catch (IllegalArgumentException e) { 207 value = null; // indicates a type mismatch 208 return; 209 } 210 } 211 value = res; 212 } finally { 213 returnClass = returnClassSaved; 214 } 215 } 216 } 217 218 @SuppressWarnings({"unchecked", "rawtypes"}) 219 public void visitEnum(Attribute.Enum e) { 220 if (returnClass.isEnum()) { 221 String constName = e.value.toString(); 222 try { 223 value = Enum.valueOf((Class)returnClass, constName); 224 } catch (IllegalArgumentException ex) { 225 value = new EnumConstantNotPresentExceptionProxy( 226 (Class<Enum<?>>) returnClass, constName); 227 } 228 } else { 229 value = null; // indicates a type mismatch 230 } 231 } 232 233 public void visitCompound(Attribute.Compound c) { 234 try { 235 Class<? extends Annotation> nested = 236 returnClass.asSubclass(Annotation.class); 237 value = generateAnnotation(c, nested); 238 } catch (ClassCastException ex) { 239 value = null; // indicates a type mismatch 240 } 241 } 242 243 public void visitError(Attribute.Error e) { 244 value = null; // indicates a type mismatch 245 } 246 247 248 /** 249 * Sets "value" to an ExceptionProxy indicating a type mismatch. 250 */ 251 private void typeMismatch(final Method method, final Attribute attr) { 252 value = new ExceptionProxy() { 253 static final long serialVersionUID = 269; 254 public String toString() { 255 return "<error>"; // eg: @Anno(value=<error>) 256 } 257 protected RuntimeException generateException() { 258 return new AnnotationTypeMismatchException(method, 259 attr.type.toString()); 260 } 261 }; 262 } 263 } 264 265 266 /** 267 * ExceptionProxy for MirroredTypeException. 268 * The toString, hashCode, and equals methods foward to the underlying 269 * type. 270 */ 271 private static class MirroredTypeExceptionProxy extends ExceptionProxy { 272 static final long serialVersionUID = 269; 273 274 private transient final TypeMirror type; 275 private final String typeString; 276 277 MirroredTypeExceptionProxy(TypeMirror t) { 278 type = t; 279 typeString = t.toString(); 280 } 281 282 public String toString() { 283 return typeString; 284 } 285 286 public int hashCode() { 287 return (type != null ? type : typeString).hashCode(); 288 } 289 290 public boolean equals(Object obj) { 291 return type != null && 292 obj instanceof MirroredTypeExceptionProxy && 293 type.equals(((MirroredTypeExceptionProxy) obj).type); 294 } 295 296 protected RuntimeException generateException() { 297 return new MirroredTypeException(type); 298 } 299 } 300 301 302 /** 303 * ExceptionProxy for MirroredTypesException. 304 * The toString, hashCode, and equals methods foward to the underlying 305 * types. 306 */ 307 private static class MirroredTypesExceptionProxy extends ExceptionProxy { 308 static final long serialVersionUID = 269; 309 310 private transient final List<TypeMirror> types; 311 private final String typeStrings; 312 313 MirroredTypesExceptionProxy(List<TypeMirror> ts) { 314 types = ts; 315 typeStrings = ts.toString(); 316 } 317 318 public String toString() { 319 return typeStrings; 320 } 321 322 public int hashCode() { 323 return (types != null ? types : typeStrings).hashCode(); 324 } 325 326 public boolean equals(Object obj) { 327 return types != null && 328 obj instanceof MirroredTypesExceptionProxy && 329 types.equals( 330 ((MirroredTypesExceptionProxy) obj).types); 331 } 332 333 protected RuntimeException generateException() { 334 return new MirroredTypesException(types); 335 } 336 } 337 }