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

org.springframework.core.annotation.MergedAnnotationPredicates Maven / Gradle / Ivy

There is a newer version: 6.1.6
Show newest version
/*
 * Copyright 2002-2019 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
 *
 *      https://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.springframework.core.annotation;

import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;

import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

/**
 * Predicate implementations that provide various test operations for
 * {@link MergedAnnotation MergedAnnotations}.
 *
 * @author Phillip Webb
 * @since 5.2
 */
public abstract class MergedAnnotationPredicates {

	private MergedAnnotationPredicates() {
	}


	/**
	 * Create a new {@link Predicate} that evaluates to {@code true} if the name of the
	 * {@linkplain MergedAnnotation#getType() merged annotation type} is contained in
	 * the specified array.
	 * @param  the annotation type
	 * @param typeNames the names that should be matched
	 * @return a {@link Predicate} to test the annotation type
	 */
	public static  Predicate> typeIn(String... typeNames) {
		return annotation -> ObjectUtils.containsElement(typeNames, annotation.getType().getName());
	}

	/**
	 * Create a new {@link Predicate} that evaluates to {@code true} if the
	 * {@linkplain MergedAnnotation#getType() merged annotation type} is contained in
	 * the specified array.
	 * @param  the annotation type
	 * @param types the types that should be matched
	 * @return a {@link Predicate} to test the annotation type
	 */
	public static  Predicate> typeIn(Class... types) {
		return annotation -> ObjectUtils.containsElement(types, annotation.getType());
	}

	/**
	 * Create a new {@link Predicate} that evaluates to {@code true} if the
	 * {@linkplain MergedAnnotation#getType() merged annotation type} is contained in
	 * the specified collection.
	 * @param  the annotation type
	 * @param types the type names or classes that should be matched
	 * @return a {@link Predicate} to test the annotation type
	 */
	public static  Predicate> typeIn(Collection types) {
		return annotation -> types.stream()
				.map(type -> type instanceof Class ? ((Class) type).getName() : type.toString())
				.anyMatch(typeName -> typeName.equals(annotation.getType().getName()));
	}

	/**
	 * Create a new stateful, single use {@link Predicate} that matches only
	 * the first run of an extracted value. For example,
	 * {@code MergedAnnotationPredicates.firstRunOf(MergedAnnotation::distance)}
	 * will match the first annotation, and any subsequent runs that have the
	 * same distance.
	 * 

NOTE: This predicate only matches the first run. Once the extracted * value changes, the predicate always returns {@code false}. For example, * if you have a set of annotations with distances {@code [1, 1, 2, 1]} then * only the first two will match. * @param valueExtractor function used to extract the value to check * @return a {@link Predicate} that matches the first run of the extracted * values */ public static Predicate> firstRunOf( Function, ?> valueExtractor) { return new FirstRunOfPredicate<>(valueExtractor); } /** * Create a new stateful, single use {@link Predicate} that matches * annotations that are unique based on the extracted key. For example * {@code MergedAnnotationPredicates.unique(MergedAnnotation::getType)} will * match the first time a unique type is encountered. * @param keyExtractor function used to extract the key used to test for * uniqueness * @return a {@link Predicate} that matches a unique annotation based on the * extracted key */ public static Predicate> unique( Function, K> keyExtractor) { return new UniquePredicate<>(keyExtractor); } /** * {@link Predicate} implementation used for * {@link MergedAnnotationPredicates#firstRunOf(Function)}. */ private static class FirstRunOfPredicate implements Predicate> { private final Function, ?> valueExtractor; private boolean hasLastValue; @Nullable private Object lastValue; FirstRunOfPredicate(Function, ?> valueExtractor) { Assert.notNull(valueExtractor, "Value extractor must not be null"); this.valueExtractor = valueExtractor; } @Override public boolean test(@Nullable MergedAnnotation annotation) { if (!this.hasLastValue) { this.hasLastValue = true; this.lastValue = this.valueExtractor.apply(annotation); } Object value = this.valueExtractor.apply(annotation); return ObjectUtils.nullSafeEquals(value, this.lastValue); } } /** * {@link Predicate} implementation used for * {@link MergedAnnotationPredicates#unique(Function)}. */ private static class UniquePredicate implements Predicate> { private final Function, K> keyExtractor; private final Set seen = new HashSet<>(); UniquePredicate(Function, K> keyExtractor) { Assert.notNull(keyExtractor, "Key extractor must not be null"); this.keyExtractor = keyExtractor; } @Override public boolean test(@Nullable MergedAnnotation annotation) { K key = this.keyExtractor.apply(annotation); return this.seen.add(key); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy