• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.dx.rop.annotation;
18 
19 import com.android.dx.rop.cst.CstString;
20 import com.android.dx.rop.cst.CstType;
21 import com.android.dx.util.MutabilityControl;
22 import com.android.dx.util.ToHuman;
23 
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.Iterator;
27 import java.util.TreeMap;
28 
29 /**
30  * An annotation on an element of a class. Annotations have an
31  * associated type and additionally consist of a set of (name, value)
32  * pairs, where the names are unique.
33  */
34 public final class Annotation extends MutabilityControl
35         implements Comparable<Annotation>, ToHuman {
36     /** {@code non-null;} type of the annotation */
37     private final CstType type;
38 
39     /** {@code non-null;} the visibility of the annotation */
40     private final AnnotationVisibility visibility;
41 
42     /** {@code non-null;} map from names to {@link NameValuePair} instances */
43     private final TreeMap<CstString, NameValuePair> elements;
44 
45     /**
46      * Construct an instance. It initially contains no elements.
47      *
48      * @param type {@code non-null;} type of the annotation
49      * @param visibility {@code non-null;} the visibility of the annotation
50      */
Annotation(CstType type, AnnotationVisibility visibility)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
equals(Object other)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} */
hashCode()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} */
compareTo(Annotation other)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
toString()128     public String toString() {
129         return toHuman();
130     }
131 
132     /** {@inheritDoc} */
toHuman()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      */
getType()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      */
getVisibility()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      */
put(NameValuePair pair)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      */
add(NameValuePair pair)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      */
getNameValuePairs()221     public Collection<NameValuePair> getNameValuePairs() {
222         return Collections.unmodifiableCollection(elements.values());
223     }
224 }
225