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 26 package com.sun.tools.javac.code; 27 28 import java.util.LinkedHashMap; 29 import java.util.Map; 30 import javax.lang.model.element.AnnotationMirror; 31 import javax.lang.model.element.AnnotationValue; 32 import javax.lang.model.element.AnnotationValueVisitor; 33 import javax.lang.model.type.DeclaredType; 34 import com.sun.tools.javac.code.Symbol.*; 35 import com.sun.tools.javac.util.*; 36 import 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 */ 45 public 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 @Override 67 @DefinedBy(Api.LANGUAGE_MODEL) 68 public boolean equals(Object o) { 69 if (o instanceof AnnotationValue) { 70 AnnotationValue that = (AnnotationValue) o; 71 return getValue().equals(that.getValue()); 72 } else { 73 return false; 74 } 75 } 76 77 @Override 78 @DefinedBy(Api.LANGUAGE_MODEL) 79 public int hashCode() { 80 return getValue().hashCode(); 81 } 82 83 public boolean isSynthesized() { 84 return false; 85 } 86 87 public TypeAnnotationPosition getPosition() { return null; } 88 89 /** The value for an annotation element of primitive type or String. */ 90 public static class Constant extends Attribute { 91 public final Object value; 92 public void accept(Visitor v) { v.visitConstant(this); } 93 public Constant(Type type, Object value) { 94 super(type); 95 this.value = value; 96 } 97 @DefinedBy(Api.LANGUAGE_MODEL) 98 public String toString() { 99 return Constants.format(value, type); 100 } 101 @DefinedBy(Api.LANGUAGE_MODEL) 102 public Object getValue() { 103 return Constants.decode(value, type); 104 } 105 @DefinedBy(Api.LANGUAGE_MODEL) 106 public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) { 107 if (value instanceof String) 108 return v.visitString((String) value, p); 109 if (value instanceof Integer) { 110 int i = (Integer) value; 111 switch (type.getTag()) { 112 case BOOLEAN: return v.visitBoolean(i != 0, p); 113 case CHAR: return v.visitChar((char) i, p); 114 case BYTE: return v.visitByte((byte) i, p); 115 case SHORT: return v.visitShort((short) i, p); 116 case INT: return v.visitInt(i, p); 117 } 118 } 119 switch (type.getTag()) { 120 case LONG: return v.visitLong((Long) value, p); 121 case FLOAT: return v.visitFloat((Float) value, p); 122 case DOUBLE: return v.visitDouble((Double) value, p); 123 } 124 throw new AssertionError("Bad annotation element value: " + value); 125 } 126 } 127 128 /** The value for an annotation element of type java.lang.Class, 129 * represented as a ClassSymbol. 130 */ 131 public static class Class extends Attribute { 132 public final Type classType; 133 public void accept(Visitor v) { v.visitClass(this); } 134 public Class(Types types, Type type) { 135 super(makeClassType(types, type)); 136 this.classType = type; 137 } 138 static Type makeClassType(Types types, Type type) { 139 Type arg = type.isPrimitive() 140 ? types.boxedClass(type).type 141 : types.erasure(type); 142 return new Type.ClassType(types.syms.classType.getEnclosingType(), 143 List.of(arg), 144 types.syms.classType.tsym); 145 } 146 @DefinedBy(Api.LANGUAGE_MODEL) 147 public String toString() { 148 return classType + ".class"; 149 } 150 @DefinedBy(Api.LANGUAGE_MODEL) 151 public Type getValue() { 152 return classType; 153 } 154 @DefinedBy(Api.LANGUAGE_MODEL) 155 public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) { 156 return v.visitType(classType, p); 157 } 158 } 159 160 /** A compound annotation element value, the type of which is an 161 * attribute interface. 162 */ 163 public static class Compound extends Attribute implements AnnotationMirror { 164 /** The attributes values, as pairs. Each pair contains a 165 * reference to the accessing method in the attribute interface 166 * and the value to be returned when that method is called to 167 * access this attribute. 168 */ 169 public final List<Pair<MethodSymbol,Attribute>> values; 170 public TypeAnnotationPosition position; 171 172 private boolean synthesized = false; 173 174 @Override 175 public boolean isSynthesized() { 176 return synthesized; 177 } 178 179 public void setSynthesized(boolean synthesized) { 180 this.synthesized = synthesized; 181 } 182 183 public Compound(Type type, 184 List<Pair<MethodSymbol,Attribute>> values, 185 TypeAnnotationPosition position) { 186 super(type); 187 this.values = values; 188 this.position = position; 189 } 190 191 public Compound(Type type, 192 List<Pair<MethodSymbol,Attribute>> values) { 193 this(type, values, null); 194 } 195 196 @Override 197 public TypeAnnotationPosition getPosition() { 198 if (hasUnknownPosition()) { 199 if (values.size() != 0) { 200 Name valueName = values.head.fst.name.table.names.value; 201 Pair<MethodSymbol, Attribute> res = getElemPair(valueName); 202 position = res == null ? null : res.snd.getPosition(); 203 } 204 } 205 return position; 206 } 207 208 public boolean isContainerTypeCompound() { 209 if (isSynthesized() && values.size() == 1) 210 return getFirstEmbeddedTC() != null; 211 return false; 212 } 213 214 private Compound getFirstEmbeddedTC() { 215 if (values.size() == 1) { 216 Pair<MethodSymbol, Attribute> val = values.get(0); 217 if (val.fst.getSimpleName().contentEquals("value") 218 && val.snd instanceof Array) { 219 Array arr = (Array) val.snd; 220 if (arr.values.length != 0 221 && arr.values[0] instanceof Attribute.TypeCompound) 222 return (Attribute.TypeCompound) arr.values[0]; 223 } 224 } 225 return null; 226 } 227 228 public boolean tryFixPosition() { 229 if (!isContainerTypeCompound()) 230 return false; 231 232 Compound from = getFirstEmbeddedTC(); 233 if (from != null && from.position != null && 234 from.position.type != TargetType.UNKNOWN) { 235 position = from.position; 236 return true; 237 } 238 return false; 239 } 240 241 public boolean hasUnknownPosition() { 242 return position.type == TargetType.UNKNOWN; 243 } 244 245 public void accept(Visitor v) { v.visitCompound(this); } 246 247 /** 248 * Returns a string representation of this annotation. 249 * String is of one of the forms: 250 * <pre> 251 * {@code @com.example.foo(name1=val1, name2=val2)} 252 * {@code @com.example.foo(val)} 253 * {@code @com.example.foo} 254 * </pre> 255 * Omit parens for marker annotations, and omit "value=" when allowed. 256 */ 257 @DefinedBy(Api.LANGUAGE_MODEL) 258 public String toString() { 259 StringBuilder buf = new StringBuilder(); 260 buf.append("@"); 261 buf.append(type); 262 int len = values.length(); 263 if (len > 0) { 264 buf.append('('); 265 boolean first = true; 266 for (Pair<MethodSymbol, Attribute> value : values) { 267 if (!first) buf.append(", "); 268 first = false; 269 270 Name name = value.fst.name; 271 if (len > 1 || name != name.table.names.value) { 272 buf.append(name); 273 buf.append('='); 274 } 275 buf.append(value.snd); 276 } 277 buf.append(')'); 278 } 279 return buf.toString(); 280 } 281 282 @Override 283 @DefinedBy(Api.LANGUAGE_MODEL) 284 public boolean equals(Object o) { 285 if (o instanceof AnnotationMirror) { 286 AnnotationMirror that = (AnnotationMirror) o; 287 return 288 getAnnotationType().equals(that.getAnnotationType()) && 289 getElementValues().equals(that.getElementValues()); 290 } else { 291 return false; 292 } 293 } 294 295 @Override 296 @DefinedBy(Api.LANGUAGE_MODEL) 297 public int hashCode() { 298 return getAnnotationType().hashCode() ^ 299 getElementValues().hashCode(); 300 } 301 302 public Attribute member(Name member) { 303 Pair<MethodSymbol,Attribute> res = getElemPair(member); 304 return res == null ? null : res.snd; 305 } 306 307 private Pair<MethodSymbol, Attribute> getElemPair(Name member) { 308 for (Pair<MethodSymbol,Attribute> pair : values) 309 if (pair.fst.name == member) return pair; 310 return null; 311 } 312 313 @DefinedBy(Api.LANGUAGE_MODEL) 314 public Attribute.Compound getValue() { 315 return this; 316 } 317 318 @DefinedBy(Api.LANGUAGE_MODEL) 319 public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) { 320 return v.visitAnnotation(this, p); 321 } 322 323 @DefinedBy(Api.LANGUAGE_MODEL) 324 public DeclaredType getAnnotationType() { 325 return (DeclaredType) type; 326 } 327 328 @DefinedBy(Api.LANGUAGE_MODEL) 329 public Map<MethodSymbol, Attribute> getElementValues() { 330 Map<MethodSymbol, Attribute> valmap = new LinkedHashMap<>(); 331 for (Pair<MethodSymbol, Attribute> value : values) 332 valmap.put(value.fst, value.snd); 333 return valmap; 334 } 335 } 336 337 public static class TypeCompound extends Compound { 338 public TypeCompound(Compound compound, 339 TypeAnnotationPosition position) { 340 super(compound.type, compound.values, position); 341 } 342 343 public TypeCompound(Type type, 344 List<Pair<MethodSymbol,Attribute>> values, 345 TypeAnnotationPosition position) { 346 super(type, values, position); 347 } 348 } 349 350 /** The value for an annotation element of an array type. 351 */ 352 public static class Array extends Attribute { 353 public final Attribute[] values; 354 public Array(Type type, Attribute[] values) { 355 super(type); 356 this.values = values; 357 } 358 359 public Array(Type type, List<Attribute> values) { 360 super(type); 361 this.values = values.toArray(new Attribute[values.size()]); 362 } 363 364 public void accept(Visitor v) { v.visitArray(this); } 365 @DefinedBy(Api.LANGUAGE_MODEL) 366 public String toString() { 367 StringBuilder buf = new StringBuilder(); 368 buf.append('{'); 369 boolean first = true; 370 for (Attribute value : values) { 371 if (!first) 372 buf.append(", "); 373 first = false; 374 buf.append(value); 375 } 376 buf.append('}'); 377 return buf.toString(); 378 } 379 @DefinedBy(Api.LANGUAGE_MODEL) 380 public List<Attribute> getValue() { 381 return List.from(values); 382 } 383 @DefinedBy(Api.LANGUAGE_MODEL) 384 public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) { 385 return v.visitArray(getValue(), p); 386 } 387 388 @Override 389 public TypeAnnotationPosition getPosition() { 390 if (values.length != 0) 391 return values[0].getPosition(); 392 else 393 return null; 394 } 395 } 396 397 /** The value for an annotation element of an enum type. 398 */ 399 public static class Enum extends Attribute { 400 public VarSymbol value; 401 public Enum(Type type, VarSymbol value) { 402 super(type); 403 this.value = Assert.checkNonNull(value); 404 } 405 public void accept(Visitor v) { v.visitEnum(this); } 406 @DefinedBy(Api.LANGUAGE_MODEL) 407 public String toString() { 408 return value.enclClass() + "." + value; // qualified name 409 } 410 @DefinedBy(Api.LANGUAGE_MODEL) 411 public VarSymbol getValue() { 412 return value; 413 } 414 @DefinedBy(Api.LANGUAGE_MODEL) 415 public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) { 416 return v.visitEnumConstant(value, p); 417 } 418 } 419 420 public static class Error extends Attribute { 421 public Error(Type type) { 422 super(type); 423 } 424 public void accept(Visitor v) { v.visitError(this); } 425 @DefinedBy(Api.LANGUAGE_MODEL) 426 public String toString() { 427 return "<error>"; 428 } 429 @DefinedBy(Api.LANGUAGE_MODEL) 430 public String getValue() { 431 return toString(); 432 } 433 @DefinedBy(Api.LANGUAGE_MODEL) 434 public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) { 435 return v.visitString(toString(), p); 436 } 437 } 438 439 public static class UnresolvedClass extends Error { 440 public Type classType; 441 public UnresolvedClass(Type type, Type classType) { 442 super(type); 443 this.classType = classType; 444 } 445 } 446 447 /** A visitor type for dynamic dispatch on the kind of attribute value. */ 448 public static interface Visitor { 449 void visitConstant(Attribute.Constant value); 450 void visitClass(Attribute.Class clazz); 451 void visitCompound(Attribute.Compound compound); 452 void visitArray(Attribute.Array array); 453 void visitEnum(Attribute.Enum e); 454 void visitError(Attribute.Error e); 455 } 456 457 /** A mirror of java.lang.annotation.RetentionPolicy. */ 458 public static enum RetentionPolicy { 459 SOURCE, 460 CLASS, 461 RUNTIME 462 } 463 }