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.CstType; 20 import com.android.dx.util.MutabilityControl; 21 import java.util.Collection; 22 import java.util.Collections; 23 import java.util.Iterator; 24 import java.util.TreeMap; 25 26 /** 27 * List of {@link Annotation} instances. 28 */ 29 public final class Annotations extends MutabilityControl 30 implements Comparable<Annotations> { 31 /** {@code non-null;} immutable empty instance */ 32 public static final Annotations EMPTY = new Annotations(); 33 34 static { 35 EMPTY.setImmutable(); 36 } 37 38 /** {@code non-null;} map from types to annotations */ 39 private final TreeMap<CstType, Annotation> annotations; 40 41 /** 42 * Constructs an immutable instance which is the combination of the 43 * two given instances. The two instances must contain disjoint sets 44 * of types. 45 * 46 * @param a1 {@code non-null;} an instance 47 * @param a2 {@code non-null;} the other instance 48 * @return {@code non-null;} the combination 49 * @throws IllegalArgumentException thrown if there is a duplicate type 50 */ 51 public static Annotations combine(Annotations a1, Annotations a2) { 52 Annotations result = new Annotations(); 53 54 result.addAll(a1); 55 result.addAll(a2); 56 result.setImmutable(); 57 58 return result; 59 } 60 61 /** 62 * Constructs an immutable instance which is the combination of the 63 * given instance with the given additional annotation. The latter's 64 * type must not already appear in the former. 65 * 66 * @param annotations {@code non-null;} the instance to augment 67 * @param annotation {@code non-null;} the additional annotation 68 * @return {@code non-null;} the combination 69 * @throws IllegalArgumentException thrown if there is a duplicate type 70 */ 71 public static Annotations combine(Annotations annotations, 72 Annotation annotation) { 73 Annotations result = new Annotations(); 74 75 result.addAll(annotations); 76 result.add(annotation); 77 result.setImmutable(); 78 79 return result; 80 } 81 82 /** 83 * Constructs an empty instance. 84 */ 85 public Annotations() { 86 annotations = new TreeMap<CstType, Annotation>(); 87 } 88 89 /** {@inheritDoc} */ 90 @Override 91 public int hashCode() { 92 return annotations.hashCode(); 93 } 94 95 /** {@inheritDoc} */ 96 @Override 97 public boolean equals(Object other) { 98 if (! (other instanceof Annotations)) { 99 return false; 100 } 101 102 Annotations otherAnnotations = (Annotations) other; 103 104 return annotations.equals(otherAnnotations.annotations); 105 } 106 107 /** {@inheritDoc} */ 108 public int compareTo(Annotations other) { 109 Iterator<Annotation> thisIter = annotations.values().iterator(); 110 Iterator<Annotation> otherIter = other.annotations.values().iterator(); 111 112 while (thisIter.hasNext() && otherIter.hasNext()) { 113 Annotation thisOne = thisIter.next(); 114 Annotation otherOne = otherIter.next(); 115 116 int result = thisOne.compareTo(otherOne); 117 if (result != 0) { 118 return result; 119 } 120 } 121 122 if (thisIter.hasNext()) { 123 return 1; 124 } else if (otherIter.hasNext()) { 125 return -1; 126 } 127 128 return 0; 129 } 130 131 /** {@inheritDoc} */ 132 public String toString() { 133 StringBuilder sb = new StringBuilder(); 134 boolean first = true; 135 136 sb.append("annotations{"); 137 138 for (Annotation a : annotations.values()) { 139 if (first) { 140 first = false; 141 } else { 142 sb.append(", "); 143 } 144 sb.append(a.toHuman()); 145 } 146 147 sb.append("}"); 148 return sb.toString(); 149 } 150 151 /** 152 * Gets the number of elements in this instance. 153 * 154 * @return {@code >= 0;} the size 155 */ 156 public int size() { 157 return annotations.size(); 158 } 159 160 /** 161 * Adds an element to this instance. There must not already be an 162 * element of the same type. 163 * 164 * @param annotation {@code non-null;} the element to add 165 * @throws IllegalArgumentException thrown if there is a duplicate type 166 */ 167 public void add(Annotation annotation) { 168 throwIfImmutable(); 169 170 if (annotation == null) { 171 throw new NullPointerException("annotation == null"); 172 } 173 174 CstType type = annotation.getType(); 175 176 if (annotations.containsKey(type)) { 177 throw new IllegalArgumentException("duplicate type: " + 178 type.toHuman()); 179 } 180 181 annotations.put(type, annotation); 182 } 183 184 /** 185 * Adds all of the elements of the given instance to this one. The 186 * instances must not have any duplicate types. 187 * 188 * @param toAdd {@code non-null;} the annotations to add 189 * @throws IllegalArgumentException thrown if there is a duplicate type 190 */ 191 public void addAll(Annotations toAdd) { 192 throwIfImmutable(); 193 194 if (toAdd == null) { 195 throw new NullPointerException("toAdd == null"); 196 } 197 198 for (Annotation a : toAdd.annotations.values()) { 199 add(a); 200 } 201 } 202 203 /** 204 * Gets the set of annotations contained in this instance. The 205 * result is always unmodifiable. 206 * 207 * @return {@code non-null;} the set of annotations 208 */ 209 public Collection<Annotation> getAnnotations() { 210 return Collections.unmodifiableCollection(annotations.values()); 211 } 212 } 213