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