1 package annotations; 2 3 import annotations.el.AnnotationDef; 4 import annotations.field.AnnotationAFT; 5 import annotations.field.AnnotationFieldType; 6 import annotations.field.ArrayAFT; 7 import annotations.field.EnumAFT; 8 import annotations.field.ScalarAFT; 9 10 import java.lang.annotation.RetentionPolicy; 11 import java.util.Collections; 12 import java.util.HashSet; 13 import java.util.LinkedHashSet; 14 import java.util.List; 15 import java.util.Map; 16 import java.util.Set; 17 18 /*>>> 19 import org.checkerframework.checker.nullness.qual.*; 20 */ 21 22 /** 23 * This noninstantiable class provides useful static methods related to 24 * annotations, following the convention of {@link java.util.Collections}. 25 */ 26 public abstract class Annotations { Annotations()27 private Annotations() {} 28 29 public static Set<Annotation> noAnnotations; 30 public static Map<String, ? extends AnnotationFieldType> noFieldTypes; 31 public static Map<String, ? extends Object> noFieldValues; 32 public static Set<Annotation> typeQualifierMetaAnnotations; 33 34 public static EnumAFT aftRetentionPolicy; 35 public static AnnotationDef adRetention; 36 public static Annotation aRetentionClass; 37 public static Annotation aRetentionRuntime; 38 public static Annotation aRetentionSource; 39 public static Set<Annotation> asRetentionClass; 40 public static Set<Annotation> asRetentionRuntime; 41 public static Set<Annotation> asRetentionSource; 42 43 public static AnnotationDef adTarget; 44 public static Annotation aTargetTypeUse; 45 46 public static AnnotationDef adDocumented; 47 public static Annotation aDocumented; 48 49 public static AnnotationDef adNonNull; 50 public static Annotation aNonNull; 51 52 public static AnnotationDef adTypeQualifier; 53 public static Annotation aTypeQualifier; 54 55 /** 56 * Annotations that are meta-annotated with themselves. Due to a flaw 57 * in the the Scene Library, it is unable to read them from classfiles. 58 * An expedient workaround is to pre-define them, so they never need be 59 * read from a classfile. 60 */ 61 public static Set<AnnotationDef> standardDefs; 62 63 // the field types for an annotation with only one field, named "value". 64 static Map<String, ? extends AnnotationFieldType> valueFieldTypeOnly(AnnotationFieldType aft)65 valueFieldTypeOnly(AnnotationFieldType aft) { 66 return Collections.singletonMap("value", aft); 67 } 68 69 // the field values for an annotation with only one field, named "value". valueFieldOnly(Object valueValue)70 public static Map<String, ? extends Object> valueFieldOnly(Object valueValue) { 71 return Collections.singletonMap("value", valueValue); 72 } 73 74 // Create an annotation definition with only a value field. createValueAnnotationDef(String name, Set<Annotation> metaAnnotations, AnnotationFieldType aft)75 public static AnnotationDef createValueAnnotationDef(String name, Set<Annotation> metaAnnotations, AnnotationFieldType aft) { 76 return new AnnotationDef(name, metaAnnotations, valueFieldTypeOnly(aft)); 77 } 78 79 // Create an annotation with only a value field. createValueAnnotation(AnnotationDef ad, Object value)80 public static Annotation createValueAnnotation(AnnotationDef ad, Object value) { 81 return new Annotation(ad, valueFieldOnly(value)); 82 } 83 getRetentionPolicyMetaAnnotation(RetentionPolicy rp)84 public static Annotation getRetentionPolicyMetaAnnotation(RetentionPolicy rp) { 85 switch (rp) { 86 case CLASS: return aRetentionClass; 87 case RUNTIME: return aRetentionRuntime; 88 case SOURCE: return aRetentionSource; 89 default: 90 throw new Error("This can't happen"); 91 } 92 } 93 getRetentionPolicyMetaAnnotationSet(RetentionPolicy rp)94 public static Set<Annotation> getRetentionPolicyMetaAnnotationSet(RetentionPolicy rp) { 95 switch (rp) { 96 case CLASS: return asRetentionClass; 97 case RUNTIME: return asRetentionRuntime; 98 case SOURCE: return asRetentionSource; 99 default: 100 throw new Error("This can't happen"); 101 } 102 } 103 104 static { 105 noAnnotations = Collections.<Annotation> emptySet(); 106 noFieldTypes = Collections.<String, AnnotationFieldType> emptyMap(); 107 noFieldValues = Collections.<String, Object> emptyMap(); 108 109 // This is slightly complicated because Retention's definition is 110 // meta-annotated by itself, we have to define the annotation 111 // before we can create the annotation on it. 112 aftRetentionPolicy = new EnumAFT("java.lang.annotation.RetentionPolicy"); 113 adRetention = new AnnotationDef("java.lang.annotation.Retention"); valueFieldTypeOnly(aftRetentionPolicy)114 adRetention.setFieldTypes(valueFieldTypeOnly(aftRetentionPolicy)); 115 aRetentionRuntime = createValueAnnotation(adRetention, "RUNTIME"); 116 adRetention.tlAnnotationsHere.add(aRetentionRuntime); 117 aRetentionClass = createValueAnnotation(adRetention, "CLASS"); 118 aRetentionSource = createValueAnnotation(adRetention, "SOURCE"); 119 asRetentionClass = Collections.singleton(aRetentionClass); 120 asRetentionRuntime = Collections.singleton(aRetentionRuntime); 121 asRetentionSource = Collections.singleton(aRetentionSource); 122 123 // Documented's definition is also self-meta-annotated. 124 adDocumented = new AnnotationDef("java.lang.annotation.Documented"); 125 adDocumented.setFieldTypes(noFieldTypes); 126 aDocumented = new Annotation(adDocumented, noFieldValues); 127 adDocumented.tlAnnotationsHere.add(aDocumented); 128 129 adTarget = createValueAnnotationDef("java.lang.annotation.Target", 130 asRetentionRuntime, 131 new ArrayAFT(new EnumAFT("java.lang.annotation.ElementType"))); 132 aTargetTypeUse = createValueAnnotation(adTarget, 133 // Problem: ElementType.TYPE_USE is defined only in JDK 7. 134 // need to decide what the canonical format for these strings is. 135 // Collections.singletonList("java.lang.annotation.ElementType.TYPE_USE") 136 // This is the way that naively reading them from classfile gives. 137 Collections.singletonList("TYPE_USE") 138 ); 139 140 typeQualifierMetaAnnotations = new HashSet<Annotation>(); 141 typeQualifierMetaAnnotations.add(aRetentionRuntime); 142 typeQualifierMetaAnnotations.add(aTargetTypeUse); 143 144 adNonNull = new AnnotationDef("org.checkerframework.checker.nullness.qual.NonNull", 145 typeQualifierMetaAnnotations, 146 noFieldTypes); 147 aNonNull = new Annotation(adNonNull, noFieldValues); 148 149 adTypeQualifier = new AnnotationDef("org.checkerframework.framework.qual.TypeQualifier", 150 asRetentionRuntime, 151 noFieldTypes); 152 aTypeQualifier = new Annotation(adTypeQualifier, noFieldValues); 153 154 standardDefs = new LinkedHashSet<AnnotationDef>(); 155 standardDefs.add(adTarget); 156 standardDefs.add(adDocumented); 157 standardDefs.add(adRetention); 158 // Because annotations can be read from classfiles, it isn't really 159 // necessary to add any more here. 160 161 } 162 163 164 /** 165 * Converts the given scalar annotation field value to one appropriate for 166 * passing to an {@link AnnotationBuilder} created by <code>af</code>. 167 * Conversion is only necessary if <code>x</code> is a subannotation, in 168 * which case we rebuild it with <code>af</code> since 169 * {@link AnnotationBuilder#addScalarField addScalarField} of an 170 * {@link AnnotationBuilder} created by <code>af</code> only accepts 171 * subannotations built by <code>af</code>. 172 */ convertAFV(ScalarAFT aft, Object x)173 private static Object convertAFV(ScalarAFT aft, Object x) { 174 if (aft instanceof AnnotationAFT) { 175 return rebuild((Annotation) x); 176 } else { 177 return x; 178 } 179 } 180 181 /** 182 * Rebuilds the annotation <code>a</code> using the factory 183 * <code>af</code> by iterating through its fields according to its 184 * definition and getting the values with {@link Annotation#getFieldValue}. 185 * Returns null if the factory is not interested in <code>a</code>. 186 */ rebuild(Annotation a)187 public static final Annotation rebuild(Annotation a) { 188 AnnotationBuilder ab = AnnotationFactory.saf.beginAnnotation(a.def()); 189 if (ab != null) { 190 for (Map. Entry<String, AnnotationFieldType> fieldDef 191 : a.def().fieldTypes.entrySet()) { 192 193 String fieldName = fieldDef.getKey(); 194 AnnotationFieldType fieldType = 195 fieldDef.getValue(); 196 Object fieldValue = 197 a.getFieldValue(fieldName); 198 199 Object nnFieldValue; 200 if (fieldValue != null) { 201 nnFieldValue = fieldValue; 202 } else throw new IllegalArgumentException( 203 "annotation has no field value"); 204 205 if (fieldType instanceof ArrayAFT) { 206 ArrayAFT aFieldType = 207 (ArrayAFT) fieldType; 208 ArrayBuilder arrb = 209 ab.beginArrayField(fieldName, aFieldType); 210 List<? extends Object> l = 211 (List<? extends Object>) fieldValue; 212 ScalarAFT nnElementType; 213 if (aFieldType.elementType != null) { 214 nnElementType = aFieldType.elementType; 215 } else { 216 throw new IllegalArgumentException( 217 "annotation field type is missing element type"); 218 } 219 for (Object o : l) { 220 arrb.appendElement(convertAFV( 221 nnElementType, o)); 222 } 223 arrb.finish(); 224 } else { 225 ScalarAFT sFieldType = 226 (ScalarAFT) fieldType; 227 ab.addScalarField(fieldName, sFieldType, 228 convertAFV(sFieldType, fieldValue)); 229 } 230 } 231 return ab.finish(); 232 } else { 233 return null; 234 } 235 } 236 237 } 238