1515 */
1616package org .springframework .data .util ;
1717
18+ import kotlin .reflect .KFunction ;
19+
1820import java .lang .annotation .ElementType ;
1921import java .lang .reflect .Method ;
2022import java .util .Map ;
2123import java .util .concurrent .ConcurrentHashMap ;
22- import java .util .function .Function ;
2324
24- import kotlin .reflect .KFunction ;
2525import org .aopalliance .intercept .MethodInterceptor ;
2626import org .aopalliance .intercept .MethodInvocation ;
27+
2728import org .springframework .core .DefaultParameterNameDiscoverer ;
2829import org .springframework .core .KotlinDetector ;
2930import org .springframework .core .MethodParameter ;
3435
3536/**
3637 * 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}.
3940 *
4041 * @author Mark Paluch
4142 * @author Johannes Englmeier
4445 * @see org.springframework.lang.NonNull
4546 * @see ReflectionUtils#isNullable(MethodParameter)
4647 * @see NullableUtils
48+ * @link <a href="https://www.thedictionaryofobscuresorrows.com/word/nullness">Nullness</a>
4749 */
48- public class NullabilityMethodInvocationValidator implements MethodInterceptor {
50+ public class NullnessMethodInvocationValidator implements MethodInterceptor {
4951
5052 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 );
6454
6555 /**
6656 * Returns {@literal true} if the {@code type} is supported by this interceptor.
@@ -80,51 +70,73 @@ public static boolean supports(Class<?> type) {
8070 public Object invoke (@ SuppressWarnings ("null" ) MethodInvocation invocation ) throws Throwable {
8171
8272 Method method = invocation .getMethod ();
83- Nullability nullability = nullabilityCache .get (method );
73+ MethodNullness nullness = nullabilityCache .get (method );
8474
85- if (nullability == null ) {
75+ if (nullness == null ) {
8676
87- nullability = Nullability .of (method , discoverer );
88- nullabilityCache .put (method , nullability );
77+ nullness = MethodNullness .of (method , discoverer );
78+ nullabilityCache .put (method , nullness );
8979 }
9080
9181 Object [] arguments = invocation .getArguments ();
9282
9383 for (int i = 0 ; i < method .getParameterCount (); i ++) {
9484
95- if (nullability .isNullableParameter (i )) {
85+ if (nullness .isNullableParameter (i )) {
9686 continue ;
9787 }
9888
9989 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 ));
10391 }
10492 }
10593
10694 Object result = invocation .proceed ();
10795
108- if ((result == null ) && !nullability .isNullableReturn ()) {
109- throw errorFunction . apply ( invocation );
96+ if ((result == null ) && !nullness .isNullableReturn ()) {
97+ throw returnValueIsNull ( method );
11098 }
11199
112100 return result ;
113101 }
114102
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 {
116128
117129 private final boolean nullableReturn ;
118130 private final boolean [] nullableParameters ;
119131 private final MethodParameter [] methodParameters ;
120132
121- private Nullability (boolean nullableReturn , boolean [] nullableParameters , MethodParameter [] methodParameters ) {
133+ private MethodNullness (boolean nullableReturn , boolean [] nullableParameters , MethodParameter [] methodParameters ) {
122134 this .nullableReturn = nullableReturn ;
123135 this .nullableParameters = nullableParameters ;
124136 this .methodParameters = methodParameters ;
125137 }
126138
127- static Nullability of (Method method , ParameterNameDiscoverer discoverer ) {
139+ static MethodNullness of (Method method , ParameterNameDiscoverer discoverer ) {
128140
129141 boolean nullableReturn = isNullableParameter (new MethodParameter (method , -1 ));
130142 boolean [] nullableParameters = new boolean [method .getParameterCount ()];
@@ -138,7 +150,7 @@ static Nullability of(Method method, ParameterNameDiscoverer discoverer) {
138150 methodParameters [i ] = parameter ;
139151 }
140152
141- return new Nullability (nullableReturn , nullableParameters , methodParameters );
153+ return new MethodNullness (nullableReturn , nullableParameters , methodParameters );
142154 }
143155
144156 String getMethodParameterName (int index ) {
@@ -203,7 +215,7 @@ public boolean equals(@Nullable Object o) {
203215 return true ;
204216 }
205217
206- if (!(o instanceof Nullability that )) {
218+ if (!(o instanceof MethodNullness that )) {
207219 return false ;
208220 }
209221
0 commit comments