org.apache.commons.collections4.collection.PredicatedCollection Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.commons.collections4.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import org.apache.commons.collections4.Bag;
import org.apache.commons.collections4.MultiSet;
import org.apache.commons.collections4.Predicate;
import org.apache.commons.collections4.bag.HashBag;
import org.apache.commons.collections4.bag.PredicatedBag;
import org.apache.commons.collections4.functors.NotNullPredicate;
import org.apache.commons.collections4.list.PredicatedList;
import org.apache.commons.collections4.multiset.HashMultiSet;
import org.apache.commons.collections4.multiset.PredicatedMultiSet;
import org.apache.commons.collections4.queue.PredicatedQueue;
import org.apache.commons.collections4.set.PredicatedSet;
/**
* Decorates another {@link Collection} to validate that additions
* match a specified predicate.
*
* This collection exists to provide validation for the decorated collection.
* It is normally created to decorate an empty collection.
* If an object cannot be added to the collection, an IllegalArgumentException is thrown.
*
*
* One usage would be to ensure that no null entries are added to the collection:
*
*
* Collection coll = PredicatedCollection.predicatedCollection(new ArrayList(), NotNullPredicate.INSTANCE);
*
*
* This class is Serializable from Commons Collections 3.1.
*
*
* @param the type of the elements in the collection
* @since 3.0
*/
public class PredicatedCollection extends AbstractCollectionDecorator {
/** Serialization version */
private static final long serialVersionUID = -5259182142076705162L;
/** The predicate to use */
protected final Predicate super E> predicate;
/**
* Returns a Builder with the given predicate.
*
* @param the element type
* @param predicate the predicate to use
* @return a new Builder for predicated collections
* @since 4.1
*/
public static Builder builder(final Predicate super E> predicate) {
return new Builder<>(predicate);
}
/**
* Returns a Builder with a NotNullPredicate.
*
* @param the element type
* @return a new Builder for predicated collections that ignores null values.
* @since 4.1
*/
public static Builder notNullBuilder() {
return new Builder<>(NotNullPredicate.notNullPredicate());
}
/**
* Factory method to create a predicated (validating) collection.
*
* If there are any elements already in the collection being decorated, they
* are validated.
*
* @param the type of the elements in the collection
* @param coll the collection to decorate, must not be null
* @param predicate the predicate to use for validation, must not be null
* @return a new predicated collection
* @throws NullPointerException if collection or predicate is null
* @throws IllegalArgumentException if the collection contains invalid elements
* @since 4.0
*/
public static PredicatedCollection predicatedCollection(final Collection coll,
final Predicate super T> predicate) {
return new PredicatedCollection<>(coll, predicate);
}
//-----------------------------------------------------------------------
/**
* Constructor that wraps (not copies).
*
* If there are any elements already in the collection being decorated, they
* are validated.
*
* @param coll the collection to decorate, must not be null
* @param predicate the predicate to use for validation, must not be null
* @throws NullPointerException if collection or predicate is null
* @throws IllegalArgumentException if the collection contains invalid elements
*/
protected PredicatedCollection(final Collection coll, final Predicate super E> predicate) {
super(coll);
if (predicate == null) {
throw new NullPointerException("Predicate must not be null.");
}
this.predicate = predicate;
for (final E item : coll) {
validate(item);
}
}
/**
* Validates the object being added to ensure it matches the predicate.
*
* The predicate itself should not throw an exception, but return false to
* indicate that the object cannot be added.
*
* @param object the object being added
* @throws IllegalArgumentException if the add is invalid
*/
protected void validate(final E object) {
if (predicate.evaluate(object) == false) {
throw new IllegalArgumentException("Cannot add Object '" + object + "' - Predicate '" +
predicate + "' rejected it");
}
}
//-----------------------------------------------------------------------
/**
* Override to validate the object being added to ensure it matches
* the predicate.
*
* @param object the object being added
* @return the result of adding to the underlying collection
* @throws IllegalArgumentException if the add is invalid
*/
@Override
public boolean add(final E object) {
validate(object);
return decorated().add(object);
}
/**
* Override to validate the objects being added to ensure they match
* the predicate. If any one fails, no update is made to the underlying
* collection.
*
* @param coll the collection being added
* @return the result of adding to the underlying collection
* @throws IllegalArgumentException if the add is invalid
*/
@Override
public boolean addAll(final Collection extends E> coll) {
for (final E item : coll) {
validate(item);
}
return decorated().addAll(coll);
}
/**
* Builder for creating predicated collections.
*
* Create a Builder with a predicate to validate elements against, then add any elements
* to the builder. Elements that fail the predicate will be added to a rejected list.
* Finally create or decorate a collection using the createPredicated[List,Set,Bag,Queue] methods.
*
* An example:
*
* Predicate<String> predicate = NotNullPredicate.notNullPredicate();
* PredicatedCollectionBuilder<String> builder = PredicatedCollection.builder(predicate);
* builder.add("item1");
* builder.add(null);
* builder.add("item2");
* List<String> predicatedList = builder.createPredicatedList();
*
*
* At the end of the code fragment above predicatedList is protected by the predicate supplied
* to the builder and it contains item1 and item2.
*
* More elements can be added to the builder once a predicated collection has been created,
* but these elements will not be reflected in already created collections.
*
* @param the element type
* @since 4.1
*/
public static class Builder {
/** The predicate to use. */
private final Predicate super E> predicate;
/** The buffer containing valid elements. */
private final List accepted = new ArrayList<>();
/** The buffer containing rejected elements. */
private final List rejected = new ArrayList<>();
// -----------------------------------------------------------------------
/**
* Constructs a PredicatedCollectionBuilder with the specified Predicate.
*
* @param predicate the predicate to use
* @throws NullPointerException if predicate is null
*/
public Builder(final Predicate super E> predicate) {
if (predicate == null) {
throw new NullPointerException("Predicate must not be null");
}
this.predicate = predicate;
}
/**
* Adds the item to the builder.
*
* If the predicate is true, it is added to the list of accepted elements,
* otherwise it is added to the rejected list.
*
* @param item the element to add
* @return the PredicatedCollectionBuilder.
*/
public Builder add(final E item) {
if (predicate.evaluate(item)) {
accepted.add(item);
} else {
rejected.add(item);
}
return this;
}
/**
* Adds all elements from the given collection to the builder.
*
* All elements for which the predicate evaluates to true will be added to the
* list of accepted elements, otherwise they are added to the rejected list.
*
* @param items the elements to add to the builder
* @return the PredicatedCollectionBuilder.
*/
public Builder addAll(final Collection extends E> items) {
if (items != null) {
for (final E item : items) {
add(item);
}
}
return this;
}
/**
* Create a new predicated list filled with the accepted elements.
*
* The builder is not modified by this method, so it is possible to create more collections
* or add more elements afterwards. Further changes will not propagate to the returned list.
*
* @return a new predicated list.
*/
public List createPredicatedList() {
return createPredicatedList(new ArrayList());
}
/**
* Decorates the given list with validating behavior using the predicate. All accepted elements
* are appended to the list. If the list already contains elements, they are validated.
*
* The builder is not modified by this method, so it is possible to create more collections
* or add more elements afterwards. Further changes will not propagate to the returned list.
*
* @param list the List to decorate, must not be null
* @return the decorated list.
* @throws NullPointerException if list is null
* @throws IllegalArgumentException if list contains invalid elements
*/
public List createPredicatedList(final List list) {
if (list == null) {
throw new NullPointerException("List must not be null.");
}
final List predicatedList = PredicatedList.predicatedList(list, predicate);
predicatedList.addAll(accepted);
return predicatedList;
}
/**
* Create a new predicated set filled with the accepted elements.
*
* The builder is not modified by this method, so it is possible to create more collections
* or add more elements afterwards. Further changes will not propagate to the returned set.
*
* @return a new predicated set.
*/
public Set createPredicatedSet() {
return createPredicatedSet(new HashSet());
}
/**
* Decorates the given list with validating behavior using the predicate. All accepted elements
* are appended to the set. If the set already contains elements, they are validated.
*
* The builder is not modified by this method, so it is possible to create more collections
* or add more elements afterwards. Further changes will not propagate to the returned set.
*
* @param set the set to decorate, must not be null
* @return the decorated set.
* @throws NullPointerException if set is null
* @throws IllegalArgumentException if set contains invalid elements
*/
public Set createPredicatedSet(final Set set) {
if (set == null) {
throw new NullPointerException("Set must not be null.");
}
final PredicatedSet predicatedSet = PredicatedSet.predicatedSet(set, predicate);
predicatedSet.addAll(accepted);
return predicatedSet;
}
/**
* Create a new predicated multiset filled with the accepted elements.
*
* The builder is not modified by this method, so it is possible to create more collections
* or add more elements afterwards. Further changes will not propagate to the returned multiset.
*
* @return a new predicated multiset.
*/
public MultiSet createPredicatedMultiSet() {
return createPredicatedMultiSet(new HashMultiSet());
}
/**
* Decorates the given multiset with validating behavior using the predicate. All accepted elements
* are appended to the multiset. If the multiset already contains elements, they are validated.
*
* The builder is not modified by this method, so it is possible to create more collections
* or add more elements afterwards. Further changes will not propagate to the returned multiset.
*
* @param multiset the multiset to decorate, must not be null
* @return the decorated multiset.
* @throws NullPointerException if multiset is null
* @throws IllegalArgumentException if multiset contains invalid elements
*/
public MultiSet createPredicatedMultiSet(final MultiSet multiset) {
if (multiset == null) {
throw new NullPointerException("MultiSet must not be null.");
}
final PredicatedMultiSet predicatedMultiSet =
PredicatedMultiSet.predicatedMultiSet(multiset, predicate);
predicatedMultiSet.addAll(accepted);
return predicatedMultiSet;
}
/**
* Create a new predicated bag filled with the accepted elements.
*
* The builder is not modified by this method, so it is possible to create more collections
* or add more elements afterwards. Further changes will not propagate to the returned bag.
*
* @return a new predicated bag.
*/
public Bag createPredicatedBag() {
return createPredicatedBag(new HashBag());
}
/**
* Decorates the given bag with validating behavior using the predicate. All accepted elements
* are appended to the bag. If the bag already contains elements, they are validated.
*
* The builder is not modified by this method, so it is possible to create more collections
* or add more elements afterwards. Further changes will not propagate to the returned bag.
*
* @param bag the bag to decorate, must not be null
* @return the decorated bag.
* @throws NullPointerException if bag is null
* @throws IllegalArgumentException if bag contains invalid elements
*/
public Bag createPredicatedBag(final Bag bag) {
if (bag == null) {
throw new NullPointerException("Bag must not be null.");
}
final PredicatedBag predicatedBag = PredicatedBag.predicatedBag(bag, predicate);
predicatedBag.addAll(accepted);
return predicatedBag;
}
/**
* Create a new predicated queue filled with the accepted elements.
*
* The builder is not modified by this method, so it is possible to create more collections
* or add more elements afterwards. Further changes will not propagate to the returned queue.
*
* @return a new predicated queue.
*/
public Queue createPredicatedQueue() {
return createPredicatedQueue(new LinkedList());
}
/**
* Decorates the given queue with validating behavior using the predicate. All accepted elements
* are appended to the queue. If the queue already contains elements, they are validated.
*
* The builder is not modified by this method, so it is possible to create more collections
* or add more elements afterwards. Further changes will not propagate to the returned queue.
*
* @param queue the queue to decorate, must not be null
* @return the decorated queue.
* @throws NullPointerException if queue is null
* @throws IllegalArgumentException if queue contains invalid elements
*/
public Queue createPredicatedQueue(final Queue queue) {
if (queue == null) {
throw new NullPointerException("queue must not be null");
}
final PredicatedQueue predicatedQueue = PredicatedQueue.predicatedQueue(queue, predicate);
predicatedQueue.addAll(accepted);
return predicatedQueue;
}
/**
* Returns an unmodifiable collection containing all rejected elements.
*
* @return an unmodifiable collection
*/
public Collection rejectedElements() {
return Collections.unmodifiableCollection(rejected);
}
}
}