1 /*
2  * Copyright 2017-2020 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      https://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.springframework.data.repository.core.support;
17
18 import lombok.NonNull;
19 import lombok.Value;
20
21 import java.lang.reflect.Method;
22 import java.util.List;
23 import java.util.function.BiPredicate;
24 import java.util.stream.Collectors;
25 import java.util.stream.Stream;
26
27 import org.springframework.util.Assert;
28
29 /**
30  * Strategy interface providing {@link MethodPredicate predicates} to resolve a method called on a composite to its
31  * implementation method.
32  * <p />
33  * {@link MethodPredicate Predicates} are ordered by filtering priority and applied individually. If a predicate does
34  * not yield any positive match, the next predicate is applied.
35  *
36  * @author Mark Paluch
37  * @since 2.0
38  * @see RepositoryComposition
39  */

40 @FunctionalInterface
41 public interface MethodLookup {
42
43     /**
44      * Return an ordered {@link List} of {@link MethodPredicate}. Each predicate is applied individually. If any
45      * {@link MethodPredicate} matches, the tested candidate {@link Method} passes the filter.
46      *
47      * @return {@link List} of {@link MethodPredicate}.
48      */

49     List<MethodPredicate> getLookups();
50
51     /**
52      * Returns a composed {@link MethodLookup} that represents a concatenation of this predicate and another. When
53      * evaluating the composed method lookup, if this lookup evaluates {@code true}, then the {@code other} method lookup
54      * is not evaluated.
55      *
56      * @param other must not be {@literal null}.
57      * @return the composed {@link MethodLookup}.
58      */

59     default MethodLookup and(MethodLookup other) {
60
61         Assert.notNull(other, "Other method lookup must not be null!");
62
63         return () -> Stream.concat(getLookups().stream(), other.getLookups().stream()).collect(Collectors.toList());
64     }
65
66     /**
67      * A method predicate to be applied on the {@link InvokedMethod} and {@link Method method candidate}.
68      */

69     @FunctionalInterface
70     interface MethodPredicate extends BiPredicate<InvokedMethod, Method> {
71
72         @Override
73         @SuppressWarnings("null")
74         boolean test(InvokedMethod invokedMethod, Method candidate);
75     }
76
77     /**
78      * Value object representing an invoked {@link Method}.
79      */

80     @Value(staticConstructor = "of")
81     class InvokedMethod {
82
83         private final @NonNull Method method;
84
85         public Class<?> getDeclaringClass() {
86             return method.getDeclaringClass();
87         }
88
89         public String getName() {
90             return method.getName();
91         }
92
93         public Class<?>[] getParameterTypes() {
94             return method.getParameterTypes();
95         }
96
97         public int getParameterCount() {
98             return method.getParameterCount();
99         }
100     }
101 }
102