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