110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Alipackage annotations;
210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
399159a24fbaf231aacf98ae0a47fcdd9d7abf5f3wdietl/*>>>
443367280222c6f50f8085ae8d12a985c257b3ea0Michael Ernstimport org.checkerframework.checker.nullness.qual.Nullable;
599159a24fbaf231aacf98ae0a47fcdd9d7abf5f3wdietl*/
610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
702ac307c0d3fa53b83666972e0a75bc098500700Michael Ernstimport annotations.el.AnnotationDef;
802ac307c0d3fa53b83666972e0a75bc098500700Michael Ernstimport annotations.field.AnnotationFieldType;
902ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst
1010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Aliimport java.util.*;
1102ac307c0d3fa53b83666972e0a75bc098500700Michael Ernstimport java.lang.reflect.*;
1202ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst
1310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
1410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali/**
1510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * A very simple annotation representation constructed with a map of field names
1610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * to values. See the rules for values on {@link Annotation#getFieldValue};
1710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * furthermore, subannotations must be {@link Annotation}s.
1810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * {@link Annotation}s are immutable.
1910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali *
2010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * <p>
2110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * {@link Annotation}s can be constructed directly or through
2210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * {@link AnnotationFactory#saf}. Either way works, but if you construct
2310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali * one directly, you must provide a matching {@link AnnotationDef} yourself.
2410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali */
253aff85d01d84fa9d8551ca791036a733ae4a4f39Michael Ernstpublic final class Annotation {
2610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
2710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    /**
2810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * The annotation definition.
2910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     */
3010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    public final AnnotationDef def;
3110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
3210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    /**
3310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * An unmodifiable copy of the passed map of field values.
3410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     */
353aff85d01d84fa9d8551ca791036a733ae4a4f39Michael Ernst    public final Map<String, Object> fieldValues;
3610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
3702ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst    /** Check the representation, throw assertion failure if it is violated. */
3802ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst    public void checkRep() {
3963adeb8daeeb8c986ffe3d4e7fa5d93109616fbeMichael Ernst        assert fieldValues != null;
4063adeb8daeeb8c986ffe3d4e7fa5d93109616fbeMichael Ernst        assert fieldValues.keySet() != null;
4163adeb8daeeb8c986ffe3d4e7fa5d93109616fbeMichael Ernst        assert def != null;
4263adeb8daeeb8c986ffe3d4e7fa5d93109616fbeMichael Ernst        assert def.fieldTypes != null;
4363adeb8daeeb8c986ffe3d4e7fa5d93109616fbeMichael Ernst        assert def.fieldTypes.keySet() != null;
4402ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst        if (! fieldValues.keySet().equals(def.fieldTypes.keySet())) {
4502ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst            for (String s : fieldValues.keySet()) {
4602ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst                assert def.fieldTypes.containsKey(s)
4702ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst                    : String.format("Annotation contains field %s but AnnotationDef does not%n  annotation: %s%n  def: %s%n", s, this, this.def);
4802ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst            }
49d3512bff0c69914f91f751a1f36f3da6449f93d9Mahmood Ali            // TODO: Faulty assertions, fails when default value is used
50d3512bff0c69914f91f751a1f36f3da6449f93d9Mahmood Ali//            for (String s : def.fieldTypes.keySet()) {
51d3512bff0c69914f91f751a1f36f3da6449f93d9Mahmood Ali//                assert fieldValues.containsKey(s)
52d3512bff0c69914f91f751a1f36f3da6449f93d9Mahmood Ali//                    : String.format("AnnotationDef contains field %s but Annotation does not", s);
53d3512bff0c69914f91f751a1f36f3da6449f93d9Mahmood Ali//            }
54d3512bff0c69914f91f751a1f36f3da6449f93d9Mahmood Ali//            assert false : "This can't happen.";
5502ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst        }
5602ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst
5702ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst        for (String fieldname : fieldValues.keySet()) {
5802ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst            AnnotationFieldType aft = def.fieldTypes.get(fieldname);
5902ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst            Object value = fieldValues.get(fieldname);
6002ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst            String valueString;
6163adeb8daeeb8c986ffe3d4e7fa5d93109616fbeMichael Ernst            String classString = value.getClass().toString();
6202ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst            if (value instanceof Object[]) {
6363adeb8daeeb8c986ffe3d4e7fa5d93109616fbeMichael Ernst                Object[] arr = (Object[]) value;
6463adeb8daeeb8c986ffe3d4e7fa5d93109616fbeMichael Ernst                valueString = Arrays.toString(arr);
6563adeb8daeeb8c986ffe3d4e7fa5d93109616fbeMichael Ernst                classString += " {";
6663adeb8daeeb8c986ffe3d4e7fa5d93109616fbeMichael Ernst                for (Object elt : arr) {
6763adeb8daeeb8c986ffe3d4e7fa5d93109616fbeMichael Ernst                    classString += " " + elt.getClass();
6863adeb8daeeb8c986ffe3d4e7fa5d93109616fbeMichael Ernst                }
6963adeb8daeeb8c986ffe3d4e7fa5d93109616fbeMichael Ernst                classString += "}";
7063adeb8daeeb8c986ffe3d4e7fa5d93109616fbeMichael Ernst            } else if (value instanceof Collection) {
71a74f2668d253bb9375805db0f23a01e30ddfba8fwdietl                Collection<?> coll = (Collection<?>) value;
7263adeb8daeeb8c986ffe3d4e7fa5d93109616fbeMichael Ernst                valueString = Arrays.toString(coll.toArray());
7363adeb8daeeb8c986ffe3d4e7fa5d93109616fbeMichael Ernst                classString += " {";
7463adeb8daeeb8c986ffe3d4e7fa5d93109616fbeMichael Ernst                for (Object elt : coll) {
7563adeb8daeeb8c986ffe3d4e7fa5d93109616fbeMichael Ernst                    classString += " " + elt.getClass();
7663adeb8daeeb8c986ffe3d4e7fa5d93109616fbeMichael Ernst                }
7763adeb8daeeb8c986ffe3d4e7fa5d93109616fbeMichael Ernst                classString += " }";
7802ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst            } else {
7902ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst                valueString = value.toString();
8063adeb8daeeb8c986ffe3d4e7fa5d93109616fbeMichael Ernst                // No need to modify valueString.
8102ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst            }
8202ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst            assert aft.isValidValue(value)
8363adeb8daeeb8c986ffe3d4e7fa5d93109616fbeMichael Ernst                : String.format("Bad field value%n  %s (%s)%nfor field%n  %s (%s)%nin annotation%n  %s",
8463adeb8daeeb8c986ffe3d4e7fa5d93109616fbeMichael Ernst                                valueString, classString, aft, aft.getClass(), def);
8502ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst        }
8602ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst    }
8702ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst
8810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    // TODO make sure the field values are valid?
8910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    /**
9010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * Constructs a {@link Annotation} with the given definition and
9110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * field values.  Make sure that the field values obey the rules given on
9210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * {@link Annotation#getFieldValue} and that subannotations are also
9310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * {@link Annotation}s; this constructor does not validate the
9410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * values.
9510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     */
9610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    public Annotation(AnnotationDef def,
973aff85d01d84fa9d8551ca791036a733ae4a4f39Michael Ernst            Map<String, ? extends Object> fields) {
9810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        this.def = def;
9910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        this.fieldValues = Collections.unmodifiableMap(
1003aff85d01d84fa9d8551ca791036a733ae4a4f39Michael Ernst                new LinkedHashMap<String, Object>(fields));
10102ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst        checkRep();
10202ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst    }
10302ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst
10402ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst    /** Use adefs to look up (or insert into it) missing AnnotationDefs. */
10502ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst    public Annotation(java.lang.annotation.Annotation ja, Map<String, AnnotationDef> adefs) {
10602ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst        Class<? extends java.lang.annotation.Annotation> jaType = ja.annotationType();
10702ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst        String name = jaType.getName();
10802ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst        if (adefs.containsKey(name)) {
10902ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst            def = adefs.get(name);
11002ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst        } else {
11102ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst            def = AnnotationDef.fromClass(jaType, adefs);
11202ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst            adefs.put(name, def);
11302ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst        }
11402ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst        fieldValues = new LinkedHashMap<String,Object>();
11502ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst        try {
11602ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst            for (String fieldname : def.fieldTypes.keySet()) {
11702ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst                AnnotationFieldType aft = def.fieldTypes.get(fieldname);
11802ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst                Method m = jaType.getDeclaredMethod(fieldname);
11902ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst                Object val = m.invoke(ja);
12002ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst                if (! aft.isValidValue(val)) {
12199159a24fbaf231aacf98ae0a47fcdd9d7abf5f3wdietl                    if (val instanceof Class[]) {
122a74f2668d253bb9375805db0f23a01e30ddfba8fwdietl                        Class<?>[] vala = (Class[]) val;
123a74f2668d253bb9375805db0f23a01e30ddfba8fwdietl                        List<Class<?>> vall = new ArrayList<Class<?>>(vala.length);
124a74f2668d253bb9375805db0f23a01e30ddfba8fwdietl                        for (Class<?> elt : vala) {
12599159a24fbaf231aacf98ae0a47fcdd9d7abf5f3wdietl                            vall.add(elt);
12699159a24fbaf231aacf98ae0a47fcdd9d7abf5f3wdietl                        }
12799159a24fbaf231aacf98ae0a47fcdd9d7abf5f3wdietl                        val = vall;
12899159a24fbaf231aacf98ae0a47fcdd9d7abf5f3wdietl                    } else if (val instanceof Object[]) {
12902ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst                        Object[] vala = (Object[]) val;
13002ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst                        List<Object> vall = new ArrayList<Object>(vala.length);
13102ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst                        for (Object elt : vala) {
13202ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst                            vall.add(elt.toString());
13302ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst                        }
13402ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst                        val = vall;
13502ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst                    } else {
13602ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst                        val = val.toString();
13702ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst                    }
13802ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst                }
13902ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst                assert aft.isValidValue(val)
14099159a24fbaf231aacf98ae0a47fcdd9d7abf5f3wdietl                    : String.format("invalid value \"%s\" for field \"%s\" of class \"%s\" and expected type \"%s\"; ja=%s", val, val.getClass(), fieldname, aft, ja);
14102ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst                fieldValues.put(fieldname, val);
14202ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst            }
14302ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst        } catch (NoSuchMethodException e) {
14402ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst            throw new Error(String.format("no such method (annotation field) in %s%n  from: %s %s", jaType, ja, adefs), e);
14502ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst        } catch (InvocationTargetException e) {
14602ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst            throw new Error(e);
14702ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst        } catch (IllegalAccessException e) {
14802ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst            throw new Error(e);
14902ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst        }
15002ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst        checkRep();
15110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    }
15210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
15310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    /**
15410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * Returns the value of the field whose name is given.
15510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     *
15610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * <p>
15710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * Everywhere in the annotation scene library, field values are to be
15810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * represented as follows:
15910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     *
16010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * <ul>
16110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * <li>Primitive value: wrapper object, such as {@link Integer}.
16210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * <li>{@link String}: {@link String}.
16310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * <li>Class token: name of the type as a {@link String}, using the source
16410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * code notation <code>int[]</code> for arrays.
16510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * <li>Enumeration constant: name of the constant as a {@link String}.
16610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * <li>Subannotation: <code>Annotation</code> object.
16710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * <li>Array: {@link List} of elements in the formats defined here.  If
16810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * the element type is unknown (see
16910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * {@link AnnotationBuilder#addEmptyArrayField}), the array must have zero
17010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * elements.
17110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * </ul>
17210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     */
1733aff85d01d84fa9d8551ca791036a733ae4a4f39Michael Ernst    public Object getFieldValue(String fieldName) {
17410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        return fieldValues.get(fieldName);
17510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    }
17610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
17710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    /**
17810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * Returns the definition of the annotation type to which this annotation
17910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * belongs.
18010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     */
18110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    public final AnnotationDef def() {
18210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        return def;
18310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    }
18410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
18510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    /**
18610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * This {@link Annotation} equals <code>o</code> if and only if
18710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * <code>o</code> is a nonnull {@link Annotation} and <code>this</code> and
18810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * <code>o</code> have recursively equal definitions and field values,
18910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * even if they were created by different {@link AnnotationFactory}s.
19010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     */
19110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    @Override
1923aff85d01d84fa9d8551ca791036a733ae4a4f39Michael Ernst    public final boolean equals(Object o) {
19310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        return o instanceof Annotation && equals((Annotation) o);
19410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    }
19510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
19610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    /**
19710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * Returns whether this annotation equals <code>o</code>; a slightly faster
19810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * variant of {@link #equals(Object)} for when the argument is statically
19902ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst     * known to be another nonnull {@link Annotation}. Subclasses may wish to
20010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * override this with a hard-coded "&amp;&amp;" of field comparisons to improve
20110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * performance.
20210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     */
2033aff85d01d84fa9d8551ca791036a733ae4a4f39Michael Ernst    public boolean equals(Annotation o) {
20410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        return def.equals(o.def())
20502ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst            && fieldValues.equals(o.fieldValues);
20610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    }
20710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
20810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    /**
20910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * Returns the hash code of this annotation as defined on
21002ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst     * {@link Annotation#hashCode}.  Subclasses may wish to override
21110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * this with a hard-coded XOR/addition of fields to improve performance.
21210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     */
21310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    @Override
2143aff85d01d84fa9d8551ca791036a733ae4a4f39Michael Ernst    public int hashCode() {
21502ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst        return def.hashCode() + fieldValues.hashCode();
21610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    }
21710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
21810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    /**
21910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * Returns a string representation of this for
22010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * debugging purposes.  For now, this method relies on
22110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * {@link AbstractMap#toString} and the {@link Object#toString toString}
22210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * methods of the field values, so the representation is only a first
22310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     * approximation to how the annotation would appear in source code.
22410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali     */
22510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    @Override
2263aff85d01d84fa9d8551ca791036a733ae4a4f39Michael Ernst    public String toString() {
22710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        StringBuilder sb = new StringBuilder("@");
22810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        sb.append(def.name);
22902ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst        if (!fieldValues.isEmpty()) {
23010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali            sb.append('(');
23102ac307c0d3fa53b83666972e0a75bc098500700Michael Ernst            sb.append(fieldValues.toString());
23210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali            sb.append(')');
23310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        }
23410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali        return sb.toString();
23510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali    }
23610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
23710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali}
23810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali
23910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali// package annotations;
24010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//
24143367280222c6f50f8085ae8d12a985c257b3ea0Michael Ernst// import org.checkerframework.checker.nullness.qual.Nullable;
242b69b006f7980741677c3acde6845363915695017Michael Ernst//
24310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali// import annotations.el.*;
24410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali// import annotations.util.coll.Keyer;
24510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//
24610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali// /**
24710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//  * A top-level annotation containing an ordinary annotation plus a retention
24810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//  * policy.  These are attached to {@link AElement}s.
24910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//  */
2503aff85d01d84fa9d8551ca791036a733ae4a4f39Michael Ernst// public final class Annotation {
25110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//     public static final Keyer<String, Annotation> nameKeyer
25210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//         = new Keyer<String, Annotation>() {
25310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//         public String getKeyFor(
2543aff85d01d84fa9d8551ca791036a733ae4a4f39Michael Ernst//                 Annotation v) {
25510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//             return v.tldef.name;
25610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//         }
25710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//     };
25810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//
25910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//     /**
26010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//      * The annotation definition.
26110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//      */
26210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//     public final AnnotationDef tldef;
26310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//
26410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//     /**
26510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//      * The ordinary annotation, which contains the data and the ordinary
26610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//      * definition.
26710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//      */
26810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//     public final Annotation ann;
26910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//
27010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//     /**
27110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//      * Wraps the given annotation in a top-level annotation using the given
27210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//      * top-level annotation definition, which provides a retention policy.
27310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//      */
27410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//     public Annotation(AnnotationDef tldef, Annotation ann) {
27510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//         if (!ann.def().equals(tldef))
27610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//             throw new IllegalArgumentException("Definitions mismatch");
27710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//         this.tldef = tldef;
27810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//         this.ann = ann;
27910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//     }
28010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//
28110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//     /**
28210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//      * Wraps the given annotation in a top-level annotation with the given
28310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//      * retention policy, generating the top-level annotation definition
28410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//      * automatically for convenience.
28510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//      */
28610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//     public Annotation(Annotation ann1,
28710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//             RetentionPolicy retention) {
28810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//         this(new AnnotationDef(ann1.def(), retention), ann1);
28910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//     }
29010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//
29110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//     /**
29210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//      * {@inheritDoc}
29310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//      */
29410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//     @Override
29510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//     public int hashCode() {
29610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//         return tldef.hashCode() + ann.hashCode();
29710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//     }
29810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//
29910353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//     @Override
30010353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//     public String toString() {
30110353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//       StringBuilder sb = new StringBuilder();
30210353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//       sb.append("tla: ");
30310353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//       sb.append(tldef.retention);
30410353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//       sb.append(":");
30510353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//       sb.append(ann.toString());
30610353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//       return sb.toString();
30710353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali//     }
30810353ed766fc48a0af6bd33d934439e695c03e3Mahmood Ali// }
309