Coverage Report - org.kuali.rice.core.api.util.collect.CollectionUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
CollectionUtils
57%
22/38
44%
15/34
2.65
CollectionUtils$1
N/A
N/A
2.65
CollectionUtils$IterableEnumeration
0%
0/7
0%
0/2
2.65
CollectionUtils$IterableEnumeration$1
0%
0/4
N/A
2.65
CollectionUtils$IterableIterator
0%
0/7
0%
0/2
2.65
CollectionUtils$SimpleEnumeration
0%
0/14
0%
0/8
2.65
 
 1  
 /*
 2  
  * Copyright 2007-2010 The Kuali Foundation
 3  
  *
 4  
  * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
 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  
 package org.kuali.rice.core.api.util.collect;
 17  
 
 18  
 import java.lang.reflect.Field;
 19  
 import java.util.ArrayList;
 20  
 import java.util.Collection;
 21  
 import java.util.Collections;
 22  
 import java.util.Enumeration;
 23  
 import java.util.Iterator;
 24  
 import java.util.List;
 25  
 import java.util.Map;
 26  
 import java.util.Set;
 27  
 
 28  
 /**
 29  
  * Yet another utility class to help work with Collections. This class contains helper methods not
 30  
  * found in any of the Collection utilities rice currently uses.
 31  
  * 
 32  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 33  
  * 
 34  
  */
 35  
 public final class CollectionUtils {
 36  
 
 37  
     /** do not call. */
 38  0
     private CollectionUtils() {
 39  0
         throw new UnsupportedOperationException("do not call");
 40  
     }
 41  
 
 42  
     /**
 43  
      * Performs a "brute force" comparison of collections by testing whether the collections contain
 44  
      * each other. This circumvents any particular uniqueness or ordering constraints on the
 45  
      * collections (for instance, lists that are unordered but contain the same elements, where a
 46  
      * hashset would not suffice for comparison purposes because it enforces element uniqueness)
 47  
      */
 48  
     public static boolean collectionsEquivalent(Collection<?> a, Collection<?> b) {
 49  0
         if (a == null && b == null) {
 50  0
             return true;
 51  
         }
 52  0
         if (a == null ^ b == null) {
 53  0
             return false;
 54  
         }
 55  0
         return a.containsAll(b) && b.containsAll(a);
 56  
     }
 57  
 
 58  
     /**
 59  
      * Creates an Iterable view of a Iterator. This allows Iterators to be used in a foreach loop.
 60  
      * 
 61  
      * <pre>
 62  
          * {@code
 63  
          *   Iterator<String> i ...
 64  
          * 
 65  
          *   for(String s : CollectionUtils.toIterable(i)) [
 66  
          *     System.out.println("i love for each " + s);        
 67  
          *   }
 68  
          * }
 69  
          * </pre>
 70  
      * 
 71  
      * @param <T> the type of the Iterable
 72  
      * @param i the iterator to wrap
 73  
      * @return the iterable
 74  
      */
 75  
     public static <T> Iterable<T> toIterable(Iterator<T> i) {
 76  0
         return new IterableIterator<T>(i);
 77  
     }
 78  
 
 79  
     /**
 80  
      * Creates an Iterable view of a Enumeration. This allows Enumerations to be used in a foreach
 81  
      * loop.
 82  
      * 
 83  
      * <pre>
 84  
          * {@code
 85  
          *   Enumeration<String> e ...
 86  
          * 
 87  
          *   for(String s : CollectionUtils.toIterable(e)) [
 88  
          *     System.out.println("i love for each " + s);        
 89  
          *   }
 90  
          * }
 91  
          * </pre>
 92  
      * 
 93  
      * @param <T> the type of the Iterable
 94  
      * @param e the enumeration to wrap
 95  
      * @return the iterable
 96  
      */
 97  
     public static <T> Iterable<T> toIterable(Enumeration<T> e) {
 98  0
         return new IterableEnumeration<T>(e);
 99  
     }
 100  
 
 101  
     /**
 102  
      * Functions as per {@link Collections#unmodifiableList(Collection)} with the exception that if the
 103  
      * given collection is null, this method will return an unmodifiable empty collection as per
 104  
      * {@link Collections#emptyList()}.
 105  
      *
 106  
      * @param collection the collection for which an unmodifiable view is to be returned
 107  
      * @return an unmodifiable view of the specified collection, or an unmodifiable empty collection if the
 108  
      *         given collection is null
 109  
      */
 110  
     public static <T> Collection<T> unmodifiableCollectionNullSafe(Collection<? extends T> collection) {
 111  0
         if (collection == null) {
 112  0
             return Collections.emptyList();
 113  
         }
 114  0
         return Collections.unmodifiableCollection(collection);
 115  
     }
 116  
 
 117  
     /**
 118  
      * Functions as per {@link Collections#unmodifiableList(List)} with the exception that if the
 119  
      * given list is null, this method will return an unmodifiable empty list as per
 120  
      * {@link Collections#emptyList()}.
 121  
      * 
 122  
      * @param list the list for which an unmodifiable view is to be returned
 123  
      * @return an unmodifiable view of the specified list, or an unmodifiable empty list if the
 124  
      *         given list is null
 125  
      */
 126  
     public static <T> List<T> unmodifiableListNullSafe(List<? extends T> list) {
 127  212
         if (list == null) {
 128  183
             return Collections.emptyList();
 129  
         }
 130  29
         return Collections.unmodifiableList(list);
 131  
     }
 132  
 
 133  
     /**
 134  
      * Functions as per {@link Collections#unmodifiableSet(Set)} with the exception that if the
 135  
      * given set is null, this method will return an unmodifiable empty set as per
 136  
      * {@link Collections#emptySet()}.
 137  
      * 
 138  
      * @param set the set for which an unmodifiable view is to be returned
 139  
      * @return an unmodifiable view of the specified set, or an unmodifiable empty set if the given
 140  
      *         set is null
 141  
      */
 142  
     public static <T> Set<T> unmodifiableSetNullSafe(Set<? extends T> set) {
 143  22
         if (set == null) {
 144  0
             return Collections.emptySet();
 145  
         }
 146  22
         return Collections.unmodifiableSet(set);
 147  
     }
 148  
 
 149  
     /**
 150  
      * Functions as per {@link Collections#unmodifiableMap(Map)} with the exception that if the
 151  
      * given map is null, this method will return an unmodifiable empty map as per
 152  
      * {@link Collections#emptyMap()}.
 153  
      * 
 154  
      * @param map the map for which an unmodifiable view is to be returned
 155  
      * @return an unmodifiable view of the specified set, or an unmodifiable empty set if the given
 156  
      *         set is null
 157  
      */
 158  
     public static <K, V> Map<K, V> unmodifiableMapNullSafe(Map<? extends K, ? extends V> map) {
 159  22
         if (map == null) {
 160  3
             return Collections.emptyMap();
 161  
         }
 162  19
         return Collections.unmodifiableMap(map);
 163  
     }
 164  
 
 165  
     /**
 166  
      * This method will iterate over all the fields on an object searching for declared fields defined as
 167  
      * Collection, List, Set, Map type.  If those fields are null they will be set to empty unmodifiable
 168  
      * instances.  If those fields are not null then it will force them to be unmodifiable.
 169  
      *
 170  
      * This method does not handle nested types.
 171  
      *
 172  
      * @param o the object to modify.  a null object will do nothing.
 173  
      */
 174  
     public static void makeUnmodifiableAndNullSafe(Object o) throws IllegalAccessException {
 175  173
         if (o == null) {
 176  0
             return;
 177  
         }
 178  
 
 179  173
         Class<?> targetClass = o.getClass();
 180  904
         for (Field f : targetClass.getDeclaredFields()) {
 181  731
             f.setAccessible(true);
 182  
             try {
 183  731
                 if (f.getType().isAssignableFrom(List.class)) {
 184  212
                     f.set(o, unmodifiableListNullSafe((List<?>) f.get(o)));
 185  519
                 } else if (f.getType().isAssignableFrom(Set.class)) {
 186  22
                     f.set(o, unmodifiableSetNullSafe((Set<?>) f.get(o)));
 187  497
                 } else if (f.getType().isAssignableFrom(Collection.class)) {
 188  0
                     f.set(o, unmodifiableCollectionNullSafe((Collection<?>) f.get(o)));
 189  497
                 } else if (f.getType().isAssignableFrom(Map.class)) {
 190  22
                     f.set(o, unmodifiableMapNullSafe((Map<?, ?>) f.get(o)));
 191  
                 }
 192  
             } finally {
 193  731
                 f.setAccessible(false);
 194  731
             }
 195  
         }
 196  173
     }
 197  
 
 198  
     /**
 199  
     * Combines multiple Enumeration into a single enumeration. The returned enumeration
 200  
     * has an enumeration that traverses the elements of each enumeration in
 201  
     * {@code inputs}. The input enumerations are not polled until necessary.
 202  
     *
 203  
     * @throws NullPointerException if any of the provided enumerations are null
 204  
     */
 205  
     public static <T> Enumeration<T> concat(Enumeration<? extends T>... inputs) {
 206  0
     return new SimpleEnumeration<T>(inputs);
 207  
     }
 208  
 
 209  0
     private static class SimpleEnumeration<T> implements Enumeration<T> {
 210  
         private final Iterator<T> iterator;
 211  
 
 212  0
         private SimpleEnumeration(Enumeration<? extends T>... enumerations) {
 213  0
             if (enumerations == null) {
 214  0
                 throw new NullPointerException("enumerations is null");
 215  
             }
 216  
 
 217  0
             final List<T> internalList = new ArrayList<T>();
 218  0
             for (Enumeration<? extends T> enumeration : enumerations) {
 219  0
                 if (enumeration == null) {
 220  0
                     throw new NullPointerException("input is null");
 221  
                 }
 222  
 
 223  0
                 while (enumeration.hasMoreElements()) {
 224  0
                     internalList.add(enumeration.nextElement());
 225  
                 }
 226  
             }
 227  0
             iterator = internalList.iterator();
 228  0
         }
 229  
 
 230  
         @Override
 231  
         public boolean hasMoreElements() {
 232  0
             return iterator.hasNext();
 233  
         }
 234  
         @Override
 235  
         public T nextElement() {
 236  0
             return iterator.next();
 237  
         }
 238  
     }
 239  
 
 240  
     /**
 241  
      * An adapter from an Enumeration to Iterable.
 242  
      * 
 243  
      * @author Kuali Rice Team (rice.collab@kuali.org)
 244  
      * 
 245  
      * @param <T> the type of Enumeration and Iterable
 246  
      */
 247  0
     private static class IterableEnumeration<T> implements Iterable<T> {
 248  
         private final Enumeration<T> e;
 249  
 
 250  0
         private IterableEnumeration(final Enumeration<T> e) {
 251  0
             if (e == null) {
 252  0
                 throw new IllegalArgumentException("the enumeration is null");
 253  
             }
 254  
 
 255  0
             this.e = e;
 256  0
         }
 257  
 
 258  
         @Override
 259  
         public Iterator<T> iterator() {
 260  0
             return new Iterator<T>() {
 261  
                 @Override
 262  
                 public boolean hasNext() {
 263  0
                     return e.hasMoreElements();
 264  
                 }
 265  
 
 266  
                 @Override
 267  
                 public T next() {
 268  0
                     return e.nextElement();
 269  
                 }
 270  
 
 271  
                 @Override
 272  
                 public void remove() {
 273  0
                     throw new UnsupportedOperationException("this iterator does not support remove");
 274  
                 }
 275  
             };
 276  
         }
 277  
     }
 278  
 
 279  
     /**
 280  
      * An adapter from an Iterator to Iterable.
 281  
      * 
 282  
      * @author Kuali Rice Team (rice.collab@kuali.org)
 283  
      * 
 284  
      * @param <T> the type of Iterator and Iterable
 285  
      */
 286  0
     private static class IterableIterator<T> implements Iterable<T> {
 287  
         private final Iterator<T> i;
 288  
 
 289  0
         private IterableIterator(final Iterator<T> i) {
 290  0
             if (i == null) {
 291  0
                 throw new IllegalArgumentException("the iterator is null");
 292  
             }
 293  
 
 294  0
             this.i = i;
 295  0
         }
 296  
 
 297  
         @Override
 298  
         public Iterator<T> iterator() {
 299  0
             return i;
 300  
         }
 301  
     }
 302  
 }