Skip to content

Commit df8b098

Browse files
committed
Add nullability annotations to module/spring-boot-jersey
See gh-46587
1 parent 50c9615 commit df8b098

File tree

11 files changed

+55
-31
lines changed

11 files changed

+55
-31
lines changed

module/spring-boot-jersey/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ dependencies {
3232
api("org.glassfish.jersey.core:jersey-server")
3333
api("org.glassfish.jersey.ext:jersey-spring6")
3434
api("org.glassfish.jersey.media:jersey-media-json-jackson")
35+
3536
compileOnly("jakarta.servlet:jakarta.servlet-api")
37+
compileOnly("com.google.code.findbugs:jsr305")
3638

3739
implementation("org.springframework:spring-web")
3840

module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/actuate/endpoint/web/JerseyEndpointResourceFactory.java

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.glassfish.jersey.server.ContainerRequest;
3838
import org.glassfish.jersey.server.model.Resource;
3939
import org.glassfish.jersey.server.model.Resource.Builder;
40+
import org.jspecify.annotations.Nullable;
4041
import reactor.core.publisher.Flux;
4142
import reactor.core.publisher.Mono;
4243

@@ -109,8 +110,8 @@ protected Resource createResource(EndpointMapping endpointMapping, WebOperation
109110
}
110111

111112
protected Resource getResource(EndpointMapping endpointMapping, WebOperation operation,
112-
WebOperationRequestPredicate requestPredicate, String path, WebServerNamespace serverNamespace,
113-
JerseyRemainingPathSegmentProvider remainingPathSegmentProvider) {
113+
WebOperationRequestPredicate requestPredicate, String path, @Nullable WebServerNamespace serverNamespace,
114+
@Nullable JerseyRemainingPathSegmentProvider remainingPathSegmentProvider) {
114115
Builder resourceBuilder = Resource.builder()
115116
.path(endpointMapping.getPath())
116117
.path(endpointMapping.createSubPath(path));
@@ -138,10 +139,10 @@ private static final class OperationInflector implements Inflector<ContainerRequ
138139

139140
private static final String PATH_SEPARATOR = AntPathMatcher.DEFAULT_PATH_SEPARATOR;
140141

141-
private static final List<Function<Object, Object>> BODY_CONVERTERS;
142+
private static final List<Function<@Nullable Object, @Nullable Object>> BODY_CONVERTERS;
142143

143144
static {
144-
List<Function<Object, Object>> converters = new ArrayList<>();
145+
List<Function<@Nullable Object, @Nullable Object>> converters = new ArrayList<>();
145146
converters.add(new ResourceBodyConverter());
146147
if (ClassUtils.isPresent("reactor.core.publisher.Mono", OperationInflector.class.getClassLoader())) {
147148
converters.add(new FluxBodyConverter());
@@ -154,12 +155,13 @@ private static final class OperationInflector implements Inflector<ContainerRequ
154155

155156
private final boolean readBody;
156157

157-
private final WebServerNamespace serverNamespace;
158+
private final @Nullable WebServerNamespace serverNamespace;
158159

159-
private final JerseyRemainingPathSegmentProvider remainingPathSegmentProvider;
160+
private final @Nullable JerseyRemainingPathSegmentProvider remainingPathSegmentProvider;
160161

161-
private OperationInflector(WebOperation operation, boolean readBody, WebServerNamespace serverNamespace,
162-
JerseyRemainingPathSegmentProvider remainingPathSegments) {
162+
private OperationInflector(WebOperation operation, boolean readBody,
163+
@Nullable WebServerNamespace serverNamespace,
164+
@Nullable JerseyRemainingPathSegmentProvider remainingPathSegments) {
163165
this.operation = operation;
164166
this.readBody = readBody;
165167
this.serverNamespace = serverNamespace;
@@ -209,15 +211,15 @@ private Map<String, Object> extractPathParameters(ContainerRequestContext reques
209211
return pathParameters;
210212
}
211213

212-
private String getRemainingPathSegments(ContainerRequestContext requestContext,
214+
private @Nullable String getRemainingPathSegments(ContainerRequestContext requestContext,
213215
Map<String, Object> pathParameters, String matchAllRemainingPathSegmentsVariable) {
214216
if (this.remainingPathSegmentProvider != null) {
215217
return this.remainingPathSegmentProvider.get(requestContext, matchAllRemainingPathSegmentsVariable);
216218
}
217219
return (String) pathParameters.get(matchAllRemainingPathSegmentsVariable);
218220
}
219221

220-
private String[] tokenizePathSegments(String path) {
222+
private String[] tokenizePathSegments(@Nullable String path) {
221223
String[] segments = StringUtils.tokenizeToStringArray(path, PATH_SEPARATOR, false, true);
222224
for (int i = 0; i < segments.length; i++) {
223225
if (segments[i].contains("%")) {
@@ -241,7 +243,7 @@ private Map<String, Object> extract(MultivaluedMap<String, String> multivaluedMa
241243
return result;
242244
}
243245

244-
private Response convertToJaxRsResponse(Object response, String httpMethod) {
246+
private Response convertToJaxRsResponse(@Nullable Object response, String httpMethod) {
245247
if (response == null) {
246248
boolean isGet = HttpMethod.GET.equals(httpMethod);
247249
Status status = isGet ? Status.NOT_FOUND : Status.NO_CONTENT;
@@ -256,8 +258,8 @@ private Response convertToJaxRsResponse(Object response, String httpMethod) {
256258
.build();
257259
}
258260

259-
private Object convertIfNecessary(Object body) {
260-
for (Function<Object, Object> converter : BODY_CONVERTERS) {
261+
private @Nullable Object convertIfNecessary(@Nullable Object body) {
262+
for (Function<@Nullable Object, @Nullable Object> converter : BODY_CONVERTERS) {
261263
body = converter.apply(body);
262264
}
263265
return body;
@@ -289,10 +291,10 @@ public Object apply(Object body) {
289291
/**
290292
* Body converter from {@link Mono} to {@link Mono#block()}.
291293
*/
292-
private static final class MonoBodyConverter implements Function<Object, Object> {
294+
private static final class MonoBodyConverter implements Function<@Nullable Object, @Nullable Object> {
293295

294296
@Override
295-
public Object apply(Object body) {
297+
public @Nullable Object apply(@Nullable Object body) {
296298
if (body instanceof Mono) {
297299
return ((Mono<?>) body).block();
298300
}
@@ -304,10 +306,10 @@ public Object apply(Object body) {
304306
/**
305307
* Body converter from {@link Flux} to {@link Flux#collectList Mono&lt;List&gt;}.
306308
*/
307-
private static final class FluxBodyConverter implements Function<Object, Object> {
309+
private static final class FluxBodyConverter implements Function<@Nullable Object, @Nullable Object> {
308310

309311
@Override
310-
public Object apply(Object body) {
312+
public @Nullable Object apply(@Nullable Object body) {
311313
if (body instanceof Flux) {
312314
return ((Flux<?>) body).collectList();
313315
}

module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/actuate/endpoint/web/package-info.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,7 @@
1717
/**
1818
* Jersey support for actuator endpoints.
1919
*/
20+
@NullMarked
2021
package org.springframework.boot.jersey.actuate.endpoint.web;
22+
23+
import org.jspecify.annotations.NullMarked;

module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/autoconfigure/DefaultJerseyApplicationPath.java

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

1919
import jakarta.ws.rs.ApplicationPath;
2020
import org.glassfish.jersey.server.ResourceConfig;
21+
import org.jspecify.annotations.Nullable;
2122

2223
import org.springframework.core.annotation.MergedAnnotation;
2324
import org.springframework.core.annotation.MergedAnnotations;
@@ -33,11 +34,11 @@
3334
*/
3435
public class DefaultJerseyApplicationPath implements JerseyApplicationPath {
3536

36-
private final String applicationPath;
37+
private final @Nullable String applicationPath;
3738

3839
private final ResourceConfig config;
3940

40-
public DefaultJerseyApplicationPath(String applicationPath, ResourceConfig config) {
41+
public DefaultJerseyApplicationPath(@Nullable String applicationPath, ResourceConfig config) {
4142
this.applicationPath = applicationPath;
4243
this.config = config;
4344
}

module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/autoconfigure/JerseyProperties.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import java.util.HashMap;
2020
import java.util.Map;
2121

22+
import org.jspecify.annotations.Nullable;
23+
2224
import org.springframework.boot.context.properties.ConfigurationProperties;
2325

2426
/**
@@ -50,7 +52,7 @@ public class JerseyProperties {
5052
* Path that serves as the base URI for the application. If specified, overrides the
5153
* value of "@ApplicationPath".
5254
*/
53-
private String applicationPath;
55+
private @Nullable String applicationPath;
5456

5557
public Filter getFilter() {
5658
return this.filter;
@@ -76,11 +78,11 @@ public void setInit(Map<String, String> init) {
7678
this.init = init;
7779
}
7880

79-
public String getApplicationPath() {
81+
public @Nullable String getApplicationPath() {
8082
return this.applicationPath;
8183
}
8284

83-
public void setApplicationPath(String applicationPath) {
85+
public void setApplicationPath(@Nullable String applicationPath) {
8486
this.applicationPath = applicationPath;
8587
}
8688

module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/autoconfigure/actuate/endpoint/web/HealthEndpointJerseyExtensionAutoConfiguration.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.glassfish.jersey.server.ResourceConfig;
2525
import org.glassfish.jersey.server.model.Resource;
2626
import org.glassfish.jersey.servlet.ServletContainer;
27+
import org.jspecify.annotations.Nullable;
2728

2829
import org.springframework.beans.factory.ObjectProvider;
2930
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
@@ -73,7 +74,7 @@ JerseyAdditionalHealthEndpointPathsResourcesRegistrar jerseyAdditionalHealthEndp
7374
return new JerseyAdditionalHealthEndpointPathsResourcesRegistrar(health, healthEndpointGroups);
7475
}
7576

76-
private static ExposableWebEndpoint getHealthEndpoint(WebEndpointsSupplier webEndpointsSupplier) {
77+
private static @Nullable ExposableWebEndpoint getHealthEndpoint(WebEndpointsSupplier webEndpointsSupplier) {
7778
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
7879
return webEndpoints.stream()
7980
.filter((endpoint) -> endpoint.getEndpointId().equals(HealthEndpoint.ID))
@@ -110,11 +111,11 @@ ServletRegistrationBean<ServletContainer> jerseyServletRegistration(JerseyApplic
110111

111112
static class JerseyAdditionalHealthEndpointPathsResourcesRegistrar implements ResourceConfigCustomizer {
112113

113-
private final ExposableWebEndpoint endpoint;
114+
private final @Nullable ExposableWebEndpoint endpoint;
114115

115116
private final HealthEndpointGroups groups;
116117

117-
JerseyAdditionalHealthEndpointPathsResourcesRegistrar(ExposableWebEndpoint endpoint,
118+
JerseyAdditionalHealthEndpointPathsResourcesRegistrar(@Nullable ExposableWebEndpoint endpoint,
118119
HealthEndpointGroups groups) {
119120
this.endpoint = endpoint;
120121
this.groups = groups;

module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/autoconfigure/actuate/endpoint/web/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 Jersey actuator web endpoint support.
1919
*/
20+
@NullMarked
2021
package org.springframework.boot.jersey.autoconfigure.actuate.endpoint.web;
22+
23+
import org.jspecify.annotations.NullMarked;

module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/autoconfigure/actuate/web/JerseyWebEndpointManagementContextConfiguration.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import jakarta.ws.rs.ext.ContextResolver;
3030
import org.glassfish.jersey.server.ResourceConfig;
3131
import org.glassfish.jersey.server.model.Resource;
32+
import org.jspecify.annotations.Nullable;
3233

3334
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
3435
import org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;
@@ -179,11 +180,11 @@ private void register(Collection<Resource> resources, ResourceConfig config) {
179180
class JerseyAdditionalHealthEndpointPathsManagementResourcesRegistrar
180181
implements ManagementContextResourceConfigCustomizer {
181182

182-
private final ExposableWebEndpoint healthEndpoint;
183+
private final @Nullable ExposableWebEndpoint healthEndpoint;
183184

184185
private final HealthEndpointGroups groups;
185186

186-
JerseyAdditionalHealthEndpointPathsManagementResourcesRegistrar(ExposableWebEndpoint healthEndpoint,
187+
JerseyAdditionalHealthEndpointPathsManagementResourcesRegistrar(@Nullable ExposableWebEndpoint healthEndpoint,
187188
HealthEndpointGroups groups) {
188189
this.healthEndpoint = healthEndpoint;
189190
this.groups = groups;
@@ -192,16 +193,16 @@ class JerseyAdditionalHealthEndpointPathsManagementResourcesRegistrar
192193
@Override
193194
public void customize(ResourceConfig config) {
194195
if (this.healthEndpoint != null) {
195-
register(config);
196+
register(config, this.healthEndpoint);
196197
}
197198
}
198199

199-
private void register(ResourceConfig config) {
200+
private void register(ResourceConfig config, ExposableWebEndpoint healthEndpoint) {
200201
EndpointMapping mapping = new EndpointMapping("");
201202
JerseyHealthEndpointAdditionalPathResourceFactory resourceFactory = new JerseyHealthEndpointAdditionalPathResourceFactory(
202203
WebServerNamespace.MANAGEMENT, this.groups);
203204
Collection<Resource> endpointResources = resourceFactory
204-
.createEndpointResources(mapping, Collections.singletonList(this.healthEndpoint))
205+
.createEndpointResources(mapping, Collections.singletonList(healthEndpoint))
205206
.stream()
206207
.filter(Objects::nonNull)
207208
.toList();
@@ -228,7 +229,7 @@ private EndpointObjectMapperContextResolver(EndpointObjectMapper endpointObjectM
228229
}
229230

230231
@Override
231-
public ObjectMapper getContext(Class<?> type) {
232+
public @Nullable ObjectMapper getContext(Class<?> type) {
232233
for (Class<?> supportedType : this.endpointObjectMapper.getSupportedTypes()) {
233234
if (supportedType.isAssignableFrom(type)) {
234235
return this.endpointObjectMapper.get();

module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/autoconfigure/actuate/web/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 Jersey actuator web concerns.
1919
*/
20+
@NullMarked
2021
package org.springframework.boot.jersey.autoconfigure.actuate.web;
22+
23+
import org.jspecify.annotations.NullMarked;

module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/autoconfigure/metrics/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 Jersey metrics.
1919
*/
20+
@NullMarked
2021
package org.springframework.boot.jersey.autoconfigure.metrics;
22+
23+
import org.jspecify.annotations.NullMarked;

0 commit comments

Comments
 (0)