Skip to content

Commit 28a5079

Browse files
committed
Merge pull request #46854 from wonyongg
* pr/46854: Polish "Support additional nullness signal for Actuator endpoints" Support additional nullness signal for Actuator endpoints Closes gh-46854
2 parents 088ef83 + efb80bc commit 28a5079

File tree

5 files changed

+110
-2
lines changed

5 files changed

+110
-2
lines changed

configuration-metadata/spring-boot-configuration-processor/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ architectureCheck {
3636

3737
dependencies {
3838
testCompileOnly("com.google.code.findbugs:jsr305:3.0.2")
39+
testCompileOnly("org.jspecify:jspecify")
3940

4041
testImplementation(enforcedPlatform(project(":platform:spring-boot-dependencies")))
4142
testImplementation(project(":test-support:spring-boot-test-support"))

configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/MetadataGenerationEnvironment.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
*/
5656
class MetadataGenerationEnvironment {
5757

58-
private static final String NULLABLE_ANNOTATION = "org.springframework.lang.Nullable";
58+
private static final String NULLABLE_ANNOTATION = "org.jspecify.annotations.Nullable";
5959

6060
private static final Set<String> TYPE_EXCLUDES = Set.of("com.zaxxer.hikari.IConnectionCustomizer",
6161
"groovy.lang.MetaClass", "groovy.text.markup.MarkupTemplateEngine", "java.io.Writer", "java.io.PrintWriter",
@@ -269,6 +269,17 @@ AnnotationMirror getAnnotation(Element element, String type) {
269269
return null;
270270
}
271271

272+
private AnnotationMirror getTypeUseAnnotation(Element element, String type) {
273+
if (element != null) {
274+
for (AnnotationMirror annotation : element.asType().getAnnotationMirrors()) {
275+
if (type.equals(annotation.getAnnotationType().toString())) {
276+
return annotation;
277+
}
278+
}
279+
}
280+
return null;
281+
}
282+
272283
/**
273284
* Collect the annotations that are annotated or meta-annotated with the specified
274285
* {@link TypeElement annotation}.
@@ -368,7 +379,7 @@ AnnotationMirror getNameAnnotation(Element element) {
368379
}
369380

370381
boolean hasNullableAnnotation(Element element) {
371-
return getAnnotation(element, NULLABLE_ANNOTATION) != null;
382+
return getTypeUseAnnotation(element, NULLABLE_ANNOTATION) != null;
372383
}
373384

374385
boolean hasOptionalParameterAnnotation(Element element) {

configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/EndpointMetadataGenerationTests.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import org.springframework.boot.configurationsample.endpoint.CustomPropertiesEndpoint;
2929
import org.springframework.boot.configurationsample.endpoint.EnabledEndpoint;
3030
import org.springframework.boot.configurationsample.endpoint.NoAccessEndpoint;
31+
import org.springframework.boot.configurationsample.endpoint.NullableParameterEndpoint;
32+
import org.springframework.boot.configurationsample.endpoint.OptionalParameterEndpoint;
3133
import org.springframework.boot.configurationsample.endpoint.ReadOnlyAccessEndpoint;
3234
import org.springframework.boot.configurationsample.endpoint.SimpleEndpoint;
3335
import org.springframework.boot.configurationsample.endpoint.SimpleEndpoint2;
@@ -45,6 +47,7 @@
4547
* @author Stephane Nicoll
4648
* @author Scott Frederick
4749
* @author Moritz Halbritter
50+
* @author Wonyong Hwang
4851
*/
4952
class EndpointMetadataGenerationTests extends AbstractMetadataGenerationTests {
5053

@@ -192,6 +195,26 @@ void shouldFailIfEndpointWithSameIdButWithConflictingEnabledByDefaultSetting() {
192195
"Existing property 'management.endpoint.simple.access' from type org.springframework.boot.configurationsample.endpoint.SimpleEndpoint has a conflicting value. Existing value: unrestricted, new value from type org.springframework.boot.configurationsample.endpoint.SimpleEndpoint3: none");
193196
}
194197

198+
@Test
199+
void endpointWithNullableParameter() {
200+
ConfigurationMetadata metadata = compile(NullableParameterEndpoint.class);
201+
assertThat(metadata)
202+
.has(Metadata.withGroup("management.endpoint.nullable").fromSource(NullableParameterEndpoint.class));
203+
assertThat(metadata).has(access("nullable", Access.UNRESTRICTED));
204+
assertThat(metadata).has(cacheTtl("nullable"));
205+
assertThat(metadata.getItems()).hasSize(3);
206+
}
207+
208+
@Test
209+
void endpointWithOptionalParameter() {
210+
ConfigurationMetadata metadata = compile(OptionalParameterEndpoint.class);
211+
assertThat(metadata)
212+
.has(Metadata.withGroup("management.endpoint.optional").fromSource(OptionalParameterEndpoint.class));
213+
assertThat(metadata).has(access("optional", Access.UNRESTRICTED));
214+
assertThat(metadata).has(cacheTtl("optional"));
215+
assertThat(metadata.getItems()).hasSize(3);
216+
}
217+
195218
private Metadata.MetadataItemCondition access(String endpointId, Access defaultValue) {
196219
return defaultAccess(endpointId, endpointId, defaultValue);
197220
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2012-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.configurationsample.endpoint;
18+
19+
import org.jspecify.annotations.Nullable;
20+
21+
import org.springframework.boot.configurationsample.Endpoint;
22+
import org.springframework.boot.configurationsample.ReadOperation;
23+
24+
/**
25+
* An endpoint that uses {@code Nullable} to signal an optional parameter.
26+
*
27+
* @author Wonyong Hwang
28+
*/
29+
@Endpoint(id = "nullable")
30+
public class NullableParameterEndpoint {
31+
32+
@ReadOperation
33+
public String invoke(@Nullable String parameter) {
34+
return "test with " + parameter;
35+
}
36+
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2012-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.configurationsample.endpoint;
18+
19+
import org.springframework.boot.configurationsample.Endpoint;
20+
import org.springframework.boot.configurationsample.OptionalParameter;
21+
import org.springframework.boot.configurationsample.ReadOperation;
22+
23+
/**
24+
* An endpoint that uses {@code OptionalParameter} to signal an optional parameter.
25+
*
26+
* @author Wonyong Hwang
27+
*/
28+
@Endpoint(id = "optional")
29+
public class OptionalParameterEndpoint {
30+
31+
@ReadOperation
32+
public String invoke(@OptionalParameter String parameter) {
33+
return "test with " + parameter;
34+
}
35+
36+
}

0 commit comments

Comments
 (0)