1 package net.sourceforge.pmd.util;
2
3 import java.lang.reflect.Array;
4 import java.util.ArrayList;
5 import java.util.Arrays;
6 import java.util.Collection;
7 import java.util.HashMap;
8 import java.util.HashSet;
9 import java.util.List;
10 import java.util.Map;
11 import java.util.Set;
12
13
14
15
16
17
18
19
20 public final class CollectionUtil {
21
22 @SuppressWarnings("PMD.UnnecessaryFullyQualifiedName")
23 public static final TypeMap COLLECTION_INTERFACES_BY_NAMES = new TypeMap(new Class[] { java.util.List.class,
24 java.util.Collection.class, java.util.Map.class, java.util.Set.class, });
25
26 @SuppressWarnings({"PMD.LooseCoupling", "PMD.UnnecessaryFullyQualifiedName"})
27 public static final TypeMap COLLECTION_CLASSES_BY_NAMES = new TypeMap(new Class[] { java.util.ArrayList.class,
28 java.util.LinkedList.class, java.util.Vector.class, java.util.HashMap.class, java.util.LinkedHashMap.class,
29 java.util.TreeMap.class, java.util.TreeSet.class, java.util.HashSet.class, java.util.LinkedHashSet.class,
30 java.util.Hashtable.class});
31
32 private CollectionUtil() {
33 };
34
35
36
37
38
39
40
41
42
43 public static int addWithoutDuplicates(Collection<String> source, Collection<String> target) {
44
45 int added = 0;
46
47 for (String item : source) {
48 if (target.contains(item)) continue;
49 target.add(item);
50 added++;
51 }
52
53 return added;
54 }
55
56
57
58
59
60
61
62 public static Class<?> getCollectionTypeFor(String shortName) {
63 Class<?> cls = COLLECTION_CLASSES_BY_NAMES.typeFor(shortName);
64 if (cls != null) {
65 return cls;
66 }
67
68 return COLLECTION_INTERFACES_BY_NAMES.typeFor(shortName);
69 }
70
71
72
73
74
75
76
77
78
79 public static boolean isCollectionType(String typeName, boolean includeInterfaces) {
80
81 if (COLLECTION_CLASSES_BY_NAMES.contains(typeName)) {
82 return true;
83 }
84
85 return includeInterfaces && COLLECTION_INTERFACES_BY_NAMES.contains(typeName);
86 }
87
88
89
90
91
92
93
94
95
96 public static boolean isCollectionType(Class<?> clazzType, boolean includeInterfaces) {
97
98 if (COLLECTION_CLASSES_BY_NAMES.contains(clazzType)) {
99 return true;
100 }
101
102 return includeInterfaces && COLLECTION_INTERFACES_BY_NAMES.contains(clazzType);
103 }
104
105
106
107
108
109
110
111 public static <T> Set<T> asSet(T[] items) {
112
113 return new HashSet<T>(Arrays.asList(items));
114 }
115
116
117
118
119
120
121
122
123
124 public static <K, V> Map<K, V> mapFrom(K[] keys, V[] values) {
125 if (keys.length != values.length) {
126 throw new RuntimeException("mapFrom keys and values arrays have different sizes");
127 }
128 Map<K, V> map = new HashMap<K, V>(keys.length);
129 for (int i = 0; i < keys.length; i++) {
130 map.put(keys[i], values[i]);
131 }
132 return map;
133 }
134
135
136
137
138
139
140
141 public static <K, V> Map<V, K> invertedMapFrom(Map<K, V> source) {
142 Map<V, K> map = new HashMap<V, K>(source.size());
143 for (Map.Entry<K, V> entry : source.entrySet()) {
144 map.put(entry.getValue(), entry.getKey());
145 }
146 return map;
147 }
148
149
150
151
152
153
154
155
156
157 public static boolean arraysAreEqual(Object value, Object otherValue) {
158 if (value instanceof Object[]) {
159 if (otherValue instanceof Object[]) {
160 return valuesAreTransitivelyEqual((Object[]) value, (Object[]) otherValue);
161 }
162 return false;
163 }
164 return false;
165 }
166
167
168
169
170
171
172
173
174
175 public static boolean valuesAreTransitivelyEqual(Object[] thisArray, Object[] thatArray) {
176 if (thisArray == thatArray) {
177 return true;
178 }
179 if (thisArray == null || thatArray == null) {
180 return false;
181 }
182 if (thisArray.length != thatArray.length) {
183 return false;
184 }
185 for (int i = 0; i < thisArray.length; i++) {
186 if (!areEqual(thisArray[i], thatArray[i])) {
187 return false;
188 }
189 }
190 return true;
191 }
192
193
194
195
196
197
198
199
200 @SuppressWarnings("PMD.CompareObjectsWithEquals")
201 public static boolean areEqual(Object value, Object otherValue) {
202 if (value == otherValue) {
203 return true;
204 }
205 if (value == null) {
206 return false;
207 }
208 if (otherValue == null) {
209 return false;
210 }
211
212 if (value.getClass().getComponentType() != null) {
213 return arraysAreEqual(value, otherValue);
214 }
215 return value.equals(otherValue);
216 }
217
218
219
220
221
222
223 public static boolean isEmpty(Object[] items) {
224 return items == null || items.length == 0;
225 }
226
227
228
229
230
231
232
233
234 public static boolean isNotEmpty(Object[] items) {
235 return !isEmpty(items);
236 }
237
238
239
240
241
242
243
244
245
246
247
248 public static <T> boolean areSemanticEquals(T[] a, T[] b) {
249
250 if (a == null) { return isEmpty(b); }
251 if (b == null) { return isEmpty(a); }
252
253 if (a.length != b.length) return false;
254
255 for (int i=0; i<a.length; i++) {
256 if (!areEqual(a[i], b[i])) return false;
257 }
258
259 return true;
260 }
261
262
263
264
265
266
267
268
269
270
271
272 public static <T> T[] addWithoutDuplicates(T[] values, T newValue) {
273
274 for (T value : values) {
275 if (value.equals(newValue)) {
276 return values;
277 }
278 }
279
280 T[] largerOne = (T[])Array.newInstance(values.getClass().getComponentType(), values.length + 1);
281 System.arraycopy(values, 0, largerOne, 0, values.length);
282 largerOne[values.length] = newValue;
283 return largerOne;
284 }
285
286
287
288
289
290
291
292
293
294 public static <T> T[] addWithoutDuplicates(T[] values, T[] newValues) {
295
296 Set<T> originals = new HashSet<T>(values.length);
297 for (T value : values) { originals.add(value); }
298 List<T> newOnes = new ArrayList<T>(newValues.length);
299 for (T value : newValues) {
300 if (originals.contains(value)) { continue; }
301 newOnes.add(value);
302 }
303
304 T[] largerOne = (T[])Array.newInstance(values.getClass().getComponentType(), values.length + newOnes.size());
305 System.arraycopy(values, 0, largerOne, 0, values.length);
306 for (int i=values.length; i<largerOne.length; i++) { largerOne[i] = newOnes.get(i-values.length); }
307 return largerOne;
308 }
309 }