• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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