org.gradle.util.CollectionUtils Maven / Gradle / Ivy
Show all versions of gradle-api Show documentation
/*
* 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 extends T> source) {
logDeprecation(7);
return singleInternal(source);
}
private static T singleInternal(Iterable extends T> source) {
Iterator extends T> 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 extends T> checkedCast(Class type, Collection> input) {
logDeprecation(7);
for (Object o : input) {
castNullable(type, o);
}
return uncheckedNonnullCast(input);
}
@Nullable
public static T findFirst(Iterable extends T> source, Spec super T> filter) {
logDeprecation(7);
for (T item : source) {
if (filter.isSatisfiedBy(item)) {
return item;
}
}
return null;
}
@Nullable
public static T findFirst(T[] source, Spec super T> filter) {
logDeprecation(7);
for (T thing : source) {
if (filter.isSatisfiedBy(thing)) {
return thing;
}
}
return null;
}
public static T first(Iterable extends T> source) {
logDeprecation(7);
return source.iterator().next();
}
public static boolean any(Iterable extends T> source, Spec super T> filter) {
return findFirst(source, filter) != null;
}
public static boolean any(T[] source, Spec super T> filter) {
return findFirst(source, filter) != null;
}
public static Set filter(Set extends T> set, Spec super T> filter) {
return filter(set, new LinkedHashSet(), filter);
}
public static List filter(List extends T> list, Spec super T> filter) {
return filter(list, Lists.newArrayListWithCapacity(list.size()), filter);
}
public static List filter(T[] array, Spec super T> 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 extends T> things, Comparator super T> 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 extends T> source, C destination, Spec super T> 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 extends R, ? super I> 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 extends R, ? super I> 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 extends R, ? super I> transformer) {
return collect(Arrays.asList(list), transformer);
}
public static Set collect(Set extends I> set, Transformer extends R, ? super I> transformer) {
return collect(set, new HashSet(set.size()), transformer);
}
public static List collect(Iterable extends I> source, Transformer extends R, ? super I> transformer) {
if (source instanceof Collection>) {
Collection extends I> collection = uncheckedNonnullCast(source);
return collect(source, new ArrayList(collection.size()), transformer);
} else {
return collect(source, new LinkedList(), transformer);
}
}
public static > C collect(Iterable extends I> source, C destination, Transformer extends R, ? super I> transformer) {
logDeprecation(7);
return collectInternal(source, destination, transformer);
}
private static > C collectInternal(Iterable extends I> source, C destination, Transformer extends R, ? super I> 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 extends T> things) {
if (things instanceof List) {
logDeprecation(7);
@SuppressWarnings("unchecked") List castThings = (List) things;
return castThings;
}
return toMutableList(things);
}
public static List toList(Enumeration extends T> things) {
logDeprecation(7);
AbstractList list = new ArrayList();
while (things.hasMoreElements()) {
list.add(things.nextElement());
}
return list;
}
private static List toMutableList(Iterable extends T> 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 extends Collection> availableValuesByDescriptor) {
logDeprecation(7);
List result = new ArrayList();
Iterator extends Collection> 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 extends T> 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 super E> filter, Transformer extends E, ? super E> 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 extends V> items, Transformer extends K, ? super V> 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 extends V> items, Transformer extends K, ? super V> keyGenerator) {
Map map = new LinkedHashMap();
collectMap(map, items, keyGenerator);
return map;
}
public static void collectMapValues(Map destination, Iterable extends K> keys, Transformer extends V, ? super K> 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 extends K> keys, Transformer extends V, ? super K> keyGenerator) {
Map map = new LinkedHashMap();
collectMapValues(map, keys, keyGenerator);
return map;
}
public static boolean every(Iterable extends T> things, Spec super T> 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 extends T> 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 extends T> left, Set extends T> right, Transformer, T> 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