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