1 package net.sourceforge.pmd.util;
2
3 import java.util.HashMap;
4 import java.util.HashSet;
5 import java.util.Iterator;
6 import java.util.Map;
7 import java.util.Set;
8 import java.util.Map.Entry;
9
10 /***
11 * Generic collection and array-related utility functions.
12 *
13 * @author Brian Remedios
14 * @version $Revision$
15 */
16 public class CollectionUtil {
17
18 public static final TypeMap collectionInterfacesByNames = new TypeMap( new Class[] {
19 java.util.List.class,
20 java.util.Collection.class,
21 java.util.Map.class,
22 java.util.Set.class,
23 });
24
25 public static final TypeMap collectionClassesByNames = new TypeMap( new Class[] {
26 java.util.ArrayList.class,
27 java.util.LinkedList.class,
28 java.util.Vector.class,
29 java.util.HashMap.class,
30 java.util.LinkedHashMap.class,
31 java.util.TreeMap.class,
32 java.util.TreeSet.class,
33 java.util.HashSet.class,
34 java.util.LinkedHashSet.class
35 });
36
37 private CollectionUtil() {};
38
39 /***
40 * Returns the collection type if we recognize it by its short name.
41 *
42 * @param shortName String
43 * @return Class
44 */
45 public static Class getCollectionTypeFor(String shortName) {
46 Class cls = collectionClassesByNames.typeFor(shortName);
47 if (cls != null) return cls;
48
49 return collectionInterfacesByNames.typeFor(shortName);
50 }
51
52 /***
53 * Return whether we can identify the typeName as a java.util collection class
54 * or interface as specified.
55 *
56 * @param typeName String
57 * @param includeInterfaces boolean
58 * @return boolean
59 */
60 public static boolean isCollectionType(String typeName, boolean includeInterfaces) {
61
62 if (collectionClassesByNames.contains(typeName)) return true;
63
64 return includeInterfaces && collectionInterfacesByNames.contains(typeName);
65 }
66
67 /***
68 * Return whether we can identify the typeName as a java.util collection class
69 * or interface as specified.
70 *
71 * @param clazzType Class
72 * @param includeInterfaces boolean
73 * @return boolean
74 */
75 public static boolean isCollectionType(Class clazzType, boolean includeInterfaces) {
76
77 if (collectionClassesByNames.contains(clazzType)) {
78 return true;
79 }
80
81 return includeInterfaces && collectionInterfacesByNames.contains(clazzType);
82 }
83
84 /***
85 * Returns the items as a populated set.
86 *
87 * @param items Object[]
88 * @return Set
89 */
90 public static Set asSet(Object[] items) {
91
92 Set set = new HashSet(items.length);
93 for (int i=0; i<items.length; i++) {
94 set.add(items[i]);
95 }
96 return set;
97 }
98
99 /***
100 * Creates and returns a map populated with the keyValuesSets where
101 * the value held by the tuples are they key and value in that order.
102 *
103 * @param keyValueSets Object[][]
104 * @return Map
105 */
106 public static Map mapFrom(Object[][] keyValueSets) {
107 Map map = new HashMap(keyValueSets.length);
108 for (int i=0; i<keyValueSets.length; i++) {
109 map.put(keyValueSets[i][0], keyValueSets[i][1]);
110 }
111 return map;
112 }
113
114 /***
115 * Returns a map based on the source but with the key & values swapped.
116 *
117 * @param source Map
118 * @return Map
119 */
120 public static Map invertedMapFrom(Map source) {
121 Map map = new HashMap(source.size());
122 Iterator iter = source.entrySet().iterator();
123 Entry entry;
124 while (iter.hasNext()) {
125 entry = (Entry)iter.next();
126 map.put(entry.getValue(), entry.getKey());
127 }
128 return map;
129 }
130
131 /***
132 * Returns true if the objects are array instances and each of their elements compares
133 * via equals as well.
134 *
135 * @param value Object
136 * @param otherValue Object
137 * @return boolean
138 */
139 public static final boolean arraysAreEqual(Object value, Object otherValue) {
140 if (value instanceof Object[]) {
141 if (otherValue instanceof Object[]) return valuesAreTransitivelyEqual((Object[])value, (Object[])otherValue);
142 return false;
143 }
144 return false;
145 }
146
147 /***
148 * Returns whether the arrays are equal by examining each of their elements, even if they are
149 * arrays themselves.
150 *
151 * @param thisArray Object[]
152 * @param thatArray Object[]
153 * @return boolean
154 */
155 public static final boolean valuesAreTransitivelyEqual(Object[] thisArray, Object[] thatArray) {
156 if (thisArray == thatArray) return true;
157 if ((thisArray == null) || (thatArray == null)) return false;
158 if (thisArray.length != thatArray.length) return false;
159 for (int i = 0; i < thisArray.length; i++) {
160 if (!areEqual(thisArray[i], thatArray[i])) return false;
161 }
162 return true;
163 }
164
165 /***
166 * A comprehensive isEqual method that handles nulls and arrays safely.
167 *
168 * @param value Object
169 * @param otherValue Object
170 * @return boolean
171 */
172 public static final boolean areEqual(Object value, Object otherValue) {
173 if (value == otherValue) return true;
174 if (value == null) return false;
175 if (otherValue == null) return false;
176
177 if (value.getClass().getComponentType() != null) return arraysAreEqual(value, otherValue);
178 return value.equals(otherValue);
179 }
180 }