/* Copyright 2013 Jonatan Jönsson * * 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 se.softhouse.common.guavaextensions; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Predicates.alwaysTrue; import java.util.List; import javax.annotation.Nonnull; import javax.annotation.concurrent.Immutable; import se.softhouse.common.strings.Describables; import com.google.common.base.Predicate; import com.google.common.base.Predicates; /** * Additional implementations of the {@link Predicate} interface, as a complement to * {@link Predicates} */ @Immutable public final class Predicates2 { private Predicates2() { } /** * Returns a predicate that throws an {@link IllegalArgumentException} if any element in a list * doesn't return true for {@code elementLimiter.apply(Object)}. Useful for input validation * where you already have a {@link Predicate} for the element type and want to check a list of * such elements. * Without {@link #listPredicate(Predicate)} it would look something like: * * <pre class="prettyprint"> * <code class="language-java"> * List<Integer> numbers = Arrays.asList(1, -1, -2); * Optional<Integer> invalidNumber = Iterables.tryFind(numbers, Predicates.not(ABOVE_ZERO)); * if(invalidNumber.isPresent()) * throw new IllegalArgumentException("'" + invalidNumber.get() + "' is not " + ABOVE_ZERO); * </code> * </pre> * * With {@link #listPredicate(Predicate)}: * * <pre class="prettyprint"> * <code class="language-java"> * Predicates2.listPredicate(ABOVE_ZERO).apply(numbers); * </code> * </pre> * * As this breaks the general contract of {@link Predicate#apply(Object)} it should be * considered useful for validating arguments only. * The detail message only mentions the first element that didn't return true. */ public static <E> Predicate<List<? extends E>> listPredicate(Predicate<E> elementLimiter) { checkNotNull(elementLimiter); if(elementLimiter == alwaysTrue()) return alwaysTrue(); return new ListPredicate<E>(elementLimiter); } private static final class ListPredicate<E> implements Predicate<List<? extends E>> { private final Predicate<E> elementLimiter; private ListPredicate(Predicate<E> elementLimiter) { this.elementLimiter = elementLimiter; } @Override public boolean apply(@Nonnull List<? extends E> values) { for(E value : values) { if(!elementLimiter.apply(value)) throw Describables.illegalArgument(Describables.format("'%s' is not %s", value, elementLimiter)); } return true; } @Override public String toString() { return elementLimiter.toString(); } } /** * Works just like {@link Predicates#and(Predicate, Predicate)} except that if {@code first} is * {@link Predicates#alwaysTrue()} {@code second} is returned directly (or vice versa). This has * the potential to make {@link Predicate#toString()} look a bit nicer for the resulting * {@link Predicate}. */ public static <T> Predicate<? super T> and(Predicate<? super T> first, Predicate<? super T> second) { if(first == alwaysTrue()) return checkNotNull(second); else if(second == alwaysTrue()) return checkNotNull(first); return Predicates.<T>and(first, second); } }