Annotation.java revision 579d7739c53a2707ad711a2d2cae46d7d782f061
107a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch/*
207a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch * Copyright (C) 2007 The Android Open Source Project
307a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch *
407a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch * Licensed under the Apache License, Version 2.0 (the "License");
507a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch * you may not use this file except in compliance with the License.
607a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch * You may obtain a copy of the License at
707a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch *
807a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch *      http://www.apache.org/licenses/LICENSE-2.0
907a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch *
107242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci * Unless required by applicable law or agreed to in writing, software
1107a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch * distributed under the License is distributed on an "AS IS" BASIS,
12c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1307a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch * See the License for the specific language governing permissions and
1407a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch * limitations under the License.
1507a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch */
1607a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch
1707a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdochpackage com.android.dx.rop.annotation;
1807a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch
1907a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdochimport com.android.dx.rop.cst.CstString;
2007a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdochimport com.android.dx.rop.cst.CstType;
2107a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdochimport com.android.dx.util.MutabilityControl;
2207a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdochimport com.android.dx.util.ToHuman;
2307a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch
247242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucciimport java.util.Collection;
257242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucciimport java.util.Collections;
267242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucciimport java.util.Iterator;
277242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucciimport java.util.TreeMap;
287242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
29a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch/**
3007a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch * An annotation on an element of a class. Annotations have an
3107a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch * associated type and additionally consist of a set of (name, value)
3207a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch * pairs, where the names are unique.
3307a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch */
3407a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdochpublic final class Annotation extends MutabilityControl
3507a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch        implements Comparable<Annotation>, ToHuman {
3607a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch    /** {@code non-null;} type of the annotation */
3707a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch    private final CstType type;
3807a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch
3907a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch    /** {@code non-null;} the visibility of the annotation */
407242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    private final AnnotationVisibility visibility;
417242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
427242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    /** {@code non-null;} map from names to {@link NameValuePair} instances */
437242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    private final TreeMap<CstString, NameValuePair> elements;
4407a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch
4507a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch    /**
4607a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch     * Construct an instance. It initially contains no elements.
4707a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch     *
48c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)     * @param type {@code non-null;} type of the annotation
4907a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch     * @param visibility {@code non-null;} the visibility of the annotation
5007a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch     */
51    public Annotation(CstType type, AnnotationVisibility visibility) {
52        if (type == null) {
53            throw new NullPointerException("type == null");
54        }
55
56        if (visibility == null) {
57            throw new NullPointerException("visibility == null");
58        }
59
60        this.type = type;
61        this.visibility = visibility;
62        this.elements = new TreeMap<CstString, NameValuePair>();
63    }
64
65    /** {@inheritDoc} */
66    @Override
67    public boolean equals(Object other) {
68        if (! (other instanceof Annotation)) {
69            return false;
70        }
71
72        Annotation otherAnnotation = (Annotation) other;
73
74        if (! (type.equals(otherAnnotation.type)
75                        && (visibility == otherAnnotation.visibility))) {
76            return false;
77        }
78
79        return elements.equals(otherAnnotation.elements);
80    }
81
82    /** {@inheritDoc} */
83    public int hashCode() {
84        int hash = type.hashCode();
85        hash = (hash * 31) + elements.hashCode();
86        hash = (hash * 31) + visibility.hashCode();
87        return hash;
88    }
89
90    /** {@inheritDoc} */
91    public int compareTo(Annotation other) {
92        int result = type.compareTo(other.type);
93
94        if (result != 0) {
95            return result;
96        }
97
98        result = visibility.compareTo(other.visibility);
99
100        if (result != 0) {
101            return result;
102        }
103
104        Iterator<NameValuePair> thisIter = elements.values().iterator();
105        Iterator<NameValuePair> otherIter = other.elements.values().iterator();
106
107        while (thisIter.hasNext() && otherIter.hasNext()) {
108            NameValuePair thisOne = thisIter.next();
109            NameValuePair otherOne = otherIter.next();
110
111            result = thisOne.compareTo(otherOne);
112            if (result != 0) {
113                return result;
114            }
115        }
116
117        if (thisIter.hasNext()) {
118            return 1;
119        } else if (otherIter.hasNext()) {
120            return -1;
121        }
122
123        return 0;
124    }
125
126    /** {@inheritDoc} */
127    @Override
128    public String toString() {
129        return toHuman();
130    }
131
132    /** {@inheritDoc} */
133    public String toHuman() {
134        StringBuilder sb = new StringBuilder();
135
136        sb.append(visibility.toHuman());
137        sb.append("-annotation ");
138        sb.append(type.toHuman());
139        sb.append(" {");
140
141        boolean first = true;
142        for (NameValuePair pair : elements.values()) {
143            if (first) {
144                first = false;
145            } else {
146                sb.append(", ");
147            }
148            sb.append(pair.getName().toHuman());
149            sb.append(": ");
150            sb.append(pair.getValue().toHuman());
151        }
152
153        sb.append("}");
154        return sb.toString();
155    }
156
157    /**
158     * Gets the type of this instance.
159     *
160     * @return {@code non-null;} the type
161     */
162    public CstType getType() {
163        return type;
164    }
165
166    /**
167     * Gets the visibility of this instance.
168     *
169     * @return {@code non-null;} the visibility
170     */
171    public AnnotationVisibility getVisibility() {
172        return visibility;
173    }
174
175    /**
176     * Put an element into the set of (name, value) pairs for this instance.
177     * If there is a preexisting element with the same name, it will be
178     * replaced by this method.
179     *
180     * @param pair {@code non-null;} the (name, value) pair to place into this instance
181     */
182    public void put(NameValuePair pair) {
183        throwIfImmutable();
184
185        if (pair == null) {
186            throw new NullPointerException("pair == null");
187        }
188
189        elements.put(pair.getName(), pair);
190    }
191
192    /**
193     * Add an element to the set of (name, value) pairs for this instance.
194     * It is an error to call this method if there is a preexisting element
195     * with the same name.
196     *
197     * @param pair {@code non-null;} the (name, value) pair to add to this instance
198     */
199    public void add(NameValuePair pair) {
200        throwIfImmutable();
201
202        if (pair == null) {
203            throw new NullPointerException("pair == null");
204        }
205
206        CstString name = pair.getName();
207
208        if (elements.get(name) != null) {
209            throw new IllegalArgumentException("name already added: " + name);
210        }
211
212        elements.put(name, pair);
213    }
214
215    /**
216     * Gets the set of name-value pairs contained in this instance. The
217     * result is always unmodifiable.
218     *
219     * @return {@code non-null;} the set of name-value pairs
220     */
221    public Collection<NameValuePair> getNameValuePairs() {
222        return Collections.unmodifiableCollection(elements.values());
223    }
224}
225