001 /*
002 * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package com.sun.tools.javac.code;
027
028 import java.util.LinkedHashMap;
029 import java.util.Map;
030 import javax.lang.model.element.AnnotationMirror;
031 import javax.lang.model.element.AnnotationValue;
032 import javax.lang.model.element.AnnotationValueVisitor;
033 import javax.lang.model.type.DeclaredType;
034 import com.sun.tools.javac.code.Symbol.*;
035 import com.sun.tools.javac.util.*;
036
037 import static com.sun.tools.javac.code.TypeTags.*;
038
039 /** An annotation value.
040 *
041 * <p><b>This is NOT part of any API supported by Sun Microsystems. If
042 * you write code that depends on this, you do so at your own risk.
043 * This code and its internal interfaces are subject to change or
044 * deletion without notice.</b>
045 */
046 public abstract class Attribute implements AnnotationValue {
047
048 /** The type of the annotation element. */
049 public Type type;
050
051 public Attribute(Type type) {
052 this.type = type;
053 }
054
055 public abstract void accept(Visitor v);
056
057 public Object getValue() {
058 throw new UnsupportedOperationException();
059 }
060
061 public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
062 throw new UnsupportedOperationException();
063 }
064
065
066 /** The value for an annotation element of primitive type or String. */
067 public static class Constant extends Attribute {
068 public final Object value;
069 public void accept(Visitor v) { v.visitConstant(this); }
070 public Constant(Type type, Object value) {
071 super(type);
072 this.value = value;
073 }
074 public String toString() {
075 return Constants.format(value, type);
076 }
077 public Object getValue() {
078 return Constants.decode(value, type);
079 }
080 public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
081 if (value instanceof String)
082 return v.visitString((String) value, p);
083 if (value instanceof Integer) {
084 int i = (Integer) value;
085 switch (type.tag) {
086 case BOOLEAN: return v.visitBoolean(i != 0, p);
087 case CHAR: return v.visitChar((char) i, p);
088 case BYTE: return v.visitByte((byte) i, p);
089 case SHORT: return v.visitShort((short) i, p);
090 case INT: return v.visitInt(i, p);
091 }
092 }
093 switch (type.tag) {
094 case LONG: return v.visitLong((Long) value, p);
095 case FLOAT: return v.visitFloat((Float) value, p);
096 case DOUBLE: return v.visitDouble((Double) value, p);
097 }
098 throw new AssertionError("Bad annotation element value: " + value);
099 }
100 }
101
102 /** The value for an annotation element of type java.lang.Class,
103 * represented as a ClassSymbol.
104 */
105 public static class Class extends Attribute {
106 public final Type type;
107 public void accept(Visitor v) { v.visitClass(this); }
108 public Class(Types types, Type type) {
109 super(makeClassType(types, type));
110 this.type = type;
111 }
112 static Type makeClassType(Types types, Type type) {
113 Type arg = type.isPrimitive()
114 ? types.boxedClass(type).type
115 : types.erasure(type);
116 return new Type.ClassType(types.syms.classType.getEnclosingType(),
117 List.of(arg),
118 types.syms.classType.tsym);
119 }
120 public String toString() {
121 return type + ".class";
122 }
123 public Type getValue() {
124 return type;
125 }
126 public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
127 return v.visitType(type, p);
128 }
129 }
130
131 /** A compound annotation element value, the type of which is an
132 * attribute interface.
133 */
134 public static class Compound extends Attribute implements AnnotationMirror {
135 /** The attributes values, as pairs. Each pair contains a
136 * reference to the accessing method in the attribute interface
137 * and the value to be returned when that method is called to
138 * access this attribute.
139 */
140 public final List<Pair<MethodSymbol,Attribute>> values;
141 public Compound(Type type,
142 List<Pair<MethodSymbol,Attribute>> values) {
143 super(type);
144 this.values = values;
145 }
146 public void accept(Visitor v) { v.visitCompound(this); }
147
148 /**
149 * Returns a string representation of this annotation.
150 * String is of one of the forms:
151 * @com.example.foo(name1=val1, name2=val2)
152 * @com.example.foo(val)
153 * @com.example.foo
154 * Omit parens for marker annotations, and omit "value=" when allowed.
155 */
156 public String toString() {
157 StringBuilder buf = new StringBuilder();
158 buf.append("@");
159 buf.append(type);
160 int len = values.length();
161 if (len > 0) {
162 buf.append('(');
163 boolean first = true;
164 for (Pair<MethodSymbol, Attribute> value : values) {
165 if (!first) buf.append(", ");
166 first = false;
167
168 Name name = value.fst.name;
169 if (len > 1 || name != name.table.names.value) {
170 buf.append(name);
171 buf.append('=');
172 }
173 buf.append(value.snd);
174 }
175 buf.append(')');
176 }
177 return buf.toString();
178 }
179
180 public Attribute member(Name member) {
181 for (Pair<MethodSymbol,Attribute> pair : values)
182 if (pair.fst.name == member) return pair.snd;
183 return null;
184 }
185
186 public Attribute.Compound getValue() {
187 return this;
188 }
189
190 public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
191 return v.visitAnnotation(this, p);
192 }
193
194 public DeclaredType getAnnotationType() {
195 return (DeclaredType) type;
196 }
197
198 public Map<MethodSymbol, Attribute> getElementValues() {
199 Map<MethodSymbol, Attribute> valmap =
200 new LinkedHashMap<MethodSymbol, Attribute>();
201 for (Pair<MethodSymbol, Attribute> value : values)
202 valmap.put(value.fst, value.snd);
203 return valmap;
204 }
205 }
206
207 /** The value for an annotation element of an array type.
208 */
209 public static class Array extends Attribute {
210 public final Attribute[] values;
211 public Array(Type type, Attribute[] values) {
212 super(type);
213 this.values = values;
214 }
215 public void accept(Visitor v) { v.visitArray(this); }
216 public String toString() {
217 StringBuilder buf = new StringBuilder();
218 buf.append('{');
219 boolean first = true;
220 for (Attribute value : values) {
221 if (!first)
222 buf.append(", ");
223 first = false;
224 buf.append(value);
225 }
226 buf.append('}');
227 return buf.toString();
228 }
229 public List<Attribute> getValue() {
230 return List.from(values);
231 }
232 public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
233 return v.visitArray(getValue(), p);
234 }
235 }
236
237 /** The value for an annotation element of an enum type.
238 */
239 public static class Enum extends Attribute {
240 public VarSymbol value;
241 public Enum(Type type, VarSymbol value) {
242 super(type);
243 assert value != null;
244 this.value = value;
245 }
246 public void accept(Visitor v) { v.visitEnum(this); }
247 public String toString() {
248 return value.enclClass() + "." + value; // qualified name
249 }
250 public VarSymbol getValue() {
251 return value;
252 }
253 public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
254 return v.visitEnumConstant(value, p);
255 }
256 }
257
258 public static class Error extends Attribute {
259 public Error(Type type) {
260 super(type);
261 }
262 public void accept(Visitor v) { v.visitError(this); }
263 public String toString() {
264 return "<error>";
265 }
266 public String getValue() {
267 return toString();
268 }
269 public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
270 return v.visitString(toString(), p);
271 }
272 }
273
274 /** A visitor type for dynamic dispatch on the kind of attribute value. */
275 public static interface Visitor {
276 void visitConstant(Attribute.Constant value);
277 void visitClass(Attribute.Class clazz);
278 void visitCompound(Attribute.Compound compound);
279 void visitArray(Attribute.Array array);
280 void visitEnum(Attribute.Enum e);
281 void visitError(Attribute.Error e);
282 }
283 }