• 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.dexgen.rop.annotation;
18 
19 import com.android.dexgen.rop.cst.Constant;
20 import com.android.dexgen.rop.cst.CstAnnotation;
21 import com.android.dexgen.rop.cst.CstFieldRef;
22 import com.android.dexgen.rop.cst.CstLiteralBits;
23 import com.android.dexgen.rop.cst.CstMethodRef;
24 import com.android.dexgen.rop.cst.CstNat;
25 import com.android.dexgen.rop.cst.CstType;
26 import com.android.dexgen.rop.cst.CstUtf8;
27 import com.android.dexgen.rop.cst.TypedConstant;
28 import com.android.dexgen.util.Hex;
29 import com.android.dexgen.util.MutabilityControl;
30 import com.android.dexgen.util.ToHuman;
31 
32 import java.util.Collection;
33 import java.util.Collections;
34 import java.util.Iterator;
35 import java.util.TreeMap;
36 
37 /**
38  * An annotation on an element of a class. Annotations have an
39  * associated type and additionally consist of a set of (name, value)
40  * pairs, where the names are unique.
41  */
42 public final class Annotation extends MutabilityControl
43         implements Comparable<Annotation>, ToHuman {
44     /** {@code non-null;} type of the annotation */
45     private final CstType type;
46 
47     /** {@code non-null;} the visibility of the annotation */
48     private final AnnotationVisibility visibility;
49 
50     /** {@code non-null;} map from names to {@link NameValuePair} instances */
51     private final TreeMap<CstUtf8, NameValuePair> elements;
52 
53     /**
54      * Construct an instance. It initially contains no elements.
55      *
56      * @param type {@code non-null;} type of the annotation
57      * @param visibility {@code non-null;} the visibility of the annotation
58      */
Annotation(CstType type, AnnotationVisibility visibility)59     public Annotation(CstType type, AnnotationVisibility visibility) {
60         if (type == null) {
61             throw new NullPointerException("type == null");
62         }
63 
64         if (visibility == null) {
65             throw new NullPointerException("visibility == null");
66         }
67 
68         this.type = type;
69         this.visibility = visibility;
70         this.elements = new TreeMap<CstUtf8, NameValuePair>();
71     }
72 
73     /** {@inheritDoc} */
74     @Override
equals(Object other)75     public boolean equals(Object other) {
76         if (! (other instanceof Annotation)) {
77             return false;
78         }
79 
80         Annotation otherAnnotation = (Annotation) other;
81 
82         if (! (type.equals(otherAnnotation.type)
83                         && (visibility == otherAnnotation.visibility))) {
84             return false;
85         }
86 
87         return elements.equals(otherAnnotation.elements);
88     }
89 
90     /** {@inheritDoc} */
hashCode()91     public int hashCode() {
92         int hash = type.hashCode();
93         hash = (hash * 31) + elements.hashCode();
94         hash = (hash * 31) + visibility.hashCode();
95         return hash;
96     }
97 
98     /** {@inheritDoc} */
compareTo(Annotation other)99     public int compareTo(Annotation other) {
100         int result = type.compareTo(other.type);
101 
102         if (result != 0) {
103             return result;
104         }
105 
106         result = visibility.compareTo(other.visibility);
107 
108         if (result != 0) {
109             return result;
110         }
111 
112         Iterator<NameValuePair> thisIter = elements.values().iterator();
113         Iterator<NameValuePair> otherIter = other.elements.values().iterator();
114 
115         while (thisIter.hasNext() && otherIter.hasNext()) {
116             NameValuePair thisOne = thisIter.next();
117             NameValuePair otherOne = otherIter.next();
118 
119             result = thisOne.compareTo(otherOne);
120             if (result != 0) {
121                 return result;
122             }
123         }
124 
125         if (thisIter.hasNext()) {
126             return 1;
127         } else if (otherIter.hasNext()) {
128             return -1;
129         }
130 
131         return 0;
132     }
133 
134     /** {@inheritDoc} */
135     @Override
toString()136     public String toString() {
137         return toHuman();
138     }
139 
140     /** {@inheritDoc} */
toHuman()141     public String toHuman() {
142         StringBuilder sb = new StringBuilder();
143 
144         sb.append(visibility.toHuman());
145         sb.append("-annotation ");
146         sb.append(type.toHuman());
147         sb.append(" {");
148 
149         boolean first = true;
150         for (NameValuePair pair : elements.values()) {
151             if (first) {
152                 first = false;
153             } else {
154                 sb.append(", ");
155             }
156             sb.append(pair.getName().toHuman());
157             sb.append(": ");
158             sb.append(pair.getValue().toHuman());
159         }
160 
161         sb.append("}");
162         return sb.toString();
163     }
164 
165     /**
166      * Gets the type of this instance.
167      *
168      * @return {@code non-null;} the type
169      */
getType()170     public CstType getType() {
171         return type;
172     }
173 
174     /**
175      * Gets the visibility of this instance.
176      *
177      * @return {@code non-null;} the visibility
178      */
getVisibility()179     public AnnotationVisibility getVisibility() {
180         return visibility;
181     }
182 
183     /**
184      * Put an element into the set of (name, value) pairs for this instance.
185      * If there is a preexisting element with the same name, it will be
186      * replaced by this method.
187      *
188      * @param pair {@code non-null;} the (name, value) pair to place into this instance
189      */
put(NameValuePair pair)190     public void put(NameValuePair pair) {
191         throwIfImmutable();
192 
193         if (pair == null) {
194             throw new NullPointerException("pair == null");
195         }
196 
197         elements.put(pair.getName(), pair);
198     }
199 
200     /**
201      * Add an element to the set of (name, value) pairs for this instance.
202      * It is an error to call this method if there is a preexisting element
203      * with the same name.
204      *
205      * @param pair {@code non-null;} the (name, value) pair to add to this instance
206      */
add(NameValuePair pair)207     public void add(NameValuePair pair) {
208         throwIfImmutable();
209 
210         if (pair == null) {
211             throw new NullPointerException("pair == null");
212         }
213 
214         CstUtf8 name = pair.getName();
215 
216         if (elements.get(name) != null) {
217             throw new IllegalArgumentException("name already added: " + name);
218         }
219 
220         elements.put(name, pair);
221     }
222 
223     /**
224      * Gets the set of name-value pairs contained in this instance. The
225      * result is always unmodifiable.
226      *
227      * @return {@code non-null;} the set of name-value pairs
228      */
getNameValuePairs()229     public Collection<NameValuePair> getNameValuePairs() {
230         return Collections.unmodifiableCollection(elements.values());
231     }
232 }
233