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