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

se.softhouse.common.guavaextensions.Predicates2 Maven / Gradle / Ivy

/*
 * 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 java.util.Objects.requireNonNull;

import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;

import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;

import se.softhouse.common.strings.Describables;

/**
 * Additional implementations of the {@link Predicate} interface
 */
@Immutable
public final class Predicates2
{
	private Predicates2()
	{
	}

	public static  Predicate alwaysTrue()
	{
		return ObjectPredicates.ALWAYS_TRUE.withNarrowedType();
	}

	public static  Predicate alwaysFalse()
	{
		return ObjectPredicates.ALWAYS_FALSE.withNarrowedType();
	}

	// Visible for testing
	enum ObjectPredicates implements Predicate
	{
		ALWAYS_TRUE((i) -> true),
		ALWAYS_FALSE((i) -> false);

	private Predicate predicate;

	ObjectPredicates(Predicate predicate)
		{
			this.predicate = predicate;
		}

	@Override
		public boolean test(Object o)
		{
			return predicate.test(o);
		}

	@SuppressWarnings("unchecked") // safe contravariant cast as all ObjectPredicates
		 Predicate withNarrowedType()
		{
			return (Predicate) this;
		}

	}

	/**
	 * 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:
	 *
	 * 
	 * 
	 * 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);
	 * 
	 * 
* * With {@link #listPredicate(Predicate)}: * *
	 * 
	 * Predicates2.listPredicate(ABOVE_ZERO).apply(numbers);
	 * 
	 * 
* * As this breaks the general contract of {@link Predicate#test(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 Predicate> listPredicate(Predicate elementLimiter) { requireNonNull(elementLimiter); if(elementLimiter == alwaysTrue()) return alwaysTrue(); return new ListPredicate(elementLimiter); } private static final class ListPredicate implements Predicate> { private final Predicate elementLimiter; private ListPredicate(Predicate elementLimiter) { this.elementLimiter = elementLimiter; } @Override public boolean test(@Nonnull List values) { for(E value : values) { if(!elementLimiter.test(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 Predicate#and(Predicate)} except that if {@code first} is * {@link Predicates2#alwaysTrue()} {@code second} is returned directly (or vice versa). This * has * the potential to make {@link Object#toString()} look a bit nicer for the resulting * {@link Predicate}. */ public static Predicate and(Predicate first, Predicate second) { requireNonNull(first); requireNonNull(second); if(first == alwaysTrue()) return second; else if(second == alwaysTrue()) return first; return new Predicate(){ @Override public boolean test(T o) { return first.test(o) && second.test(o); } @Override public String toString() { return "AND(" + first + ", " + second + ")"; } }; } /** * Creates a {@link Predicate} which mandates that {@code target} contains the tested object * * @param target the collection that contains the "ok" objects * @param type of objects in {@code target} * @return the newly created {@link Predicate} */ public static Predicate in(Collection target) { requireNonNull(target); return (e) -> target.contains(e); } }