Author: tn
Date: Sat Jan 24 14:03:40 2015
New Revision: 1654518
URL: http://svn.apache.org/r1654518
Log:
[COLLECTIONS-530] Added Builder for PredicatedCollection. Thanks to Erik.
Added:
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/collection/PredicatedCollectionBuilderTest.java
(with props)
Modified:
commons/proper/collections/trunk/src/changes/changes.xml
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/collection/PredicatedCollection.java
Modified: commons/proper/collections/trunk/src/changes/changes.xml
URL:
http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/changes/changes.xml?rev=1654518&r1=1654517&r2=1654518&view=diff
==============================================================================
--- commons/proper/collections/trunk/src/changes/changes.xml (original)
+++ commons/proper/collections/trunk/src/changes/changes.xml Sat Jan 24
14:03:40 2015
@@ -22,6 +22,11 @@
<body>
<release version="4.1" date="TBD" description="">
+ <action issue="COLLECTIONS-530" dev="tn" type="fix" due-to="Erik">
+ Added a Builder for "PredicatedCollection". Elements added to the builder
+ that fail the predicate will not throw an IllegalArgumentException. The
builder
+ supports creating predicated lists, bags, sets and queues.
+ </action>
<action issue="COLLECTIONS-545" dev="tn" type="fix" due-to="Oswaldo Olivo">
Documented runtime complexity of "CollectionUtils#removeAll(Collection,
Collection).
</action>
Modified:
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/collection/PredicatedCollection.java
URL:
http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/collection/PredicatedCollection.java?rev=1654518&r1=1654517&r2=1654518&view=diff
==============================================================================
---
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/collection/PredicatedCollection.java
(original)
+++
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/collection/PredicatedCollection.java
Sat Jan 24 14:03:40 2015
@@ -16,9 +16,23 @@
*/
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.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.queue.PredicatedQueue;
+import org.apache.commons.collections4.set.PredicatedSet;
/**
* Decorates another {@link Collection} to validate that additions
@@ -28,8 +42,10 @@ import org.apache.commons.collections4.P
* It is normally created to decorate an empty collection.
* If an object cannot be added to the collection, an IllegalArgumentException
is thrown.
* <p>
- * One usage would be to ensure that no null entries are added to the
collection.
- * <pre>Collection coll = PredicatedCollection.decorate(new ArrayList(),
NotNullPredicate.INSTANCE);</pre>
+ * One usage would be to ensure that no null entries are added to the
collection:
+ * <pre>
+ * Collection coll = PredicatedCollection.predicatedCollection(new
ArrayList(), NotNullPredicate.INSTANCE);
+ * </pre>
* <p>
* This class is Serializable from Commons Collections 3.1.
*
@@ -46,6 +62,29 @@ public class PredicatedCollection<E> ext
protected final Predicate<? super E> predicate;
/**
+ * Returns a Builder with the given predicate.
+ *
+ * @param <E> the element type
+ * @param predicate the predicate to use
+ * @return a new Builder for predicated collections
+ * @since 4.1
+ */
+ public static <E> Builder<E> builder(final Predicate<? super E> predicate)
{
+ return new Builder<E>(predicate);
+ }
+
+ /**
+ * Returns a Builder with a NotNullPredicate.
+ *
+ * @param <E> the element type
+ * @return a new Builder for predicated collections that ignores null
values.
+ * @since 4.1
+ */
+ public static <E> Builder<E> notNullBuilder() {
+ return new Builder<E>(NotNullPredicate.<E>notNullPredicate());
+ }
+
+ /**
* Factory method to create a predicated (validating) collection.
* <p>
* If there are any elements already in the collection being decorated,
they
@@ -135,4 +174,230 @@ public class PredicatedCollection<E> ext
return decorated().addAll(coll);
}
+ /**
+ * Builder for creating predicated collections.
+ * <p>
+ * 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.
+ * <p>
+ * An example:
+ * <pre>
+ * 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();
+ * </pre>
+ * <p>
+ * At the end of the code fragment above predicatedList is protected by
the predicate supplied
+ * to the builder and it contains item1 and item2.
+ * <p>
+ * 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 <E> the element type
+ * @since 4.1
+ */
+ public static class Builder<E> {
+
+ /** The predicate to use. */
+ private final Predicate<? super E> predicate;
+
+ /** The buffer containing valid elements. */
+ private final List<E> accepted = new ArrayList<E>();
+
+ /** The buffer containing rejected elements. */
+ private final List<E> rejected = new ArrayList<E>();
+
+ //
-----------------------------------------------------------------------
+ /**
+ * Constructs a PredicatedCollectionBuilder with the specified
Predicate.
+ *
+ * @param predicate the predicate to use
+ * @throws IllegalArgumentException if predicate is null
+ */
+ public Builder(final Predicate<? super E> predicate) {
+ if (predicate == null) {
+ throw new IllegalArgumentException("Predicate must not be
null");
+ }
+ this.predicate = predicate;
+ }
+
+ /**
+ * Adds the item to the builder.
+ * <p>
+ * 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<E> 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.
+ * <p>
+ * 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<E> addAll(final Collection<? extends E> items) {
+ if (items != null) {
+ for (E item : items) {
+ add(item);
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Create a new predicated list filled with the accepted elements.
+ * <p>
+ * 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<E> createPredicatedList() {
+ return createPredicatedList(new ArrayList<E>());
+ }
+
+ /**
+ * 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.
+ * <p>
+ * 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 IllegalArgumentException if list is null or contains
invalid elements
+ */
+ public List<E> createPredicatedList(final List<E> list) {
+ if (list == null) {
+ throw new IllegalArgumentException("list must not be null");
+ }
+ final List<E> predicatedList = PredicatedList.predicatedList(list,
predicate);
+ predicatedList.addAll(accepted);
+ return predicatedList;
+ }
+
+ /**
+ * Create a new predicated set filled with the accepted elements.
+ * <p>
+ * 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<E> createPredicatedSet() {
+ return createPredicatedSet(new HashSet<E>());
+ }
+
+ /**
+ * 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.
+ * <p>
+ * 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 IllegalArgumentException if set is null or contains invalid
elements
+ */
+ public Set<E> createPredicatedSet(final Set<E> set) {
+ if (set == null) {
+ throw new IllegalArgumentException("set must not be null");
+ }
+ final PredicatedSet<E> predicatedSet =
PredicatedSet.predicatedSet(set, predicate);
+ predicatedSet.addAll(accepted);
+ return predicatedSet;
+ }
+
+ /**
+ * Create a new predicated bag filled with the accepted elements.
+ * <p>
+ * 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<E> createPredicatedBag() {
+ return createPredicatedBag(new HashBag<E>());
+ }
+
+ /**
+ * 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.
+ * <p>
+ * 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 IllegalArgumentException if bag is null or contains invalid
elements
+ */
+ public Bag<E> createPredicatedBag(final Bag<E> bag) {
+ if (bag == null) {
+ throw new IllegalArgumentException("bag must not be null");
+ }
+ final PredicatedBag<E> predicatedBag =
PredicatedBag.predicatedBag(bag, predicate);
+ predicatedBag.addAll(accepted);
+ return predicatedBag;
+ }
+
+ /**
+ * Create a new predicated queue filled with the accepted elements.
+ * <p>
+ * 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<E> createPredicatedQueue() {
+ return createPredicatedQueue(new LinkedList<E>());
+ }
+
+ /**
+ * 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.
+ * <p>
+ * 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 IllegalArgumentException if queue is null or contains
invalid elements
+ */
+ public Queue<E> createPredicatedQueue(final Queue<E> queue) {
+ if (queue == null) {
+ throw new IllegalArgumentException("queue must not be null");
+ }
+ final PredicatedQueue<E> predicatedQueue =
PredicatedQueue.predicatedQueue(queue, predicate);
+ predicatedQueue.addAll(accepted);
+ return predicatedQueue;
+ }
+
+ /**
+ * Returns an unmodifiable collection containing all rejected elements.
+ *
+ * @return an unmodifiable collection
+ */
+ public Collection<E> rejectedElements() {
+ return Collections.unmodifiableCollection(rejected);
+ }
+
+ }
+
}
Added:
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/collection/PredicatedCollectionBuilderTest.java
URL:
http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/collection/PredicatedCollectionBuilderTest.java?rev=1654518&view=auto
==============================================================================
---
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/collection/PredicatedCollectionBuilderTest.java
(added)
+++
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/collection/PredicatedCollectionBuilderTest.java
Sat Jan 24 14:03:40 2015
@@ -0,0 +1,144 @@
+/*
+ * 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.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Queue;
+import java.util.Set;
+
+import org.apache.commons.collections4.Bag;
+import org.apache.commons.collections4.Predicate;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Tests the PredicatedCollection.Builder class.
+ *
+ * @since 4.1
+ * @version $Id$
+ */
+public class PredicatedCollectionBuilderTest {
+
+ /**
+ * Verify that passing the Predicate means ending up in the buffer.
+ */
+ @Test
+ public void addPass() {
+ PredicatedCollection.Builder<String> builder =
PredicatedCollection.notNullBuilder();
+ builder.add("test");
+ Assert.assertEquals(builder.createPredicatedList().size(), 1);
+ }
+
+ /**
+ * Verify that failing the Predicate means NOT ending up in the buffer.
+ */
+ @Test
+ public void addFail() {
+ PredicatedCollection.Builder<String> builder =
PredicatedCollection.notNullBuilder();
+ builder.add((String) null);
+ Assert.assertTrue(builder.createPredicatedList().isEmpty());
+
+ Assert.assertEquals(1, builder.rejectedElements().size());
+ }
+
+ /**
+ * Verify that only items that pass the Predicate end up in the buffer.
+ */
+ @Test
+ public void addAllPass() {
+ PredicatedCollection.Builder<String> builder =
PredicatedCollection.notNullBuilder();
+ builder.addAll(Arrays.asList("test1", null, "test2"));
+ Assert.assertEquals(builder.createPredicatedList().size(), 2);
+ }
+
+ @Test
+ public void createPredicatedCollectionWithNotNullPredicate() {
+ PredicatedCollection.Builder<String> builder =
PredicatedCollection.notNullBuilder();
+ builder.add("test1");
+ builder.add((String) null);
+
+ List<String> predicatedList = builder.createPredicatedList();
+ checkPredicatedCollection1(predicatedList);
+
+ Set<String> predicatedSet = builder.createPredicatedSet();
+ checkPredicatedCollection1(predicatedSet);
+
+ Bag<String> predicatedBag = builder.createPredicatedBag();
+ checkPredicatedCollection1(predicatedBag);
+
+ Queue<String> predicatedQueue = builder.createPredicatedQueue();
+ checkPredicatedCollection1(predicatedQueue);
+ }
+
+ private void checkPredicatedCollection1(final Collection<String>
collection) {
+ Assert.assertEquals(1, collection.size());
+
+ collection.add("test2");
+ Assert.assertEquals(2, collection.size());
+
+ try {
+ collection.add(null);
+ Assert.fail("Expecting IllegalArgumentException for failing
predicate!");
+ } catch (IllegalArgumentException iae) {
+ // expected
+ }
+ }
+
+ @Test
+ public void createPredicatedCollectionWithPredicate() {
+ OddPredicate p = new OddPredicate();
+ PredicatedCollection.Builder<Integer> builder =
PredicatedCollection.builder(p);
+
+ builder.add(1);
+ builder.add(2);
+ builder.add(3);
+
+ List<Integer> predicatedList = builder.createPredicatedList();
+ checkPredicatedCollection2(predicatedList);
+
+ Set<Integer> predicatedSet = builder.createPredicatedSet();
+ checkPredicatedCollection2(predicatedSet);
+
+ Bag<Integer> predicatedBag = builder.createPredicatedBag();
+ checkPredicatedCollection2(predicatedBag);
+
+ Queue<Integer> predicatedQueue = builder.createPredicatedQueue();
+ checkPredicatedCollection2(predicatedQueue);
+ }
+
+ private void checkPredicatedCollection2(final Collection<Integer>
collection) {
+ Assert.assertEquals(2, collection.size());
+
+ try {
+ collection.add(4);
+ Assert.fail("Expecting IllegalArgumentException for failing
predicate!");
+ } catch (IllegalArgumentException iae) {
+ }
+ Assert.assertEquals(2, collection.size());
+
+ collection.add(5);
+ Assert.assertEquals(3, collection.size());
+ }
+
+ private static class OddPredicate implements Predicate<Integer> {
+ public boolean evaluate(Integer value) {
+ return value % 2 == 1;
+ }
+ }
+}
Propchange:
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/collection/PredicatedCollectionBuilderTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/collection/PredicatedCollectionBuilderTest.java
------------------------------------------------------------------------------
svn:keywords = Id Revision HeadURL
Propchange:
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/collection/PredicatedCollectionBuilderTest.java
------------------------------------------------------------------------------
svn:mime-type = text/plain