View Javadoc

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