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

org.gradle.util.CollectionUtils Maven / Gradle / Ivy

There is a newer version: 8.11.1
Show newest version
/*
 * Copyright 2022 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.gradle.util;

import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import org.gradle.api.Action;
import org.gradle.api.Transformer;
import org.gradle.api.specs.Spec;
import org.gradle.internal.Factory;
import org.gradle.internal.Pair;
import org.gradle.internal.Transformers;
import org.gradle.internal.deprecation.DeprecationLogger;

import javax.annotation.Nullable;
import java.lang.reflect.Array;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;

import static org.gradle.internal.Cast.cast;
import static org.gradle.internal.Cast.castNullable;
import static org.gradle.internal.Cast.uncheckedNonnullCast;

/**
 * This class is only here to maintain binary compatibility with existing plugins.
 * 

* Plugins should prefer external collection frameworks over this class. * Internally, all code should use {@link org.gradle.util.internal.CollectionUtils}. * * @deprecated Will be removed in Gradle 9.0. */ @Deprecated public abstract class CollectionUtils { private static void logDeprecation(int upgradeGuideMajorVersion) { DeprecationLogger.deprecateType(CollectionUtils.class) .willBeRemovedInGradle9() .withUpgradeGuideSection(upgradeGuideMajorVersion, "org_gradle_util_reports_deprecations") .nagUser(); } public CollectionUtils() { logDeprecation(7); } /** * Returns null if the collection is empty otherwise expects a {@link #single(Iterable)} element to be found. */ @Nullable public static T findSingle(Iterable source) { logDeprecation(7); return Iterables.isEmpty(source) ? null : singleInternal(source); } /** * Returns the single element in the collection or throws. */ public static T single(Iterable source) { logDeprecation(7); return singleInternal(source); } private static T singleInternal(Iterable source) { Iterator iterator = source.iterator(); if (!iterator.hasNext()) { throw new NoSuchElementException("Expecting collection with single element, got none."); } T element = iterator.next(); if (iterator.hasNext()) { throw new IllegalArgumentException("Expecting collection with single element, got multiple."); } return element; } public static Collection checkedCast(Class type, Collection input) { logDeprecation(7); for (Object o : input) { castNullable(type, o); } return uncheckedNonnullCast(input); } @Nullable public static T findFirst(Iterable source, Spec filter) { logDeprecation(7); for (T item : source) { if (filter.isSatisfiedBy(item)) { return item; } } return null; } @Nullable public static T findFirst(T[] source, Spec filter) { logDeprecation(7); for (T thing : source) { if (filter.isSatisfiedBy(thing)) { return thing; } } return null; } public static T first(Iterable source) { logDeprecation(7); return source.iterator().next(); } public static boolean any(Iterable source, Spec filter) { return findFirst(source, filter) != null; } public static boolean any(T[] source, Spec filter) { return findFirst(source, filter) != null; } public static Set filter(Set set, Spec filter) { return filter(set, new LinkedHashSet(), filter); } public static List filter(List list, Spec filter) { return filter(list, Lists.newArrayListWithCapacity(list.size()), filter); } public static List filter(T[] array, Spec filter) { return filter(Arrays.asList(array), Lists.newArrayListWithCapacity(array.length), filter); } /** * Returns a sorted copy of the provided collection of things. Uses the provided comparator to sort. */ public static List sort(Iterable things, Comparator comparator) { List copy = toMutableList(things); Collections.sort(copy, comparator); return copy; } /** * Returns a sorted copy of the provided collection of things. Uses the natural ordering of the things. */ public static > List sort(Iterable things) { List copy = toMutableList(things); Collections.sort(copy); return copy; } public static > C filter(Iterable source, C destination, Spec filter) { logDeprecation(7); for (T item : source) { if (filter.isSatisfiedBy(item)) { destination.add(item); } } return destination; } public static Map filter(Map map, Spec> filter) { return filter(map, new HashMap(), filter); } public static Map filter(Map map, Map destination, Spec> filter) { logDeprecation(7); for (Map.Entry entry : map.entrySet()) { if (filter.isSatisfiedBy(entry)) { destination.put(entry.getKey(), entry.getValue()); } } return destination; } public static R[] collectArray(I[] list, Class newType, Transformer transformer) { @SuppressWarnings("unchecked") R[] destination = (R[]) Array.newInstance(newType, list.length); return collectArray(list, destination, transformer); } public static R[] collectArray(I[] list, R[] destination, Transformer transformer) { logDeprecation(7); assert list.length <= destination.length; for (int i = 0; i < list.length; ++i) { destination[i] = transformer.transform(list[i]); } return destination; } public static List collect(I[] list, Transformer transformer) { return collect(Arrays.asList(list), transformer); } public static Set collect(Set set, Transformer transformer) { return collect(set, new HashSet(set.size()), transformer); } public static List collect(Iterable source, Transformer transformer) { if (source instanceof Collection) { Collection collection = uncheckedNonnullCast(source); return collect(source, new ArrayList(collection.size()), transformer); } else { return collect(source, new LinkedList(), transformer); } } public static > C collect(Iterable source, C destination, Transformer transformer) { logDeprecation(7); return collectInternal(source, destination, transformer); } private static > C collectInternal(Iterable source, C destination, Transformer transformer) { for (I item : source) { destination.add(transformer.transform(item)); } return destination; } public static List toStringList(Iterable iterable) { return collect(iterable, new LinkedList(), String::valueOf); } /** * Recursively unpacks all the given things into a flat list. * * Nulls are not removed, they are left intact. * * @param things The things to flatten * @return A flattened list of the given things */ public static List flattenCollections(Object... things) { return flattenCollections(Object.class, things); } /** * Recursively unpacks all the given things into a flat list, ensuring they are of a certain type. * * Nulls are not removed, they are left intact. * * If a non null object cannot be cast to the target type, a ClassCastException will be thrown. * * @param things The things to flatten * @param The target type in the flattened list * @return A flattened list of the given things */ public static List flattenCollections(Class type, Object... things) { logDeprecation(7); return flattenCollectionsInternal(type, things); } private static List flattenCollectionsInternal(Class type, Object... things) { if (things == null) { return Collections.singletonList(null); } else if (things.length == 0) { return Collections.emptyList(); } else if (things.length == 1) { Object thing = things[0]; if (thing == null) { return Collections.singletonList(null); } // Casts to Class below are to workaround Eclipse compiler bug // See: https://github.com/gradle/gradle/pull/200 if (thing.getClass().isArray()) { Object[] thingArray = (Object[]) thing; List list = new ArrayList(thingArray.length); for (Object thingThing : thingArray) { list.addAll(flattenCollections(type, thingThing)); } return list; } if (thing instanceof Collection) { Collection collection = (Collection) thing; List list = new ArrayList(); for (Object element : collection) { list.addAll(flattenCollections(type, element)); } return list; } return Collections.singletonList(cast(type, thing)); } else { List list = new ArrayList(); for (Object thing : things) { list.addAll(flattenCollections(type, thing)); } return list; } } public static List toList(Iterable things) { if (things instanceof List) { logDeprecation(7); @SuppressWarnings("unchecked") List castThings = (List) things; return castThings; } return toMutableList(things); } public static List toList(Enumeration things) { logDeprecation(7); AbstractList list = new ArrayList(); while (things.hasMoreElements()) { list.add(things.nextElement()); } return list; } private static List toMutableList(Iterable things) { logDeprecation(7); if (things == null) { return new ArrayList(0); } List list = new ArrayList(); for (T thing : things) { list.add(thing); } return list; } public static List intersection(Collection> availableValuesByDescriptor) { logDeprecation(7); List result = new ArrayList(); Iterator> iterator = availableValuesByDescriptor.iterator(); if (iterator.hasNext()) { Collection firstSet = iterator.next(); result.addAll(firstSet); while (iterator.hasNext()) { Collection next = iterator.next(); result.retainAll(next); } } return result; } public static List toList(T[] things) { logDeprecation(7); if (things == null || things.length == 0) { return new ArrayList(0); } List list = new ArrayList(things.length); Collections.addAll(list, things); return list; } public static Set toSet(Iterable things) { logDeprecation(7); if (things == null) { return new HashSet(0); } if (things instanceof Set) { @SuppressWarnings("unchecked") Set castThings = (Set) things; return castThings; } Set set = new LinkedHashSet(); for (T thing : things) { set.add(thing); } return set; } public static List compact(List list) { logDeprecation(7); boolean foundAtLeastOneNull = false; List compacted = null; int i = 0; for (E element : list) { if (element == null) { if (!foundAtLeastOneNull) { compacted = new ArrayList(list.size()); if (i > 0) { compacted.addAll(list.subList(0, i)); } } foundAtLeastOneNull = true; } else if (foundAtLeastOneNull) { compacted.add(element); } ++i; } return foundAtLeastOneNull ? compacted : list; } public static > C stringize(Iterable source, C destination) { logDeprecation(7); return stringizeInternal(source, destination); } public static List stringize(Collection source) { logDeprecation(8); return stringizeInternal(source, new ArrayList(source.size())); } private static > C stringizeInternal(Iterable source, C destination) { return collectInternal(source, destination, String::valueOf); } public static boolean replace(List list, Spec filter, Transformer transformer) { logDeprecation(7); boolean replaced = false; int i = 0; for (E it : list) { if (filter.isSatisfiedBy(it)) { list.set(i, transformer.transform(it)); replaced = true; } ++i; } return replaced; } public static void collectMap(Map destination, Iterable items, Transformer keyGenerator) { logDeprecation(7); for (V item : items) { destination.put(keyGenerator.transform(item), item); } } /** * Given a set of values, derive a set of keys and return a map */ public static Map collectMap(Iterable items, Transformer keyGenerator) { Map map = new LinkedHashMap(); collectMap(map, items, keyGenerator); return map; } public static void collectMapValues(Map destination, Iterable keys, Transformer keyGenerator) { logDeprecation(7); for (K item : keys) { destination.put(item, keyGenerator.transform(item)); } } /** * Given a set of keys, derive a set of values and return a map */ public static Map collectMapValues(Iterable keys, Transformer keyGenerator) { Map map = new LinkedHashMap(); collectMapValues(map, keys, keyGenerator); return map; } public static boolean every(Iterable things, Spec predicate) { logDeprecation(7); for (T thing : things) { if (!predicate.isSatisfiedBy(thing)) { return false; } } return true; } /** * Utility for adding an iterable to a collection. * * @param t1 The collection to add to * @param t2 The iterable to add each item of to the collection * @param The element type of t1 * @return t1 */ public static > C addAll(C t1, Iterable t2) { logDeprecation(7); for (T t : t2) { t1.add(t); } return t1; } /** * Utility for adding an array to a collection. * * @param t1 The collection to add to * @param t2 The iterable to add each item of to the collection * @param The element type of t1 * @return t1 */ // TODO Use @SafeVarargs and make method final @SuppressWarnings("unchecked") public static > C addAll(C t1, T... t2) { logDeprecation(7); Collections.addAll(t1, t2); return t1; } /** * The result of diffing two sets. * * @param The type of element the sets contain * @see CollectionUtils#diffSetsBy(java.util.Set, java.util.Set, org.gradle.api.Transformer) */ public static class SetDiff { public Set leftOnly = new HashSet(); public Set> common = new HashSet>(); public Set rightOnly = new HashSet(); public SetDiff() { this(true); } private SetDiff(boolean logDeprecation) { if (logDeprecation) { logDeprecation(7); } } } /** * Provides a “diff report” of how the two sets are similar and how they are different, comparing the entries by some aspect. * * The transformer is used to generate the value to use to compare the entries by. That is, the entries are not compared by equals by an attribute or characteristic. * * The transformer is expected to produce a unique value for each entry in a single set. Behaviour is undefined if this condition is not met. * * @param left The set on the “left” side of the comparison. * @param right The set on the “right” side of the comparison. * @param compareBy Provides the value to compare entries from either side by * @param The type of the entry objects * @return A representation of the difference */ public static SetDiff diffSetsBy(Set left, Set right, Transformer compareBy) { logDeprecation(7); if (left == null) { throw new NullPointerException("'left' set is null"); } if (right == null) { throw new NullPointerException("'right' set is null"); } SetDiff setDiff = new SetDiff(false); Map indexedLeft = collectMap(left, compareBy); Map indexedRight = collectMap(right, compareBy); for (Map.Entry leftEntry : indexedLeft.entrySet()) { T rightValue = indexedRight.remove(leftEntry.getKey()); if (rightValue == null) { setDiff.leftOnly.add(leftEntry.getValue()); } else { Pair pair = Pair.of(leftEntry.getValue(), rightValue); setDiff.common.add(pair); } } for (T rightValue : indexedRight.values()) { setDiff.rightOnly.add(rightValue); } return setDiff; } /** * Creates a string with {@code toString()} of each object with the given separator. * *

     * expect:
     * join(",", new Object[]{"a"}) == "a"
     * join(",", new Object[]{"a", "b", "c"}) == "a,b,c"
     * join(",", new Object[]{}) == ""
     * 
* * The {@code separator} must not be null and {@code objects} must not be null. * * @param separator The string by which to join each string representation * @param objects The objects to join the string representations of * @return The joined string */ public static String join(String separator, Object[] objects) { return join(separator, objects == null ? null : Arrays.asList(objects)); } /** * Creates a string with {@code toString()} of each object with the given separator. * *
     * expect:
     * join(",", ["a"]) == "a"
     * join(",", ["a", "b", "c"]) == "a,b,c"
     * join(",", []) == ""
     * 
* * The {@code separator} must not be null and {@code objects} must not be null. * * @param separator The string by which to join each string representation * @param objects The objects to join the string representations of * @return The joined string */ public static String join(String separator, Iterable objects) { logDeprecation(7); if (separator == null) { throw new NullPointerException("The 'separator' cannot be null"); } if (objects == null) { throw new NullPointerException("The 'objects' cannot be null"); } StringBuilder string = new StringBuilder(); Iterator iterator = objects.iterator(); if (iterator.hasNext()) { string.append(iterator.next().toString()); while (iterator.hasNext()) { string.append(separator); string.append(iterator.next().toString()); } } return string.toString(); } /** * Partition given Collection into a Pair of Collections. * *
Left
Collection containing entries that satisfy the given predicate *
Right
Collection containing entries that do NOT satisfy the given predicate */ public static Pair, Collection> partition(Iterable items, Spec predicate) { logDeprecation(7); Preconditions.checkNotNull(items, "Cannot partition null Collection"); Preconditions.checkNotNull(predicate, "Cannot apply null Spec when partitioning"); Collection left = new LinkedList(); Collection right = new LinkedList(); for (T item : items) { if (predicate.isSatisfiedBy(item)) { left.add(item); } else { right.add(item); } } return Pair.of(left, right); } /** * Injection step. * * @param target type. * @param item type. */ @Deprecated public static class InjectionStep { private final T target; private final I item; public InjectionStep(T target, I item) { this(target, item, true); } private InjectionStep(T target, I item, boolean logDeprecation) { this.target = target; this.item = item; if (logDeprecation) { logDeprecation(7); } } public T getTarget() { return target; } public I getItem() { return item; } } public static T inject(T target, Iterable items, Action> action) { logDeprecation(7); if (target == null) { throw new NullPointerException("The 'target' cannot be null"); } if (items == null) { throw new NullPointerException("The 'items' cannot be null"); } if (action == null) { throw new NullPointerException("The 'action' cannot be null"); } for (I item : items) { action.execute(new InjectionStep(target, item, false)); } return target; } public static Map> groupBy(Iterable iterable, Transformer grouper) { logDeprecation(7); ImmutableListMultimap.Builder builder = ImmutableListMultimap.builder(); for (V element : iterable) { K key = grouper.transform(element); builder.put(key, element); } return builder.build().asMap(); } public static Iterable unpack(final Iterable> factories) { logDeprecation(7); return new Iterable() { private final Iterator> delegate = factories.iterator(); @Override public Iterator iterator() { return new Iterator() { @Override public boolean hasNext() { return delegate.hasNext(); } @Override public T next() { return delegate.next().create(); } @Override public void remove() { throw new UnsupportedOperationException(); } }; } }; } @Nullable public static List nonEmptyOrNull(Iterable iterable) { logDeprecation(7); ImmutableList list = ImmutableList.copyOf(iterable); return list.isEmpty() ? null : list; } public static String asCommandLine(Iterable arguments) { logDeprecation(7); return Joiner.on(" ").join(collect(arguments, Transformers.asSafeCommandLineArgument())); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy