Attribute.java revision 2571:10fc81ac75b4
1/*
2 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. 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.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.tools.javac.code;
27
28import java.util.LinkedHashMap;
29import java.util.Map;
30import javax.lang.model.element.AnnotationMirror;
31import javax.lang.model.element.AnnotationValue;
32import javax.lang.model.element.AnnotationValueVisitor;
33import javax.lang.model.type.DeclaredType;
34import com.sun.tools.javac.code.Symbol.*;
35import com.sun.tools.javac.util.*;
36
37/** An annotation value.
38 *
39 *  <p><b>This is NOT part of any supported API.
40 *  If you write code that depends on this, you do so at your own risk.
41 *  This code and its internal interfaces are subject to change or
42 *  deletion without notice.</b>
43 */
44public abstract class Attribute implements AnnotationValue {
45
46    /** The type of the annotation element. */
47    public Type type;
48
49    public Attribute(Type type) {
50        this.type = type;
51    }
52
53    public abstract void accept(Visitor v);
54
55    public Object getValue() {
56        throw new UnsupportedOperationException();
57    }
58
59    public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
60        throw new UnsupportedOperationException();
61    }
62
63    public boolean isSynthesized() {
64        return false;
65    }
66
67    public TypeAnnotationPosition getPosition() { return null; }
68
69    /** The value for an annotation element of primitive type or String. */
70    public static class Constant extends Attribute {
71        public final Object value;
72        public void accept(Visitor v) { v.visitConstant(this); }
73        public Constant(Type type, Object value) {
74            super(type);
75            this.value = value;
76        }
77        public String toString() {
78            return Constants.format(value, type);
79        }
80        public Object getValue() {
81            return Constants.decode(value, type);
82        }
83        public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
84            if (value instanceof String)
85                return v.visitString((String) value, p);
86            if (value instanceof Integer) {
87                int i = (Integer) value;
88                switch (type.getTag()) {
89                case BOOLEAN:   return v.visitBoolean(i != 0, p);
90                case CHAR:      return v.visitChar((char) i, p);
91                case BYTE:      return v.visitByte((byte) i, p);
92                case SHORT:     return v.visitShort((short) i, p);
93                case INT:       return v.visitInt(i, p);
94                }
95            }
96            switch (type.getTag()) {
97            case LONG:          return v.visitLong((Long) value, p);
98            case FLOAT:         return v.visitFloat((Float) value, p);
99            case DOUBLE:        return v.visitDouble((Double) value, p);
100            }
101            throw new AssertionError("Bad annotation element value: " + value);
102        }
103    }
104
105    /** The value for an annotation element of type java.lang.Class,
106     *  represented as a ClassSymbol.
107     */
108    public static class Class extends Attribute {
109        public final Type classType;
110        public void accept(Visitor v) { v.visitClass(this); }
111        public Class(Types types, Type type) {
112            super(makeClassType(types, type));
113            this.classType = type;
114        }
115        static Type makeClassType(Types types, Type type) {
116            Type arg = type.isPrimitive()
117                ? types.boxedClass(type).type
118                : types.erasure(type);
119            return new Type.ClassType(types.syms.classType.getEnclosingType(),
120                                      List.of(arg),
121                                      types.syms.classType.tsym,
122                                      Type.noAnnotations);
123        }
124        public String toString() {
125            return classType + ".class";
126        }
127        public Type getValue() {
128            return classType;
129        }
130        public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
131            return v.visitType(classType, p);
132        }
133    }
134
135    /** A compound annotation element value, the type of which is an
136     *  attribute interface.
137     */
138    public static class Compound extends Attribute implements AnnotationMirror {
139        /** The attributes values, as pairs.  Each pair contains a
140         *  reference to the accessing method in the attribute interface
141         *  and the value to be returned when that method is called to
142         *  access this attribute.
143         */
144        public final List<Pair<MethodSymbol,Attribute>> values;
145        public final TypeAnnotationPosition position;
146
147        private boolean synthesized = false;
148
149        @Override
150        public boolean isSynthesized() {
151            return synthesized;
152        }
153
154        public void setSynthesized(boolean synthesized) {
155            this.synthesized = synthesized;
156        }
157
158        public Compound(Type type,
159                        List<Pair<MethodSymbol,Attribute>> values,
160                        TypeAnnotationPosition position) {
161            super(type);
162            this.values = values;
163            this.position = position;
164        }
165
166        public Compound(Type type,
167                        List<Pair<MethodSymbol,Attribute>> values) {
168            this(type, values, null);
169        }
170
171        @Override
172        public TypeAnnotationPosition getPosition() {
173            return position;
174        }
175
176        public void accept(Visitor v) { v.visitCompound(this); }
177
178        /**
179         * Returns a string representation of this annotation.
180         * String is of one of the forms:
181         *     @com.example.foo(name1=val1, name2=val2)
182         *     @com.example.foo(val)
183         *     @com.example.foo
184         * Omit parens for marker annotations, and omit "value=" when allowed.
185         */
186        public String toString() {
187            StringBuilder buf = new StringBuilder();
188            buf.append("@");
189            buf.append(type);
190            int len = values.length();
191            if (len > 0) {
192                buf.append('(');
193                boolean first = true;
194                for (Pair<MethodSymbol, Attribute> value : values) {
195                    if (!first) buf.append(", ");
196                    first = false;
197
198                    Name name = value.fst.name;
199                    if (len > 1 || name != name.table.names.value) {
200                        buf.append(name);
201                        buf.append('=');
202                    }
203                    buf.append(value.snd);
204                }
205                buf.append(')');
206            }
207            return buf.toString();
208        }
209
210        public Attribute member(Name member) {
211            Pair<MethodSymbol,Attribute> res = getElemPair(member);
212            return res == null ? null : res.snd;
213        }
214
215        private Pair<MethodSymbol, Attribute> getElemPair(Name member) {
216            for (Pair<MethodSymbol,Attribute> pair : values)
217                if (pair.fst.name == member) return pair;
218            return null;
219        }
220
221        public Attribute.Compound getValue() {
222            return this;
223        }
224
225        public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
226            return v.visitAnnotation(this, p);
227        }
228
229        public DeclaredType getAnnotationType() {
230            return (DeclaredType) type;
231        }
232
233        public Map<MethodSymbol, Attribute> getElementValues() {
234            Map<MethodSymbol, Attribute> valmap = new LinkedHashMap<>();
235            for (Pair<MethodSymbol, Attribute> value : values)
236                valmap.put(value.fst, value.snd);
237            return valmap;
238        }
239
240        public TypeCompound toTypeCompound() {
241            // It is safe to alias the position.
242            return new TypeCompound(this, this.position);
243        }
244
245    }
246
247    public static class TypeCompound extends Compound {
248        public TypeCompound(Compound compound,
249                             TypeAnnotationPosition position) {
250            super(compound.type, compound.values, position);
251        }
252
253        public TypeCompound(Type type,
254                             List<Pair<MethodSymbol,Attribute>> values,
255                             TypeAnnotationPosition position) {
256            super(type, values, position);
257        }
258    }
259
260    /** The value for an annotation element of an array type.
261     */
262    public static class Array extends Attribute {
263        public final Attribute[] values;
264        public Array(Type type, Attribute[] values) {
265            super(type);
266            this.values = values;
267        }
268
269        public Array(Type type, List<Attribute> values) {
270            super(type);
271            this.values = values.toArray(new Attribute[values.size()]);
272        }
273
274        public void accept(Visitor v) { v.visitArray(this); }
275        public String toString() {
276            StringBuilder buf = new StringBuilder();
277            buf.append('{');
278            boolean first = true;
279            for (Attribute value : values) {
280                if (!first)
281                    buf.append(", ");
282                first = false;
283                buf.append(value);
284            }
285            buf.append('}');
286            return buf.toString();
287        }
288        public List<Attribute> getValue() {
289            return List.from(values);
290        }
291        public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
292            return v.visitArray(getValue(), p);
293        }
294
295        @Override
296        public TypeAnnotationPosition getPosition() {
297            if (values.length != 0)
298                return values[0].getPosition();
299            else
300                return null;
301        }
302    }
303
304    /** The value for an annotation element of an enum type.
305     */
306    public static class Enum extends Attribute {
307        public VarSymbol value;
308        public Enum(Type type, VarSymbol value) {
309            super(type);
310            this.value = Assert.checkNonNull(value);
311        }
312        public void accept(Visitor v) { v.visitEnum(this); }
313        public String toString() {
314            return value.enclClass() + "." + value;     // qualified name
315        }
316        public VarSymbol getValue() {
317            return value;
318        }
319        public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
320            return v.visitEnumConstant(value, p);
321        }
322    }
323
324    public static class Error extends Attribute {
325        public Error(Type type) {
326            super(type);
327        }
328        public void accept(Visitor v) { v.visitError(this); }
329        public String toString() {
330            return "<error>";
331        }
332        public String getValue() {
333            return toString();
334        }
335        public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
336            return v.visitString(toString(), p);
337        }
338    }
339
340    public static class UnresolvedClass extends Error {
341        public Type classType;
342        public UnresolvedClass(Type type, Type classType) {
343            super(type);
344            this.classType = classType;
345        }
346    }
347
348    /** A visitor type for dynamic dispatch on the kind of attribute value. */
349    public static interface Visitor {
350        void visitConstant(Attribute.Constant value);
351        void visitClass(Attribute.Class clazz);
352        void visitCompound(Attribute.Compound compound);
353        void visitArray(Attribute.Array array);
354        void visitEnum(Attribute.Enum e);
355        void visitError(Attribute.Error e);
356    }
357
358    /** A mirror of java.lang.annotation.RetentionPolicy. */
359    public static enum RetentionPolicy {
360        SOURCE,
361        CLASS,
362        RUNTIME
363    }
364}
365