From d7db1a065bd2cc3e95e6d55ca769c44f4531df5f Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Wed, 21 May 2025 09:30:32 +0200 Subject: [PATCH] Apply Nullability changes This commit removes the new deprecated `org.springframework.lang.Nullable` annotations and replaces them with JSpecify equivalents. Note, because those new annotations are applied on type usage, this commit not only renames imports, but also moves annotations close to the nullable usage types. Closes gh-1132 --- .../tester/AbstractGraphQlTesterBuilder.java | 5 +- ...tExecutionGraphQlServiceTesterBuilder.java | 8 ++-- .../test/tester/DefaultGraphQlTester.java | 13 ++---- .../tester/EncoderDecoderMappingProvider.java | 11 ++--- .../graphql/test/tester/GraphQlTester.java | 2 +- .../WebGraphQlHandlerGraphQlTransport.java | 2 +- .../graphql/test/tester/package-info.java | 8 ++-- .../graphql/ExecutionGraphQlRequest.java | 9 ++-- .../graphql/GraphQlRequest.java | 7 ++- .../graphql/GraphQlResponse.java | 5 +- .../graphql/ResponseError.java | 6 +-- .../graphql/ResponseField.java | 6 +-- .../client/AbstractGraphQlClientBuilder.java | 12 ++--- .../AbstractGraphQlClientSyncBuilder.java | 8 ++-- .../graphql/client/ClientResponseField.java | 9 ++-- .../graphql/client/CodecDelegate.java | 4 +- .../client/DefaultClientGraphQlRequest.java | 3 +- .../client/DefaultClientResponseField.java | 14 +++--- .../graphql/client/DefaultGraphQlClient.java | 19 ++++---- .../DefaultRSocketGraphQlClientBuilder.java | 20 +++----- .../DefaultWebSocketGraphQlClientBuilder.java | 5 +- .../graphql/client/DgsGraphQlClient.java | 12 ++--- .../graphql/client/GraphQlClient.java | 8 ++-- .../client/GraphQlClientException.java | 3 +- .../client/GraphQlTransportException.java | 5 +- .../graphql/client/HttpGraphQlTransport.java | 6 ++- .../client/HttpMessageConverterDelegate.java | 8 ++-- .../client/RSocketGraphQlTransport.java | 3 +- .../client/ResponseMapGraphQlResponse.java | 7 ++- .../client/WebSocketGraphQlTransport.java | 20 ++++---- .../graphql/client/package-info.java | 8 ++-- .../graphql/data/ArgumentValue.java | 9 ++-- .../graphql/data/GraphQlArgumentBinder.java | 34 ++++++-------- .../data/federation/EntitiesDataFetcher.java | 11 ++++- .../EntityArgumentMethodArgumentResolver.java | 9 ++-- ...EntityArgumentsMethodArgumentResolver.java | 3 +- .../data/federation/EntityHandlerMethod.java | 4 +- .../federation/FederationSchemaFactory.java | 8 ++-- .../federation/RepresentationException.java | 12 ++--- .../graphql/data/federation/package-info.java | 8 ++-- .../graphql/data/method/HandlerMethod.java | 43 +++++++++-------- .../method/HandlerMethodArgumentResolver.java | 5 +- ...andlerMethodArgumentResolverComposite.java | 8 ++-- .../method/InvocableHandlerMethodSupport.java | 21 ++++----- .../data/method/annotation/package-info.java | 8 ++-- .../AnnotatedControllerConfigurer.java | 23 ++++------ .../AnnotatedControllerDetectionSupport.java | 23 ++++------ .../AnnotatedControllerExceptionResolver.java | 13 +++--- .../ArgumentMethodArgumentResolver.java | 7 ++- .../ArgumentsMethodArgumentResolver.java | 3 +- ...thenticationPrincipalArgumentResolver.java | 17 +++---- .../support/BatchLoaderHandlerMethod.java | 33 ++++++------- .../ContextValueMethodArgumentResolver.java | 7 ++- ...inuationHandlerMethodArgumentResolver.java | 3 +- .../support/DataFetcherHandlerMethod.java | 26 ++++++----- .../DataFetcherHandlerMethodSupport.java | 6 +-- .../support/DataFetcherMappingInfo.java | 2 +- ...hingEnvironmentMethodArgumentResolver.java | 3 +- .../DataLoaderMethodArgumentResolver.java | 46 +++++++++++-------- .../HandlerDataFetcherExceptionResolver.java | 2 +- ...calContextValueMethodArgumentResolver.java | 3 +- ...rojectedPayloadMethodArgumentResolver.java | 3 +- ...BeanFactoryInitializationAotProcessor.java | 4 +- .../ScrollSubrangeMethodArgumentResolver.java | 3 +- .../SubrangeMethodArgumentResolver.java | 2 +- .../annotation/support/ValidationHelper.java | 39 ++++++++-------- .../annotation/support/package-info.java | 8 ++-- .../graphql/data/method/package-info.java | 8 ++-- .../graphql/data/package-info.java | 8 ++-- .../CompositeConnectionAdapter.java | 6 +-- .../ConnectionFieldTypeVisitor.java | 14 ++---- .../graphql/data/pagination/Subrange.java | 2 +- .../graphql/data/pagination/package-info.java | 8 ++-- .../data/query/AbstractSortStrategy.java | 7 ++- ...toRegistrationRuntimeWiringConfigurer.java | 8 ++-- .../data/query/QueryByExampleDataFetcher.java | 27 ++++------- .../data/query/QuerydslDataFetcher.java | 22 ++++----- .../graphql/data/query/RepositoryUtils.java | 5 +- .../graphql/data/query/ScrollSubrange.java | 3 +- .../graphql/data/query/package-info.java | 8 ++-- .../AbstractGraphQlSourceBuilder.java | 5 +- .../execution/ClassNameTypeResolver.java | 11 ++--- .../ContextDataFetcherDecorator.java | 4 +- .../execution/ContextPropagationHelper.java | 3 +- .../DataFetcherExceptionResolverAdapter.java | 12 ++--- .../execution/DefaultBatchLoaderRegistry.java | 17 ++++--- .../DefaultExecutionGraphQlService.java | 5 +- ...ultSchemaResourceGraphQlSourceBuilder.java | 18 +++----- .../ExceptionResolversExceptionHandler.java | 5 +- .../ReactiveAdapterRegistryHelper.java | 8 ++-- .../execution/SchemaMappingInspector.java | 20 +++----- .../graphql/execution/SchemaReport.java | 5 +- .../SecurityContextThreadLocalAccessor.java | 5 +- .../SecurityDataFetcherExceptionResolver.java | 3 +- .../SubscriptionExceptionResolverAdapter.java | 9 ++-- .../SubscriptionPublisherException.java | 2 +- .../graphql/execution/package-info.java | 8 ++-- .../DataFetcherObservationContext.java | 7 +-- .../ExecutionRequestObservationContext.java | 9 ++-- .../GraphQlObservationInstrumentation.java | 18 +++----- .../graphql/observation/package-info.java | 8 ++-- .../springframework/graphql/package-info.java | 8 ++-- .../DefaultWebGraphQlHandlerBuilder.java | 8 ++-- .../graphql/server/RSocketGraphQlRequest.java | 19 +++++--- .../graphql/server/WebGraphQlRequest.java | 15 +++--- .../server/WebSocketGraphQlRequest.java | 3 +- .../graphql/server/WebSocketSessionInfo.java | 5 +- .../graphql/server/package-info.java | 8 ++-- ...actAuthenticationWebSocketInterceptor.java | 7 ++- .../BearerTokenAuthenticationExtractor.java | 5 +- .../support/GraphQlWebSocketMessage.java | 14 ++---- .../support/SerializableGraphQlRequest.java | 27 ++++------- .../graphql/server/support/package-info.java | 8 ++-- .../webflux/AbstractGraphQlHttpHandler.java | 5 +- .../webflux/GraphQlRequestPredicates.java | 2 +- .../server/webflux/GraphQlSseHandler.java | 8 ++-- .../webflux/GraphQlWebSocketHandler.java | 12 +++-- .../webflux/WebSocketCodecDelegate.java | 3 +- .../graphql/server/webflux/package-info.java | 8 ++-- .../webmvc/AbstractGraphQlHttpHandler.java | 10 ++-- .../server/webmvc/GraphQlHttpHandler.java | 2 +- .../webmvc/GraphQlRequestPredicates.java | 2 +- .../server/webmvc/GraphQlSseHandler.java | 8 ++-- .../webmvc/GraphQlWebSocketHandler.java | 15 +++--- .../graphql/server/webmvc/package-info.java | 8 ++-- .../support/AbstractGraphQlResponse.java | 11 ++--- .../DefaultExecutionGraphQlRequest.java | 10 ++-- .../DefaultExecutionGraphQlResponse.java | 5 +- .../support/DefaultGraphQlRequest.java | 9 ++-- .../graphql/support/package-info.java | 8 ++-- 130 files changed, 570 insertions(+), 706 deletions(-) diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/AbstractGraphQlTesterBuilder.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/AbstractGraphQlTesterBuilder.java index 19118200..5fd62028 100644 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/AbstractGraphQlTesterBuilder.java +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/AbstractGraphQlTesterBuilder.java @@ -27,6 +27,7 @@ import com.jayway.jsonpath.Configuration; import com.jayway.jsonpath.spi.json.JacksonJsonProvider; import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider; import com.jayway.jsonpath.spi.mapper.MappingProvider; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -40,7 +41,6 @@ import org.springframework.graphql.client.GraphQlClient; import org.springframework.graphql.client.GraphQlTransport; import org.springframework.graphql.support.DocumentSource; import org.springframework.graphql.support.ResourceDocumentSource; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -66,8 +66,7 @@ public abstract class AbstractGraphQlTesterBuilder errorFilter; + private @Nullable Predicate errorFilter; private DocumentSource documentSource; diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultExecutionGraphQlServiceTesterBuilder.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultExecutionGraphQlServiceTesterBuilder.java index 2f33956b..c5440fc5 100644 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultExecutionGraphQlServiceTesterBuilder.java +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultExecutionGraphQlServiceTesterBuilder.java @@ -24,11 +24,11 @@ import java.util.function.BiFunction; import java.util.function.Consumer; import graphql.ExecutionInput; +import org.jspecify.annotations.Nullable; import org.springframework.core.codec.Decoder; import org.springframework.core.codec.Encoder; import org.springframework.graphql.ExecutionGraphQlService; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -46,11 +46,9 @@ final class DefaultExecutionGraphQlServiceTesterBuilder private final List> executionInputConfigurers; - @Nullable - private Encoder encoder; + private @Nullable Encoder encoder; - @Nullable - private Decoder decoder; + private @Nullable Decoder decoder; DefaultExecutionGraphQlServiceTesterBuilder(ExecutionGraphQlService service) { diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultGraphQlTester.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultGraphQlTester.java index e538009b..862b8257 100644 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultGraphQlTester.java +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultGraphQlTester.java @@ -31,6 +31,7 @@ import com.jayway.jsonpath.Configuration; import com.jayway.jsonpath.DocumentContext; import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath.TypeRef; +import org.jspecify.annotations.Nullable; import org.skyscreamer.jsonassert.JSONAssert; import org.springframework.core.ParameterizedTypeReference; @@ -41,7 +42,6 @@ import org.springframework.graphql.ResponseError; import org.springframework.graphql.client.GraphQlTransport; import org.springframework.graphql.support.DefaultGraphQlRequest; import org.springframework.graphql.support.DocumentSource; -import org.springframework.lang.Nullable; import org.springframework.test.util.AssertionErrors; import org.springframework.test.util.JsonPathExpectationsHelper; import org.springframework.util.Assert; @@ -61,8 +61,7 @@ final class DefaultGraphQlTester implements GraphQlTester { private final GraphQlTransport transport; - @Nullable - private final Predicate errorFilter; + private final @Nullable Predicate errorFilter; private final Configuration jsonPathConfig; @@ -120,8 +119,7 @@ final class DefaultGraphQlTester implements GraphQlTester { private final String document; - @Nullable - private String operationName; + private @Nullable String operationName; List fragments = new ArrayList<>(); @@ -173,7 +171,7 @@ final class DefaultGraphQlTester implements GraphQlTester { return this; } - @SuppressWarnings("ConstantConditions") + @SuppressWarnings({"ConstantConditions", "NullAway"}) @Override public Response execute() { return DefaultGraphQlTester.this.transport.execute(request()) @@ -374,8 +372,7 @@ final class DefaultGraphQlTester implements GraphQlTester { */ private static final class DefaultPath implements Path { - @Nullable - private final String basePath; + private final @Nullable String basePath; private final String path; diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/EncoderDecoderMappingProvider.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/EncoderDecoderMappingProvider.java index 89103e01..9a074e0a 100644 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/EncoderDecoderMappingProvider.java +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/EncoderDecoderMappingProvider.java @@ -25,6 +25,7 @@ import java.util.stream.Stream; import com.jayway.jsonpath.Configuration; import com.jayway.jsonpath.TypeRef; import com.jayway.jsonpath.spi.mapper.MappingProvider; +import org.jspecify.annotations.Nullable; import org.springframework.core.ResolvableType; import org.springframework.core.codec.Decoder; @@ -36,7 +37,6 @@ import org.springframework.http.MediaType; import org.springframework.http.codec.CodecConfigurer; import org.springframework.http.codec.DecoderHttpMessageReader; import org.springframework.http.codec.EncoderHttpMessageWriter; -import org.springframework.lang.Nullable; import org.springframework.util.MimeType; import org.springframework.util.MimeTypeUtils; @@ -107,21 +107,18 @@ final class EncoderDecoderMappingProvider implements MappingProvider { } - @Nullable @Override - public T map(Object source, Class targetType, Configuration configuration) { + public @Nullable T map(Object source, Class targetType, Configuration configuration) { return mapToTargetType(source, ResolvableType.forClass(targetType)); } - @Nullable @Override - public T map(Object source, TypeRef targetType, Configuration configuration) { + public @Nullable T map(Object source, TypeRef targetType, Configuration configuration) { return mapToTargetType(source, ResolvableType.forType(targetType.getType())); } @SuppressWarnings("unchecked") - @Nullable - private T mapToTargetType(Object source, ResolvableType targetType) { + private @Nullable T mapToTargetType(Object source, ResolvableType targetType) { DataBufferFactory bufferFactory = DefaultDataBufferFactory.sharedInstance; MimeType mimeType = MimeTypeUtils.APPLICATION_JSON; diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/GraphQlTester.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/GraphQlTester.java index 61c51113..f4bbfa33 100644 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/GraphQlTester.java +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/GraphQlTester.java @@ -22,6 +22,7 @@ import java.util.Map; import java.util.function.Consumer; import java.util.function.Predicate; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Flux; import org.springframework.core.ParameterizedTypeReference; @@ -30,7 +31,6 @@ import org.springframework.graphql.ResponseError; import org.springframework.graphql.client.GraphQlTransport; import org.springframework.graphql.support.DocumentSource; import org.springframework.graphql.support.ResourceDocumentSource; -import org.springframework.lang.Nullable; /** * Define a workflow to test GraphQL requests that is independent of the diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/WebGraphQlHandlerGraphQlTransport.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/WebGraphQlHandlerGraphQlTransport.java index eaadadf1..fed0528b 100644 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/WebGraphQlHandlerGraphQlTransport.java +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/WebGraphQlHandlerGraphQlTransport.java @@ -20,6 +20,7 @@ package org.springframework.graphql.test.tester; import java.net.URI; import java.util.Collections; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.graphql.ExecutionGraphQlRequest; @@ -28,7 +29,6 @@ import org.springframework.graphql.server.WebGraphQlHandler; import org.springframework.graphql.server.WebGraphQlRequest; import org.springframework.http.HttpHeaders; import org.springframework.http.codec.CodecConfigurer; -import org.springframework.lang.Nullable; /** diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/package-info.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/package-info.java index 67cbae3b..8863502b 100644 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/package-info.java +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2020 the original author or authors. + * Copyright 2020-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,9 +17,7 @@ /** * GraphQL client testing support. */ -@NonNullApi -@NonNullFields +@NullMarked package org.springframework.graphql.test.tester; -import org.springframework.lang.NonNullApi; -import org.springframework.lang.NonNullFields; +import org.jspecify.annotations.NullMarked; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/ExecutionGraphQlRequest.java b/spring-graphql/src/main/java/org/springframework/graphql/ExecutionGraphQlRequest.java index 25b20ed2..5ea13d9f 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/ExecutionGraphQlRequest.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/ExecutionGraphQlRequest.java @@ -21,8 +21,7 @@ import java.util.function.BiFunction; import graphql.ExecutionInput; import graphql.execution.ExecutionId; - -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** @@ -70,14 +69,12 @@ public interface ExecutionGraphQlRequest extends GraphQlRequest { /** * Return the configured {@link #executionId(ExecutionId) executionId}. */ - @Nullable - ExecutionId getExecutionId(); + @Nullable ExecutionId getExecutionId(); /** * Return the transport assigned locale value, if any. */ - @Nullable - Locale getLocale(); + @Nullable Locale getLocale(); /** * Provide a {@code BiFunction} to help initialize the {@link ExecutionInput} diff --git a/spring-graphql/src/main/java/org/springframework/graphql/GraphQlRequest.java b/spring-graphql/src/main/java/org/springframework/graphql/GraphQlRequest.java index 0e979209..f97acc94 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/GraphQlRequest.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/GraphQlRequest.java @@ -18,7 +18,7 @@ package org.springframework.graphql; import java.util.Map; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** @@ -45,11 +45,10 @@ public interface GraphQlRequest { * Return the name of the operation in the {@link #getDocument() document} * to execute, if the document contains multiple operations. */ - @Nullable - String getOperationName(); + @Nullable String getOperationName(); /** - * Return values for variable defined by the operation. + * Return values for variables defined by the operation. */ Map getVariables(); diff --git a/spring-graphql/src/main/java/org/springframework/graphql/GraphQlResponse.java b/spring-graphql/src/main/java/org/springframework/graphql/GraphQlResponse.java index 661b8556..b190f985 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/GraphQlResponse.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/GraphQlResponse.java @@ -20,7 +20,7 @@ package org.springframework.graphql; import java.util.List; import java.util.Map; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** * Represents a GraphQL response with the result of executing a request operation. @@ -51,8 +51,7 @@ public interface GraphQlResponse { * is not {@link #isValid() valid}. * @param a map or a list */ - @Nullable - T getData(); + @Nullable T getData(); /** * Return errors included in the response. diff --git a/spring-graphql/src/main/java/org/springframework/graphql/ResponseError.java b/spring-graphql/src/main/java/org/springframework/graphql/ResponseError.java index 10297819..05bc9db4 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/ResponseError.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/ResponseError.java @@ -21,8 +21,7 @@ import java.util.Map; import graphql.ErrorClassification; import graphql.language.SourceLocation; - -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** * Represents a GraphQL response error. @@ -36,8 +35,7 @@ public interface ResponseError { * Return the message with a description of the error intended for the * developer as a guide to understand and correct the error. */ - @Nullable - String getMessage(); + @Nullable String getMessage(); /** * Return a classification for the error that is specific to GraphQL Java. diff --git a/spring-graphql/src/main/java/org/springframework/graphql/ResponseField.java b/spring-graphql/src/main/java/org/springframework/graphql/ResponseField.java index 45c20367..63800021 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/ResponseField.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/ResponseField.java @@ -18,8 +18,9 @@ package org.springframework.graphql; import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.graphql.client.ClientGraphQlResponse; -import org.springframework.lang.Nullable; /** @@ -49,8 +50,7 @@ public interface ResponseField { * @param the expected value type to cast to * @return the value */ - @Nullable - T getValue(); + @Nullable T getValue(); /** * Return all errors that have a path, and it is at above, or below the field path. diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/AbstractGraphQlClientBuilder.java b/spring-graphql/src/main/java/org/springframework/graphql/client/AbstractGraphQlClientBuilder.java index 9f414dea..f05e7cc8 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/AbstractGraphQlClientBuilder.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/AbstractGraphQlClientBuilder.java @@ -23,6 +23,8 @@ import java.util.Collections; import java.util.List; import java.util.function.Consumer; +import org.jspecify.annotations.Nullable; + import org.springframework.core.codec.Decoder; import org.springframework.core.codec.Encoder; import org.springframework.core.io.ClassPathResource; @@ -33,7 +35,6 @@ import org.springframework.graphql.support.DocumentSource; import org.springframework.graphql.support.ResourceDocumentSource; import org.springframework.http.codec.json.Jackson2JsonDecoder; import org.springframework.http.codec.json.Jackson2JsonEncoder; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -62,14 +63,11 @@ public abstract class AbstractGraphQlClientBuilder jsonEncoder; + private @Nullable Encoder jsonEncoder; - @Nullable - private Decoder jsonDecoder; + private @Nullable Decoder jsonDecoder; - @Nullable - private Duration blockingTimeout; + private @Nullable Duration blockingTimeout; /** diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/AbstractGraphQlClientSyncBuilder.java b/spring-graphql/src/main/java/org/springframework/graphql/client/AbstractGraphQlClientSyncBuilder.java index dd13692a..b969f39f 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/AbstractGraphQlClientSyncBuilder.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/AbstractGraphQlClientSyncBuilder.java @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.List; import java.util.function.Consumer; +import org.jspecify.annotations.Nullable; import reactor.core.scheduler.Scheduler; import reactor.core.scheduler.Schedulers; @@ -35,7 +36,6 @@ import org.springframework.graphql.support.DocumentSource; import org.springframework.graphql.support.ResourceDocumentSource; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -65,13 +65,11 @@ public abstract class AbstractGraphQlClientSyncBuilder jsonConverter; + private @Nullable HttpMessageConverter jsonConverter; private Scheduler scheduler = Schedulers.boundedElastic(); - @Nullable - private Duration blockingTimeout; + private @Nullable Duration blockingTimeout; /** * Default constructor for use from subclasses. diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/ClientResponseField.java b/spring-graphql/src/main/java/org/springframework/graphql/client/ClientResponseField.java index 66b5146d..baf0bca8 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/ClientResponseField.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/ClientResponseField.java @@ -19,10 +19,11 @@ package org.springframework.graphql.client; import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.core.ParameterizedTypeReference; import org.springframework.graphql.GraphQlResponse; import org.springframework.graphql.ResponseField; -import org.springframework.lang.Nullable; /** * Extends {@link ResponseField} to add options for decoding the field value. @@ -42,16 +43,14 @@ public interface ClientResponseField extends ResponseField { * response is not {@link GraphQlResponse#isValid() valid} or the field has * {@link ResponseField#getErrors() errors}. */ - @Nullable - D toEntity(Class entityType); + @Nullable D toEntity(Class entityType); /** * Variant of {@link #toEntity(Class)} with a {@link ParameterizedTypeReference}. * @param the entity type * @param entityType the type to convert to */ - @Nullable - D toEntity(ParameterizedTypeReference entityType); + @Nullable D toEntity(ParameterizedTypeReference entityType); /** * Variant of {@link #toEntity(Class)} to decode to a list of entities. diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/CodecDelegate.java b/spring-graphql/src/main/java/org/springframework/graphql/client/CodecDelegate.java index 841f1219..8dc458e7 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/CodecDelegate.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/CodecDelegate.java @@ -19,6 +19,8 @@ package org.springframework.graphql.client; import java.util.List; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; + import org.springframework.core.ResolvableType; import org.springframework.core.codec.Decoder; import org.springframework.core.codec.Encoder; @@ -108,7 +110,7 @@ final class CodecDelegate { } @SuppressWarnings("ConstantConditions") - GraphQlWebSocketMessage decode(WebSocketMessage webSocketMessage) { + @Nullable GraphQlWebSocketMessage decode(WebSocketMessage webSocketMessage) { DataBuffer buffer = DataBufferUtils.retain(webSocketMessage.getPayload()); return (GraphQlWebSocketMessage) this.decoder.decode(buffer, MESSAGE_TYPE, null, null); } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultClientGraphQlRequest.java b/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultClientGraphQlRequest.java index 8f0e6c83..a8dfb02a 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultClientGraphQlRequest.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultClientGraphQlRequest.java @@ -20,8 +20,9 @@ package org.springframework.graphql.client; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import org.jspecify.annotations.Nullable; + import org.springframework.graphql.support.DefaultGraphQlRequest; -import org.springframework.lang.Nullable; /** * Default implementation of {@link ClientGraphQlRequest}. diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultClientResponseField.java b/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultClientResponseField.java index 870349a9..9a1129d6 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultClientResponseField.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultClientResponseField.java @@ -20,6 +20,8 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.ResolvableType; import org.springframework.core.codec.Decoder; @@ -29,7 +31,6 @@ import org.springframework.core.io.buffer.DataBufferFactory; import org.springframework.core.io.buffer.DefaultDataBufferFactory; import org.springframework.graphql.ResponseError; import org.springframework.graphql.ResponseField; -import org.springframework.lang.Nullable; import org.springframework.util.MimeType; import org.springframework.util.MimeTypeUtils; @@ -65,7 +66,7 @@ final class DefaultClientResponseField implements ClientResponseField { } @Override - public T getValue() { + public @Nullable T getValue() { return this.field.getValue(); } @@ -75,12 +76,12 @@ final class DefaultClientResponseField implements ClientResponseField { } @Override - public D toEntity(Class entityType) { + public @Nullable D toEntity(Class entityType) { return toEntity(ResolvableType.forType(entityType)); } @Override - public D toEntity(ParameterizedTypeReference entityType) { + public @Nullable D toEntity(ParameterizedTypeReference entityType) { return toEntity(ResolvableType.forType(entityType)); } @@ -96,9 +97,8 @@ final class DefaultClientResponseField implements ClientResponseField { return (list != null) ? list : Collections.emptyList(); } - @SuppressWarnings("unchecked") - @Nullable - private T toEntity(ResolvableType targetType) { + @SuppressWarnings("unchecked") + private @Nullable T toEntity(ResolvableType targetType) { if (getValue() == null) { if (this.response.isValid() && getErrors().isEmpty()) { return null; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultGraphQlClient.java b/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultGraphQlClient.java index 489f323f..96cb7db8 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultGraphQlClient.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultGraphQlClient.java @@ -23,13 +23,13 @@ import java.util.List; import java.util.Map; import java.util.function.Consumer; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.scheduler.Scheduler; import org.springframework.core.ParameterizedTypeReference; import org.springframework.graphql.support.DocumentSource; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -47,8 +47,7 @@ final class DefaultGraphQlClient implements GraphQlClient { private final GraphQlClientInterceptor.SubscriptionChain subscriptionChain; - @Nullable - private final Duration blockingTimeout; + private final @Nullable Duration blockingTimeout; DefaultGraphQlClient( @@ -89,7 +88,7 @@ final class DefaultGraphQlClient implements GraphQlClient { return (request) -> Mono.fromCallable(() -> blockingChain.next(request)).subscribeOn(scheduler); } - @SuppressWarnings("DataFlowIssue") + @SuppressWarnings({"DataFlowIssue", "NullAway"}) private static SyncGraphQlClientInterceptor.Chain adaptToBlockingChain( GraphQlClientInterceptor.Chain executeChain, @Nullable Duration blockingTimeout) { @@ -126,8 +125,7 @@ final class DefaultGraphQlClient implements GraphQlClient { private final Mono documentMono; - @Nullable - private String operationName; + private @Nullable String operationName; private final Map variables = new LinkedHashMap<>(); @@ -198,7 +196,7 @@ final class DefaultGraphQlClient implements GraphQlClient { return new DefaultRetrieveSubscriptionSpec(executeSubscription(), path); } - @SuppressWarnings("DataFlowIssue") + @SuppressWarnings({"DataFlowIssue", "NullAway"}) @Override public ClientGraphQlResponse executeSync() { Mono mono = initRequest(); @@ -244,8 +242,7 @@ final class DefaultGraphQlClient implements GraphQlClient { * @throws FieldAccessException in case of an invalid response or any * field error at, above or below the field path */ - @Nullable - protected ClientResponseField getValidField(ClientGraphQlResponse response) { + protected @Nullable ClientResponseField getValidField(ClientGraphQlResponse response) { ClientResponseField field = response.field(this.path); if (!response.isValid() || !field.getErrors().isEmpty()) { throw new FieldAccessException( @@ -267,13 +264,13 @@ final class DefaultGraphQlClient implements GraphQlClient { } @Override - public D toEntity(Class entityType) { + public @Nullable D toEntity(Class entityType) { ClientResponseField field = getValidField(this.response); return (field != null) ? field.toEntity(entityType) : null; } @Override - public D toEntity(ParameterizedTypeReference entityType) { + public @Nullable D toEntity(ParameterizedTypeReference entityType) { ClientResponseField field = getValidField(this.response); return (field != null) ? field.toEntity(entityType) : null; } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultRSocketGraphQlClientBuilder.java b/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultRSocketGraphQlClientBuilder.java index 68e6fe0a..1b766e63 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultRSocketGraphQlClientBuilder.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultRSocketGraphQlClientBuilder.java @@ -25,10 +25,10 @@ import io.rsocket.loadbalance.LoadbalanceTarget; import io.rsocket.transport.ClientTransport; import io.rsocket.transport.netty.client.TcpClientTransport; import io.rsocket.transport.netty.client.WebsocketClientTransport; +import org.jspecify.annotations.Nullable; import org.reactivestreams.Publisher; import reactor.core.publisher.Mono; -import org.springframework.lang.Nullable; import org.springframework.messaging.rsocket.RSocketRequester; import org.springframework.messaging.rsocket.RSocketStrategies; import org.springframework.util.Assert; @@ -48,14 +48,11 @@ final class DefaultRSocketGraphQlClientBuilder private final RSocketRequester.Builder requesterBuilder; - @Nullable - private Publisher> targetPublisher; + private @Nullable Publisher> targetPublisher; - @Nullable - private LoadbalanceStrategy loadbalanceStrategy; + private @Nullable LoadbalanceStrategy loadbalanceStrategy; - @Nullable - private ClientTransport clientTransport; + private @Nullable ClientTransport clientTransport; private String route; @@ -169,14 +166,11 @@ final class DefaultRSocketGraphQlClientBuilder private final RSocketRequester.Builder requesterBuilder; - @Nullable - private final ClientTransport clientTransport; + private final @Nullable ClientTransport clientTransport; - @Nullable - private final Publisher> targetPublisher; + private final @Nullable Publisher> targetPublisher; - @Nullable - private final LoadbalanceStrategy loadbalanceStrategy; + private final @Nullable LoadbalanceStrategy loadbalanceStrategy; private final String route; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultWebSocketGraphQlClientBuilder.java b/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultWebSocketGraphQlClientBuilder.java index 5bcb3a72..257b438c 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultWebSocketGraphQlClientBuilder.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultWebSocketGraphQlClientBuilder.java @@ -22,12 +22,12 @@ import java.util.Arrays; import java.util.List; import java.util.function.Consumer; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.http.HttpHeaders; import org.springframework.http.codec.ClientCodecConfigurer; import org.springframework.http.codec.CodecConfigurer; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.web.reactive.socket.client.WebSocketClient; import org.springframework.web.util.DefaultUriBuilderFactory; @@ -51,8 +51,7 @@ final class DefaultWebSocketGraphQlClientBuilder private final CodecConfigurer codecConfigurer; - @Nullable - private Duration keepAlive; + private @Nullable Duration keepAlive; /** * Constructor to start via {@link WebSocketGraphQlClient#builder(String, WebSocketClient)}. diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/DgsGraphQlClient.java b/spring-graphql/src/main/java/org/springframework/graphql/client/DgsGraphQlClient.java index 90284579..3baf35bc 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/DgsGraphQlClient.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/DgsGraphQlClient.java @@ -25,10 +25,10 @@ import com.netflix.graphql.dgs.client.codegen.BaseProjectionNode; import com.netflix.graphql.dgs.client.codegen.GraphQLQuery; import com.netflix.graphql.dgs.client.codegen.GraphQLQueryRequest; import graphql.schema.Coercing; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -91,14 +91,11 @@ public final class DgsGraphQlClient { private final GraphQLQuery query; - @Nullable - private BaseProjectionNode projectionNode; + private @Nullable BaseProjectionNode projectionNode; - @Nullable - private Map, Coercing> coercingMap; + private @Nullable Map, Coercing> coercingMap; - @Nullable - private Map attributes; + private @Nullable Map attributes; private RequestSpec(GraphQLQuery query) { Assert.notNull(query, "Expected GraphQLQuery"); @@ -243,6 +240,7 @@ public final class DgsGraphQlClient { return initRequestSpec().executeSubscription(); } + @SuppressWarnings("NullAway") private GraphQlClient.RequestSpec initRequestSpec() { Assert.state(this.projectionNode != null || this.coercingMap == null, diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/GraphQlClient.java b/spring-graphql/src/main/java/org/springframework/graphql/client/GraphQlClient.java index 41afb5db..6f9b9023 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/GraphQlClient.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/GraphQlClient.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.Map; import java.util.function.Consumer; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.scheduler.Scheduler; @@ -31,7 +32,6 @@ import org.springframework.graphql.GraphQlResponse; import org.springframework.graphql.ResponseField; import org.springframework.graphql.support.DocumentSource; import org.springframework.graphql.support.ResourceDocumentSource; -import org.springframework.lang.Nullable; /** * Define a workflow to execute GraphQL requests that is independent of the @@ -337,16 +337,14 @@ public interface GraphQlClient { * errors} or an {@link GraphQlResponse#isValid() invalid} response; * @see ResponseField#getErrors() */ - @Nullable - D toEntity(Class entityType); + @Nullable D toEntity(Class entityType); /** * Variant of {@link #toEntity(Class)} with a {@link ParameterizedTypeReference}. * @param the type to convert to * @param entityType the type to convert to */ - @Nullable - D toEntity(ParameterizedTypeReference entityType); + @Nullable D toEntity(ParameterizedTypeReference entityType); /** * Variant of {@link #toEntity(Class)} to decode to a List of entities. diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/GraphQlClientException.java b/spring-graphql/src/main/java/org/springframework/graphql/client/GraphQlClientException.java index 9cce8bce..4c2e4115 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/GraphQlClientException.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/GraphQlClientException.java @@ -17,9 +17,10 @@ package org.springframework.graphql.client; +import org.jspecify.annotations.Nullable; + import org.springframework.core.NestedRuntimeException; import org.springframework.graphql.GraphQlRequest; -import org.springframework.lang.Nullable; /** diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/GraphQlTransportException.java b/spring-graphql/src/main/java/org/springframework/graphql/client/GraphQlTransportException.java index e7f80067..265e3104 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/GraphQlTransportException.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/GraphQlTransportException.java @@ -17,8 +17,9 @@ package org.springframework.graphql.client; +import org.jspecify.annotations.Nullable; + import org.springframework.graphql.GraphQlRequest; -import org.springframework.lang.Nullable; /** * Exception raised by a {@link GraphQlTransport} or used to wrap an exception @@ -36,7 +37,7 @@ public class GraphQlTransportException extends GraphQlClientException { * @param request the request that failed at the transport level */ public GraphQlTransportException(@Nullable Throwable cause, GraphQlRequest request) { - super("GraphQlTransport error: " + cause.getMessage(), cause, request); + super("GraphQlTransport error" + ((cause != null) ? ": " + cause.getMessage() : ""), cause, request); } /** diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/HttpGraphQlTransport.java b/spring-graphql/src/main/java/org/springframework/graphql/client/HttpGraphQlTransport.java index 0d44ba3e..acfeaf9f 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/HttpGraphQlTransport.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/HttpGraphQlTransport.java @@ -16,6 +16,7 @@ package org.springframework.graphql.client; +import java.util.Collections; import java.util.Map; import reactor.core.publisher.Flux; @@ -118,7 +119,10 @@ final class HttpGraphQlTransport implements GraphQlTransport { .retrieve() .bodyToFlux(SSE_TYPE) .takeWhile((event) -> "next".equals(event.event())) - .map((event) -> new ResponseMapGraphQlResponse(event.data())); + .map((event) -> { + Map data = (event.data() != null) ? event.data() : Collections.emptyMap(); + return new ResponseMapGraphQlResponse(data); + }); } } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/HttpMessageConverterDelegate.java b/spring-graphql/src/main/java/org/springframework/graphql/client/HttpMessageConverterDelegate.java index 2952a90a..d098ad3e 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/HttpMessageConverterDelegate.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/HttpMessageConverterDelegate.java @@ -25,6 +25,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import org.jspecify.annotations.Nullable; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -43,7 +44,6 @@ import org.springframework.http.HttpOutputMessage; import org.springframework.http.MediaType; import org.springframework.http.converter.GenericHttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.lang.Nullable; import org.springframework.util.MimeType; @@ -77,8 +77,7 @@ final class HttpMessageConverterDelegate { return new HttpMessageConverterDecoder(converter); } - @Nullable - private static MediaType toMediaType(@Nullable MimeType mimeType) { + private static @Nullable MediaType toMediaType(@Nullable MimeType mimeType) { if (mimeType instanceof MediaType mediaType) { return mediaType; } @@ -126,7 +125,8 @@ final class HttpMessageConverterDelegate { return bufferFactory.wrap(messageAdapter.toByteArray()); } catch (IOException ex) { - throw new EncodingException(ex.getMessage(), ex); + // TODO: revisit + throw new EncodingException("Error while encoding: " + ex.getMessage(), ex); } } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/RSocketGraphQlTransport.java b/spring-graphql/src/main/java/org/springframework/graphql/client/RSocketGraphQlTransport.java index 3d19b614..94963117 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/RSocketGraphQlTransport.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/RSocketGraphQlTransport.java @@ -89,7 +89,8 @@ final class RSocketGraphQlTransport implements GraphQlTransport { @SuppressWarnings("unchecked") private Exception decodeErrors(GraphQlRequest request, RejectedException ex) { try { - byte[] errorData = ex.getMessage().getBytes(StandardCharsets.UTF_8); + String errorMessage = (ex.getMessage() != null) ? ex.getMessage() : ""; + byte[] errorData = errorMessage.getBytes(StandardCharsets.UTF_8); List errors = (List) this.jsonDecoder.decode( DefaultDataBufferFactory.sharedInstance.wrap(errorData), LIST_TYPE, null, null); GraphQlResponse response = new ResponseMapGraphQlResponse(Collections.singletonMap("errors", errors)); diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/ResponseMapGraphQlResponse.java b/spring-graphql/src/main/java/org/springframework/graphql/client/ResponseMapGraphQlResponse.java index a4d7caad..cebf98d8 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/ResponseMapGraphQlResponse.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/ResponseMapGraphQlResponse.java @@ -24,11 +24,11 @@ import java.util.stream.Collectors; import graphql.ErrorClassification; import graphql.GraphQLError; import graphql.language.SourceLocation; +import org.jspecify.annotations.Nullable; import org.springframework.graphql.GraphQlResponse; import org.springframework.graphql.ResponseError; import org.springframework.graphql.support.AbstractGraphQlResponse; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -76,7 +76,7 @@ class ResponseMapGraphQlResponse extends AbstractGraphQlResponse { @SuppressWarnings("unchecked") @Override - public T getData() { + public @Nullable T getData() { return (T) this.responseMap.get("data"); } @@ -160,8 +160,7 @@ class ResponseMapGraphQlResponse extends AbstractGraphQlResponse { @Override - @Nullable - public String getMessage() { + public @Nullable String getMessage() { return (String) this.errorMap.get("message"); } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/WebSocketGraphQlTransport.java b/spring-graphql/src/main/java/org/springframework/graphql/client/WebSocketGraphQlTransport.java index 02c1ae48..a9c2cb0d 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/WebSocketGraphQlTransport.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/WebSocketGraphQlTransport.java @@ -27,6 +27,7 @@ import java.util.concurrent.atomic.AtomicLong; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import reactor.core.Scannable; import reactor.core.publisher.Flux; import reactor.core.publisher.FluxSink; @@ -41,7 +42,6 @@ import org.springframework.graphql.server.support.GraphQlWebSocketMessage; import org.springframework.graphql.server.support.GraphQlWebSocketMessageType; import org.springframework.http.HttpHeaders; import org.springframework.http.codec.CodecConfigurer; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.web.reactive.socket.CloseStatus; import org.springframework.web.reactive.socket.WebSocketHandler; @@ -68,8 +68,7 @@ final class WebSocketGraphQlTransport implements GraphQlTransport { private final Mono graphQlSessionMono; - @Nullable - private final Duration keepAlive; + private final @Nullable Duration keepAlive; WebSocketGraphQlTransport( @@ -167,8 +166,7 @@ final class WebSocketGraphQlTransport implements GraphQlTransport { return this.graphQlSessionMono.flatMapMany((session) -> session.executeSubscription(request)); } - @Nullable - Duration getKeepAlive() { + @Nullable Duration getKeepAlive() { return this.keepAlive; } @@ -193,8 +191,7 @@ final class WebSocketGraphQlTransport implements GraphQlTransport { private final AtomicBoolean stopped = new AtomicBoolean(); - @Nullable - private final Duration keepAlive; + private final @Nullable Duration keepAlive; GraphQlSessionHandler( @@ -267,6 +264,7 @@ final class WebSocketGraphQlTransport implements GraphQlTransport { if (sessionNotInitialized()) { try { GraphQlWebSocketMessage message = this.codecDelegate.decode(webSocketMessage); + Assert.notNull(message, () -> "Cannot decode graphql message from: " + webSocketMessage); Assert.state(message.resolvedType() == GraphQlWebSocketMessageType.CONNECTION_ACK, () -> "Unexpected message before connection_ack: " + message); return this.interceptor.handleConnectionAck(message.getPayload()) @@ -290,6 +288,9 @@ final class WebSocketGraphQlTransport implements GraphQlTransport { else { try { GraphQlWebSocketMessage message = this.codecDelegate.decode(webSocketMessage); + if (message == null) { + throw new IllegalStateException("Cannot decode graphql message from: " + webSocketMessage); + } switch (message.resolvedType()) { case NEXT -> graphQlSession.handleNext(message); case PING -> graphQlSession.sendPong(null); @@ -300,7 +301,7 @@ final class WebSocketGraphQlTransport implements GraphQlTransport { "Unexpected message type: '" + message.getType() + "'"); } } - catch (Exception ex) { + catch (Throwable ex) { if (logger.isErrorEnabled()) { logger.error("Closing " + session + ": " + ex); } @@ -654,8 +655,7 @@ final class WebSocketGraphQlTransport implements GraphQlTransport { */ private static final class RequestSink { - @Nullable - private FluxSink requestSink; + private @Nullable FluxSink requestSink; private boolean hasSentMessages; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/package-info.java b/spring-graphql/src/main/java/org/springframework/graphql/client/package-info.java index d9fd92bd..bb7ba71b 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/package-info.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * Copyright 2020-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,9 +18,7 @@ * This package contains a {@link org.springframework.graphql.client.GraphQlClient} * along with HTTP and WebSocket extensions. */ -@NonNullApi -@NonNullFields +@NullMarked package org.springframework.graphql.client; -import org.springframework.lang.NonNullApi; -import org.springframework.lang.NonNullFields; +import org.jspecify.annotations.NullMarked; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/ArgumentValue.java b/spring-graphql/src/main/java/org/springframework/graphql/data/ArgumentValue.java index 5ce87f2f..3f5e26ab 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/ArgumentValue.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/ArgumentValue.java @@ -20,7 +20,8 @@ package org.springframework.graphql.data; import java.util.Optional; import java.util.function.Consumer; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -54,8 +55,7 @@ public final class ArgumentValue { private static final ArgumentValue OMITTED = new ArgumentValue<>(null, true); - @Nullable - private final T value; + private final @Nullable T value; private final boolean omitted; @@ -94,8 +94,7 @@ public final class ArgumentValue { /** * Return the contained value, or {@code null}. */ - @Nullable - public T value() { + public @Nullable T value() { return this.value; } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/GraphQlArgumentBinder.java b/spring-graphql/src/main/java/org/springframework/graphql/data/GraphQlArgumentBinder.java index 20f37189..1150f33f 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/GraphQlArgumentBinder.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/GraphQlArgumentBinder.java @@ -24,6 +24,7 @@ import java.util.Map; import java.util.Optional; import graphql.schema.DataFetchingEnvironment; +import org.jspecify.annotations.Nullable; import org.springframework.beans.BeanInstantiationException; import org.springframework.beans.BeanUtils; @@ -40,7 +41,7 @@ import org.springframework.core.ResolvableType; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.TypeDescriptor; import org.springframework.data.util.DirectFieldAccessFallbackBeanWrapper; -import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; import org.springframework.validation.AbstractBindingResult; @@ -76,8 +77,7 @@ import org.springframework.validation.FieldError; */ public class GraphQlArgumentBinder { - @Nullable - private final SimpleTypeConverter typeConverter; + private final @Nullable SimpleTypeConverter typeConverter; private final boolean fallBackOnDirectFieldAccess; @@ -95,8 +95,7 @@ public class GraphQlArgumentBinder { this.fallBackOnDirectFieldAccess = fallBackOnDirectFieldAccess; } - @Nullable - private static SimpleTypeConverter initTypeConverter(@Nullable ConversionService conversionService) { + private static @Nullable SimpleTypeConverter initTypeConverter(@Nullable ConversionService conversionService) { if (conversionService == null) { // Not thread-safe when using PropertyEditors return null; @@ -119,8 +118,7 @@ public class GraphQlArgumentBinder { * @throws BindException containing one or more accumulated errors from * matching and/or converting arguments to the target Object */ - @Nullable - public Object bind( + public @Nullable Object bind( DataFetchingEnvironment environment, @Nullable String name, ResolvableType targetType) throws BindException { @@ -139,8 +137,7 @@ public class GraphQlArgumentBinder { * @param targetType the type of Object to create * @since 1.3.0 */ - @Nullable - public Object bind(@Nullable Object rawValue, boolean isOmitted, ResolvableType targetType) throws BindException { + public @Nullable Object bind(@Nullable Object rawValue, boolean isOmitted, ResolvableType targetType) throws BindException { ArgumentsBindingResult bindingResult = new ArgumentsBindingResult(targetType); Class targetClass = targetType.resolve(Object.class); Object value = bindRawValue("$", rawValue, isOmitted, targetType, targetClass, bindingResult); @@ -168,8 +165,7 @@ public class GraphQlArgumentBinder { * a {@link BindException} at the end to record as many errors as possible */ @SuppressWarnings({"ConstantConditions", "unchecked"}) - @Nullable - private Object bindRawValue( + private @Nullable Object bindRawValue( String name, @Nullable Object rawValue, boolean isOmitted, ResolvableType targetType, Class targetClass, ArgumentsBindingResult bindingResult) { @@ -179,6 +175,7 @@ public class GraphQlArgumentBinder { if (isOptional || isArgumentValue) { targetType = targetType.getNested(2); targetClass = targetType.resolve(); + Assert.state(targetClass != null, "Could not resolve target type for: " + targetType); } Object value; @@ -229,8 +226,7 @@ public class GraphQlArgumentBinder { return collection; } - @Nullable - private Object bindMap( + private @Nullable Object bindMap( String name, Map rawMap, ResolvableType targetType, Class targetClass, ArgumentsBindingResult bindingResult) { @@ -272,13 +268,12 @@ public class GraphQlArgumentBinder { return map; } - @Nullable - private Object bindViaConstructorAndSetters(Constructor constructor, + private @Nullable Object bindViaConstructorAndSetters(Constructor constructor, Map rawMap, ResolvableType ownerType, ArgumentsBindingResult bindingResult) { String[] paramNames = BeanUtils.getParameterNames(constructor); Class[] paramTypes = constructor.getParameterTypes(); - Object[] constructorArguments = new Object[paramTypes.length]; + @Nullable Object[] constructorArguments = new Object[paramTypes.length]; for (int i = 0; i < paramNames.length; i++) { String name = paramNames[i]; @@ -359,8 +354,7 @@ public class GraphQlArgumentBinder { } @SuppressWarnings("unchecked") - @Nullable - private T convertValue( + private @Nullable T convertValue( String name, @Nullable Object rawValue, ResolvableType type, Class clazz, ArgumentsBindingResult bindingResult) { @@ -398,12 +392,12 @@ public class GraphQlArgumentBinder { } @Override - public Object getTarget() { + public @Nullable Object getTarget() { return null; } @Override - protected Object getActualFieldValue(String field) { + protected @Nullable Object getActualFieldValue(String field) { return null; } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/federation/EntitiesDataFetcher.java b/spring-graphql/src/main/java/org/springframework/graphql/data/federation/EntitiesDataFetcher.java index 51116a74..51c7a33b 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/federation/EntitiesDataFetcher.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/federation/EntitiesDataFetcher.java @@ -35,11 +35,11 @@ import graphql.execution.ExecutionStepInfo; import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; import graphql.schema.DelegatingDataFetchingEnvironment; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.graphql.data.method.annotation.support.HandlerDataFetcherExceptionResolver; import org.springframework.graphql.execution.ErrorType; -import org.springframework.lang.Nullable; /** * DataFetcher that handles the "_entities" query by invoking @@ -155,7 +155,7 @@ final class EntitiesDataFetcher implements DataFetcher resolveException( Throwable ex, DataFetchingEnvironment env, @Nullable EntityHandlerMethod handlerMethod, int index) { - Throwable theEx = (ex instanceof CompletionException) ? ex.getCause() : ex; + Throwable theEx = unwrapException(ex); DataFetchingEnvironment theEnv = new IndexedDataFetchingEnvironment(env, index); Object handler = (handlerMethod != null) ? handlerMethod.getBean() : null; @@ -164,6 +164,13 @@ final class EntitiesDataFetcher implements DataFetcher createDefaultError(theEx, theEnv))); } + private Throwable unwrapException(Throwable exception) { + if (exception instanceof CompletionException completionException) { + return (completionException.getCause() != null) ? completionException.getCause() : exception; + } + return exception; + } + private ErrorContainer createDefaultError(Throwable ex, DataFetchingEnvironment env) { ErrorType errorType = (ex instanceof RepresentationException representationEx) ? diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/federation/EntityArgumentMethodArgumentResolver.java b/spring-graphql/src/main/java/org/springframework/graphql/data/federation/EntityArgumentMethodArgumentResolver.java index 28202284..2f36d553 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/federation/EntityArgumentMethodArgumentResolver.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/federation/EntityArgumentMethodArgumentResolver.java @@ -22,12 +22,12 @@ import java.util.Map; import graphql.schema.DataFetchingEnvironment; import graphql.schema.DelegatingDataFetchingEnvironment; +import org.jspecify.annotations.Nullable; import org.springframework.core.ResolvableType; import org.springframework.graphql.data.GraphQlArgumentBinder; import org.springframework.graphql.data.method.annotation.Argument; import org.springframework.graphql.data.method.annotation.support.ArgumentMethodArgumentResolver; -import org.springframework.lang.Nullable; import org.springframework.validation.BindException; /** @@ -47,7 +47,7 @@ final class EntityArgumentMethodArgumentResolver extends ArgumentMethodArgumentR @Override - protected Object doBind( + protected @Nullable Object doBind( DataFetchingEnvironment environment, String name, ResolvableType targetType) throws BindException { if (environment instanceof EntityDataFetchingEnvironment entityEnv) { @@ -56,7 +56,7 @@ final class EntityArgumentMethodArgumentResolver extends ArgumentMethodArgumentR else if (environment instanceof EntityBatchDataFetchingEnvironment batchEnv) { name = dePluralize(name); targetType = targetType.getNested(2); - List values = new ArrayList<>(); + List<@Nullable Object> values = new ArrayList<>(); for (Map representation : batchEnv.getRepresentations()) { values.add(doBind(name, targetType, representation)); } @@ -67,8 +67,7 @@ final class EntityArgumentMethodArgumentResolver extends ArgumentMethodArgumentR } } - @Nullable - private Object doBind(String name, ResolvableType targetType, Map entityMap) throws BindException { + private @Nullable Object doBind(String name, ResolvableType targetType, Map entityMap) throws BindException { Object rawValue = entityMap.get(name); boolean isOmitted = !entityMap.containsKey(name); return getArgumentBinder().bind(rawValue, isOmitted, targetType); diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/federation/EntityArgumentsMethodArgumentResolver.java b/spring-graphql/src/main/java/org/springframework/graphql/data/federation/EntityArgumentsMethodArgumentResolver.java index 767d7c64..6a0e0de7 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/federation/EntityArgumentsMethodArgumentResolver.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/federation/EntityArgumentsMethodArgumentResolver.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.Map; import graphql.schema.DataFetchingEnvironment; +import org.jspecify.annotations.Nullable; import org.springframework.core.MethodParameter; import org.springframework.core.ResolvableType; @@ -60,7 +61,7 @@ final class EntityArgumentsMethodArgumentResolver implements HandlerMethodArgume } @Override - public Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment env) throws Exception { + public @Nullable Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment env) throws Exception { ResolvableType targetType = ResolvableType.forMethodParameter(parameter); if (env instanceof EntityDataFetchingEnvironment entityEnv) { return this.argumentBinder.bind(entityEnv.getRepresentation(), false, targetType); diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/federation/EntityHandlerMethod.java b/spring-graphql/src/main/java/org/springframework/graphql/data/federation/EntityHandlerMethod.java index 578c21df..830baebd 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/federation/EntityHandlerMethod.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/federation/EntityHandlerMethod.java @@ -21,12 +21,12 @@ import java.util.Map; import java.util.concurrent.Executor; import graphql.schema.DataFetchingEnvironment; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.graphql.data.method.HandlerMethodArgumentResolverComposite; import org.springframework.graphql.data.method.annotation.support.DataFetcherHandlerMethodSupport; import org.springframework.graphql.execution.ReactiveAdapterRegistryHelper; -import org.springframework.lang.Nullable; /** * Invokable controller method to fetch a federated entity. @@ -63,7 +63,7 @@ final class EntityHandlerMethod extends DataFetcherHandlerMethodSupport { } private Mono doInvoke(DataFetchingEnvironment env) { - Object[] args; + @Nullable Object[] args; try { args = getMethodArgumentValues(env); } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/federation/FederationSchemaFactory.java b/spring-graphql/src/main/java/org/springframework/graphql/data/federation/FederationSchemaFactory.java index c6182917..ec9efbc9 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/federation/FederationSchemaFactory.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/federation/FederationSchemaFactory.java @@ -32,6 +32,7 @@ import graphql.schema.GraphQLSchema; import graphql.schema.TypeResolver; import graphql.schema.idl.RuntimeWiring; import graphql.schema.idl.TypeDefinitionRegistry; +import org.jspecify.annotations.Nullable; import org.springframework.context.ApplicationContext; import org.springframework.context.expression.BeanFactoryResolver; @@ -53,7 +54,6 @@ import org.springframework.graphql.data.method.annotation.support.LocalContextVa import org.springframework.graphql.data.method.annotation.support.PrincipalMethodArgumentResolver; import org.springframework.graphql.execution.ClassNameTypeResolver; import org.springframework.graphql.execution.GraphQlSource.SchemaResourceBuilder; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -73,8 +73,7 @@ import org.springframework.util.StringUtils; public final class FederationSchemaFactory extends AnnotatedControllerDetectionSupport { - @Nullable - private TypeResolver typeResolver; + private @Nullable TypeResolver typeResolver; private final Map handlerMethods = new LinkedHashMap<>(); @@ -141,8 +140,7 @@ public final class FederationSchemaFactory @Override - @Nullable - protected EntityMappingInfo getMappingInfo(Method method, Object handler, Class handlerType) { + protected @Nullable EntityMappingInfo getMappingInfo(Method method, Object handler, Class handlerType) { EntityMapping mapping = AnnotatedElementUtils.findMergedAnnotation(method, EntityMapping.class); if (mapping == null) { return null; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/federation/RepresentationException.java b/spring-graphql/src/main/java/org/springframework/graphql/data/federation/RepresentationException.java index d69b1162..94d17e08 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/federation/RepresentationException.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/federation/RepresentationException.java @@ -19,9 +19,10 @@ package org.springframework.graphql.data.federation; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.graphql.data.method.HandlerMethod; import org.springframework.graphql.execution.ErrorType; -import org.springframework.lang.Nullable; /** * Raised when a representation could not be resolved because: @@ -41,8 +42,7 @@ public class RepresentationException extends RuntimeException { private final Map representation; - @Nullable - private final HandlerMethod handlerMethod; + private final @Nullable HandlerMethod handlerMethod; private final ErrorType errorType; @@ -62,16 +62,14 @@ public class RepresentationException extends RuntimeException { /** * Return the entity "representation" input map. */ - @Nullable - public Map getRepresentation() { + public @Nullable Map getRepresentation() { return this.representation; } /** * Return the mapped controller method, or {@code null} if it could not be mapped. */ - @Nullable - public HandlerMethod getHandlerMethod() { + public @Nullable HandlerMethod getHandlerMethod() { return this.handlerMethod; } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/federation/package-info.java b/spring-graphql/src/main/java/org/springframework/graphql/data/federation/package-info.java index b82ed4fe..ef254c4b 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/federation/package-info.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/federation/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * Copyright 2020-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,9 +21,7 @@ * via {@link org.springframework.graphql.data.federation.EntityMapping @EntityMapping} * controller methods. */ -@NonNullApi -@NonNullFields +@NullMarked package org.springframework.graphql.data.federation; -import org.springframework.lang.NonNullApi; -import org.springframework.lang.NonNullFields; +import org.jspecify.annotations.NullMarked; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/HandlerMethod.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/HandlerMethod.java index c493bdec..659a5527 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/HandlerMethod.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/HandlerMethod.java @@ -26,6 +26,7 @@ import java.util.stream.IntStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.BeanFactory; import org.springframework.core.BridgeMethodResolver; @@ -33,7 +34,6 @@ import org.springframework.core.MethodParameter; import org.springframework.core.ResolvableType; import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.annotation.SynthesizingMethodParameter; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; @@ -61,8 +61,7 @@ public class HandlerMethod { private final Object bean; - @Nullable - private final BeanFactory beanFactory; + private final @Nullable BeanFactory beanFactory; private final Class beanType; @@ -72,8 +71,7 @@ public class HandlerMethod { private final MethodParameter[] parameters; - @Nullable - private volatile List interfaceParameterAnnotations; + private volatile @Nullable List interfaceParameterAnnotations; /** @@ -221,8 +219,7 @@ public class HandlerMethod { * @return the annotation, or {@code null} if none found * @see AnnotatedElementUtils#findMergedAnnotation */ - @Nullable - public A getMethodAnnotation(Class annotationType) { + public @Nullable A getMethodAnnotation(Class annotationType) { return AnnotatedElementUtils.findMergedAnnotation(this.method, annotationType); } @@ -242,9 +239,8 @@ public class HandlerMethod { */ public HandlerMethod createWithResolvedBean() { Object handler = this.bean; - if (this.bean instanceof String) { + if (this.bean instanceof String beanName) { Assert.state(this.beanFactory != null, "Cannot resolve bean name without BeanFactory"); - String beanName = (String) this.bean; handler = this.beanFactory.getBean(beanName); } return new HandlerMethod(this, handler); @@ -317,9 +313,7 @@ public class HandlerMethod { // Support methods for use in "InvocableHandlerMethod" sub-class variants.. - - @Nullable - protected static Object findProvidedArgument(MethodParameter parameter, @Nullable Object... providedArgs) { + protected static @Nullable Object findProvidedArgument(MethodParameter parameter, Object... providedArgs) { if (!ObjectUtils.isEmpty(providedArgs)) { for (Object providedArg : providedArgs) { if (parameter.getParameterType().isInstance(providedArg)) { @@ -345,7 +339,7 @@ public class HandlerMethod { * @param targetBean the bean instance * @param args the method arguments */ - protected void assertTargetBean(Method method, Object targetBean, Object[] args) { + protected void assertTargetBean(Method method, Object targetBean, @Nullable Object[] args) { Class methodDeclaringClass = method.getDeclaringClass(); Class targetBeanClass = targetBean.getClass(); if (!methodDeclaringClass.isAssignableFrom(targetBeanClass)) { @@ -357,12 +351,18 @@ public class HandlerMethod { } } - protected String formatInvokeError(String text, Object[] args) { + protected String formatInvokeError(String text, @Nullable Object[] args) { String formattedArgs = IntStream.range(0, args.length) - .mapToObj((i) -> (args[i] != null) ? - "[" + i + "] [type=" + args[i].getClass().getName() + "] [value=" + args[i] + "]" : - "[" + i + "] [null]") + .mapToObj((i) -> { + Object arg = args[i]; + if (arg != null) { + return "[" + i + "] [type=" + arg.getClass().getName() + "] [value=" + arg + "]"; + } + else { + return "[" + i + "] [null]"; + } + }) .collect(Collectors.joining(",\n", " ", " ")); return text + "\n" + @@ -377,8 +377,7 @@ public class HandlerMethod { */ protected class HandlerMethodParameter extends SynthesizingMethodParameter { - @Nullable - private volatile Annotation[] combinedAnnotations; + private volatile Annotation @Nullable [] combinedAnnotations; public HandlerMethodParameter(int index) { super(HandlerMethod.this.bridgedMethod, index); @@ -394,7 +393,7 @@ public class HandlerMethod { } @Override - public T getMethodAnnotation(Class annotationType) { + public @Nullable T getMethodAnnotation(Class annotationType) { return HandlerMethod.this.getMethodAnnotation(annotationType); } @@ -404,6 +403,7 @@ public class HandlerMethod { } @Override + @SuppressWarnings("NullAway") public Annotation[] getParameterAnnotations() { Annotation[] anns = this.combinedAnnotations; if (anns == null) { @@ -450,8 +450,7 @@ public class HandlerMethod { */ private class ReturnValueMethodParameter extends HandlerMethodParameter { - @Nullable - private final Object returnValue; + private final @Nullable Object returnValue; ReturnValueMethodParameter(@Nullable Object returnValue) { super(-1); diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/HandlerMethodArgumentResolver.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/HandlerMethodArgumentResolver.java index e4cd87ce..e1a216af 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/HandlerMethodArgumentResolver.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/HandlerMethodArgumentResolver.java @@ -17,9 +17,9 @@ package org.springframework.graphql.data.method; import graphql.schema.DataFetchingEnvironment; +import org.jspecify.annotations.Nullable; import org.springframework.core.MethodParameter; -import org.springframework.lang.Nullable; /** * Strategy interface for resolving method parameters into argument values in @@ -50,7 +50,6 @@ public interface HandlerMethodArgumentResolver { * requires asynchronous resolution. * @throws Exception in case of errors with the preparation of argument values */ - @Nullable - Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) throws Exception; + @Nullable Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) throws Exception; } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/HandlerMethodArgumentResolverComposite.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/HandlerMethodArgumentResolverComposite.java index b94addd1..beae9ff7 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/HandlerMethodArgumentResolverComposite.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/HandlerMethodArgumentResolverComposite.java @@ -23,9 +23,9 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import graphql.schema.DataFetchingEnvironment; +import org.jspecify.annotations.Nullable; import org.springframework.core.MethodParameter; -import org.springframework.lang.Nullable; /** * Container for a list of resolvers that looks for one that supports a given @@ -74,8 +74,7 @@ public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgu * @throws IllegalArgumentException if no suitable argument resolver is found */ @Override - @Nullable - public Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) throws Exception { + public @Nullable Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) throws Exception { HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter); if (resolver == null) { throw new IllegalArgumentException("Unsupported parameter [" + parameter + "]."); @@ -88,8 +87,7 @@ public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgu * the given method parameter. * @param parameter the method parameter */ - @Nullable - public HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) { + public @Nullable HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) { return this.argumentResolverCache.computeIfAbsent(parameter, (p) -> { for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) { if (resolver.supportsParameter(parameter)) { diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/InvocableHandlerMethodSupport.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/InvocableHandlerMethodSupport.java index b551a7d8..5ec5c896 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/InvocableHandlerMethodSupport.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/InvocableHandlerMethodSupport.java @@ -27,13 +27,13 @@ import java.util.concurrent.Executor; import graphql.GraphQLContext; import io.micrometer.context.ContextSnapshot; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.core.CoroutinesUtils; import org.springframework.core.KotlinDetector; import org.springframework.data.util.KotlinReflectionUtils; import org.springframework.graphql.execution.ContextPropagationHelper; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -48,8 +48,7 @@ public abstract class InvocableHandlerMethodSupport extends HandlerMethod { private static final Object NO_VALUE = new Object(); - @Nullable - private final Executor executor; + private final @Nullable Executor executor; private final boolean hasCallableReturnValue; @@ -97,8 +96,7 @@ public abstract class InvocableHandlerMethodSupport extends HandlerMethod { * if the invocation fails. */ @SuppressWarnings("ReactiveStreamsUnusedPublisher") - @Nullable - protected Object doInvoke(GraphQLContext graphQLContext, Object... argValues) { + protected @Nullable Object doInvoke(GraphQLContext graphQLContext, @Nullable Object... argValues) { if (logger.isTraceEnabled()) { logger.trace("Invoking " + getBridgedMethod().getName() + "(" + Arrays.toString(argValues) + ")"); } @@ -134,7 +132,7 @@ public abstract class InvocableHandlerMethodSupport extends HandlerMethod { } @SuppressWarnings({"ReactiveStreamsUnusedPublisher", "unchecked"}) - private static Object invokeSuspendingFunction(Object bean, Method method, Object[] argValues) { + private static Object invokeSuspendingFunction(Object bean, Method method, @Nullable Object[] argValues) { Object result = CoroutinesUtils.invokeSuspendingFunction(method, bean, argValues); // Support use of DataLoader from suspending function @@ -148,9 +146,10 @@ public abstract class InvocableHandlerMethodSupport extends HandlerMethod { @SuppressWarnings("DataFlowIssue") private CompletableFuture adaptCallable( - GraphQLContext graphQLContext, Callable result, Method method, Object[] argValues) { + GraphQLContext graphQLContext, Callable result, Method method, @Nullable Object[] argValues) { CompletableFuture future = new CompletableFuture<>(); + Assert.state(this.executor != null, "No Executor configured for Callable return values"); this.executor.execute(() -> { try { ContextSnapshot snapshot = ContextPropagationHelper.captureFrom(graphQLContext); @@ -171,14 +170,14 @@ public abstract class InvocableHandlerMethodSupport extends HandlerMethod { } private IllegalStateException processIllegalArgumentException( - Object[] argValues, IllegalArgumentException ex, Method method) { + @Nullable Object[] argValues, IllegalArgumentException ex, Method method) { assertTargetBean(method, getBean(), argValues); String text = (ex.getMessage() != null) ? ex.getMessage() : "Illegal argument"; return new IllegalStateException(formatInvokeError(text, argValues), ex); } - private Throwable processInvocationTargetException(Object[] argValues, InvocationTargetException ex) { + private Throwable processInvocationTargetException(@Nullable Object[] argValues, InvocationTargetException ex) { // Unwrap for DataFetcherExceptionResolvers ... Throwable targetException = ex.getTargetException(); if (targetException instanceof Error || targetException instanceof Exception) { @@ -193,8 +192,8 @@ public abstract class InvocableHandlerMethodSupport extends HandlerMethod { * useful when at least one of the values is a {@link Mono} * @param args the arguments to be resolved asynchronously */ - @SuppressWarnings("unchecked") - protected Mono toArgsMono(Object[] args) { + @SuppressWarnings({"unchecked", "NullAway"}) + protected Mono<@Nullable Object[]> toArgsMono(@Nullable Object[] args) { List> monoList = new ArrayList<>(); for (Object arg : args) { Mono argMono = ((arg instanceof Mono) ? (Mono) arg : Mono.justOrEmpty(arg)); diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/package-info.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/package-info.java index f2145028..0a98173d 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/package-info.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * Copyright 2020-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,9 +18,7 @@ * Annotations for binding data fetching methods to GraphQL schema queries, * mutations, subscriptions, and fields. */ -@NonNullApi -@NonNullFields +@NullMarked package org.springframework.graphql.data.method.annotation; -import org.springframework.lang.NonNullApi; -import org.springframework.lang.NonNullFields; +import org.jspecify.annotations.NullMarked; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerConfigurer.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerConfigurer.java index 1df1b6ec..42e3128d 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerConfigurer.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerConfigurer.java @@ -45,6 +45,7 @@ import graphql.schema.GraphQLCodeRegistry; import graphql.schema.idl.RuntimeWiring; import graphql.schema.idl.TypeDefinitionRegistry; import org.dataloader.DataLoader; +import org.jspecify.annotations.Nullable; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -76,7 +77,6 @@ import org.springframework.graphql.execution.ReactiveAdapterRegistryHelper; import org.springframework.graphql.execution.RuntimeWiringConfigurer; import org.springframework.graphql.execution.SelfDescribingDataFetcher; import org.springframework.graphql.execution.SubscriptionPublisherException; -import org.springframework.lang.Nullable; import org.springframework.stereotype.Controller; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -129,8 +129,7 @@ public class AnnotatedControllerConfigurer private final InterfaceMappingHelper interfaceMappingHelper = new InterfaceMappingHelper(); - @Nullable - private ValidationHelper validationHelper; + private @Nullable ValidationHelper validationHelper; /** @@ -252,7 +251,7 @@ public class AnnotatedControllerConfigurer } @Override - protected DataFetcherMappingInfo getMappingInfo(Method method, Object handler, Class handlerType) { + protected @Nullable DataFetcherMappingInfo getMappingInfo(Method method, Object handler, Class handlerType) { Set annotations = AnnotatedElementUtils.findAllMergedAnnotations( method, new LinkedHashSet<>(Arrays.asList(BatchMapping.class, SchemaMapping.class))); @@ -434,13 +433,11 @@ public class AnnotatedControllerConfigurer private final HandlerMethodArgumentResolverComposite argumentResolvers; - @Nullable - private final BiConsumer methodValidationHelper; + private final @Nullable BiConsumer methodValidationHelper; private final HandlerDataFetcherExceptionResolver exceptionResolver; - @Nullable - private final Executor executor; + private final @Nullable Executor executor; private final boolean invokeAsync; @@ -511,7 +508,7 @@ public class AnnotatedControllerConfigurer @Override @SuppressWarnings({"ConstantConditions", "ReactiveStreamsUnusedPublisher"}) - public Object get(DataFetchingEnvironment environment) throws Exception { + public @Nullable Object get(DataFetchingEnvironment environment) throws Exception { DataFetcherHandlerMethod handlerMethod = new DataFetcherHandlerMethod( getHandlerMethod(), this.argumentResolvers, this.methodValidationHelper, @@ -527,9 +524,8 @@ public class AnnotatedControllerConfigurer } @SuppressWarnings({"unchecked", "ReactiveStreamsUnusedPublisher"}) - @Nullable - private Object applyExceptionHandling( - DataFetchingEnvironment env, DataFetcherHandlerMethod handlerMethod, Object result) { + private @Nullable Object applyExceptionHandling( + DataFetchingEnvironment env, DataFetcherHandlerMethod handlerMethod, @Nullable Object result) { if (this.subscription) { return ReactiveAdapterRegistryHelper.toSubscriptionFlux(result) @@ -603,7 +599,8 @@ public class AnnotatedControllerConfigurer @Override public Object get(DataFetchingEnvironment env) { DataLoader dataLoader = env.getDataLoader(this.dataLoaderKey); - Assert.state(dataLoader != null, "No DataLoader for key '" + this.dataLoaderKey + "'"); + Assert.state(dataLoader != null, () -> "No DataLoader for key '" + this.dataLoaderKey + "'"); + Assert.state(env.getSource() != null, () -> "Missing Source in environment"); return ((env.getLocalContext() != null) ? dataLoader.load(env.getSource(), env.getLocalContext()) : dataLoader.load(env.getSource())); diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerDetectionSupport.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerDetectionSupport.java index 1e059021..7c1d25a2 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerDetectionSupport.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerDetectionSupport.java @@ -30,6 +30,7 @@ import java.util.function.Predicate; import graphql.schema.DataFetcher; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.aop.support.AopUtils; import org.springframework.beans.factory.InitializingBean; @@ -46,7 +47,6 @@ import org.springframework.format.support.FormattingConversionService; import org.springframework.graphql.data.method.HandlerMethod; import org.springframework.graphql.data.method.HandlerMethodArgumentResolverComposite; import org.springframework.graphql.execution.DataFetcherExceptionResolver; -import org.springframework.lang.Nullable; import org.springframework.scheduling.SchedulingTaskExecutor; import org.springframework.stereotype.Controller; import org.springframework.util.Assert; @@ -90,20 +90,16 @@ public abstract class AnnotatedControllerDetectionSupport implements Applicat private boolean fallBackOnDirectFieldAccess; - @Nullable - private AnnotatedControllerExceptionResolver exceptionResolver; + private @Nullable AnnotatedControllerExceptionResolver exceptionResolver; - @Nullable - private Executor executor; + private @Nullable Executor executor; private Predicate blockingMethodPredicate = (virtualThreadsPresent) ? new BlockingHandlerMethodPredicate() : ((method) -> false); - @Nullable - private HandlerMethodArgumentResolverComposite argumentResolvers; + private @Nullable HandlerMethodArgumentResolverComposite argumentResolvers; - @Nullable - private ApplicationContext applicationContext; + private @Nullable ApplicationContext applicationContext; /** @@ -171,8 +167,7 @@ public abstract class AnnotatedControllerDetectionSupport implements Applicat /** * Return the {@link #setExecutor(Executor) configured Executor}. */ - @Nullable - public Executor getExecutor() { + public @Nullable Executor getExecutor() { return this.executor; } @@ -207,8 +202,7 @@ public abstract class AnnotatedControllerDetectionSupport implements Applicat this.applicationContext = applicationContext; } - @Nullable - protected ApplicationContext getApplicationContext() { + protected @Nullable ApplicationContext getApplicationContext() { return this.applicationContext; } @@ -273,8 +267,7 @@ public abstract class AnnotatedControllerDetectionSupport implements Applicat return map.values(); } - @Nullable - protected abstract M getMappingInfo(Method method, Object handler, Class handlerType); + protected abstract @Nullable M getMappingInfo(Method method, Object handler, Class handlerType); protected HandlerMethod createHandlerMethod(Method originalMethod, Object handler, Class handlerType) { Method method = AopUtils.selectInvocableMethod(originalMethod, handlerType); diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerExceptionResolver.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerExceptionResolver.java index 1ddc505d..45f3c250 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerExceptionResolver.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerExceptionResolver.java @@ -31,6 +31,7 @@ import graphql.GraphQLError; import graphql.schema.DataFetchingEnvironment; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.context.ApplicationContext; @@ -44,7 +45,6 @@ import org.springframework.graphql.data.method.HandlerMethod; import org.springframework.graphql.data.method.HandlerMethodArgumentResolverComposite; import org.springframework.graphql.data.method.annotation.GraphQlExceptionHandler; import org.springframework.graphql.execution.DataFetcherExceptionResolver; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ConcurrentReferenceHashMap; @@ -204,7 +204,7 @@ final class AnnotatedControllerExceptionResolver implements HandlerDataFetcherEx } } - if (methodReturnValueAdapter == null) { + if (methodReturnValueAdapter == null || controllerOrAdvice == null) { return Mono.empty(); } @@ -267,7 +267,7 @@ final class AnnotatedControllerExceptionResolver implements HandlerDataFetcherEx */ private static final class MethodResolver { - @SuppressWarnings("DataFlowIssue") + @SuppressWarnings({"DataFlowIssue", "NullAway"}) private static final MethodReturnValueAdapter NO_MATCH = new MethodReturnValueAdapter(ReflectionUtils.findMethod(MethodResolver.class, "noMatch")); @@ -287,8 +287,7 @@ final class AnnotatedControllerExceptionResolver implements HandlerDataFetcherEx * @param exception the exception * @return the exception handler to use, or {@code null} if no match */ - @Nullable - MethodReturnValueAdapter resolveMethod(Throwable exception) { + @Nullable MethodReturnValueAdapter resolveMethod(Throwable exception) { MethodReturnValueAdapter method = resolveMethodByExceptionType(exception.getClass()); if (method == null) { Throwable cause = exception.getCause(); @@ -299,8 +298,7 @@ final class AnnotatedControllerExceptionResolver implements HandlerDataFetcherEx return method; } - @Nullable - private MethodReturnValueAdapter resolveMethodByExceptionType(Class exceptionType) { + private @Nullable MethodReturnValueAdapter resolveMethodByExceptionType(Class exceptionType) { MethodReturnValueAdapter method = this.resolvedExceptionCache.get(exceptionType); if (method == null) { method = getMappedMethod(exceptionType); @@ -309,6 +307,7 @@ final class AnnotatedControllerExceptionResolver implements HandlerDataFetcherEx return (method != NO_MATCH) ? method : null; } + @SuppressWarnings("NullAway") private MethodReturnValueAdapter getMappedMethod(Class exceptionType) { List> matches = new ArrayList<>(); for (Class mappedException : this.exceptionMappings.keySet()) { diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ArgumentMethodArgumentResolver.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ArgumentMethodArgumentResolver.java index f7366853..67ddd4c1 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ArgumentMethodArgumentResolver.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ArgumentMethodArgumentResolver.java @@ -17,6 +17,7 @@ package org.springframework.graphql.data.method.annotation.support; import graphql.schema.DataFetchingEnvironment; +import org.jspecify.annotations.Nullable; import org.springframework.core.MethodParameter; import org.springframework.core.ResolvableType; @@ -24,7 +25,6 @@ import org.springframework.graphql.data.ArgumentValue; import org.springframework.graphql.data.GraphQlArgumentBinder; import org.springframework.graphql.data.method.HandlerMethodArgumentResolver; import org.springframework.graphql.data.method.annotation.Argument; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.validation.BindException; @@ -76,7 +76,7 @@ public class ArgumentMethodArgumentResolver implements HandlerMethodArgumentReso } @Override - public Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) throws Exception { + public @Nullable Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) throws Exception { String name = getArgumentName(parameter); ResolvableType targetType = ResolvableType.forMethodParameter(parameter); return doBind(environment, name, targetType); @@ -89,8 +89,7 @@ public class ArgumentMethodArgumentResolver implements HandlerMethodArgumentReso * @param targetType the type of Object to create * @since 1.3.0 */ - @Nullable - protected Object doBind( + protected @Nullable Object doBind( DataFetchingEnvironment environment, String name, ResolvableType targetType) throws BindException { return this.argumentBinder.bind(environment, name, targetType); diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ArgumentsMethodArgumentResolver.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ArgumentsMethodArgumentResolver.java index 3291fb8c..69b61a3b 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ArgumentsMethodArgumentResolver.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ArgumentsMethodArgumentResolver.java @@ -17,6 +17,7 @@ package org.springframework.graphql.data.method.annotation.support; import graphql.schema.DataFetchingEnvironment; +import org.jspecify.annotations.Nullable; import org.springframework.core.MethodParameter; import org.springframework.core.ResolvableType; @@ -56,7 +57,7 @@ public class ArgumentsMethodArgumentResolver implements HandlerMethodArgumentRes } @Override - public Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) throws Exception { + public @Nullable Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) throws Exception { ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter); return this.argumentBinder.bind(environment, null, resolvableType); } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AuthenticationPrincipalArgumentResolver.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AuthenticationPrincipalArgumentResolver.java index 6a077057..1dbcf8c7 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AuthenticationPrincipalArgumentResolver.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AuthenticationPrincipalArgumentResolver.java @@ -19,6 +19,7 @@ package org.springframework.graphql.data.method.annotation.support; import java.lang.annotation.Annotation; import graphql.schema.DataFetchingEnvironment; +import org.jspecify.annotations.Nullable; import org.reactivestreams.Publisher; import reactor.core.publisher.Mono; @@ -30,7 +31,6 @@ import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.graphql.data.method.HandlerMethodArgumentResolver; -import org.springframework.lang.Nullable; import org.springframework.security.core.Authentication; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.core.context.ReactiveSecurityContextHolder; @@ -79,8 +79,7 @@ public class AuthenticationPrincipalArgumentResolver implements HandlerMethodArg * directly on the {@link MethodParameter} or on a custom annotation that * is meta-annotated with it. */ - @Nullable - private static AuthenticationPrincipal findMethodAnnotation(MethodParameter parameter) { + private static @Nullable AuthenticationPrincipal findMethodAnnotation(MethodParameter parameter) { AuthenticationPrincipal annotation = parameter.getParameterAnnotation(AuthenticationPrincipal.class); if (annotation != null) { return annotation; @@ -96,7 +95,7 @@ public class AuthenticationPrincipalArgumentResolver implements HandlerMethodArg } @Override - public Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) throws Exception { + public @Nullable Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) throws Exception { return getCurrentAuthentication(parameter) .mapNotNull((auth) -> resolvePrincipal(parameter, auth.getPrincipal())) .transform((argument) -> isPublisherOrMono(parameter) ? Mono.just(argument) : argument); @@ -113,20 +112,18 @@ public class AuthenticationPrincipalArgumentResolver implements HandlerMethodArg return (value instanceof Authentication auth) ? Mono.just(auth) : (Mono) value; } - @Nullable - private Object resolvePrincipal(MethodParameter parameter, Object principal) { + private @Nullable Object resolvePrincipal(MethodParameter parameter, Object principal) { AuthenticationPrincipal annotation = findMethodAnnotation(parameter); - String expressionValue = annotation.expression(); - if (StringUtils.hasLength(expressionValue)) { + if (annotation != null && StringUtils.hasLength(annotation.expression())) { StandardEvaluationContext context = new StandardEvaluationContext(); context.setRootObject(principal); context.setVariable("this", principal); context.setBeanResolver(this.beanResolver); - Expression expression = this.parser.parseExpression(expressionValue); + Expression expression = this.parser.parseExpression(annotation.expression()); principal = expression.getValue(context); } if (isInvalidType(parameter, principal)) { - if (annotation.errorOnInvalidType()) { + if (annotation != null && annotation.errorOnInvalidType()) { throw new ClassCastException(principal + " is not assignable to " + parameter.getParameterType()); } return null; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/BatchLoaderHandlerMethod.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/BatchLoaderHandlerMethod.java index 7e5610f9..bfff3caf 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/BatchLoaderHandlerMethod.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/BatchLoaderHandlerMethod.java @@ -25,6 +25,7 @@ import java.util.concurrent.Executor; import graphql.GraphQLContext; import org.dataloader.BatchLoaderEnvironment; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -36,7 +37,6 @@ import org.springframework.graphql.data.method.HandlerMethod; import org.springframework.graphql.data.method.InvocableHandlerMethodSupport; import org.springframework.graphql.data.method.annotation.ContextValue; import org.springframework.graphql.execution.ReactiveAdapterRegistryHelper; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -91,15 +91,16 @@ public class BatchLoaderHandlerMethod extends InvocableHandlerMethodSupport { * @param the type of values in the map * @return a {@code Mono} with map of key-value pairs. */ - @Nullable - public Mono> invokeForMap(Collection keys, BatchLoaderEnvironment environment) { - Object[] args = getMethodArgumentValues(keys, environment); + public @Nullable Mono> invokeForMap(Collection keys, BatchLoaderEnvironment environment) { + @Nullable Object[] args = getMethodArgumentValues(keys, environment); + GraphQLContext context = environment.getContext(); + Assert.notNull(context, "No GraphQLContext available"); if (doesNotHaveAsyncArgs(args)) { - Object result = doInvoke(environment.getContext(), args); + Object result = doInvoke(context, args); return ReactiveAdapterRegistryHelper.toMono(result); } return toArgsMono(args).flatMap((argValues) -> { - Object result = doInvoke(environment.getContext(), argValues); + Object result = doInvoke(context, argValues); return ReactiveAdapterRegistryHelper.toMono(result); }); } @@ -113,27 +114,28 @@ public class BatchLoaderHandlerMethod extends InvocableHandlerMethodSupport { * @return a {@code Flux} of values. */ public Flux invokeForIterable(Collection keys, BatchLoaderEnvironment environment) { - Object[] args = getMethodArgumentValues(keys, environment); + @Nullable Object[] args = getMethodArgumentValues(keys, environment); + GraphQLContext context = environment.getContext(); + Assert.notNull(context, "No GraphQLContext available"); if (doesNotHaveAsyncArgs(args)) { - Object result = doInvoke(environment.getContext(), args); + Object result = doInvoke(context, args); return ReactiveAdapterRegistryHelper.toFluxFromCollection(result); } return toArgsMono(args).flatMapMany((resolvedArgs) -> { - Object result = doInvoke(environment.getContext(), resolvedArgs); + Object result = doInvoke(context, resolvedArgs); return ReactiveAdapterRegistryHelper.toFluxFromCollection(result); }); } - private Object[] getMethodArgumentValues(Collection keys, BatchLoaderEnvironment environment) { - Object[] args = new Object[getMethodParameters().length]; + private @Nullable Object[] getMethodArgumentValues(Collection keys, BatchLoaderEnvironment environment) { + @Nullable Object[] args = new Object[getMethodParameters().length]; for (int i = 0; i < getMethodParameters().length; i++) { args[i] = resolveArgument(getMethodParameters()[i], keys, environment); } return args; } - @Nullable - private Object resolveArgument( + private @Nullable Object resolveArgument( MethodParameter parameter, Collection keys, BatchLoaderEnvironment environment) { parameter.initParameterNameDiscovery(this.parameterNameDiscoverer); @@ -169,8 +171,7 @@ public class BatchLoaderHandlerMethod extends InvocableHandlerMethodSupport { } } - @Nullable - private Object resolveContextValueArgument(MethodParameter parameter, BatchLoaderEnvironment environment) { + private @Nullable Object resolveContextValueArgument(MethodParameter parameter, BatchLoaderEnvironment environment) { ContextValue annotation = parameter.getParameterAnnotation(ContextValue.class); Assert.state(annotation != null, "Expected @ContextValue annotation"); @@ -180,7 +181,7 @@ public class BatchLoaderHandlerMethod extends InvocableHandlerMethodSupport { name, annotation.required(), parameter, environment.getContext()); } - private boolean doesNotHaveAsyncArgs(Object[] args) { + private boolean doesNotHaveAsyncArgs(@Nullable Object[] args) { return Arrays.stream(args).noneMatch((arg) -> arg instanceof Mono); } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ContextValueMethodArgumentResolver.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ContextValueMethodArgumentResolver.java index e06c566e..977aca06 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ContextValueMethodArgumentResolver.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ContextValueMethodArgumentResolver.java @@ -21,12 +21,12 @@ import java.util.Optional; import graphql.GraphQLContext; import graphql.schema.DataFetchingEnvironment; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.core.MethodParameter; import org.springframework.graphql.data.method.HandlerMethodArgumentResolver; import org.springframework.graphql.data.method.annotation.ContextValue; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -45,7 +45,7 @@ public class ContextValueMethodArgumentResolver implements HandlerMethodArgument } @Override - public Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) { + public @Nullable Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) { ContextValue annotation = parameter.getParameterAnnotation(ContextValue.class); Assert.state(annotation != null, "Expected @ContextValue annotation"); @@ -67,8 +67,7 @@ public class ContextValueMethodArgumentResolver implements HandlerMethodArgument "and parameter name information not found in class file either."); } - @Nullable - static Object resolveContextValue( + static @Nullable Object resolveContextValue( String contextValueName, boolean required, MethodParameter parameter, @Nullable GraphQLContext graphQlContext) { diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ContinuationHandlerMethodArgumentResolver.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ContinuationHandlerMethodArgumentResolver.java index 903e5666..a5091d51 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ContinuationHandlerMethodArgumentResolver.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ContinuationHandlerMethodArgumentResolver.java @@ -17,6 +17,7 @@ package org.springframework.graphql.data.method.annotation.support; import graphql.schema.DataFetchingEnvironment; +import org.jspecify.annotations.Nullable; import org.springframework.core.MethodParameter; import org.springframework.graphql.data.method.HandlerMethodArgumentResolver; @@ -35,7 +36,7 @@ public class ContinuationHandlerMethodArgumentResolver implements HandlerMethodA } @Override - public Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) { + public @Nullable Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) { return null; } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethod.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethod.java index ee830009..3185f7fc 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethod.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethod.java @@ -22,13 +22,13 @@ import java.util.concurrent.Executor; import java.util.function.BiConsumer; import graphql.schema.DataFetchingEnvironment; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.graphql.data.method.HandlerMethod; import org.springframework.graphql.data.method.HandlerMethodArgumentResolver; import org.springframework.graphql.data.method.HandlerMethodArgumentResolverComposite; import org.springframework.graphql.execution.ReactiveAdapterRegistryHelper; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -39,7 +39,7 @@ import org.springframework.util.Assert; */ public class DataFetcherHandlerMethod extends DataFetcherHandlerMethodSupport { - private final BiConsumer validationHelper; + private final BiConsumer validationHelper; private final boolean subscription; @@ -56,7 +56,7 @@ public class DataFetcherHandlerMethod extends DataFetcherHandlerMethodSupport { @Deprecated(since = "1.3.0", forRemoval = true) public DataFetcherHandlerMethod( HandlerMethod handlerMethod, HandlerMethodArgumentResolverComposite resolvers, - @Nullable BiConsumer validationHelper, @Nullable Executor executor, + @Nullable BiConsumer validationHelper, @Nullable Executor executor, boolean subscription) { this(handlerMethod, resolvers, validationHelper, executor, subscription, false); @@ -74,12 +74,17 @@ public class DataFetcherHandlerMethod extends DataFetcherHandlerMethodSupport { */ public DataFetcherHandlerMethod( HandlerMethod handlerMethod, HandlerMethodArgumentResolverComposite resolvers, - @Nullable BiConsumer validationHelper, + @Nullable BiConsumer validationHelper, @Nullable Executor executor, boolean invokeAsync, boolean subscription) { super(handlerMethod, resolvers, executor, invokeAsync); Assert.isTrue(!resolvers.getResolvers().isEmpty(), "No argument resolvers"); - this.validationHelper = (validationHelper != null) ? validationHelper : (controller, args) -> { }; + this.validationHelper = (validationHelper != null) ? validationHelper : new BiConsumer() { + @Override + public void accept(Object o, @Nullable Object[] objects) { + + } + }; this.subscription = subscription; } @@ -98,8 +103,7 @@ public class DataFetcherHandlerMethod extends DataFetcherHandlerMethodSupport { * {@code Mono} in case a method argument requires asynchronous resolution; * {@code Mono} is returned if invocation fails. */ - @Nullable - public Object invoke(DataFetchingEnvironment environment) { + public @Nullable Object invoke(DataFetchingEnvironment environment) { return invoke(environment, new Object[0]); } @@ -111,9 +115,8 @@ public class DataFetcherHandlerMethod extends DataFetcherHandlerMethodSupport { * @since 1.2.0 */ @SuppressWarnings("ReactiveStreamsUnusedPublisher") - @Nullable - public Object invoke(DataFetchingEnvironment environment, Object... providedArgs) { - Object[] args; + public @Nullable Object invoke(DataFetchingEnvironment environment, Object... providedArgs) { + @Nullable Object[] args; try { args = getMethodArgumentValues(environment, providedArgs); } @@ -136,8 +139,7 @@ public class DataFetcherHandlerMethod extends DataFetcherHandlerMethodSupport { }); } - @Nullable - private Object validateAndInvoke(Object[] args, DataFetchingEnvironment environment) { + private @Nullable Object validateAndInvoke(@Nullable Object[] args, DataFetchingEnvironment environment) { this.validationHelper.accept(getBean(), args); return doInvoke(environment.getGraphQlContext(), args); } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethodSupport.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethodSupport.java index fb8a42ff..fff900f0 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethodSupport.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethodSupport.java @@ -19,6 +19,7 @@ package org.springframework.graphql.data.method.annotation.support; import java.util.concurrent.Executor; import graphql.schema.DataFetchingEnvironment; +import org.jspecify.annotations.Nullable; import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.core.MethodParameter; @@ -26,7 +27,6 @@ import org.springframework.core.ParameterNameDiscoverer; import org.springframework.graphql.data.method.HandlerMethod; import org.springframework.graphql.data.method.HandlerMethodArgumentResolverComposite; import org.springframework.graphql.data.method.InvocableHandlerMethodSupport; -import org.springframework.lang.Nullable; import org.springframework.util.ObjectUtils; @@ -69,7 +69,7 @@ public class DataFetcherHandlerMethodSupport extends InvocableHandlerMethodSuppo * @param environment the data fetching environment to resolve arguments from * @param providedArgs the arguments provided directly */ - protected Object[] getMethodArgumentValues( + protected @Nullable Object[] getMethodArgumentValues( DataFetchingEnvironment environment, Object... providedArgs) throws Exception { MethodParameter[] parameters = getMethodParameters(); @@ -77,7 +77,7 @@ public class DataFetcherHandlerMethodSupport extends InvocableHandlerMethodSuppo return EMPTY_ARGS; } - Object[] args = new Object[parameters.length]; + @Nullable Object[] args = new Object[parameters.length]; for (int i = 0; i < parameters.length; i++) { MethodParameter parameter = parameters[i]; parameter.initParameterNameDiscovery(this.parameterNameDiscoverer); diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetcherMappingInfo.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetcherMappingInfo.java index 7b386f55..75e79539 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetcherMappingInfo.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetcherMappingInfo.java @@ -17,11 +17,11 @@ package org.springframework.graphql.data.method.annotation.support; import graphql.schema.FieldCoordinates; +import org.jspecify.annotations.Nullable; import org.springframework.graphql.data.method.HandlerMethod; import org.springframework.graphql.data.method.annotation.BatchMapping; import org.springframework.graphql.data.method.annotation.SchemaMapping; -import org.springframework.lang.Nullable; /** diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetchingEnvironmentMethodArgumentResolver.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetchingEnvironmentMethodArgumentResolver.java index 1bef3e3a..bed0574b 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetchingEnvironmentMethodArgumentResolver.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetchingEnvironmentMethodArgumentResolver.java @@ -23,6 +23,7 @@ import graphql.GraphQLContext; import graphql.GraphqlErrorBuilder; import graphql.schema.DataFetchingEnvironment; import graphql.schema.DataFetchingFieldSelectionSet; +import org.jspecify.annotations.Nullable; import org.springframework.core.MethodParameter; import org.springframework.graphql.data.method.HandlerMethodArgumentResolver; @@ -55,7 +56,7 @@ public class DataFetchingEnvironmentMethodArgumentResolver implements HandlerMet } @Override - public Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) { + public @Nullable Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) { Class type = parameter.getParameterType(); if (type.equals(GraphQLContext.class)) { return environment.getGraphQlContext(); diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataLoaderMethodArgumentResolver.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataLoaderMethodArgumentResolver.java index 02d2155e..d0355a75 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataLoaderMethodArgumentResolver.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataLoaderMethodArgumentResolver.java @@ -21,11 +21,11 @@ import java.lang.reflect.Type; import graphql.schema.DataFetchingEnvironment; import org.dataloader.DataLoader; +import org.jspecify.annotations.Nullable; import org.springframework.core.MethodParameter; import org.springframework.core.ResolvableType; import org.springframework.graphql.data.method.HandlerMethodArgumentResolver; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -73,8 +73,7 @@ public class DataLoaderMethodArgumentResolver implements HandlerMethodArgumentRe return dataLoader; } - @Nullable - private Class getValueType(MethodParameter param) { + private @Nullable Class getValueType(MethodParameter param) { Assert.isAssignable(DataLoader.class, param.getParameterType()); Type genericType = param.getGenericParameterType(); if (genericType instanceof ParameterizedType) { @@ -92,27 +91,36 @@ public class DataLoaderMethodArgumentResolver implements HandlerMethodArgumentRe MethodParameter parameter, DataFetchingEnvironment environment, @Nullable Class valueType, @Nullable String parameterName) { - String message = "Cannot resolve DataLoader for parameter" + - ((parameterName != null) ? " '" + parameterName + "'" : "[" + parameter.getParameterIndex() + "]") + - " in method " + parameter.getMethod().toGenericString() + ". "; + StringBuilder builder = new StringBuilder("Cannot resolve DataLoader for parameter"); - if (valueType == null) { - message += "If the batch loader was registered without a name, " + - "then declaring the DataLoader argument with generic types should help " + - "to look up the DataLoader based on the value type name."; - } - else if (parameterName == null) { - message += "If the batch loader was registered with a name, " + - "then compiling with \"-parameters\" should help " + - "to look up the DataLoader based on the parameter name."; + if (parameterName != null) { + builder.append(" '").append(parameterName).append("'"); } else { - message += "Neither the name of the declared value type '" + valueType + "' " + - "nor the method parameter name '" + parameterName + "' match to any DataLoader. " + - "The DataLoaderRegistry contains: " + environment.getDataLoaderRegistry().getKeys(); + builder.append("[").append(parameter.getParameterIndex()).append("]"); } + if (parameter.getMethod() != null) { + builder.append(" in method ").append(parameter.getMethod().toGenericString()); + } + builder.append(". "); - return message; + if (valueType == null) { + builder.append("If the batch loader was registered without a name, " + + "then declaring the DataLoader argument with generic types should help " + + "to look up the DataLoader based on the value type name."); + } + else if (parameterName == null) { + builder.append("If the batch loader was registered with a name, " + + "then compiling with \"-parameters\" should help " + + "to look up the DataLoader based on the parameter name."); + } + else { + builder.append("Neither the name of the declared value type '").append(valueType) + .append("' nor the method parameter name '").append(parameterName) + .append("' match to any DataLoader. The DataLoaderRegistry contains: ") + .append(environment.getDataLoaderRegistry().getKeys()); + } + return builder.toString(); } } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/HandlerDataFetcherExceptionResolver.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/HandlerDataFetcherExceptionResolver.java index 7ade226f..6b6ff602 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/HandlerDataFetcherExceptionResolver.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/HandlerDataFetcherExceptionResolver.java @@ -20,10 +20,10 @@ import java.util.List; import graphql.GraphQLError; import graphql.schema.DataFetchingEnvironment; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.graphql.execution.DataFetcherExceptionResolver; -import org.springframework.lang.Nullable; /** * Extension of {@link DataFetcherExceptionResolver} with overloaded method to diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/LocalContextValueMethodArgumentResolver.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/LocalContextValueMethodArgumentResolver.java index 5915bdc9..102aba89 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/LocalContextValueMethodArgumentResolver.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/LocalContextValueMethodArgumentResolver.java @@ -18,6 +18,7 @@ package org.springframework.graphql.data.method.annotation.support; import graphql.GraphQLContext; import graphql.schema.DataFetchingEnvironment; +import org.jspecify.annotations.Nullable; import org.springframework.core.MethodParameter; import org.springframework.graphql.data.method.HandlerMethodArgumentResolver; @@ -40,7 +41,7 @@ public class LocalContextValueMethodArgumentResolver implements HandlerMethodArg } @Override - public Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) { + public @Nullable Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) { LocalContextValue annotation = parameter.getParameterAnnotation(LocalContextValue.class); Assert.state(annotation != null, "Expected @LocalContextValue annotation"); diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ProjectedPayloadMethodArgumentResolver.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ProjectedPayloadMethodArgumentResolver.java index 628f7a30..d493cf96 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ProjectedPayloadMethodArgumentResolver.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ProjectedPayloadMethodArgumentResolver.java @@ -21,6 +21,7 @@ import java.util.Map; import java.util.Optional; import graphql.schema.DataFetchingEnvironment; +import org.jspecify.annotations.Nullable; import org.springframework.context.ApplicationContext; import org.springframework.core.MethodParameter; @@ -104,7 +105,7 @@ public class ProjectedPayloadMethodArgumentResolver implements HandlerMethodArgu } @Override - public Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) throws Exception { + public @Nullable Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) throws Exception { String name = (parameter.hasParameterAnnotation(Argument.class) ? ArgumentMethodArgumentResolver.getArgumentName(parameter) : null); diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingBeanFactoryInitializationAotProcessor.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingBeanFactoryInitializationAotProcessor.java index da47ab22..5310a97d 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingBeanFactoryInitializationAotProcessor.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingBeanFactoryInitializationAotProcessor.java @@ -139,7 +139,7 @@ class SchemaMappingBeanFactoryInitializationAotProcessor implements BeanFactoryI RuntimeHints runtimeHints = context.getRuntimeHints(); registerSpringDataSpelSupport(runtimeHints); this.controllers.forEach((controller) -> { - runtimeHints.reflection().registerType(controller, MemberCategory.INTROSPECT_DECLARED_METHODS); + runtimeHints.reflection().registerType(controller); ReflectionUtils.doWithMethods(controller, (method) -> processSchemaMappingMethod(runtimeHints, method), this::isGraphQlHandlerMethod); @@ -148,7 +148,7 @@ class SchemaMappingBeanFactoryInitializationAotProcessor implements BeanFactoryI this::isExceptionHandlerMethod); }); this.controllerAdvices.forEach((controllerAdvice) -> { - runtimeHints.reflection().registerType(controllerAdvice, MemberCategory.INTROSPECT_DECLARED_METHODS); + runtimeHints.reflection().registerType(controllerAdvice); ReflectionUtils.doWithMethods(controllerAdvice, (method) -> processExceptionHandlerMethod(runtimeHints, method), this::isExceptionHandlerMethod); diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ScrollSubrangeMethodArgumentResolver.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ScrollSubrangeMethodArgumentResolver.java index fbc259b7..05d1054c 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ScrollSubrangeMethodArgumentResolver.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ScrollSubrangeMethodArgumentResolver.java @@ -17,11 +17,12 @@ package org.springframework.graphql.data.method.annotation.support; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.data.domain.ScrollPosition; import org.springframework.graphql.data.pagination.CursorStrategy; import org.springframework.graphql.data.query.ScrollSubrange; -import org.springframework.lang.Nullable; /** diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/SubrangeMethodArgumentResolver.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/SubrangeMethodArgumentResolver.java index 949b39b9..f6aa41c6 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/SubrangeMethodArgumentResolver.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/SubrangeMethodArgumentResolver.java @@ -18,12 +18,12 @@ package org.springframework.graphql.data.method.annotation.support; import graphql.schema.DataFetchingEnvironment; +import org.jspecify.annotations.Nullable; import org.springframework.core.MethodParameter; import org.springframework.graphql.data.method.HandlerMethodArgumentResolver; import org.springframework.graphql.data.pagination.CursorStrategy; import org.springframework.graphql.data.pagination.Subrange; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ValidationHelper.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ValidationHelper.java index 778eb614..01676249 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ValidationHelper.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ValidationHelper.java @@ -26,13 +26,13 @@ import jakarta.validation.ConstraintViolation; import jakarta.validation.ConstraintViolationException; import jakarta.validation.Valid; import jakarta.validation.Validator; +import org.jspecify.annotations.Nullable; import org.springframework.context.ApplicationContext; import org.springframework.core.MethodParameter; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.MergedAnnotations; import org.springframework.graphql.data.method.HandlerMethod; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.validation.annotation.Validated; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; @@ -61,8 +61,7 @@ final class ValidationHelper { * possibly {@code null} if the method or the method parameters do not have * {@link Validated}, {@link Valid}, or {@link Constraint} annotations. */ - @Nullable - BiConsumer getValidationHelperFor(HandlerMethod handlerMethod) { + @Nullable BiConsumer getValidationHelperFor(HandlerMethod handlerMethod) { boolean requiresMethodValidation = false; Class[] methodValidationGroups = null; @@ -76,7 +75,7 @@ final class ValidationHelper { requiresMethodValidation = true; } - BiConsumer parameterValidator = null; + BiConsumer parameterValidator = null; MethodParameter[] parameters = handlerMethod.getMethodParameters(); for (int i = 0; i < parameters.length; i++) { @@ -95,7 +94,7 @@ final class ValidationHelper { } } - BiConsumer result = (requiresMethodValidation) ? + BiConsumer result = (requiresMethodValidation) ? new HandlerMethodValidator(handlerMethod, methodValidationGroups) : null; if (parameterValidator != null) { @@ -105,8 +104,7 @@ final class ValidationHelper { return result; } - @Nullable - private A findAnnotation(HandlerMethod method, Class annotationType) { + private @Nullable A findAnnotation(HandlerMethod method, Class annotationType) { A annotation = AnnotationUtils.findAnnotation(method.getMethod(), annotationType); if (annotation == null) { annotation = AnnotationUtils.findAnnotation(method.getBeanType(), annotationType); @@ -119,8 +117,7 @@ final class ValidationHelper { * Factory method to create a {@link ValidationHelper} if there is a * {@link Validator} bean declared, or {@code null} otherwise. */ - @Nullable - static ValidationHelper createIfValidatorPresent(ApplicationContext context) { + static @Nullable ValidationHelper createIfValidatorPresent(ApplicationContext context) { Validator validator = context.getBeanProvider(Validator.class).getIfAvailable(); if (validator instanceof LocalValidatorFactoryBean) { validator = ((LocalValidatorFactoryBean) validator).getValidator(); @@ -142,20 +139,20 @@ final class ValidationHelper { /** * Callback to apply validation to the invocation of a {@link HandlerMethod}. */ - private class HandlerMethodValidator implements BiConsumer { + private class HandlerMethodValidator implements BiConsumer { private final Method method; private final Class[] validationGroups; - HandlerMethodValidator(HandlerMethod handlerMethod, @Nullable Class[] validationGroups) { + HandlerMethodValidator(HandlerMethod handlerMethod, Class @Nullable[] validationGroups) { Assert.notNull(handlerMethod, "HandlerMethod is required"); this.method = handlerMethod.getMethod(); this.validationGroups = (validationGroups != null) ? validationGroups : new Class[] {}; } @Override - public void accept(Object controller, Object[] arguments) { + public void accept(Object controller, @Nullable Object[] arguments) { Set> violations = ValidationHelper.this.validator.forExecutables() @@ -173,25 +170,27 @@ final class ValidationHelper { * because it's annotated with Spring's {@code @Validated} rather than with * {@code @Valid}. */ - private class MethodParameterValidator implements BiConsumer { + private class MethodParameterValidator implements BiConsumer { private final int index; private final Class[] validationGroups; - MethodParameterValidator(int index, @Nullable Class[] validationGroups) { + MethodParameterValidator(int index, Class @Nullable[] validationGroups) { this.index = index; this.validationGroups = (validationGroups != null) ? validationGroups : new Class[] {}; } @Override - public void accept(Object controller, Object[] arguments) { + public void accept(Object controller, @Nullable Object[] arguments) { + Object argument = arguments[this.index]; + if (argument != null) { + Set> violations = + ValidationHelper.this.validator.validate(argument, this.validationGroups); - Set> violations = - ValidationHelper.this.validator.validate(arguments[this.index], this.validationGroups); - - if (!violations.isEmpty()) { - throw new ConstraintViolationException(violations); + if (!violations.isEmpty()) { + throw new ConstraintViolationException(violations); + } } } } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/package-info.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/package-info.java index fea82553..a623e4dd 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/package-info.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2024 the original author or authors. + * Copyright 2020-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,9 +18,7 @@ * Resolvers for method parameters of annotated handler methods. */ -@NonNullApi -@NonNullFields +@NullMarked package org.springframework.graphql.data.method.annotation.support; -import org.springframework.lang.NonNullApi; -import org.springframework.lang.NonNullFields; +import org.jspecify.annotations.NullMarked; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/package-info.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/package-info.java index 4e0ee83c..d5a0602b 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/package-info.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * Copyright 2020-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,9 +19,7 @@ * {@link org.springframework.graphql.data.method.annotation.SchemaMapping} * annotations. */ -@NonNullApi -@NonNullFields +@NullMarked package org.springframework.graphql.data.method; -import org.springframework.lang.NonNullApi; -import org.springframework.lang.NonNullFields; +import org.jspecify.annotations.NullMarked; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/package-info.java b/spring-graphql/src/main/java/org/springframework/graphql/data/package-info.java index e4de0a1a..cc254820 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/package-info.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * Copyright 2020-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,9 +17,7 @@ /** * Support for various ways to implement {@link graphql.schema.DataFetcher}s. */ -@NonNullApi -@NonNullFields +@NullMarked package org.springframework.graphql.data; -import org.springframework.lang.NonNullApi; -import org.springframework.lang.NonNullFields; +import org.jspecify.annotations.NullMarked; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/pagination/CompositeConnectionAdapter.java b/spring-graphql/src/main/java/org/springframework/graphql/data/pagination/CompositeConnectionAdapter.java index 4c79a3b8..3c9927ba 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/pagination/CompositeConnectionAdapter.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/pagination/CompositeConnectionAdapter.java @@ -19,7 +19,8 @@ package org.springframework.graphql.data.pagination; import java.util.Collection; import java.util.List; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; /** @@ -70,8 +71,7 @@ final class CompositeConnectionAdapter implements ConnectionAdapter { return adapter; } - @Nullable - private ConnectionAdapter getAdapter(Class containerType) { + private @Nullable ConnectionAdapter getAdapter(Class containerType) { for (ConnectionAdapter adapter : this.adapters) { if (adapter.supports(containerType)) { return adapter; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/pagination/ConnectionFieldTypeVisitor.java b/spring-graphql/src/main/java/org/springframework/graphql/data/pagination/ConnectionFieldTypeVisitor.java index c610b9f1..0799bacb 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/pagination/ConnectionFieldTypeVisitor.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/pagination/ConnectionFieldTypeVisitor.java @@ -46,10 +46,10 @@ import graphql.util.TraversalControl; import graphql.util.TraverserContext; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.graphql.execution.TypeVisitorHelper; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -144,13 +144,11 @@ public final class ConnectionFieldTypeVisitor extends GraphQLTypeVisitorStub { return true; } - @Nullable - private static GraphQLObjectType getAsObjectType(@Nullable GraphQLFieldDefinition field) { + private static @Nullable GraphQLObjectType getAsObjectType(@Nullable GraphQLFieldDefinition field) { return (getType(field) instanceof GraphQLObjectType type) ? type : null; } - @Nullable - private static GraphQLObjectType getEdgeType(@Nullable GraphQLFieldDefinition field) { + private static @Nullable GraphQLObjectType getEdgeType(@Nullable GraphQLFieldDefinition field) { if (getType(field) instanceof GraphQLList listType) { if (unwrapNonNullType(listType.getWrappedType()) instanceof GraphQLObjectType type) { return type; @@ -159,16 +157,14 @@ public final class ConnectionFieldTypeVisitor extends GraphQLTypeVisitorStub { return null; } - @Nullable - private static GraphQLType getType(@Nullable GraphQLFieldDefinition field) { + private static @Nullable GraphQLType getType(@Nullable GraphQLFieldDefinition field) { if (field == null) { return null; } return unwrapNonNullType(field.getType()); } - @Nullable - private static GraphQLType unwrapNonNullType(@Nullable GraphQLType type) { + private static @Nullable GraphQLType unwrapNonNullType(@Nullable GraphQLType type) { if (type == null) { return null; } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/pagination/Subrange.java b/spring-graphql/src/main/java/org/springframework/graphql/data/pagination/Subrange.java index bf390fd0..51d3fbe9 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/pagination/Subrange.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/pagination/Subrange.java @@ -20,7 +20,7 @@ package org.springframework.graphql.data.pagination; import java.util.Optional; import java.util.OptionalInt; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** * Container for parameters that limit result elements to a subrange including a diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/pagination/package-info.java b/spring-graphql/src/main/java/org/springframework/graphql/data/pagination/package-info.java index f2bb459f..2e91cccd 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/pagination/package-info.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/pagination/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * Copyright 2020-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,9 +17,7 @@ /** * Core contracts and generic infrastructure classes for pagination. */ -@NonNullApi -@NonNullFields +@NullMarked package org.springframework.graphql.data.pagination; -import org.springframework.lang.NonNullApi; -import org.springframework.lang.NonNullFields; +import org.jspecify.annotations.NullMarked; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/query/AbstractSortStrategy.java b/spring-graphql/src/main/java/org/springframework/graphql/data/query/AbstractSortStrategy.java index ad182c30..e29b0fb1 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/query/AbstractSortStrategy.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/query/AbstractSortStrategy.java @@ -21,9 +21,9 @@ import java.util.ArrayList; import java.util.List; import graphql.schema.DataFetchingEnvironment; +import org.jspecify.annotations.Nullable; import org.springframework.data.domain.Sort; -import org.springframework.lang.Nullable; import org.springframework.util.ObjectUtils; /** @@ -48,7 +48,7 @@ public abstract class AbstractSortStrategy implements SortStrategy { } return Sort.by(sortOrders); } - return null; + return Sort.unsorted(); } /** @@ -61,7 +61,6 @@ public abstract class AbstractSortStrategy implements SortStrategy { * Return the sort direction to use, or {@code null}. * @param environment the data fetching environment for this operation */ - @Nullable - protected abstract Sort.Direction getDirection(DataFetchingEnvironment environment); + protected abstract Sort.@Nullable Direction getDirection(DataFetchingEnvironment environment); } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/query/AutoRegistrationRuntimeWiringConfigurer.java b/spring-graphql/src/main/java/org/springframework/graphql/data/query/AutoRegistrationRuntimeWiringConfigurer.java index 8e48b09a..924d66b4 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/query/AutoRegistrationRuntimeWiringConfigurer.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/query/AutoRegistrationRuntimeWiringConfigurer.java @@ -32,9 +32,9 @@ import graphql.schema.idl.RuntimeWiring; import graphql.schema.idl.WiringFactory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.graphql.execution.RuntimeWiringConfigurer; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -98,8 +98,7 @@ class AutoRegistrationRuntimeWiringConfigurer implements RuntimeWiringConfigurer private final RuntimeWiring.Builder builder; - @Nullable - private Predicate existingQueryDataFetcherPredicate; + private @Nullable Predicate existingQueryDataFetcherPredicate; AutoRegistrationWiringFactory(RuntimeWiring.Builder builder) { this.builder = builder; @@ -129,8 +128,7 @@ class AutoRegistrationRuntimeWiringConfigurer implements RuntimeWiringConfigurer return result; } - @Nullable - private String getOutputTypeName(FieldWiringEnvironment environment) { + private @Nullable String getOutputTypeName(FieldWiringEnvironment environment) { GraphQLType outputType = removeNonNullWrapper(environment.getFieldType()); if (isConnectionType(outputType)) { diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/query/QueryByExampleDataFetcher.java b/spring-graphql/src/main/java/org/springframework/graphql/data/query/QueryByExampleDataFetcher.java index 434cfce5..cfd15f95 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/query/QueryByExampleDataFetcher.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/query/QueryByExampleDataFetcher.java @@ -29,6 +29,7 @@ import graphql.schema.DataFetchingFieldSelectionSet; import graphql.schema.GraphQLArgument; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -50,7 +51,6 @@ import org.springframework.graphql.data.pagination.CursorStrategy; import org.springframework.graphql.data.query.AutoRegistrationRuntimeWiringConfigurer.DataFetcherFactory; import org.springframework.graphql.execution.RuntimeWiringConfigurer; import org.springframework.graphql.execution.SelfDescribingDataFetcher; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.validation.BindException; @@ -128,7 +128,7 @@ public abstract class QueryByExampleDataFetcher { * @param environment contextual info for the GraphQL request * @return the resulting example */ - @SuppressWarnings({"ConstantConditions", "unchecked"}) + @SuppressWarnings({"ConstantConditions", "unchecked", "NullAway"}) protected Example buildExample(DataFetchingEnvironment environment) throws BindException { String name = getArgumentName(environment); ResolvableType targetType = ResolvableType.forClass(this.domainType.getType()); @@ -140,8 +140,7 @@ public abstract class QueryByExampleDataFetcher { * name, thereby nesting and having the example Object populated from the * sub-map. Otherwise, {@code null} to bind using the top-level map. */ - @Nullable - private static String getArgumentName(DataFetchingEnvironment environment) { + private static @Nullable String getArgumentName(DataFetchingEnvironment environment) { Map arguments = environment.getArguments(); List definedArguments = environment.getFieldDefinition().getArguments(); if (definedArguments.size() == 1) { @@ -328,14 +327,11 @@ public abstract class QueryByExampleDataFetcher { private final Class resultType; - @Nullable - private final CursorStrategy cursorStrategy; + private final @Nullable CursorStrategy cursorStrategy; - @Nullable - private final Integer defaultScrollCount; + private final @Nullable Integer defaultScrollCount; - @Nullable - private final Function defaultScrollPosition; + private final @Nullable Function defaultScrollPosition; private final Sort sort; @@ -507,14 +503,11 @@ public abstract class QueryByExampleDataFetcher { private final Class resultType; - @Nullable - private final CursorStrategy cursorStrategy; + private final @Nullable CursorStrategy cursorStrategy; - @Nullable - private final Integer defaultScrollCount; + private final @Nullable Integer defaultScrollCount; - @Nullable - private final Function defaultScrollPosition; + private final @Nullable Function defaultScrollPosition; private final Sort sort; @@ -695,7 +688,7 @@ public abstract class QueryByExampleDataFetcher { @Override @SuppressWarnings({"ConstantConditions", "unchecked"}) - public R get(DataFetchingEnvironment env) throws BindException { + public @Nullable R get(DataFetchingEnvironment env) throws BindException { return this.executor.findBy(buildExample(env), (query) -> { FluentQuery.FetchableFluentQuery queryToUse = (FluentQuery.FetchableFluentQuery) query; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/query/QuerydslDataFetcher.java b/spring-graphql/src/main/java/org/springframework/graphql/data/query/QuerydslDataFetcher.java index 11a7c41e..e3cc64aa 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/query/QuerydslDataFetcher.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/query/QuerydslDataFetcher.java @@ -30,6 +30,7 @@ import graphql.schema.DataFetchingEnvironment; import graphql.schema.DataFetchingFieldSelectionSet; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -54,7 +55,6 @@ import org.springframework.graphql.data.pagination.CursorStrategy; import org.springframework.graphql.data.query.AutoRegistrationRuntimeWiringConfigurer.DataFetcherFactory; import org.springframework.graphql.execution.RuntimeWiringConfigurer; import org.springframework.graphql.execution.SelfDescribingDataFetcher; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; @@ -374,14 +374,11 @@ public abstract class QuerydslDataFetcher { private final Class resultType; - @Nullable - private final CursorStrategy cursorStrategy; + private final @Nullable CursorStrategy cursorStrategy; - @Nullable - private final Integer defaultScrollCount; + private final @Nullable Integer defaultScrollCount; - @Nullable - private final Function defaultScrollPosition; + private final @Nullable Function defaultScrollPosition; private final Sort sort; @@ -579,14 +576,11 @@ public abstract class QuerydslDataFetcher { private final Class resultType; - @Nullable - private final CursorStrategy cursorStrategy; + private final @Nullable CursorStrategy cursorStrategy; - @Nullable - private final Integer defaultScrollCount; + private final @Nullable Integer defaultScrollCount; - @Nullable - private final Function defaultScrollPosition; + private final @Nullable Function defaultScrollPosition; private final Sort sort; @@ -797,7 +791,7 @@ public abstract class QuerydslDataFetcher { @Override @SuppressWarnings({"ConstantConditions", "unchecked"}) - public R get(DataFetchingEnvironment env) { + public @Nullable R get(DataFetchingEnvironment env) { return this.executor.findBy(buildPredicate(env), (query) -> { FetchableFluentQuery queryToUse = (FetchableFluentQuery) query; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/query/RepositoryUtils.java b/spring-graphql/src/main/java/org/springframework/graphql/data/query/RepositoryUtils.java index b99c2434..fc0aa8d4 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/query/RepositoryUtils.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/query/RepositoryUtils.java @@ -20,6 +20,7 @@ import java.lang.reflect.Type; import java.util.function.Function; import graphql.schema.DataFetchingEnvironment; +import org.jspecify.annotations.Nullable; import org.springframework.core.ResolvableType; import org.springframework.core.annotation.AnnotatedElementUtils; @@ -32,7 +33,6 @@ import org.springframework.data.repository.core.support.DefaultRepositoryMetadat import org.springframework.graphql.data.GraphQlRepository; import org.springframework.graphql.data.pagination.CursorEncoder; import org.springframework.graphql.data.pagination.CursorStrategy; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -71,8 +71,7 @@ final class RepositoryUtils { String.format("Cannot resolve repository interface from %s", executor)); } - @Nullable - static String getGraphQlTypeName(Object repository) { + static @Nullable String getGraphQlTypeName(Object repository) { GraphQlRepository annotation = AnnotatedElementUtils.findMergedAnnotation(repository.getClass(), GraphQlRepository.class); diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/query/ScrollSubrange.java b/spring-graphql/src/main/java/org/springframework/graphql/data/query/ScrollSubrange.java index 595f27ac..cb39a878 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/query/ScrollSubrange.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/query/ScrollSubrange.java @@ -17,11 +17,12 @@ package org.springframework.graphql.data.query; +import org.jspecify.annotations.Nullable; + import org.springframework.data.domain.KeysetScrollPosition; import org.springframework.data.domain.OffsetScrollPosition; import org.springframework.data.domain.ScrollPosition; import org.springframework.graphql.data.pagination.Subrange; -import org.springframework.lang.Nullable; /** * {@link Subrange} implementation for a {@link ScrollPosition} cursor. diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/query/package-info.java b/spring-graphql/src/main/java/org/springframework/graphql/data/query/package-info.java index eb77d17b..c62df879 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/query/package-info.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/query/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * Copyright 2020-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,9 +23,7 @@ * @see * Spring Data Querydsl */ -@NonNullApi -@NonNullFields +@NullMarked package org.springframework.graphql.data.query; -import org.springframework.lang.NonNullApi; -import org.springframework.lang.NonNullFields; +import org.jspecify.annotations.NullMarked; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/execution/AbstractGraphQlSourceBuilder.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/AbstractGraphQlSourceBuilder.java index 09b6af76..e9c80c3d 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/execution/AbstractGraphQlSourceBuilder.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/execution/AbstractGraphQlSourceBuilder.java @@ -30,8 +30,8 @@ import graphql.schema.GraphQLSchema; import graphql.schema.GraphQLTypeVisitor; import graphql.schema.SchemaTransformer; import graphql.schema.SchemaTraverser; +import org.jspecify.annotations.Nullable; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -56,8 +56,7 @@ public abstract class AbstractGraphQlSourceBuilder instrumentations = new ArrayList<>(); - @Nullable - private Consumer graphQlConfigurer; + private @Nullable Consumer graphQlConfigurer; private GraphQlSource.Factory graphQlSourceFactory = FixedGraphQlSource::new; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/execution/ClassNameTypeResolver.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/ClassNameTypeResolver.java index 8832f475..3c2f4c33 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/execution/ClassNameTypeResolver.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/execution/ClassNameTypeResolver.java @@ -25,8 +25,8 @@ import graphql.schema.GraphQLObjectType; import graphql.schema.GraphQLSchema; import graphql.schema.GraphQLType; import graphql.schema.TypeResolver; +import org.jspecify.annotations.Nullable; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -76,8 +76,7 @@ public class ClassNameTypeResolver implements TypeResolver { } @Override - @Nullable - public GraphQLObjectType getType(TypeResolutionEnvironment environment) { + public @Nullable GraphQLObjectType getType(TypeResolutionEnvironment environment) { Class clazz = environment.getObject().getClass(); GraphQLSchema schema = environment.getSchema(); @@ -88,8 +87,7 @@ public class ClassNameTypeResolver implements TypeResolver { return getTypeForClass(clazz, schema); } - @Nullable - private GraphQLObjectType getTypeForClass(Class clazz, GraphQLSchema schema) { + private @Nullable GraphQLObjectType getTypeForClass(Class clazz, GraphQLSchema schema) { if (clazz.getName().startsWith("java.")) { return null; } @@ -126,8 +124,7 @@ public class ClassNameTypeResolver implements TypeResolver { return null; } - @Nullable - private String getMapping(Class targetClass) { + private @Nullable String getMapping(Class targetClass) { for (Map.Entry, String> entry : this.mappings.entrySet()) { if (entry.getKey().isAssignableFrom(targetClass)) { return entry.getValue(); diff --git a/spring-graphql/src/main/java/org/springframework/graphql/execution/ContextDataFetcherDecorator.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/ContextDataFetcherDecorator.java index 3b0c0535..18aa5bed 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/execution/ContextDataFetcherDecorator.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/execution/ContextDataFetcherDecorator.java @@ -37,12 +37,12 @@ import graphql.util.TraversalControl; import graphql.util.TraverserContext; import io.micrometer.context.ContextSnapshot; import io.micrometer.context.ContextSnapshotFactory; +import org.jspecify.annotations.Nullable; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import org.springframework.core.ResolvableType; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -81,7 +81,7 @@ class ContextDataFetcherDecorator implements DataFetcher { @Override - public Object get(DataFetchingEnvironment env) throws Exception { + public @Nullable Object get(DataFetchingEnvironment env) throws Exception { GraphQLContext graphQlContext = env.getGraphQlContext(); ContextSnapshotFactory snapshotFactory = ContextPropagationHelper.getInstance(graphQlContext); diff --git a/spring-graphql/src/main/java/org/springframework/graphql/execution/ContextPropagationHelper.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/ContextPropagationHelper.java index 7a45d7ff..4e408881 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/execution/ContextPropagationHelper.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/execution/ContextPropagationHelper.java @@ -19,14 +19,13 @@ package org.springframework.graphql.execution; import graphql.GraphQLContext; import io.micrometer.context.ContextSnapshot; import io.micrometer.context.ContextSnapshotFactory; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.publisher.Sinks; import reactor.util.context.Context; import reactor.util.context.ContextView; -import org.springframework.lang.Nullable; - /** * Helper for propagating context values from and to Reactor and GraphQL contexts. * diff --git a/spring-graphql/src/main/java/org/springframework/graphql/execution/DataFetcherExceptionResolverAdapter.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/DataFetcherExceptionResolverAdapter.java index 0956ad83..41d83a1c 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/execution/DataFetcherExceptionResolverAdapter.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/execution/DataFetcherExceptionResolverAdapter.java @@ -25,10 +25,9 @@ import graphql.schema.DataFetchingEnvironment; import io.micrometer.context.ThreadLocalAccessor; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; -import org.springframework.lang.Nullable; - /** * Adapter for {@link DataFetcherExceptionResolver} that pre-implements the * asynchronous contract and exposes the following synchronous protected methods: @@ -92,8 +91,7 @@ public abstract class DataFetcherExceptionResolverAdapter implements DataFetcher return Mono.defer(() -> Mono.justOrEmpty(resolveInternal(ex, env))); } - @Nullable - private List resolveInternal(Throwable exception, DataFetchingEnvironment env) { + private @Nullable List resolveInternal(Throwable exception, DataFetchingEnvironment env) { try { return (this.threadLocalContextAware) ? ContextPropagationHelper.captureFrom(env.getGraphQlContext()) @@ -113,8 +111,7 @@ public abstract class DataFetcherExceptionResolverAdapter implements DataFetcher * @param env the environment for the invoked {@code DataFetcher} * @return the resolved errors or {@code null} if unresolved */ - @Nullable - protected List resolveToMultipleErrors(Throwable ex, DataFetchingEnvironment env) { + protected @Nullable List resolveToMultipleErrors(Throwable ex, DataFetchingEnvironment env) { GraphQLError error = resolveToSingleError(ex, env); return (error != null) ? Collections.singletonList(error) : null; } @@ -125,8 +122,7 @@ public abstract class DataFetcherExceptionResolverAdapter implements DataFetcher * @param env the environment for the invoked {@code DataFetcher} * @return the resolved error or {@code null} if unresolved */ - @Nullable - protected GraphQLError resolveToSingleError(Throwable ex, DataFetchingEnvironment env) { + protected @Nullable GraphQLError resolveToSingleError(Throwable ex, DataFetchingEnvironment env) { return null; } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/execution/DefaultBatchLoaderRegistry.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/DefaultBatchLoaderRegistry.java index d779e6cf..ec9602d0 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/execution/DefaultBatchLoaderRegistry.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/execution/DefaultBatchLoaderRegistry.java @@ -36,10 +36,10 @@ import org.dataloader.DataLoaderFactory; import org.dataloader.DataLoaderOptions; import org.dataloader.DataLoaderRegistry; import org.dataloader.MappedBatchLoaderWithContext; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -111,6 +111,7 @@ public class DefaultBatchLoaderRegistry implements BatchLoaderRegistry { } } + @SuppressWarnings("NullAway") // DataLoaderRegistry#getDataLoader should be @Nullable private void registerDataLoader(DataLoader dataLoader, DataLoaderRegistry registry) { if (registry.getDataLoader(dataLoader.getName()) != null) { throw new IllegalStateException("More than one DataLoader named '" + dataLoader.getName() + "'"); @@ -121,17 +122,13 @@ public class DefaultBatchLoaderRegistry implements BatchLoaderRegistry { private class DefaultRegistrationSpec implements RegistrationSpec { - @Nullable - private final Class valueType; + private final @Nullable Class valueType; - @Nullable - private String name; + private @Nullable String name; - @Nullable - private DataLoaderOptions options; + private @Nullable DataLoaderOptions options; - @Nullable - private Consumer optionsBuilderConsumer; + private @Nullable Consumer optionsBuilderConsumer; DefaultRegistrationSpec(Class valueType) { this.valueType = valueType; @@ -232,6 +229,7 @@ public class DefaultBatchLoaderRegistry implements BatchLoaderRegistry { @Override public CompletionStage> load(List keys, BatchLoaderEnvironment environment) { GraphQLContext graphQLContext = environment.getContext(); + Assert.state(graphQLContext != null, "No GraphQLContext available"); ContextSnapshot snapshot = ContextPropagationHelper.captureFrom(graphQLContext); try { return snapshot.wrap(() -> @@ -280,6 +278,7 @@ public class DefaultBatchLoaderRegistry implements BatchLoaderRegistry { @Override public CompletionStage> load(Set keys, BatchLoaderEnvironment environment) { GraphQLContext graphQLContext = environment.getContext(); + Assert.state(graphQLContext != null, "No GraphQLContext available"); ContextSnapshot snapshot = ContextPropagationHelper.captureFrom(graphQLContext); try { return snapshot.wrap(() -> diff --git a/spring-graphql/src/main/java/org/springframework/graphql/execution/DefaultExecutionGraphQlService.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/DefaultExecutionGraphQlService.java index b1343cb1..ba95c81f 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/execution/DefaultExecutionGraphQlService.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/execution/DefaultExecutionGraphQlService.java @@ -29,6 +29,7 @@ import graphql.execution.ExecutionIdProvider; import graphql.execution.instrumentation.dataloader.EmptyDataLoaderRegistryInstance; import io.micrometer.context.ContextSnapshotFactory; import org.dataloader.DataLoaderRegistry; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import reactor.core.publisher.Sinks; @@ -36,7 +37,6 @@ import org.springframework.graphql.ExecutionGraphQlRequest; import org.springframework.graphql.ExecutionGraphQlResponse; import org.springframework.graphql.ExecutionGraphQlService; import org.springframework.graphql.support.DefaultExecutionGraphQlResponse; -import org.springframework.lang.Nullable; /** * {@link ExecutionGraphQlService} that uses a {@link GraphQlSource} to obtain a @@ -55,8 +55,7 @@ public class DefaultExecutionGraphQlService implements ExecutionGraphQlService { private final List dataLoaderRegistrars = new ArrayList<>(); - @Nullable - private Boolean hasDataLoaderRegistrations; + private @Nullable Boolean hasDataLoaderRegistrations; private final boolean isDefaultExecutionIdProvider; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/execution/DefaultSchemaResourceGraphQlSourceBuilder.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/DefaultSchemaResourceGraphQlSourceBuilder.java index be163f48..abc190d5 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/execution/DefaultSchemaResourceGraphQlSourceBuilder.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/execution/DefaultSchemaResourceGraphQlSourceBuilder.java @@ -43,9 +43,9 @@ import graphql.schema.idl.TypeDefinitionRegistry; import graphql.schema.idl.WiringFactory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.core.io.Resource; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -70,19 +70,15 @@ final class DefaultSchemaResourceGraphQlSourceBuilder private final List runtimeWiringConfigurers = new ArrayList<>(); - @Nullable - private TypeResolver typeResolver; + private @Nullable TypeResolver typeResolver; - @Nullable - private BiFunction schemaFactory; + private @Nullable BiFunction schemaFactory; - @Nullable - private Consumer schemaReportConsumer; + private @Nullable Consumer schemaReportConsumer; private Consumer inspectorInitializerConsumer = (initializer) -> { }; - @Nullable - private Consumer schemaReportRunner; + private @Nullable Consumer schemaReportRunner; @Override @@ -133,6 +129,7 @@ final class DefaultSchemaResourceGraphQlSourceBuilder } @Override + @SuppressWarnings("NullAway") protected GraphQLSchema initGraphQlSchema() { TypeDefinitionRegistry registry = this.schemaResources.stream() @@ -166,8 +163,7 @@ final class DefaultSchemaResourceGraphQlSourceBuilder // visitors may transform the schema, for example to add Connection types. if (this.schemaReportConsumer != null) { - this.schemaReportRunner = (schema) -> - this.schemaReportConsumer.accept(createSchemaReport(schema, runtimeWiring)); + this.schemaReportRunner = (schema) -> this.schemaReportConsumer.accept(createSchemaReport(schema, runtimeWiring)); } return (this.schemaFactory != null) ? diff --git a/spring-graphql/src/main/java/org/springframework/graphql/execution/ExceptionResolversExceptionHandler.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/ExceptionResolversExceptionHandler.java index d2913c08..f3898ee5 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/execution/ExceptionResolversExceptionHandler.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/execution/ExceptionResolversExceptionHandler.java @@ -88,7 +88,10 @@ class ExceptionResolversExceptionHandler implements DataFetcherExceptionHandler private Throwable unwrapException(DataFetcherExceptionHandlerParameters params) { Throwable ex = params.getException(); - return ((ex instanceof CompletionException) ? ex.getCause() : ex); + if (ex instanceof CompletionException completionException) { + return (completionException.getCause() != null) ? completionException.getCause() : completionException; + } + return ex; } private void logResolvedException(Throwable ex, DataFetcherExceptionHandlerResult result) { diff --git a/spring-graphql/src/main/java/org/springframework/graphql/execution/ReactiveAdapterRegistryHelper.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/ReactiveAdapterRegistryHelper.java index 4368f566..6f10a11e 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/execution/ReactiveAdapterRegistryHelper.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/execution/ReactiveAdapterRegistryHelper.java @@ -18,7 +18,7 @@ package org.springframework.graphql.execution; import java.util.Collection; -import io.micrometer.context.Nullable; +import org.jspecify.annotations.Nullable; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -60,8 +60,7 @@ public abstract class ReactiveAdapterRegistryHelper { * @return the same instance or a {@code Mono} if the object is known to * {@code ReactiveAdapterRegistry} */ - @Nullable - public static Object toMonoIfReactive(@Nullable Object result) { + public static @Nullable Object toMonoIfReactive(@Nullable Object result) { ReactiveAdapter adapter = ((result != null) ? registry.getAdapter(result.getClass()) : null); if (adapter == null) { return result; @@ -77,8 +76,7 @@ public abstract class ReactiveAdapterRegistryHelper { * @param result the result Object to adapt * @return the same instance, a {@code Mono}, or a {@code Flux} */ - @Nullable - public static Object toMonoOrFluxIfReactive(@Nullable Object result) { + public static @Nullable Object toMonoOrFluxIfReactive(@Nullable Object result) { ReactiveAdapter adapter = ((result != null) ? registry.getAdapter(result.getClass()) : null); if (adapter == null) { return result; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/execution/SchemaMappingInspector.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/SchemaMappingInspector.java index 99d53c22..50b6b014 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/execution/SchemaMappingInspector.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/execution/SchemaMappingInspector.java @@ -49,6 +49,7 @@ import graphql.schema.GraphQLUnionType; import graphql.schema.idl.RuntimeWiring; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.beans.BeanUtils; import org.springframework.beans.BeansException; @@ -56,7 +57,6 @@ import org.springframework.core.MethodParameter; import org.springframework.core.ReactiveAdapter; import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.core.ResolvableType; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.LinkedMultiValueMap; @@ -104,8 +104,7 @@ public final class SchemaMappingInspector { private final ReportBuilder reportBuilder = new ReportBuilder(); - @Nullable - private SchemaReport report; + private @Nullable SchemaReport report; private SchemaMappingInspector( @@ -262,8 +261,7 @@ public final class SchemaMappingInspector { } } - @Nullable - private PropertyDescriptor getProperty(ResolvableType resolvableType, String fieldName) { + private @Nullable PropertyDescriptor getProperty(ResolvableType resolvableType, String fieldName) { try { Class clazz = resolvableType.resolve(); return (clazz != null) ? BeanUtils.getPropertyDescriptor(clazz, fieldName) : null; @@ -274,8 +272,7 @@ public final class SchemaMappingInspector { } } - @Nullable - private Field getField(ResolvableType resolvableType, String fieldName) { + private @Nullable Field getField(ResolvableType resolvableType, String fieldName) { try { Class clazz = resolvableType.resolve(); return (clazz != null) ? clazz.getField(fieldName) : null; @@ -285,8 +282,7 @@ public final class SchemaMappingInspector { } } - @Nullable - private static Method getRecordLikeMethod(ResolvableType resolvableType, String fieldName) { + private static @Nullable Method getRecordLikeMethod(ResolvableType resolvableType, String fieldName) { Class clazz = resolvableType.resolve(); if (clazz != null) { for (Method method : clazz.getDeclaredMethods()) { @@ -721,8 +717,7 @@ public final class SchemaMappingInspector { return (type instanceof GraphQLNonNull graphQLNonNull) ? graphQLNonNull.getWrappedType() : type; } - @Nullable - private static GraphQLType getPaginatedType(GraphQLType type) { + private static @Nullable GraphQLType getPaginatedType(GraphQLType type) { if (!(type instanceof GraphQLObjectType cot && cot.getName().endsWith("Connection"))) { return null; } @@ -912,8 +907,7 @@ public final class SchemaMappingInspector { } @Override - @Nullable - public DataFetcher dataFetcher(FieldCoordinates coordinates) { + public @Nullable DataFetcher dataFetcher(FieldCoordinates coordinates) { return SchemaMappingInspector.this.dataFetchers .getOrDefault(coordinates.getTypeName(), Collections.emptyMap()) .get(coordinates.getFieldName()); diff --git a/spring-graphql/src/main/java/org/springframework/graphql/execution/SchemaReport.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/SchemaReport.java index 7860a7c0..bec3fbe0 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/execution/SchemaReport.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/execution/SchemaReport.java @@ -25,8 +25,8 @@ import graphql.schema.DataFetcher; import graphql.schema.FieldCoordinates; import graphql.schema.GraphQLSchema; import graphql.schema.GraphQLType; +import org.jspecify.annotations.Nullable; -import org.springframework.lang.Nullable; import org.springframework.util.MultiValueMap; /** @@ -81,8 +81,7 @@ public interface SchemaReport { * Return the {@code DataFetcher} for the given field coordinates, if registered. * @param coordinates the field coordinates */ - @Nullable - DataFetcher dataFetcher(FieldCoordinates coordinates); + @Nullable DataFetcher dataFetcher(FieldCoordinates coordinates); /** diff --git a/spring-graphql/src/main/java/org/springframework/graphql/execution/SecurityContextThreadLocalAccessor.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/SecurityContextThreadLocalAccessor.java index 81ff664d..baa445af 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/execution/SecurityContextThreadLocalAccessor.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/execution/SecurityContextThreadLocalAccessor.java @@ -17,6 +17,7 @@ package org.springframework.graphql.execution; import io.micrometer.context.ThreadLocalAccessor; +import org.jspecify.annotations.Nullable; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; @@ -58,7 +59,7 @@ public class SecurityContextThreadLocalAccessor implements ThreadLocalAccessor resolveToMultipleErrors(Throwable exception) { + protected @Nullable List resolveToMultipleErrors(Throwable exception) { GraphQLError error = resolveToSingleError(exception); return (error != null) ? Collections.singletonList(error) : null; } @@ -115,8 +113,7 @@ public abstract class SubscriptionExceptionResolverAdapter implements Subscripti * @param exception the exception to resolve * @return the resolved error or {@code null} if unresolved */ - @Nullable - protected GraphQLError resolveToSingleError(Throwable exception) { + protected @Nullable GraphQLError resolveToSingleError(Throwable exception) { return null; } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/execution/SubscriptionPublisherException.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/SubscriptionPublisherException.java index 75a40b3d..2c136224 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/execution/SubscriptionPublisherException.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/execution/SubscriptionPublisherException.java @@ -21,9 +21,9 @@ import java.util.Map; import graphql.ExecutionResult; import graphql.GraphQLError; +import org.jspecify.annotations.Nullable; import org.springframework.core.NestedRuntimeException; -import org.springframework.lang.Nullable; /** * An exception raised after a GraphQL subscription diff --git a/spring-graphql/src/main/java/org/springframework/graphql/execution/package-info.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/package-info.java index f4eb7f0d..0dc616fb 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/execution/package-info.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/execution/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * Copyright 2020-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,9 +18,7 @@ * Support for GraphQL request execution, including abstractions to configure and invoke * {@link graphql.GraphQL}. */ -@NonNullApi -@NonNullFields +@NullMarked package org.springframework.graphql.execution; -import org.springframework.lang.NonNullApi; -import org.springframework.lang.NonNullFields; +import org.jspecify.annotations.NullMarked; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/observation/DataFetcherObservationContext.java b/spring-graphql/src/main/java/org/springframework/graphql/observation/DataFetcherObservationContext.java index d32b5aff..f924de68 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/observation/DataFetcherObservationContext.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/observation/DataFetcherObservationContext.java @@ -18,6 +18,7 @@ package org.springframework.graphql.observation; import graphql.schema.DataFetchingEnvironment; import io.micrometer.observation.Observation; +import org.jspecify.annotations.Nullable; /** * Context that holds information for metadata collection during observations @@ -30,7 +31,7 @@ public class DataFetcherObservationContext extends Observation.Context { private final DataFetchingEnvironment environment; - private Object value; + private @Nullable Object value; DataFetcherObservationContext(DataFetchingEnvironment environment) { this.environment = environment; @@ -47,11 +48,11 @@ public class DataFetcherObservationContext extends Observation.Context { * Return the value returned by the {@link graphql.schema.DataFetcher}, if any. * @see #getError() for the exception thrown by the data fetcher. */ - public Object getValue() { + public @Nullable Object getValue() { return this.value; } - void setValue(Object value) { + void setValue(@Nullable Object value) { this.value = value; } } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/observation/ExecutionRequestObservationContext.java b/spring-graphql/src/main/java/org/springframework/graphql/observation/ExecutionRequestObservationContext.java index b07956dd..e7451695 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/observation/ExecutionRequestObservationContext.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/observation/ExecutionRequestObservationContext.java @@ -19,8 +19,7 @@ package org.springframework.graphql.observation; import graphql.ExecutionInput; import graphql.ExecutionResult; import io.micrometer.observation.Observation; - -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** * Context that holds information for metadata collection during observations @@ -33,8 +32,7 @@ public class ExecutionRequestObservationContext extends Observation.Context { private final ExecutionInput executionInput; - @Nullable - private ExecutionResult executionResult; + private @Nullable ExecutionResult executionResult; public ExecutionRequestObservationContext(ExecutionInput executionInput) { this.executionInput = executionInput; @@ -52,8 +50,7 @@ public class ExecutionRequestObservationContext extends Observation.Context { * Return the {@link ExecutionResult result} for the request execution. * @since 1.1.4 */ - @Nullable - public ExecutionResult getExecutionResult() { + public @Nullable ExecutionResult getExecutionResult() { return this.executionResult; } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/observation/GraphQlObservationInstrumentation.java b/spring-graphql/src/main/java/org/springframework/graphql/observation/GraphQlObservationInstrumentation.java index d5be3435..40218713 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/observation/GraphQlObservationInstrumentation.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/observation/GraphQlObservationInstrumentation.java @@ -42,10 +42,10 @@ import org.dataloader.DataLoader; import org.dataloader.DataLoaderRegistry; import org.dataloader.instrumentation.DataLoaderInstrumentation; import org.dataloader.instrumentation.DataLoaderInstrumentationContext; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; import org.springframework.graphql.execution.SelfDescribingDataFetcher; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; /** * {@link graphql.execution.instrumentation.Instrumentation} that creates @@ -77,14 +77,11 @@ public class GraphQlObservationInstrumentation extends SimplePerformantInstrumen private final ObservationRegistry observationRegistry; - @Nullable - private final ExecutionRequestObservationConvention requestObservationConvention; + private final @Nullable ExecutionRequestObservationConvention requestObservationConvention; - @Nullable - private final DataFetcherObservationConvention dataFetcherObservationConvention; + private final @Nullable DataFetcherObservationConvention dataFetcherObservationConvention; - @Nullable - private final DataLoaderObservationConvention dataLoaderObservationConvention; + private final @Nullable DataLoaderObservationConvention dataLoaderObservationConvention; /** * Create an {@code GraphQlObservationInstrumentation} that records observations @@ -148,7 +145,7 @@ public class GraphQlObservationInstrumentation extends SimplePerformantInstrumen } @Override - public InstrumentationContext beginExecution(InstrumentationExecutionParameters parameters, + public @Nullable InstrumentationContext beginExecution(InstrumentationExecutionParameters parameters, InstrumentationState state) { if (state == RequestObservationInstrumentationState.INSTANCE) { ExecutionRequestObservationContext observationContext = new ExecutionRequestObservationContext(parameters.getExecutionInput()); @@ -235,8 +232,7 @@ public class GraphQlObservationInstrumentation extends SimplePerformantInstrumen return dataFetcher; } - @Nullable - private static Observation getCurrentObservation(DataFetchingEnvironment environment) { + private static @Nullable Observation getCurrentObservation(DataFetchingEnvironment environment) { Observation currentObservation = null; if (environment.getLocalContext() instanceof GraphQLContext localContext) { currentObservation = localContext.get(ObservationThreadLocalAccessor.KEY); diff --git a/spring-graphql/src/main/java/org/springframework/graphql/observation/package-info.java b/spring-graphql/src/main/java/org/springframework/graphql/observation/package-info.java index 1901f993..fef3fcb6 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/observation/package-info.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/observation/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2022 the original author or authors. + * Copyright 2020-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,9 +17,7 @@ /** * Support for GraphQL {@link io.micrometer.observation.Observation observability}. */ -@NonNullApi -@NonNullFields +@NullMarked package org.springframework.graphql.observation; -import org.springframework.lang.NonNullApi; -import org.springframework.lang.NonNullFields; +import org.jspecify.annotations.NullMarked; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/package-info.java b/spring-graphql/src/main/java/org/springframework/graphql/package-info.java index 933810f6..cccef9a3 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/package-info.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * Copyright 2020-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,9 +17,7 @@ /** * Top level abstractions for processing GraphQL requests. */ -@NonNullApi -@NonNullFields +@NullMarked package org.springframework.graphql; -import org.springframework.lang.NonNullApi; -import org.springframework.lang.NonNullFields; +import org.jspecify.annotations.NullMarked; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/DefaultWebGraphQlHandlerBuilder.java b/spring-graphql/src/main/java/org/springframework/graphql/server/DefaultWebGraphQlHandlerBuilder.java index d66cf536..a37e4acf 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/DefaultWebGraphQlHandlerBuilder.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/DefaultWebGraphQlHandlerBuilder.java @@ -22,12 +22,12 @@ import java.util.List; import io.micrometer.context.ContextSnapshot; import io.micrometer.context.ContextSnapshotFactory; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.graphql.ExecutionGraphQlService; import org.springframework.graphql.execution.ContextPropagationHelper; import org.springframework.graphql.server.WebGraphQlInterceptor.Chain; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -42,11 +42,9 @@ class DefaultWebGraphQlHandlerBuilder implements WebGraphQlHandler.Builder { private final List interceptors = new ArrayList<>(); - @Nullable - private ContextSnapshotFactory snapshotFactory; + private @Nullable ContextSnapshotFactory snapshotFactory; - @Nullable - private WebSocketGraphQlInterceptor webSocketInterceptor; + private @Nullable WebSocketGraphQlInterceptor webSocketInterceptor; DefaultWebGraphQlHandlerBuilder(ExecutionGraphQlService service) { diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/RSocketGraphQlRequest.java b/spring-graphql/src/main/java/org/springframework/graphql/server/RSocketGraphQlRequest.java index fddabeb8..b9bf82e6 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/RSocketGraphQlRequest.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/RSocketGraphQlRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2023 the original author or authors. + * Copyright 2020-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,10 +20,10 @@ import java.util.Locale; import java.util.Map; import io.rsocket.exceptions.RejectedException; +import org.jspecify.annotations.Nullable; import org.springframework.graphql.ExecutionGraphQlRequest; import org.springframework.graphql.support.DefaultExecutionGraphQlRequest; -import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; /** @@ -43,16 +43,21 @@ public class RSocketGraphQlRequest extends DefaultExecutionGraphQlRequest implem * @param locale the locale from the HTTP request, if any */ public RSocketGraphQlRequest(Map body, String id, @Nullable Locale locale) { - super(getKey(QUERY_KEY, body), getKey(OPERATION_NAME_KEY, body), + super(getQuery(body), getKey(OPERATION_NAME_KEY, body), getKey(VARIABLES_KEY, body), getKey(EXTENSIONS_KEY, body), id, locale); } @SuppressWarnings("unchecked") - private static T getKey(String key, Map body) { - if (key.equals("query") && !StringUtils.hasText((String) body.get(key))) { - throw new RejectedException("No \"query\" in the request document"); - } + private static @Nullable T getKey(String key, Map body) { return (T) body.get(key); } + private static String getQuery(Map body) { + String query = getKey(QUERY_KEY, body); + if (!StringUtils.hasText(query)) { + throw new RejectedException("No \"query\" in the request document"); + } + return query; + } + } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/WebGraphQlRequest.java b/spring-graphql/src/main/java/org/springframework/graphql/server/WebGraphQlRequest.java index 52c735e7..6bf59945 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/WebGraphQlRequest.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/WebGraphQlRequest.java @@ -22,12 +22,13 @@ import java.util.Collections; import java.util.Locale; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.graphql.ExecutionGraphQlRequest; import org.springframework.graphql.GraphQlRequest; import org.springframework.graphql.support.DefaultExecutionGraphQlRequest; import org.springframework.http.HttpCookie; import org.springframework.http.HttpHeaders; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.LinkedMultiValueMap; @@ -59,8 +60,7 @@ public class WebGraphQlRequest extends DefaultExecutionGraphQlRequest implements private final MultiValueMap cookies; - @Nullable - private final InetSocketAddress remoteAddress; + private final @Nullable InetSocketAddress remoteAddress; private final Map attributes; @@ -156,8 +156,7 @@ public class WebGraphQlRequest extends DefaultExecutionGraphQlRequest implements return (String) value; } - @Nullable - private static String getOperation(Map body) { + private static @Nullable String getOperation(Map body) { Object value = body.get(OPERATION_NAME_KEY); if (value != null && !(value instanceof String)) { throw new ServerWebInputException("Invalid value for '" + OPERATION_NAME_KEY + "'"); @@ -166,8 +165,7 @@ public class WebGraphQlRequest extends DefaultExecutionGraphQlRequest implements } @SuppressWarnings("unchecked") - @Nullable - private static Map getMap(String key, Map body) { + private static @Nullable Map getMap(String key, Map body) { Object value = body.get(key); if (value != null && !(value instanceof Map)) { throw new ServerWebInputException("Invalid value for '" + key + "'"); @@ -221,8 +219,7 @@ public class WebGraphQlRequest extends DefaultExecutionGraphQlRequest implements * Return the remote address of the client, if available. * @since 1.3.0 */ - @Nullable - public InetSocketAddress getRemoteAddress() { + public @Nullable InetSocketAddress getRemoteAddress() { return this.remoteAddress; } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/WebSocketGraphQlRequest.java b/spring-graphql/src/main/java/org/springframework/graphql/server/WebSocketGraphQlRequest.java index fc50ee17..8c720812 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/WebSocketGraphQlRequest.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/WebSocketGraphQlRequest.java @@ -22,9 +22,10 @@ import java.net.URI; import java.util.Locale; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.http.HttpCookie; import org.springframework.http.HttpHeaders; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.MultiValueMap; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/WebSocketSessionInfo.java b/spring-graphql/src/main/java/org/springframework/graphql/server/WebSocketSessionInfo.java index 4290a5cc..b7956ad7 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/WebSocketSessionInfo.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/WebSocketSessionInfo.java @@ -21,10 +21,10 @@ import java.net.URI; import java.security.Principal; import java.util.Map; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.http.HttpHeaders; -import org.springframework.lang.Nullable; /** * Expose information about the underlying WebSocketSession including the @@ -64,7 +64,6 @@ public interface WebSocketSessionInfo { * For a server session this is the remote address where the handshake * request came from. For a client session, it is {@code null}. */ - @Nullable - InetSocketAddress getRemoteAddress(); + @Nullable InetSocketAddress getRemoteAddress(); } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/package-info.java b/spring-graphql/src/main/java/org/springframework/graphql/server/package-info.java index 7a0d285a..0d8d86b8 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/package-info.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * Copyright 2020-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,9 +17,7 @@ /** * Server transports handling GraphQL requests over the HTTP, WebSocket, and RSocket. */ -@NonNullApi -@NonNullFields +@NullMarked package org.springframework.graphql.server; -import org.springframework.lang.NonNullApi; -import org.springframework.lang.NonNullFields; +import org.jspecify.annotations.NullMarked; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/support/AbstractAuthenticationWebSocketInterceptor.java b/spring-graphql/src/main/java/org/springframework/graphql/server/support/AbstractAuthenticationWebSocketInterceptor.java index 7973cf22..17ba1397 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/support/AbstractAuthenticationWebSocketInterceptor.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/support/AbstractAuthenticationWebSocketInterceptor.java @@ -82,8 +82,11 @@ public abstract class AbstractAuthenticationWebSocketInterceptor implements WebS } Map attributes = webSocketRequest.getSessionInfo().getAttributes(); SecurityContext securityContext = (SecurityContext) attributes.get(this.authenticationAttribute); - ContextView contextView = getContextToWrite(securityContext); - return chain.next(request).contextWrite(contextView); + if (securityContext != null) { + ContextView contextView = getContextToWrite(securityContext); + return chain.next(request).contextWrite(contextView); + } + return chain.next(request); } /** diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/support/BearerTokenAuthenticationExtractor.java b/spring-graphql/src/main/java/org/springframework/graphql/server/support/BearerTokenAuthenticationExtractor.java index bbc3acd9..6774233d 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/support/BearerTokenAuthenticationExtractor.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/support/BearerTokenAuthenticationExtractor.java @@ -20,9 +20,9 @@ import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; -import org.springframework.lang.Nullable; import org.springframework.security.core.Authentication; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.server.resource.BearerTokenError; @@ -89,8 +89,7 @@ public final class BearerTokenAuthenticationExtractor implements AuthenticationE return Mono.just(new BearerTokenAuthenticationToken(token)); } - @Nullable - private String getAuthorizationValue(Map payload) { + private @Nullable String getAuthorizationValue(Map payload) { String value = (String) payload.get(this.authorizationKey); if (value != null) { return value; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/support/GraphQlWebSocketMessage.java b/spring-graphql/src/main/java/org/springframework/graphql/server/support/GraphQlWebSocketMessage.java index d510eb8e..ff360d78 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/support/GraphQlWebSocketMessage.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/support/GraphQlWebSocketMessage.java @@ -22,9 +22,9 @@ import java.util.Map; import java.util.stream.Collectors; import graphql.GraphQLError; +import org.jspecify.annotations.Nullable; import org.springframework.graphql.GraphQlRequest; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -38,14 +38,11 @@ import org.springframework.util.ObjectUtils; */ public class GraphQlWebSocketMessage { - @Nullable - private String id; + private @Nullable String id; - @Nullable - private GraphQlWebSocketMessageType type; + private @Nullable GraphQlWebSocketMessageType type; - @Nullable - private Object payload; + private @Nullable Object payload; /** @@ -73,8 +70,7 @@ public class GraphQlWebSocketMessage { * Return the request id that is applicable to messages associated with a * request, or {@code null} for connection level messages. */ - @Nullable - public String getId() { + public @Nullable String getId() { return this.id; } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/support/SerializableGraphQlRequest.java b/spring-graphql/src/main/java/org/springframework/graphql/server/support/SerializableGraphQlRequest.java index 1e9878ba..d1cd662d 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/support/SerializableGraphQlRequest.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/support/SerializableGraphQlRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,12 +16,13 @@ package org.springframework.graphql.server.support; +import java.util.Collections; import java.util.Map; import graphql.execution.preparsed.persisted.PersistedQuerySupport; +import org.jspecify.annotations.Nullable; import org.springframework.graphql.GraphQlRequest; -import org.springframework.lang.Nullable; import org.springframework.web.server.ServerWebInputException; @@ -33,25 +34,20 @@ import org.springframework.web.server.ServerWebInputException; */ public class SerializableGraphQlRequest implements GraphQlRequest { - @Nullable - private String query; + private @Nullable String query; - @Nullable - private String operationName; + private @Nullable String operationName; - @Nullable - private Map variables; + private Map variables = Collections.emptyMap(); - @Nullable - private Map extensions; + private Map extensions = Collections.emptyMap(); public void setQuery(String query) { this.query = query; } - @Nullable - public String getQuery() { + public @Nullable String getQuery() { return this.query; } @@ -59,9 +55,8 @@ public class SerializableGraphQlRequest implements GraphQlRequest { this.operationName = operationName; } - @Nullable @Override - public String getOperationName() { + public @Nullable String getOperationName() { return this.operationName; } @@ -69,7 +64,6 @@ public class SerializableGraphQlRequest implements GraphQlRequest { this.variables = variables; } - @Nullable @Override public Map getVariables() { return this.variables; @@ -79,7 +73,6 @@ public class SerializableGraphQlRequest implements GraphQlRequest { this.extensions = extensions; } - @Nullable @Override public Map getExtensions() { return this.extensions; @@ -88,7 +81,7 @@ public class SerializableGraphQlRequest implements GraphQlRequest { @Override public String getDocument() { if (this.query == null) { - if (this.extensions != null && this.extensions.get("persistedQuery") != null) { + if (this.extensions.get("persistedQuery") != null) { return PersistedQuerySupport.PERSISTED_QUERY_MARKER; } throw new ServerWebInputException("No 'query'"); diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/support/package-info.java b/spring-graphql/src/main/java/org/springframework/graphql/server/support/package-info.java index 3537c5a9..797b8dda 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/support/package-info.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/support/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * Copyright 2020-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,9 +17,7 @@ /** * Support classes for Web transports. */ -@NonNullApi -@NonNullFields +@NullMarked package org.springframework.graphql.server.support; -import org.springframework.lang.NonNullApi; -import org.springframework.lang.NonNullFields; +import org.jspecify.annotations.NullMarked; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/AbstractGraphQlHttpHandler.java b/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/AbstractGraphQlHttpHandler.java index 0f038c43..4d52c53f 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/AbstractGraphQlHttpHandler.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/AbstractGraphQlHttpHandler.java @@ -22,6 +22,7 @@ import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.core.io.buffer.DataBuffer; @@ -34,7 +35,6 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.InvalidMediaTypeException; import org.springframework.http.MediaType; import org.springframework.http.codec.CodecConfigurer; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -57,8 +57,7 @@ public abstract class AbstractGraphQlHttpHandler { private final WebGraphQlHandler graphQlHandler; - @Nullable - private final HttpCodecDelegate codecDelegate; + private final @Nullable HttpCodecDelegate codecDelegate; protected AbstractGraphQlHttpHandler( diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/GraphQlRequestPredicates.java b/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/GraphQlRequestPredicates.java index af64e382..2ed9114a 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/GraphQlRequestPredicates.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/GraphQlRequestPredicates.java @@ -21,6 +21,7 @@ import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.graphql.MediaTypes; import org.springframework.http.HttpHeaders; @@ -28,7 +29,6 @@ import org.springframework.http.HttpMethod; import org.springframework.http.InvalidMediaTypeException; import org.springframework.http.MediaType; import org.springframework.http.server.PathContainer; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.MimeTypeUtils; import org.springframework.web.cors.reactive.CorsUtils; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/GraphQlSseHandler.java b/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/GraphQlSseHandler.java index cb3bd1e3..785a23c2 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/GraphQlSseHandler.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/GraphQlSseHandler.java @@ -25,6 +25,7 @@ import graphql.ErrorType; import graphql.ExecutionResult; import graphql.GraphQLError; import graphql.GraphqlErrorBuilder; +import org.jspecify.annotations.Nullable; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -34,7 +35,6 @@ import org.springframework.graphql.server.WebGraphQlHandler; import org.springframework.graphql.server.WebGraphQlResponse; import org.springframework.http.MediaType; import org.springframework.http.codec.ServerSentEvent; -import org.springframework.lang.Nullable; import org.springframework.web.reactive.function.BodyInserters; import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; @@ -57,11 +57,9 @@ public class GraphQlSseHandler extends AbstractGraphQlHttpHandler { private static final Mono>> COMPLETE_EVENT_MONO = Mono.just(ServerSentEvent.>builder(Collections.emptyMap()).event("complete").build()); - @Nullable - private final Duration timeout; + private final @Nullable Duration timeout; - @Nullable - private final Duration keepAliveDuration; + private final @Nullable Duration keepAliveDuration; /** diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/GraphQlWebSocketHandler.java b/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/GraphQlWebSocketHandler.java index 264ca9f1..09c79cc8 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/GraphQlWebSocketHandler.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/GraphQlWebSocketHandler.java @@ -32,6 +32,7 @@ import graphql.GraphQLError; import graphql.GraphqlErrorBuilder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.reactivestreams.Publisher; import org.reactivestreams.Subscription; import reactor.core.publisher.Flux; @@ -48,7 +49,6 @@ import org.springframework.graphql.server.WebSocketSessionInfo; import org.springframework.graphql.server.support.GraphQlWebSocketMessage; import org.springframework.http.HttpHeaders; import org.springframework.http.codec.CodecConfigurer; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.web.reactive.socket.CloseStatus; @@ -81,8 +81,7 @@ public class GraphQlWebSocketHandler implements WebSocketHandler { private final Duration initTimeoutDuration; - @Nullable - private final Duration keepAliveDuration; + private final @Nullable Duration keepAliveDuration; /** @@ -141,7 +140,7 @@ public class GraphQlWebSocketHandler implements WebSocketHandler { // Session state WebSocketSessionInfo sessionInfo = new WebFluxSessionInfo(session); - AtomicReference> connectionInitPayloadRef = new AtomicReference<>(); + AtomicReference<@Nullable Map> connectionInitPayloadRef = new AtomicReference<>(); Map subscriptions = new ConcurrentHashMap<>(); Mono.delay(this.initTimeoutDuration) @@ -164,6 +163,9 @@ public class GraphQlWebSocketHandler implements WebSocketHandler { return session.send(session.receive().flatMap((webSocketMessage) -> { GraphQlWebSocketMessage message = this.codecDelegate.decode(webSocketMessage); + if (message == null) { + return GraphQlStatus.close(session, GraphQlStatus.INVALID_MESSAGE_STATUS); + } String id = message.getId(); Map payload = message.getPayload(); switch (message.resolvedType()) { @@ -329,7 +331,7 @@ public class GraphQlWebSocketHandler implements WebSocketHandler { } @Override - public InetSocketAddress getRemoteAddress() { + public @Nullable InetSocketAddress getRemoteAddress() { return this.session.getHandshakeInfo().getRemoteAddress(); } } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/WebSocketCodecDelegate.java b/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/WebSocketCodecDelegate.java index 4c73ebdc..62affeb4 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/WebSocketCodecDelegate.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/WebSocketCodecDelegate.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.Map; import graphql.GraphQLError; +import org.jspecify.annotations.Nullable; import org.springframework.core.ResolvableType; import org.springframework.core.codec.Decoder; @@ -88,7 +89,7 @@ final class WebSocketCodecDelegate { } @SuppressWarnings("ConstantConditions") - GraphQlWebSocketMessage decode(WebSocketMessage webSocketMessage) { + @Nullable GraphQlWebSocketMessage decode(WebSocketMessage webSocketMessage) { DataBuffer buffer = DataBufferUtils.retain(webSocketMessage.getPayload()); return (GraphQlWebSocketMessage) this.decoder.decode(buffer, MESSAGE_TYPE, null, null); } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/package-info.java b/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/package-info.java index 949f295e..0fcfa6fb 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/package-info.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * Copyright 2020-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,9 +17,7 @@ /** * HTTP and WebSocket handlers for use in a Spring WebFlux application. */ -@NonNullApi -@NonNullFields +@NullMarked package org.springframework.graphql.server.webflux; -import org.springframework.lang.NonNullApi; -import org.springframework.lang.NonNullFields; +import org.jspecify.annotations.NullMarked; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/AbstractGraphQlHttpHandler.java b/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/AbstractGraphQlHttpHandler.java index a1604382..57442cb8 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/AbstractGraphQlHttpHandler.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/AbstractGraphQlHttpHandler.java @@ -26,6 +26,7 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.context.i18n.LocaleContextHolder; @@ -43,7 +44,6 @@ import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.http.server.ServletServerHttpResponse; -import org.springframework.lang.Nullable; import org.springframework.util.AlternativeJdkIdGenerator; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; @@ -75,8 +75,7 @@ public abstract class AbstractGraphQlHttpHandler { private final WebGraphQlHandler graphQlHandler; - @Nullable - private final HttpMessageConverter messageConverter; + private final @Nullable HttpMessageConverter messageConverter; @SuppressWarnings("unchecked") @@ -97,8 +96,7 @@ public abstract class AbstractGraphQlHttpHandler { * @return the write function, or {@code null} if a * {@code HttpMessageConverter} was not provided to the constructor */ - @Nullable - protected ServerResponse.HeadersBuilder.WriteFunction getWriteFunction( + protected ServerResponse.HeadersBuilder.@Nullable WriteFunction getWriteFunction( Map resultMap, MediaType contentType) { return (this.messageConverter != null) ? @@ -221,7 +219,7 @@ public abstract class AbstractGraphQlHttpHandler { implements ServerResponse.HeadersBuilder.WriteFunction { @Override - public ModelAndView write(HttpServletRequest request, HttpServletResponse response) throws Exception { + public @Nullable ModelAndView write(HttpServletRequest request, HttpServletResponse response) throws Exception { ServletServerHttpResponse httpResponse = new ServletServerHttpResponse(response); this.converter.write(this.resultMap, this.contentType, httpResponse); return null; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/GraphQlHttpHandler.java b/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/GraphQlHttpHandler.java index 3490dac8..4aefe097 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/GraphQlHttpHandler.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/GraphQlHttpHandler.java @@ -19,6 +19,7 @@ package org.springframework.graphql.server.webmvc; import java.util.List; import java.util.Map; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.graphql.MediaTypes; @@ -29,7 +30,6 @@ import org.springframework.http.HttpStatus; import org.springframework.http.InvalidMediaTypeException; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.lang.Nullable; import org.springframework.web.server.NotAcceptableStatusException; import org.springframework.web.servlet.function.ServerRequest; import org.springframework.web.servlet.function.ServerResponse; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/GraphQlRequestPredicates.java b/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/GraphQlRequestPredicates.java index b3091138..3e34ea31 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/GraphQlRequestPredicates.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/GraphQlRequestPredicates.java @@ -21,6 +21,7 @@ import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.graphql.MediaTypes; import org.springframework.http.HttpHeaders; @@ -28,7 +29,6 @@ import org.springframework.http.HttpMethod; import org.springframework.http.InvalidMediaTypeException; import org.springframework.http.MediaType; import org.springframework.http.server.PathContainer; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.MimeTypeUtils; import org.springframework.web.cors.CorsUtils; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/GraphQlSseHandler.java b/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/GraphQlSseHandler.java index 8171b983..16b07791 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/GraphQlSseHandler.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/GraphQlSseHandler.java @@ -27,6 +27,7 @@ import graphql.ExecutionResult; import graphql.GraphQLError; import graphql.GraphqlErrorBuilder; import org.apache.commons.logging.Log; +import org.jspecify.annotations.Nullable; import org.reactivestreams.Publisher; import reactor.core.publisher.BaseSubscriber; import reactor.core.publisher.Flux; @@ -36,7 +37,6 @@ import reactor.core.publisher.Sinks; import org.springframework.graphql.execution.SubscriptionPublisherException; import org.springframework.graphql.server.WebGraphQlHandler; import org.springframework.graphql.server.WebGraphQlResponse; -import org.springframework.lang.Nullable; import org.springframework.web.context.request.async.AsyncRequestTimeoutException; import org.springframework.web.servlet.function.ServerRequest; import org.springframework.web.servlet.function.ServerResponse; @@ -56,11 +56,9 @@ public class GraphQlSseHandler extends AbstractGraphQlHttpHandler { private static final Map HEARTBEAT_MAP = new LinkedHashMap<>(0); - @Nullable - private final Duration timeout; + private final @Nullable Duration timeout; - @Nullable - private final Duration keepAliveDuration; + private final @Nullable Duration keepAliveDuration; /** diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/GraphQlWebSocketHandler.java b/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/GraphQlWebSocketHandler.java index 43ef24c4..4492e82e 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/GraphQlWebSocketHandler.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/GraphQlWebSocketHandler.java @@ -39,6 +39,7 @@ import io.micrometer.context.ContextSnapshot; import io.micrometer.context.ContextSnapshotFactory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.reactivestreams.Publisher; import org.reactivestreams.Subscription; import reactor.core.publisher.BaseSubscriber; @@ -63,7 +64,6 @@ import org.springframework.http.converter.GenericHttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.web.socket.CloseStatus; @@ -104,8 +104,7 @@ public class GraphQlWebSocketHandler extends TextWebSocketHandler implements Sub private final HttpMessageConverter converter; - @Nullable - private final Duration keepAliveDuration; + private final @Nullable Duration keepAliveDuration; private final Map sessionInfoMap = new ConcurrentHashMap<>(); @@ -495,8 +494,7 @@ public class GraphQlWebSocketHandler extends TextWebSocketHandler implements Sub return this.sessionInfo; } - @Nullable - Map getConnectionInitPayload() { + @Nullable Map getConnectionInitPayload() { return this.connectionInitPayloadRef.get(); } @@ -553,8 +551,9 @@ public class GraphQlWebSocketHandler extends TextWebSocketHandler implements Sub @Override public URI getUri() { - Assert.notNull(this.session.getUri(), "Expected URI"); - return this.session.getUri(); + URI uri = this.session.getUri(); + Assert.notNull(uri, "Expected URI"); + return uri; } @Override @@ -568,7 +567,7 @@ public class GraphQlWebSocketHandler extends TextWebSocketHandler implements Sub } @Override - public InetSocketAddress getRemoteAddress() { + public @Nullable InetSocketAddress getRemoteAddress() { return this.session.getRemoteAddress(); } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/package-info.java b/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/package-info.java index 46299ab6..d2ac304c 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/package-info.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * Copyright 2020-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,9 +17,7 @@ /** * HTTP and WebSocket handlers for use in a Spring WebMvc application. */ -@NonNullApi -@NonNullFields +@NullMarked package org.springframework.graphql.server.webmvc; -import org.springframework.lang.NonNullApi; -import org.springframework.lang.NonNullFields; +import org.jspecify.annotations.NullMarked; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/support/AbstractGraphQlResponse.java b/spring-graphql/src/main/java/org/springframework/graphql/support/AbstractGraphQlResponse.java index e3222678..b5f3d18b 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/support/AbstractGraphQlResponse.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/support/AbstractGraphQlResponse.java @@ -23,10 +23,11 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; + import org.springframework.graphql.GraphQlResponse; import org.springframework.graphql.ResponseError; import org.springframework.graphql.ResponseField; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -58,8 +59,7 @@ public abstract class AbstractGraphQlResponse implements GraphQlResponse { private final List parsedPath; - @Nullable - private final Object value; + private final @Nullable Object value; private final List fieldErrors; @@ -112,8 +112,7 @@ public abstract class AbstractGraphQlResponse implements GraphQlResponse { return dataPath; } - @Nullable - private static Object initFieldValue(List path, GraphQlResponse response) { + private static @Nullable Object initFieldValue(List path, GraphQlResponse response) { Object value = (response.isValid() ? response.getData() : null); for (Object segment : path) { if (value == null) { @@ -162,7 +161,7 @@ public abstract class AbstractGraphQlResponse implements GraphQlResponse { @SuppressWarnings("unchecked") @Override - public T getValue() { + public @Nullable T getValue() { return (T) this.value; } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/support/DefaultExecutionGraphQlRequest.java b/spring-graphql/src/main/java/org/springframework/graphql/support/DefaultExecutionGraphQlRequest.java index d05171fc..425645d8 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/support/DefaultExecutionGraphQlRequest.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/support/DefaultExecutionGraphQlRequest.java @@ -24,10 +24,10 @@ import java.util.function.BiFunction; import graphql.ExecutionInput; import graphql.execution.ExecutionId; +import org.jspecify.annotations.Nullable; import org.springframework.graphql.ExecutionGraphQlRequest; import org.springframework.graphql.GraphQlRequest; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -47,8 +47,7 @@ public class DefaultExecutionGraphQlRequest extends DefaultGraphQlRequest implem private final String id; - @Nullable - private ExecutionId executionId; + private @Nullable ExecutionId executionId; private final Locale locale; @@ -88,8 +87,7 @@ public class DefaultExecutionGraphQlRequest extends DefaultGraphQlRequest implem } @Override - @Nullable - public ExecutionId getExecutionId() { + public @Nullable ExecutionId getExecutionId() { return this.executionId; } @@ -125,7 +123,7 @@ public class DefaultExecutionGraphQlRequest extends DefaultGraphQlRequest implem @Override public String toString() { - return super.toString() + ", id=" + getId() + ((getLocale() != null) ? ", Locale=" + getLocale() : ""); + return super.toString() + ", id=" + getId() + ", Locale=" + getLocale(); } } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/support/DefaultExecutionGraphQlResponse.java b/spring-graphql/src/main/java/org/springframework/graphql/support/DefaultExecutionGraphQlResponse.java index 37bd3d0b..0f28eb81 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/support/DefaultExecutionGraphQlResponse.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/support/DefaultExecutionGraphQlResponse.java @@ -27,11 +27,11 @@ import graphql.ExecutionResult; import graphql.ExecutionResultImpl; import graphql.GraphQLError; import graphql.language.SourceLocation; +import org.jspecify.annotations.Nullable; import org.springframework.graphql.ExecutionGraphQlResponse; import org.springframework.graphql.GraphQlResponse; import org.springframework.graphql.ResponseError; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -85,9 +85,8 @@ public class DefaultExecutionGraphQlResponse extends AbstractGraphQlResponse imp return (this.result.isDataPresent() && this.result.getData() != null); } - @Nullable @Override - public T getData() { + public @Nullable T getData() { return this.result.getData(); } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/support/DefaultGraphQlRequest.java b/spring-graphql/src/main/java/org/springframework/graphql/support/DefaultGraphQlRequest.java index e118463a..a18245bd 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/support/DefaultGraphQlRequest.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/support/DefaultGraphQlRequest.java @@ -20,8 +20,9 @@ import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.graphql.GraphQlRequest; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; @@ -46,8 +47,7 @@ public class DefaultGraphQlRequest implements GraphQlRequest { private final String document; - @Nullable - private final String operationName; + private final @Nullable String operationName; private final Map variables; @@ -87,8 +87,7 @@ public class DefaultGraphQlRequest implements GraphQlRequest { } @Override - @Nullable - public String getOperationName() { + public @Nullable String getOperationName() { return this.operationName; } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/support/package-info.java b/spring-graphql/src/main/java/org/springframework/graphql/support/package-info.java index 02c31774..6680d9e6 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/support/package-info.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/support/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2022 the original author or authors. + * Copyright 2020-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,9 +17,7 @@ /** * Support classes for Spring GraphQL. */ -@NonNullApi -@NonNullFields +@NullMarked package org.springframework.graphql.support; -import org.springframework.lang.NonNullApi; -import org.springframework.lang.NonNullFields; +import org.jspecify.annotations.NullMarked;