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