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