diff --git a/module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoke/reflect/OperationMethodParameter.java b/module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoke/reflect/OperationMethodParameter.java index bad1e144e1f3..bd1e39a3098a 100644 --- a/module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoke/reflect/OperationMethodParameter.java +++ b/module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoke/reflect/OperationMethodParameter.java @@ -80,6 +80,7 @@ public boolean isMandatory() { @SuppressWarnings("deprecation") private boolean isOptional() { return this.parameter.getAnnotationsByType(org.springframework.lang.Nullable.class).length > 0 + || this.parameter.getAnnotatedType().isAnnotationPresent(org.jspecify.annotations.Nullable.class) || this.optional.test(this.parameter); } diff --git a/module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/invoke/reflect/OperationMethodParameterTests.java b/module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/invoke/reflect/OperationMethodParameterTests.java index d8be6c5a022e..5ab2072543ce 100644 --- a/module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/invoke/reflect/OperationMethodParameterTests.java +++ b/module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/invoke/reflect/OperationMethodParameterTests.java @@ -61,6 +61,9 @@ class OperationMethodParameterTests { private Method exampleAnnotation = ReflectionUtils.findMethod(getClass(), "exampleAnnotation", String.class); + private final Method exampleJSpecifyNullable = ReflectionUtils.findMethod(getClass(), "exampleJSpecifyNullable", + String.class, String.class); + @Test void getNameShouldReturnName() { OperationMethodParameter parameter = new OperationMethodParameter("name", this.example.getParameters()[0], @@ -126,6 +129,13 @@ void getAnnotationShouldReturnAnnotation() { assertThat(annotation.match()).isEqualTo(Match.ALL_REMAINING); } + @Test + void isMandatoryWhenJSpecifyNullableAnnotationShouldReturnFalse() { + OperationMethodParameter parameter = new OperationMethodParameter("name", + this.exampleJSpecifyNullable.getParameters()[1], this::isOptionalParameter); + assertThat(parameter.isMandatory()).isFalse(); + } + private boolean isOptionalParameter(Parameter parameter) { return MergedAnnotations.from(parameter).isPresent(TestOptional.class); } @@ -149,6 +159,9 @@ void exampleJsr305NonNull(String one, @javax.annotation.Nonnull String two) { void exampleAnnotation(@Selector(match = Match.ALL_REMAINING) String allRemaining) { } + void exampleJSpecifyNullable(String one, @org.jspecify.annotations.Nullable String two) { + } + @TypeQualifier @Retention(RetentionPolicy.RUNTIME) @Nonnull(when = When.MAYBE)