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    }