15
15
*/
16
16
package org .springframework .data .util ;
17
17
18
+ import kotlin .reflect .KFunction ;
19
+
18
20
import java .lang .annotation .ElementType ;
19
21
import java .lang .reflect .Method ;
20
22
import java .util .Map ;
21
23
import java .util .concurrent .ConcurrentHashMap ;
22
- import java .util .function .Function ;
23
24
24
- import kotlin .reflect .KFunction ;
25
25
import org .aopalliance .intercept .MethodInterceptor ;
26
26
import org .aopalliance .intercept .MethodInvocation ;
27
+
27
28
import org .springframework .core .DefaultParameterNameDiscoverer ;
28
29
import org .springframework .core .KotlinDetector ;
29
30
import org .springframework .core .MethodParameter ;
34
35
35
36
/**
36
37
* Interceptor enforcing required return value and method parameter constraints declared on repository query methods.
37
- * Supports Kotlin nullability markers and JSR-305 Non-null annotations.
38
- * Originally implemented via {@link org.springframework.data.repository.core.support.MethodInvocationValidator}.
38
+ * Supports Kotlin nullness markers and JSR-305 Non-null annotations. Originally implemented via
39
+ * {@link org.springframework.data.repository.core.support.MethodInvocationValidator}.
39
40
*
40
41
* @author Mark Paluch
41
42
* @author Johannes Englmeier
44
45
* @see org.springframework.lang.NonNull
45
46
* @see ReflectionUtils#isNullable(MethodParameter)
46
47
* @see NullableUtils
48
+ * @link <a href="https://www.thedictionaryofobscuresorrows.com/word/nullness">Nullness</a>
47
49
*/
48
- public class NullabilityMethodInvocationValidator implements MethodInterceptor {
50
+ public class NullnessMethodInvocationValidator implements MethodInterceptor {
49
51
50
52
private final ParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer ();
51
- private final Map <Method , Nullability > nullabilityCache = new ConcurrentHashMap <>(16 );
52
- private final Function <MethodInvocation , RuntimeException > errorFunction ;
53
-
54
- public NullabilityMethodInvocationValidator () {
55
- this ((invocation ) -> new NullPointerException ("Method marked non nullable used with null value. If this is by design consider providing additional metadata using @Nullable annotations." ));
56
- }
57
-
58
- /**
59
- * @param errorFunction custom function creating the error in case of failure.
60
- */
61
- protected NullabilityMethodInvocationValidator (Function <MethodInvocation , RuntimeException > errorFunction ) {
62
- this .errorFunction = errorFunction ;
63
- }
53
+ private final Map <Method , MethodNullness > nullabilityCache = new ConcurrentHashMap <>(16 );
64
54
65
55
/**
66
56
* Returns {@literal true} if the {@code type} is supported by this interceptor.
@@ -80,51 +70,73 @@ public static boolean supports(Class<?> type) {
80
70
public Object invoke (@ SuppressWarnings ("null" ) MethodInvocation invocation ) throws Throwable {
81
71
82
72
Method method = invocation .getMethod ();
83
- Nullability nullability = nullabilityCache .get (method );
73
+ MethodNullness nullness = nullabilityCache .get (method );
84
74
85
- if (nullability == null ) {
75
+ if (nullness == null ) {
86
76
87
- nullability = Nullability .of (method , discoverer );
88
- nullabilityCache .put (method , nullability );
77
+ nullness = MethodNullness .of (method , discoverer );
78
+ nullabilityCache .put (method , nullness );
89
79
}
90
80
91
81
Object [] arguments = invocation .getArguments ();
92
82
93
83
for (int i = 0 ; i < method .getParameterCount (); i ++) {
94
84
95
- if (nullability .isNullableParameter (i )) {
85
+ if (nullness .isNullableParameter (i )) {
96
86
continue ;
97
87
}
98
88
99
89
if ((arguments .length < i ) || (arguments [i ] == null )) {
100
- throw new IllegalArgumentException (
101
- String .format ("Parameter %s in %s.%s must not be null" , nullability .getMethodParameterName (i ),
102
- ClassUtils .getShortName (method .getDeclaringClass ()), method .getName ()));
90
+ throw argumentIsNull (method , nullness .getMethodParameterName (i ));
103
91
}
104
92
}
105
93
106
94
Object result = invocation .proceed ();
107
95
108
- if ((result == null ) && !nullability .isNullableReturn ()) {
109
- throw errorFunction . apply ( invocation );
96
+ if ((result == null ) && !nullness .isNullableReturn ()) {
97
+ throw returnValueIsNull ( method );
110
98
}
111
99
112
100
return result ;
113
101
}
114
102
115
- static final class Nullability {
103
+ /**
104
+ * Template method to construct a {@link RuntimeException} indicating failure to provide a non-{@literal null} value
105
+ * for a method parameter.
106
+ *
107
+ * @param method
108
+ * @param parameterName
109
+ * @return
110
+ */
111
+ protected RuntimeException argumentIsNull (Method method , String parameterName ) {
112
+ return new IllegalArgumentException (String .format ("Parameter %s in %s.%s must not be null" , parameterName ,
113
+ ClassUtils .getShortName (method .getDeclaringClass ()), method .getName ()));
114
+ }
115
+
116
+ /**
117
+ * Template method to construct a {@link RuntimeException} indicating failure to return a non-{@literal null} return
118
+ * value.
119
+ *
120
+ * @param method
121
+ * @return
122
+ */
123
+ protected RuntimeException returnValueIsNull (Method method ) {
124
+ return new NullPointerException ("Return value is null but must not be null" );
125
+ }
126
+
127
+ static final class MethodNullness {
116
128
117
129
private final boolean nullableReturn ;
118
130
private final boolean [] nullableParameters ;
119
131
private final MethodParameter [] methodParameters ;
120
132
121
- private Nullability (boolean nullableReturn , boolean [] nullableParameters , MethodParameter [] methodParameters ) {
133
+ private MethodNullness (boolean nullableReturn , boolean [] nullableParameters , MethodParameter [] methodParameters ) {
122
134
this .nullableReturn = nullableReturn ;
123
135
this .nullableParameters = nullableParameters ;
124
136
this .methodParameters = methodParameters ;
125
137
}
126
138
127
- static Nullability of (Method method , ParameterNameDiscoverer discoverer ) {
139
+ static MethodNullness of (Method method , ParameterNameDiscoverer discoverer ) {
128
140
129
141
boolean nullableReturn = isNullableParameter (new MethodParameter (method , -1 ));
130
142
boolean [] nullableParameters = new boolean [method .getParameterCount ()];
@@ -138,7 +150,7 @@ static Nullability of(Method method, ParameterNameDiscoverer discoverer) {
138
150
methodParameters [i ] = parameter ;
139
151
}
140
152
141
- return new Nullability (nullableReturn , nullableParameters , methodParameters );
153
+ return new MethodNullness (nullableReturn , nullableParameters , methodParameters );
142
154
}
143
155
144
156
String getMethodParameterName (int index ) {
@@ -203,7 +215,7 @@ public boolean equals(@Nullable Object o) {
203
215
return true ;
204
216
}
205
217
206
- if (!(o instanceof Nullability that )) {
218
+ if (!(o instanceof MethodNullness that )) {
207
219
return false ;
208
220
}
209
221
0 commit comments