15
15
*/
16
16
package org .springframework .data .repository .query ;
17
17
18
+ import lombok .AccessLevel ;
18
19
import lombok .AllArgsConstructor ;
19
20
import lombok .Value ;
20
21
21
22
import java .lang .reflect .Method ;
22
23
import java .util .Collections ;
23
- import java .util .HashMap ;
24
24
import java .util .List ;
25
25
import java .util .Map ;
26
26
import java .util .Optional ;
29
29
30
30
import org .springframework .core .convert .TypeDescriptor ;
31
31
import org .springframework .data .repository .query .spi .Function ;
32
- import org .springframework .util .CollectionUtils ;
32
+ import org .springframework .util .LinkedMultiValueMap ;
33
33
import org .springframework .util .MultiValueMap ;
34
34
35
35
/**
38
38
* value lists are actually unique with respect to the signature.
39
39
*
40
40
* @author Jens Schauder
41
+ * @author Oliver Gierke
41
42
* @since 2.0
42
43
*/
43
44
class Functions {
44
45
45
- private final MultiValueMap <NameAndArgumentCount , Function > functions = CollectionUtils
46
- .toMultiValueMap (new HashMap <>());
46
+ private static final String MESSAGE_TEMPLATE = "There are multiple matching methods of name '%s' for parameter types (%s), but no "
47
+ + "exact match. Make sure to provide only one matching overload or one with exactly those types." ;
48
+
49
+ private final MultiValueMap <NameAndArgumentCount , Function > functions = new LinkedMultiValueMap <>();
47
50
48
51
void addAll (Map <String , Function > newFunctions ) {
49
52
50
53
newFunctions .forEach ((n , f ) -> {
51
- NameAndArgumentCount k = new NameAndArgumentCount (n , f .getParameterCount ());
54
+
55
+ NameAndArgumentCount k = NameAndArgumentCount .of (n , f .getParameterCount ());
52
56
List <Function > currentElements = get (k );
57
+
53
58
if (!contains (currentElements , f )) {
54
59
functions .add (k , f );
55
60
}
@@ -59,7 +64,9 @@ void addAll(Map<String, Function> newFunctions) {
59
64
void addAll (MultiValueMap <NameAndArgumentCount , Function > newFunctions ) {
60
65
61
66
newFunctions .forEach ((k , list ) -> {
67
+
62
68
List <Function > currentElements = get (k );
69
+
63
70
list .stream () //
64
71
.filter (f -> !contains (currentElements , f )) //
65
72
.forEach (f -> functions .add (k , f ));
@@ -82,7 +89,7 @@ List<Function> get(NameAndArgumentCount key) {
82
89
*/
83
90
Optional <Function > get (String name , List <TypeDescriptor > argumentTypes ) {
84
91
85
- Stream <Function > candidates = get (new NameAndArgumentCount (name , argumentTypes .size ())).stream () //
92
+ Stream <Function > candidates = get (NameAndArgumentCount . of (name , argumentTypes .size ())).stream () //
86
93
.filter (f -> f .supports (argumentTypes ));
87
94
return bestMatch (candidates .collect (Collectors .toList ()), argumentTypes );
88
95
}
@@ -96,11 +103,13 @@ private static Optional<Function> bestMatch(List<Function> candidates, List<Type
96
103
if (candidates .isEmpty ()) {
97
104
return Optional .empty ();
98
105
}
106
+
99
107
if (candidates .size () == 1 ) {
100
108
return Optional .of (candidates .get (0 ));
101
109
}
102
110
103
111
Optional <Function > exactMatch = candidates .stream ().filter (f -> f .supportsExact (argumentTypes )).findFirst ();
112
+
104
113
if (!exactMatch .isPresent ()) {
105
114
throw new IllegalStateException (createErrorMessage (candidates , argumentTypes ));
106
115
}
@@ -110,24 +119,22 @@ private static Optional<Function> bestMatch(List<Function> candidates, List<Type
110
119
111
120
private static String createErrorMessage (List <Function > candidates , List <TypeDescriptor > argumentTypes ) {
112
121
113
- String argumentTypeString = String . join ( //
114
- "," , //
115
- argumentTypes . stream (). map ( TypeDescriptor :: getName ). collect (Collectors .toList () ));
122
+ String argumentTypeString = argumentTypes . stream () //
123
+ . map ( TypeDescriptor :: getName ) //
124
+ . collect (Collectors .joining ( "," ));
116
125
117
- String messageTemplate = "There are multiple matching methods of name '%s' for parameter types (%s), but no "
118
- + "exact match. Make sure to provide only one matching overload or one with exactly those types." ;
119
-
120
- return String .format (messageTemplate , candidates .get (0 ).getName (), argumentTypeString );
126
+ return String .format (MESSAGE_TEMPLATE , candidates .get (0 ).getName (), argumentTypeString );
121
127
}
122
128
123
129
@ Value
124
- @ AllArgsConstructor
130
+ @ AllArgsConstructor ( access = AccessLevel . PRIVATE , staticName = "of" )
125
131
static class NameAndArgumentCount {
132
+
126
133
String name ;
127
134
int count ;
128
135
129
136
static NameAndArgumentCount of (Method m ) {
130
- return new NameAndArgumentCount (m .getName (), m .getParameterCount ());
137
+ return NameAndArgumentCount . of (m .getName (), m .getParameterCount ());
131
138
}
132
139
}
133
140
}
0 commit comments