Skip to content

Commit 071f012

Browse files
committed
Add nullability annotations to module/spring-boot-cloudfoundry
See gh-46587
1 parent 1b6aa9e commit 071f012

16 files changed

+93
-43
lines changed

module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/actuate/autoconfigure/endpoint/CloudFoundryAuthorizationException.java

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

1717
package org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint;
1818

19+
import org.jspecify.annotations.Nullable;
20+
1921
import org.springframework.http.HttpStatus;
2022

2123
/**
@@ -28,11 +30,11 @@ public class CloudFoundryAuthorizationException extends RuntimeException {
2830

2931
private final Reason reason;
3032

31-
public CloudFoundryAuthorizationException(Reason reason, String message) {
33+
public CloudFoundryAuthorizationException(Reason reason, @Nullable String message) {
3234
this(reason, message, null);
3335
}
3436

35-
public CloudFoundryAuthorizationException(Reason reason, String message, Throwable cause) {
37+
public CloudFoundryAuthorizationException(Reason reason, @Nullable String message, @Nullable Throwable cause) {
3638
super(message, cause);
3739
this.reason = reason;
3840
}

module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/actuate/autoconfigure/endpoint/CloudFoundryEndpointExposureOutcomeContributor.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import java.util.Set;
2020

21+
import org.jspecify.annotations.Nullable;
22+
2123
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.EndpointExposureOutcomeContributor;
2224
import org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;
2325
import org.springframework.boot.actuate.autoconfigure.endpoint.expose.IncludeExcludeEndpointFilter;
@@ -38,15 +40,15 @@ class CloudFoundryEndpointExposureOutcomeContributor implements EndpointExposure
3840

3941
private static final String PROPERTY = "management.endpoints.cloud-foundry.exposure";
4042

41-
private final IncludeExcludeEndpointFilter<?> filter;
43+
private final @Nullable IncludeExcludeEndpointFilter<?> filter;
4244

4345
CloudFoundryEndpointExposureOutcomeContributor(Environment environment) {
4446
this.filter = (!CloudPlatform.CLOUD_FOUNDRY.isActive(environment)) ? null
4547
: new IncludeExcludeEndpointFilter<>(ExposableEndpoint.class, environment, PROPERTY, "*");
4648
}
4749

4850
@Override
49-
public ConditionOutcome getExposureOutcome(EndpointId endpointId, Set<EndpointExposure> exposures,
51+
public @Nullable ConditionOutcome getExposureOutcome(EndpointId endpointId, Set<EndpointExposure> exposures,
5052
Builder message) {
5153
if (exposures.contains(EndpointExposure.WEB) && this.filter != null && this.filter.match(endpointId)) {
5254
return ConditionOutcome.match(message.because("marked as exposed by a '" + PROPERTY + "' property"));

module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/actuate/autoconfigure/endpoint/CloudFoundryWebEndpointDiscoverer.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import java.util.Collection;
2020
import java.util.List;
2121

22+
import org.jspecify.annotations.Nullable;
23+
2224
import org.springframework.aot.hint.MemberCategory;
2325
import org.springframework.aot.hint.RuntimeHints;
2426
import org.springframework.aot.hint.RuntimeHintsRegistrar;
@@ -60,7 +62,7 @@ public class CloudFoundryWebEndpointDiscoverer extends WebEndpointDiscoverer {
6062
*/
6163
public CloudFoundryWebEndpointDiscoverer(ApplicationContext applicationContext,
6264
ParameterValueMapper parameterValueMapper, EndpointMediaTypes endpointMediaTypes,
63-
List<PathMapper> endpointPathMappers, Collection<OperationInvokerAdvisor> invokerAdvisors,
65+
@Nullable List<PathMapper> endpointPathMappers, Collection<OperationInvokerAdvisor> invokerAdvisors,
6466
Collection<EndpointFilter<ExposableWebEndpoint>> endpointFilters,
6567
Collection<OperationFilter<WebOperation>> operationFilters) {
6668
super(applicationContext, parameterValueMapper, endpointMediaTypes, endpointPathMappers, null, invokerAdvisors,
@@ -89,7 +91,7 @@ private boolean isCloudFoundryHealthEndpointExtension(Class<?> extensionBeanType
8991
static class CloudFoundryWebEndpointDiscovererRuntimeHints implements RuntimeHintsRegistrar {
9092

9193
@Override
92-
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
94+
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
9395
hints.reflection()
9496
.registerType(CloudFoundryEndpointFilter.class, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
9597
}

module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/actuate/autoconfigure/endpoint/SecurityResponse.java

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

1717
package org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint;
1818

19+
import org.jspecify.annotations.Nullable;
20+
1921
import org.springframework.http.HttpStatus;
2022

2123
/**
@@ -28,13 +30,13 @@ public class SecurityResponse {
2830

2931
private final HttpStatus status;
3032

31-
private final String message;
33+
private final @Nullable String message;
3234

3335
public SecurityResponse(HttpStatus status) {
3436
this(status, null);
3537
}
3638

37-
public SecurityResponse(HttpStatus status, String message) {
39+
public SecurityResponse(HttpStatus status, @Nullable String message) {
3840
this.status = status;
3941
this.message = message;
4042
}
@@ -43,7 +45,7 @@ public HttpStatus getStatus() {
4345
return this.status;
4446
}
4547

46-
public String getMessage() {
48+
public @Nullable String getMessage() {
4749
return this.message;
4850
}
4951

module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/actuate/autoconfigure/endpoint/package-info.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,7 @@
1717
/**
1818
* Auto-configuration for Cloud Foundry endpoints.
1919
*/
20+
@NullMarked
2021
package org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint;
22+
23+
import org.jspecify.annotations.NullMarked;

module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/actuate/autoconfigure/endpoint/reactive/CloudFoundryReactiveActuatorAutoConfiguration.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import java.util.List;
2424
import java.util.function.Supplier;
2525

26+
import org.jspecify.annotations.Nullable;
27+
2628
import org.springframework.beans.BeansException;
2729
import org.springframework.beans.factory.ObjectProvider;
2830
import org.springframework.beans.factory.config.BeanPostProcessor;
@@ -128,12 +130,13 @@ CloudFoundryWebFluxEndpointHandlerMapping cloudFoundryWebFluxEndpointHandlerMapp
128130

129131
private SecurityInterceptor getSecurityInterceptor(WebClient.Builder webClientBuilder, Environment environment) {
130132
SecurityService cloudfoundrySecurityService = getCloudFoundrySecurityService(webClientBuilder, environment);
131-
TokenValidator tokenValidator = new TokenValidator(cloudfoundrySecurityService);
133+
TokenValidator tokenValidator = (cloudfoundrySecurityService != null)
134+
? new TokenValidator(cloudfoundrySecurityService) : null;
132135
return new SecurityInterceptor(tokenValidator, cloudfoundrySecurityService,
133136
environment.getProperty("vcap.application.application_id"));
134137
}
135138

136-
private SecurityService getCloudFoundrySecurityService(WebClient.Builder webClientBuilder,
139+
private @Nullable SecurityService getCloudFoundrySecurityService(WebClient.Builder webClientBuilder,
137140
Environment environment) {
138141
String cloudControllerUrl = environment.getProperty("vcap.application.cf_api");
139142
boolean skipSslValidation = environment.getProperty("management.cloudfoundry.skip-ssl-validation",

module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/actuate/autoconfigure/endpoint/reactive/CloudFoundryWebFluxEndpointHandlerMapping.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.util.Map;
2323
import java.util.stream.Collectors;
2424

25+
import org.jspecify.annotations.Nullable;
2526
import org.reactivestreams.Publisher;
2627
import reactor.core.publisher.Mono;
2728

@@ -111,7 +112,7 @@ public Publisher<ResponseEntity<Object>> links(ServerWebExchange exchange) {
111112
});
112113
}
113114

114-
private Map<String, Link> getAccessibleLinks(AccessLevel accessLevel, Map<String, Link> links) {
115+
private Map<String, Link> getAccessibleLinks(@Nullable AccessLevel accessLevel, Map<String, Link> links) {
115116
if (accessLevel == null) {
116117
return new LinkedHashMap<>();
117118
}
@@ -169,7 +170,7 @@ static class CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints implements Ru
169170
private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
170171

171172
@Override
172-
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
173+
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
173174
this.reflectiveRegistrar.registerRuntimeHints(hints, CloudFoundryLinksHandler.class);
174175
this.bindingRegistrar.registerReflectionHints(hints.reflection(), Link.class);
175176
}

module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/actuate/autoconfigure/endpoint/reactive/SecurityInterceptor.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import org.apache.commons.logging.Log;
2222
import org.apache.commons.logging.LogFactory;
23+
import org.jspecify.annotations.Nullable;
2324
import reactor.core.publisher.Mono;
2425

2526
import org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint.CloudFoundryAuthorizationException;
@@ -28,6 +29,7 @@
2829
import org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint.Token;
2930
import org.springframework.http.HttpStatus;
3031
import org.springframework.http.server.reactive.ServerHttpRequest;
32+
import org.springframework.util.Assert;
3133
import org.springframework.util.StringUtils;
3234
import org.springframework.web.cors.reactive.CorsUtils;
3335
import org.springframework.web.server.ServerWebExchange;
@@ -41,16 +43,16 @@ class SecurityInterceptor {
4143

4244
private static final Log logger = LogFactory.getLog(SecurityInterceptor.class);
4345

44-
private final TokenValidator tokenValidator;
46+
private final @Nullable TokenValidator tokenValidator;
4547

46-
private final SecurityService cloudFoundrySecurityService;
48+
private final @Nullable SecurityService cloudFoundrySecurityService;
4749

48-
private final String applicationId;
50+
private final @Nullable String applicationId;
4951

5052
private static final Mono<SecurityResponse> SUCCESS = Mono.just(SecurityResponse.success());
5153

52-
SecurityInterceptor(TokenValidator tokenValidator, SecurityService cloudFoundrySecurityService,
53-
String applicationId) {
54+
SecurityInterceptor(@Nullable TokenValidator tokenValidator, @Nullable SecurityService cloudFoundrySecurityService,
55+
@Nullable String applicationId) {
5456
this.tokenValidator = tokenValidator;
5557
this.cloudFoundrySecurityService = cloudFoundrySecurityService;
5658
this.applicationId = applicationId;
@@ -65,7 +67,7 @@ Mono<SecurityResponse> preHandle(ServerWebExchange exchange, String id) {
6567
return Mono.error(new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE,
6668
"Application id is not available"));
6769
}
68-
if (this.cloudFoundrySecurityService == null) {
70+
if (this.cloudFoundrySecurityService == null || this.tokenValidator == null) {
6971
return Mono.error(new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE,
7072
"Cloud controller URL is not available"));
7173
}
@@ -77,6 +79,9 @@ private void logError(Throwable ex) {
7779
}
7880

7981
private Mono<Void> check(ServerWebExchange exchange, String id) {
82+
Assert.state(this.tokenValidator != null, "'tokenValidator' must not be null");
83+
Assert.state(this.cloudFoundrySecurityService != null, "'cloudFoundrySecurityService' must not be null");
84+
Assert.state(this.applicationId != null, "'applicationId' must not be null");
8085
try {
8186
Token token = getToken(exchange.getRequest());
8287
return this.tokenValidator.validate(token)

module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/actuate/autoconfigure/endpoint/reactive/SecurityService.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,9 @@ private Mono<? extends Map<String, String>> fetchTokenKeys(String url) {
135135

136136
private Map<String, String> extractTokenKeys(Map<String, Object> response) {
137137
Map<String, String> tokenKeys = new HashMap<>();
138-
for (Object key : (List<?>) response.get("keys")) {
138+
List<?> keys = (List<?>) response.get("keys");
139+
Assert.state(keys != null, "'keys' must not be null");
140+
for (Object key : keys) {
139141
Map<?, ?> tokenKey = (Map<?, ?>) key;
140142
tokenKeys.put((String) tokenKey.get("kid"), (String) tokenKey.get("value"));
141143
}

module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/actuate/autoconfigure/endpoint/reactive/package-info.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,7 @@
1717
/**
1818
* Auto-configuration for Cloud Foundry WebFlux endpoints.
1919
*/
20+
@NullMarked
2021
package org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint.reactive;
22+
23+
import org.jspecify.annotations.NullMarked;

0 commit comments

Comments
 (0)