All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.tsl2.nano.collection.CollectionUtil Maven / Gradle / Ivy

There is a newer version: 2.5.1
Show newest version
/*
 * Copyright © 2002-2009 Thomas Schneider
 * Alle Rechte vorbehalten.
 * Weiterverbreitung, Benutzung, Vervielfältigung oder Offenlegung,
 * auch auszugsweise, nur mit Genehmigung.
 * 
 * $Id$ 
 */
package de.tsl2.nano.collection;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import de.tsl2.nano.core.IPredicate;
import de.tsl2.nano.core.ITransformer;
import de.tsl2.nano.core.ManagedException;
import de.tsl2.nano.core.cls.BeanAttribute;
import de.tsl2.nano.core.util.ListSet;
import de.tsl2.nano.core.util.ObjectUtil;
import de.tsl2.nano.core.util.StringUtil;

/**
 * some transformation und filter methods for collections
 * 
 * @author Thomas Schneider
 * @version $Revision$
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
public class CollectionUtil extends de.tsl2.nano.core.util.CollectionUtil {
//    private static final Log LOG = LogFactory.getLog(CollectionUtil.class);

    /**
     * if both interfaces ({@link List} and {@link Set}) are needed for one instance, the given collection will be
     * wrapped into a {@link ListSet}.
     * 
     * @param  item type
     * @param listOrSet implementation of {@link List} or {@link Set} to be combined in a new instance of
     *            {@link ListSet}.
     * @return new instanceof {@link ListSet}.
     *         

* TODO: how to create generics expression to define Set or List like: , L extends List> * with listOrSet ? */ public static final ListSet asListSet(Collection listOrSet) { if (listOrSet instanceof ListSet) { return (ListSet) listOrSet; } else { return new ListSet(listOrSet); } } /** * delegates to {@link #getTransformedCollection(Collection, String, Class)}. */ public static Collection getTransformedCollection(Collection toTransform, final String attributeName) { return (Collection) getTransformedCollection(toTransform, attributeName, Object.class); } /** * transform a collection. * * @param real type of collection items * @param transformed type of collection items * @param toTransform original collection * @param attributeName attribute name to use to get the transformed type * @return transformed collection */ public static Collection getTransformedCollection(Collection toTransform, final String attributeName, Class transformedType) { final ITransformer transformer = new ITransformer() { BeanAttribute attribute = null; @Override public T transform(S arg0) { if (attribute == null) { attribute = BeanAttribute.getBeanAttribute(arg0.getClass(), attributeName); } return (T) attribute.getValue(arg0); } }; return getList(getTransforming(toTransform, transformer).iterator()); } public static Collection toStringTransformed(Collection toTransform) { final ITransformer transformer = new ITransformer() { @Override public String transform(S arg0) { return arg0 != null ? arg0.toString() : ""; } }; return getList(getTransforming(toTransform, transformer).iterator()); } /** * @deprecated: use {@link #getFilteringBetween(Iterable, Comparable, Comparable)} or * {@link #getFilteringBetween(Iterable, Object, Object, boolean)} instead. getFilteredCollection * * @param src full collection * @param predicate filter * @return filtering collection */ public static Collection getFilteredCollection(Iterable src, IPredicate predicate) { return getList(getFiltering(src, predicate).iterator()); } /** * remove * * @param collection type * @param source source collection * @param attributeName attribute name of type * @param value value to search to be removed * @return removed item or null, if remove failed */ public static final T remove(Collection source, Class type, String attributeName, Object value) { final BeanAttribute attribute = BeanAttribute.getBeanAttribute(type, attributeName); for (final T t : source) { if (value.equals(attribute.getValue(t))) { if (source.remove(t)) { return t; } else { return null; } } } return null; } /** * finds an entry through bean-reflection * * @param collection type * @param source source collection * @param attributeName attribute name of type * @param value value to search to be found * @return found item or null */ public static final T find(Collection source, Class type, String attributeName, Object value) { final BeanAttribute attribute = BeanAttribute.getBeanAttribute(type, attributeName); for (final T t : source) { if (value.equals(attribute.getValue(t))) { return t; } } return null; } /** * wrap source collection holding instances of type 'type' into a new collection - holding values given by * attributeName. * * @param source collection item type * @param source source collection * @param type source collection type * @param attributeName attribute of source collection item to get the value as wrapper stored in the new collection * @return new collection holding wrapped item instances */ public static final Collection wrap(Collection source, Class type, String attributeName) { final Collection wrapCollection = new ArrayList(source.size()); final BeanAttribute attribute = BeanAttribute.getBeanAttribute(type, attributeName); for (final T t : source) { wrapCollection.add(attribute.getValue(t)); } return wrapCollection; } /** * iterates through next count elements and returns a new sublist containing them. useful for performance * optimizations sending statements to a server. if you don't need a transformer you may use List.sublist(..) * instead. *

* Example: * *

     * Collection myEntities = null;
     * Iterator<MySearchViewBean> searchIt = akten.iterator();
     * ITransformer<MySearchViewBean, Long> toNumbers = new ITransformer<MySearchViewBean, Long>() {
     *     @Override
     *     public Long transform(MySearchViewBean arg0) {
     *         return arg0.getSpecificNumber();
     *     }
     * };
     * for (Collection<Long> specNumbers = CollectionUtil.next(searchIt, blockSize, toNumbers); searchIt.hasNext(); specNumbers = CollectionUtil.next(searchIt,
     *     blockSize,
     *     toNumbers)) {
     *     myEntities = myService.getMyEntityBeans(specNumbers);
     *     ...
     * }
     * 
     * 
* * @param element type * @param elements iterator on each next call this iterator should be the identical instance! * @param count block size for. will be the size of the returned sub list * @param transformer (optional) to transform the items of elements to the type T to be filled into the new list. * @return sublist */ public static final Collection next(Iterator elements, int count, ITransformer transformer) { ArrayList sublist = new ArrayList(count); for (int i = 0; i < count && elements.hasNext(); i++) { sublist.add(transformer != null ? transformer.transform(elements.next()) : (T) elements.next()); } return sublist; } /** * delegates to {@link #getFilteringBetween(Iterable, Comparable, Comparable)}, copying the filtered list. */ public static final > Collection getFilteredBetween(Collection src, final T from, final T to) { return getList(getFilteringBetween(src, from, to).iterator()); } /** * delegates to {@link #getFilteringBetween(Iterable, Object, Object, boolean)}, copying the filtered list. */ public static final Collection getFilteredBetween(Collection src, final T from, final T to, final boolean ignoreCase) { return getList(getFilteringBetween(src, from, to, ignoreCase).iterator()); } /** * getFiltering * * @param src collection to filter * @param filter filter * @return filtering collection */ public static final , T> I getFiltering(I src, IPredicate filter) { return FilteringIterator.getFilteringIterable(src, filter); } /** * getFiltering * * @param src map to filter * @param filter key filter * @return filtering map */ public static final , S, T extends Comparable> I getFilteringMapKey(I src, IPredicate filter) { return FilteringIterator.getFilteringMap(src, filter); } /** * filters the given collection. *

* Attention: if 'expression' changes afterwards, the collection iterator may change, too! If you do not want that, * use {@link #getList(Iterator) to create a copy. * * @param collection item type * @param src collection to filter * @param expression regular expression to be used as filter. the toString() methods of objects will be used to * match against. * @return filtered collection */ public static final , T> I getFiltering(I src, final StringBuilder expression) { return FilteringIterator.getFilteringIterable(src, new IPredicate() { @Override public boolean eval(T arg0) { String arg = arg0 != null ? arg0.toString() : ""; return arg.matches(expression.toString()); } }); } /** * filters the given collection. *

* Attention: if 'from' or 'to' are mutables and change afterwards, the collection iterator may change, too! If you * do not want that, use {@link #getList(Iterator)} to create a copy. * * @param collection item type * @param src collection to filter * @param from minimum object * @param to maximum object * @return filtered collection */ public static final , T extends Comparable> I getFilteringBetween(I src, final T from, final T to) { if (from == null && to == null) { return src; } final boolean useNull = from == null || to == null; return FilteringIterator.getFilteringIterable(src, new IPredicate() { @Override public boolean eval(T arg) { return (arg == null && useNull) || ((from == null || arg.compareTo(from) >= 0) && (to == null || arg.compareTo(to) <= 0)); } }); } /** * filters the given collection through its string representations. *

* Attention: if 'from' or 'to' are mutables and change afterwards, the collection iterator may change, too! If you * do not want that, use {@link #getList(Iterator)} to create a copy. * * @param collection item type * @param src collection to filter * @param from minimum object * @param to maximum object * @return filtered collection */ public static final , T> I getFilteringBetween(I src, final T from, final T to, final boolean ignoreCase) { if (from == null && to == null) { return src; } return FilteringIterator.getFilteringIterable(src, new IPredicate() { @Override public boolean eval(T arg0) { // to be able to reuse the predicate, we can't do the calculations outside (which would be better for the performance) String sfrom = from != null && !ObjectUtil.isEmpty(from) ? ignoreCase && from.toString() != null ? from.toString() .toUpperCase() : from.toString() : null; if (StringUtil.STR_ANY.equals(sfrom)) { sfrom = null; } String sto = to != null && !ObjectUtil.isEmpty(to) ? ignoreCase && to.toString() != null ? to.toString() .toUpperCase() : to.toString() : null; if (StringUtil.STR_ANY.equals(sto)) { sto = null; } boolean useNull = from == null || to == null; String sarg = arg0 != null ? ignoreCase && arg0.toString() != null ? arg0.toString().toUpperCase() : arg0.toString() : null; return (sarg == null && useNull) || ((sfrom == null || sarg.compareTo(sfrom) >= 0) && (sto == null || sarg.compareTo(sto) <= 0)); } }); } /** * getTransforming * * @param iterable type * @param iterable content type * @param src mostly a collection * @param transformer transformer * @return proxied iterable giving {@link TransformingIterator} as iterator. */ public static final , S, T> I getTransforming(Iterable src, ITransformer transformer) { return TransformingIterator.getTransformingIterable(src, transformer); } /** * combines transforming and filtering a collection * * @param iterable type * @param iterable content type * @param src mostly a collection * @param transformer transformer * @param filter filter * @return filtered and transformed iterable */ public static final , S, T> I getTransforming(Iterable src, ITransformer transformer, IPredicate filter) { return TransformingIterator.getTransformingIterable((Iterable) getFiltering((Iterable) src, filter), transformer); } /** * see {@link MapEntrySet}. * * @param m map to wrap into a proxy to combine the both interfaces {@link List} and {@link Map}. * @return proxy implementing both interfaces through delegation. */ public static Set> asEntrySetExtender(final Map m) { // /** // * Extender of a maps entry set - used by MapUtil to provide a combination of Collection and Map. workaround in cause of // * interface naming clash of {@link Collection} and {@link Map} (method remove(Object) with different return types). // * // * @author Tom // * @version $Revision$ // */ // public interface EntrySetExtender { // /** // * @return the map behind the entry set // */ // Map map(); // // /** // * overwrite the entryset add method that will throw an unsupported operation exception. // */ // boolean add(E entry); // boolean addAll(Collection c); // /** // * creates a new entry using the {@link #map()}. the new entry should be returned. // */ // Map.Entry addEntry(K key, V value); // } // EntrySetExtender entrySetExtender = new EntrySetExtender() { // PrivateAccessor> mapAccessor = new PrivateAccessor>(m); // // @Override // public Map map() { // return m; // } // // @Override // public boolean add(Object entry) { // Map.Entry e = (Entry) entry; // addEntry(e.getKey(), e.getValue()); // return true; // } // // @Override // public boolean addAll(Collection c) { // for (Object object : c) { // Map.Entry e = (Entry) object; // m.put(e.getKey(), e.getValue()); // } // return true; // } // // @Override // public Entry addEntry(K key, V value) { // m.put(key, value); // return mapAccessor.call("getEntry", Map.Entry.class, new Class[] { Object.class }, key); // } // // }; return new MapEntrySet(m); // return (Set>) DelegatorProxy.delegator(new Class[] { EntrySetExtender.class, Set.class }, // entrySetExtender, m.entrySet()); // return (Set>) MultipleInheritanceProxy.createMultipleInheritance(new Class[] { EntrySetExtender.class, // Set.class }, Arrays.asList(entrySetExtender, m.entrySet()), EntrySetExtender.class.getClassLoader()); } /** * if {@link #isContainer(Object)} returns true, obj is an array, collection or map. this method returns a * collection where obj is wrapped into. * * @param obj * @return */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static final Collection getContainer(Object obj) { if (obj == null) { return null; } Class cls = obj.getClass(); if (cls.isArray()) { return asList(obj); } else if (Collection.class.isAssignableFrom(cls)) { return (Collection) obj; } else if (Map.class.isAssignableFrom(cls)) { return CollectionUtil.asEntrySetExtender((Map) obj); } else { throw new ManagedException(obj + " is not a container!"); } } }