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