Skip to content

Commit d7c482a

Browse files
committed
Replace @OptionalParameter with JSpecify's @nullable
This commit removes OptionalParameter in favor of the nullness support introduced in Spring Framework 7. The parameter of an action can now be flagged as optional using JSpecify's @nullable, and simplifies the setup for those who are using JSpecify as only a single annotation is required. Closes gh-45390
1 parent ee83ff5 commit d7c482a

File tree

30 files changed

+71
-345
lines changed

30 files changed

+71
-345
lines changed

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

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,6 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor
109109

110110
static final String READ_OPERATION_ANNOTATION = "org.springframework.boot.actuate.endpoint.annotation.ReadOperation";
111111

112-
static final String OPTIONAL_PARAMETER_ANNOTATION = "org.springframework.boot.actuate.endpoint.annotation.OptionalParameter";
113-
114112
static final String NAME_ANNOTATION = "org.springframework.boot.context.properties.bind.Name";
115113

116114
static final String ENDPOINT_ACCESS_ENUM = "org.springframework.boot.actuate.endpoint.Access";
@@ -166,10 +164,6 @@ protected String nameAnnotation() {
166164
return NAME_ANNOTATION;
167165
}
168166

169-
protected String optionalParameterAnnotation() {
170-
return OPTIONAL_PARAMETER_ANNOTATION;
171-
}
172-
173167
protected String endpointAccessEnum() {
174168
return ENDPOINT_ACCESS_ENUM;
175169
}
@@ -194,8 +188,7 @@ public synchronized void init(ProcessingEnvironment env) {
194188
this.metadataEnv = new MetadataGenerationEnvironment(env, configurationPropertiesAnnotation(),
195189
configurationPropertiesSourceAnnotation(), nestedConfigurationPropertyAnnotation(),
196190
deprecatedConfigurationPropertyAnnotation(), constructorBindingAnnotation(), autowiredAnnotation(),
197-
defaultValueAnnotation(), endpointAnnotations(), readOperationAnnotation(),
198-
optionalParameterAnnotation(), nameAnnotation());
191+
defaultValueAnnotation(), endpointAnnotations(), readOperationAnnotation(), nameAnnotation());
199192
}
200193

201194
@Override
@@ -383,18 +376,13 @@ private boolean hasMainReadOperation(TypeElement element) {
383376

384377
private boolean hasNoOrOptionalParameters(ExecutableElement method) {
385378
for (VariableElement parameter : method.getParameters()) {
386-
if (!isOptionalParameter(parameter)) {
379+
if (!this.metadataEnv.hasNullableAnnotation(parameter)) {
387380
return false;
388381
}
389382
}
390383
return true;
391384
}
392385

393-
private boolean isOptionalParameter(VariableElement parameter) {
394-
return this.metadataEnv.hasNullableAnnotation(parameter)
395-
|| this.metadataEnv.hasOptionalParameterAnnotation(parameter);
396-
}
397-
398386
private String getPrefix(AnnotationMirror annotation) {
399387
String prefix = this.metadataEnv.getAnnotationElementStringValue(annotation, "prefix");
400388
if (prefix != null) {

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

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,6 @@ class MetadataGenerationEnvironment {
9898

9999
private final String readOperationAnnotation;
100100

101-
private final String optionalParameterAnnotation;
102-
103101
private final String nameAnnotation;
104102

105103
private final String autowiredAnnotation;
@@ -108,7 +106,7 @@ class MetadataGenerationEnvironment {
108106
String configurationPropertiesSourceAnnotation, String nestedConfigurationPropertyAnnotation,
109107
String deprecatedConfigurationPropertyAnnotation, String constructorBindingAnnotation,
110108
String autowiredAnnotation, String defaultValueAnnotation, Set<String> endpointAnnotations,
111-
String readOperationAnnotation, String optionalParameterAnnotation, String nameAnnotation) {
109+
String readOperationAnnotation, String nameAnnotation) {
112110
this.typeUtils = new TypeUtils(environment);
113111
this.elements = environment.getElementUtils();
114112
this.messager = environment.getMessager();
@@ -123,7 +121,6 @@ class MetadataGenerationEnvironment {
123121
this.defaultValueAnnotation = defaultValueAnnotation;
124122
this.endpointAnnotations = endpointAnnotations;
125123
this.readOperationAnnotation = readOperationAnnotation;
126-
this.optionalParameterAnnotation = optionalParameterAnnotation;
127124
this.nameAnnotation = nameAnnotation;
128125
}
129126

@@ -382,10 +379,6 @@ boolean hasNullableAnnotation(Element element) {
382379
return getTypeUseAnnotation(element, NULLABLE_ANNOTATION) != null;
383380
}
384381

385-
boolean hasOptionalParameterAnnotation(Element element) {
386-
return getAnnotation(element, this.optionalParameterAnnotation) != null;
387-
}
388-
389382
private boolean isElementDeprecated(Element element) {
390383
return hasAnnotation(element, "java.lang.Deprecated")
391384
|| hasAnnotation(element, this.deprecatedConfigurationPropertyAnnotation);

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

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import org.springframework.boot.configurationsample.endpoint.EnabledEndpoint;
3030
import org.springframework.boot.configurationsample.endpoint.NoAccessEndpoint;
3131
import org.springframework.boot.configurationsample.endpoint.NullableParameterEndpoint;
32-
import org.springframework.boot.configurationsample.endpoint.OptionalParameterEndpoint;
3332
import org.springframework.boot.configurationsample.endpoint.ReadOnlyAccessEndpoint;
3433
import org.springframework.boot.configurationsample.endpoint.SimpleEndpoint;
3534
import org.springframework.boot.configurationsample.endpoint.SimpleEndpoint2;
@@ -153,7 +152,7 @@ void incrementalEndpointBuildChangeCacheFlag() {
153152
assertThat(metadata).has(access("incremental", Access.UNRESTRICTED));
154153
assertThat(metadata).has(cacheTtl("incremental"));
155154
assertThat(metadata.getItems()).hasSize(3);
156-
project.replaceText(IncrementalEndpoint.class, "@OptionalParameter String param", "String param");
155+
project.replaceText(IncrementalEndpoint.class, "@Nullable String param", "String param");
157156
metadata = project.compile();
158157
assertThat(metadata)
159158
.has(Metadata.withGroup("management.endpoint.incremental").fromSource(IncrementalEndpoint.class));
@@ -205,16 +204,6 @@ void endpointWithNullableParameter() {
205204
assertThat(metadata.getItems()).hasSize(3);
206205
}
207206

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-
218207
private Metadata.MetadataItemCondition access(String endpointId, Access defaultValue) {
219208
return defaultAccess(endpointId, endpointId, defaultValue);
220209
}

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ public MetadataGenerationEnvironment apply(ProcessingEnvironment environment) {
4949
TestConfigurationMetadataAnnotationProcessor.AUTOWIRED_ANNOTATION,
5050
TestConfigurationMetadataAnnotationProcessor.DEFAULT_VALUE_ANNOTATION, endpointAnnotations,
5151
TestConfigurationMetadataAnnotationProcessor.READ_OPERATION_ANNOTATION,
52-
TestConfigurationMetadataAnnotationProcessor.OPTIONAL_PARAMETER_ANNOTATION,
5352
TestConfigurationMetadataAnnotationProcessor.NAME_ANNOTATION);
5453
}
5554

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

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,6 @@ public class TestConfigurationMetadataAnnotationProcessor extends ConfigurationM
7575

7676
public static final String READ_OPERATION_ANNOTATION = "org.springframework.boot.configurationsample.ReadOperation";
7777

78-
public static final String OPTIONAL_PARAMETER_ANNOTATION = "org.springframework.boot.configurationsample.OptionalParameter";
79-
8078
public static final String NAME_ANNOTATION = "org.springframework.boot.configurationsample.Name";
8179

8280
public static final String ENDPOINT_ACCESS_ENUM = "org.springframework.boot.configurationsample.Access";
@@ -130,11 +128,6 @@ protected String readOperationAnnotation() {
130128
return READ_OPERATION_ANNOTATION;
131129
}
132130

133-
@Override
134-
protected String optionalParameterAnnotation() {
135-
return OPTIONAL_PARAMETER_ANNOTATION;
136-
}
137-
138131
@Override
139132
protected String nameAnnotation() {
140133
return NAME_ANNOTATION;

configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/OptionalParameter.java

Lines changed: 0 additions & 36 deletions
This file was deleted.

configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/endpoint/OptionalParameterEndpoint.java

Lines changed: 0 additions & 36 deletions
This file was deleted.

configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/endpoint/SpecificEndpoint.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@
1616

1717
package org.springframework.boot.configurationsample.endpoint;
1818

19+
import org.jspecify.annotations.Nullable;
20+
1921
import org.springframework.boot.configurationsample.Access;
20-
import org.springframework.boot.configurationsample.OptionalParameter;
2122
import org.springframework.boot.configurationsample.ReadOperation;
2223
import org.springframework.boot.configurationsample.WebEndpoint;
2324

@@ -31,7 +32,7 @@
3132
public class SpecificEndpoint {
3233

3334
@ReadOperation
34-
String invoke(@OptionalParameter String param) {
35+
String invoke(@Nullable String param) {
3536
return "test";
3637
}
3738

configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/endpoint/incremental/IncrementalEndpoint.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@
1616

1717
package org.springframework.boot.configurationsample.endpoint.incremental;
1818

19+
import org.jspecify.annotations.Nullable;
20+
1921
import org.springframework.boot.configurationsample.Endpoint;
20-
import org.springframework.boot.configurationsample.OptionalParameter;
2122
import org.springframework.boot.configurationsample.ReadOperation;
2223

2324
/**
@@ -29,7 +30,7 @@
2930
public class IncrementalEndpoint {
3031

3132
@ReadOperation
32-
public String invoke(@OptionalParameter String param) {
33+
public String invoke(@Nullable String param) {
3334
return "test";
3435
}
3536

documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/endpoints.adoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ Operations on an endpoint receive input through their parameters.
412412
When exposed over the web, the values for these parameters are taken from the URL's query parameters and from the JSON request body.
413413
When exposed over JMX, the parameters are mapped to the parameters of the MBean's operations.
414414
Parameters are required by default.
415-
They can be made optional by annotating them with either javadoc:org.springframework.boot.actuate.endpoint.annotation.OptionalParameter[format=annotation] or JSpecify's javadoc:org.jspecify.annotations.Nullable[format=annotation].
415+
They can be made optional by annotating them with JSpecify's javadoc:org.jspecify.annotations.Nullable[format=annotation].
416416
Kotlin null safety is also supported.
417417

418418
You can map each root property in the JSON request body to a parameter of the endpoint.
@@ -544,7 +544,7 @@ When using Spring MVC or Spring Web Flux, operations that return a javadoc:org.s
544544
==== Web Endpoint Security
545545

546546
An operation on a web endpoint or a web-specific endpoint extension can receive the current javadoc:java.security.Principal[] or javadoc:org.springframework.boot.actuate.endpoint.SecurityContext[] as a method parameter.
547-
The former is typically used in conjunction with either javadoc:org.springframework.boot.actuate.endpoint.annotation.OptionalParameter[format=annotation] or javadoc:org.jspecify.annotations.Nullable[format=annotation] to provide different behavior for authenticated and unauthenticated users.
547+
The former is typically used in conjunction with javadoc:org.jspecify.annotations.Nullable[format=annotation] to provide different behavior for authenticated and unauthenticated users.
548548
The latter is typically used to perform authorization checks by using its `isUserInRole(String)` method.
549549

550550

0 commit comments

Comments
 (0)