Attribute.java revision 2628:8df25ec8c930
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 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 if (hasUnknownPosition()) { 183 if (values.size() != 0) { 184 Name valueName = values.head.fst.name.table.names.value; 185 Pair<MethodSymbol, Attribute> res = getElemPair(valueName); 186 position = res == null ? null : res.snd.getPosition(); 187 } 188 } 189 return position; 190 } 191 192 public boolean isContainerTypeCompound() { 193 if (isSynthesized() && values.size() == 1) 194 return getFirstEmbeddedTC() != null; 195 return false; 196 } 197 198 private Compound getFirstEmbeddedTC() { 199 if (values.size() == 1) { 200 Pair<MethodSymbol, Attribute> val = values.get(0); 201 if (val.fst.getSimpleName().contentEquals("value") 202 && val.snd instanceof Array) { 203 Array arr = (Array) val.snd; 204 if (arr.values.length != 0 205 && arr.values[0] instanceof Attribute.TypeCompound) 206 return (Attribute.TypeCompound) arr.values[0]; 207 } 208 } 209 return null; 210 } 211 212 public boolean tryFixPosition() { 213 if (!isContainerTypeCompound()) 214 return false; 215 216 Compound from = getFirstEmbeddedTC(); 217 if (from != null && from.position != null && 218 from.position.type != TargetType.UNKNOWN) { 219 position = from.position; 220 return true; 221 } 222 return false; 223 } 224 225 public boolean hasUnknownPosition() { 226 return position.type == TargetType.UNKNOWN; 227 } 228 229 public void accept(Visitor v) { v.visitCompound(this); } 230 231 /** 232 * Returns a string representation of this annotation. 233 * String is of one of the forms: 234 * @com.example.foo(name1=val1, name2=val2) 235 * @com.example.foo(val) 236 * @com.example.foo 237 * Omit parens for marker annotations, and omit "value=" when allowed. 238 */ 239 @DefinedBy(Api.LANGUAGE_MODEL) 240 public String toString() { 241 StringBuilder buf = new StringBuilder(); 242 buf.append("@"); 243 buf.append(type); 244 int len = values.length(); 245 if (len > 0) { 246 buf.append('('); 247 boolean first = true; 248 for (Pair<MethodSymbol, Attribute> value : values) { 249 if (!first) buf.append(", "); 250 first = false; 251 252 Name name = value.fst.name; 253 if (len > 1 || name != name.table.names.value) { 254 buf.append(name); 255 buf.append('='); 256 } 257 buf.append(value.snd); 258 } 259 buf.append(')'); 260 } 261 return buf.toString(); 262 } 263 264 public Attribute member(Name member) { 265 Pair<MethodSymbol,Attribute> res = getElemPair(member); 266 return res == null ? null : res.snd; 267 } 268 269 private Pair<MethodSymbol, Attribute> getElemPair(Name member) { 270 for (Pair<MethodSymbol,Attribute> pair : values) 271 if (pair.fst.name == member) return pair; 272 return null; 273 } 274 275 @DefinedBy(Api.LANGUAGE_MODEL) 276 public Attribute.Compound getValue() { 277 return this; 278 } 279 280 @DefinedBy(Api.LANGUAGE_MODEL) 281 public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) { 282 return v.visitAnnotation(this, p); 283 } 284 285 @DefinedBy(Api.LANGUAGE_MODEL) 286 public DeclaredType getAnnotationType() { 287 return (DeclaredType) type; 288 } 289 290 @DefinedBy(Api.LANGUAGE_MODEL) 291 public Map<MethodSymbol, Attribute> getElementValues() { 292 Map<MethodSymbol, Attribute> valmap = new LinkedHashMap<>(); 293 for (Pair<MethodSymbol, Attribute> value : values) 294 valmap.put(value.fst, value.snd); 295 return valmap; 296 } 297 } 298 299 public static class TypeCompound extends Compound { 300 public TypeCompound(Compound compound, 301 TypeAnnotationPosition position) { 302 super(compound.type, compound.values, position); 303 } 304 305 public TypeCompound(Type type, 306 List<Pair<MethodSymbol,Attribute>> values, 307 TypeAnnotationPosition position) { 308 super(type, values, position); 309 } 310 } 311 312 /** The value for an annotation element of an array type. 313 */ 314 public static class Array extends Attribute { 315 public final Attribute[] values; 316 public Array(Type type, Attribute[] values) { 317 super(type); 318 this.values = values; 319 } 320 321 public Array(Type type, List<Attribute> values) { 322 super(type); 323 this.values = values.toArray(new Attribute[values.size()]); 324 } 325 326 public void accept(Visitor v) { v.visitArray(this); } 327 @DefinedBy(Api.LANGUAGE_MODEL) 328 public String toString() { 329 StringBuilder buf = new StringBuilder(); 330 buf.append('{'); 331 boolean first = true; 332 for (Attribute value : values) { 333 if (!first) 334 buf.append(", "); 335 first = false; 336 buf.append(value); 337 } 338 buf.append('}'); 339 return buf.toString(); 340 } 341 @DefinedBy(Api.LANGUAGE_MODEL) 342 public List<Attribute> getValue() { 343 return List.from(values); 344 } 345 @DefinedBy(Api.LANGUAGE_MODEL) 346 public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) { 347 return v.visitArray(getValue(), p); 348 } 349 350 @Override 351 public TypeAnnotationPosition getPosition() { 352 if (values.length != 0) 353 return values[0].getPosition(); 354 else 355 return null; 356 } 357 } 358 359 /** The value for an annotation element of an enum type. 360 */ 361 public static class Enum extends Attribute { 362 public VarSymbol value; 363 public Enum(Type type, VarSymbol value) { 364 super(type); 365 this.value = Assert.checkNonNull(value); 366 } 367 public void accept(Visitor v) { v.visitEnum(this); } 368 @DefinedBy(Api.LANGUAGE_MODEL) 369 public String toString() { 370 return value.enclClass() + "." + value; // qualified name 371 } 372 @DefinedBy(Api.LANGUAGE_MODEL) 373 public VarSymbol getValue() { 374 return value; 375 } 376 @DefinedBy(Api.LANGUAGE_MODEL) 377 public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) { 378 return v.visitEnumConstant(value, p); 379 } 380 } 381 382 public static class Error extends Attribute { 383 public Error(Type type) { 384 super(type); 385 } 386 public void accept(Visitor v) { v.visitError(this); } 387 @DefinedBy(Api.LANGUAGE_MODEL) 388 public String toString() { 389 return "<error>"; 390 } 391 @DefinedBy(Api.LANGUAGE_MODEL) 392 public String getValue() { 393 return toString(); 394 } 395 @DefinedBy(Api.LANGUAGE_MODEL) 396 public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) { 397 return v.visitString(toString(), p); 398 } 399 } 400 401 public static class UnresolvedClass extends Error { 402 public Type classType; 403 public UnresolvedClass(Type type, Type classType) { 404 super(type); 405 this.classType = classType; 406 } 407 } 408 409 /** A visitor type for dynamic dispatch on the kind of attribute value. */ 410 public static interface Visitor { 411 void visitConstant(Attribute.Constant value); 412 void visitClass(Attribute.Class clazz); 413 void visitCompound(Attribute.Compound compound); 414 void visitArray(Attribute.Array array); 415 void visitEnum(Attribute.Enum e); 416 void visitError(Attribute.Error e); 417 } 418 419 /** A mirror of java.lang.annotation.RetentionPolicy. */ 420 public static enum RetentionPolicy { 421 SOURCE, 422 CLASS, 423 RUNTIME 424 } 425} 426