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