From 657f731c905d12001cef17def111f438b0eb557e Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Wed, 30 Jul 2025 00:32:35 +0700 Subject: [PATCH] Support JSpecify for actuator endpoint parameters Signed-off-by: Tran Ngoc Nhan --- .../invoke/reflect/OperationMethodParameter.java | 1 + .../reflect/OperationMethodParameterTests.java | 13 +++++++++++++ 2 files changed, 14 insertions(+) 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)