Thu, 09 Oct 2008 16:19:13 +0100
6731573: diagnostic output should optionally include source line
Summary: Added an -XD option to optionally prints out source lines in error messages
Reviewed-by: jjg
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 */
26 package com.sun.tools.javac.model;
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.*;
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;
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 */
57 public class AnnotationProxyMaker {
59 private final Attribute.Compound anno;
60 private final Class<? extends Annotation> annoType;
63 private AnnotationProxyMaker(Attribute.Compound anno,
64 Class<? extends Annotation> annoType) {
65 this.anno = anno;
66 this.annoType = annoType;
67 }
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 }
80 /**
81 * Returns a dynamic proxy for an annotation mirror.
82 */
83 private Annotation generateAnnotation() {
84 return AnnotationParser.annotationForMap(annoType,
85 getAllReflectedValues());
86 }
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>();
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 }
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>();
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 }
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 }
145 private class ValueVisitor implements Attribute.Visitor {
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"
151 ValueVisitor(MethodSymbol meth) {
152 this.meth = meth;
153 }
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 }
173 public void visitConstant(Attribute.Constant c) {
174 value = c.getValue();
175 }
177 public void visitClass(Attribute.Class c) {
178 value = new MirroredTypeExceptionProxy(c.type);
179 }
181 public void visitArray(Attribute.Array a) {
182 Name elemName = ((ArrayType) a.type).elemtype.tsym.name;
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);
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 }
218 @SuppressWarnings("unchecked")
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) returnClass, constName);
227 }
228 } else {
229 value = null; // indicates a type mismatch
230 }
231 }
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 }
243 public void visitError(Attribute.Error e) {
244 value = null; // indicates a type mismatch
245 }
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 }
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;
274 private transient final TypeMirror type;
275 private final String typeString;
277 MirroredTypeExceptionProxy(TypeMirror t) {
278 type = t;
279 typeString = t.toString();
280 }
282 public String toString() {
283 return typeString;
284 }
286 public int hashCode() {
287 return (type != null ? type : typeString).hashCode();
288 }
290 public boolean equals(Object obj) {
291 return type != null &&
292 obj instanceof MirroredTypeExceptionProxy &&
293 type.equals(((MirroredTypeExceptionProxy) obj).type);
294 }
296 protected RuntimeException generateException() {
297 return new MirroredTypeException(type);
298 }
299 }
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;
310 private transient final List<TypeMirror> types;
311 private final String typeStrings;
313 MirroredTypesExceptionProxy(List<TypeMirror> ts) {
314 types = ts;
315 typeStrings = ts.toString();
316 }
318 public String toString() {
319 return typeStrings;
320 }
322 public int hashCode() {
323 return (types != null ? types : typeStrings).hashCode();
324 }
326 public boolean equals(Object obj) {
327 return types != null &&
328 obj instanceof MirroredTypesExceptionProxy &&
329 types.equals(
330 ((MirroredTypesExceptionProxy) obj).types);
331 }
333 protected RuntimeException generateException() {
334 return new MirroredTypesException(types);
335 }
336 }
337 }