From 44d119bf9a9aa903197b26bd675b58202a53a24e Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 6 Feb 2025 15:53:50 +0100 Subject: [PATCH] Migrate to JSpecify annotations for nullability constraints. Closes #3170 --- .../data/annotation/AccessType.java | 3 +- .../data/annotation/package-info.java | 2 +- .../springframework/data/aot/AotContext.java | 3 +- .../AuditingBeanRegistrationAotProcessor.java | 3 +- .../data/aot/DefaultAotContext.java | 4 +- ...BeanFactoryInitializationAotProcessor.java | 17 ++- ...agedTypesBeanRegistrationAotProcessor.java | 5 +- ...nagedTypesRegistrationAotContribution.java | 3 +- .../data/aot/package-info.java | 2 +- .../data/auditing/AuditableBeanWrapper.java | 3 +- .../data/auditing/AuditingHandlerSupport.java | 2 +- .../data/auditing/Auditor.java | 3 +- .../DefaultAuditableBeanWrapperFactory.java | 11 +- .../MappingAuditableBeanWrapperFactory.java | 7 +- .../AuditingHandlerBeanDefinitionParser.java | 6 +- .../data/auditing/config/package-info.java | 2 +- .../data/auditing/package-info.java | 2 +- .../data/config/ParsingUtils.java | 4 +- .../data/config/TypeFilterParser.java | 6 +- .../data/config/package-info.java | 2 +- ...notatedPropertyValueConverterAccessor.java | 8 +- .../ConfigurableTypeInformationMapper.java | 6 +- .../data/convert/CustomConversions.java | 27 ++-- .../data/convert/DefaultConverterBuilder.java | 6 +- .../data/convert/DefaultTypeMapper.java | 15 +-- .../convert/DtoInstantiatingConverter.java | 6 +- .../data/convert/Jsr310Converters.java | 3 +- .../MappingContextTypeInformationMapper.java | 6 +- .../PropertyValueConversionService.java | 11 +- .../data/convert/PropertyValueConverter.java | 22 ++-- .../PropertyValueConverterFactories.java | 27 ++-- .../PropertyValueConverterFactory.java | 9 +- .../SimplePropertyValueConversions.java | 16 +-- .../SimplePropertyValueConverterRegistry.java | 4 +- .../convert/SimpleTypeInformationMapper.java | 6 +- .../data/convert/TypeInformationMapper.java | 3 +- .../data/convert/TypeMapper.java | 3 +- .../data/convert/ValueConversionContext.java | 21 ++- .../data/convert/ValueConverterRegistry.java | 7 +- .../data/convert/package-info.java | 2 +- .../data/crossstore/ChangeSet.java | 6 +- .../data/crossstore/HashMapChangeSet.java | 9 +- .../data/crossstore/package-info.java | 2 +- .../data/domain/Auditable.java | 2 +- .../data/domain/ExampleMatcher.java | 28 ++-- .../data/domain/KeysetScrollPosition.java | 3 +- .../springframework/data/domain/Limit.java | 3 +- .../data/domain/OffsetScrollPosition.java | 3 +- .../springframework/data/domain/PageImpl.java | 3 +- .../data/domain/PageRequest.java | 1 - .../springframework/data/domain/Pageable.java | 6 +- .../data/domain/Persistable.java | 2 +- .../springframework/data/domain/Range.java | 3 +- .../data/domain/SliceImpl.java | 2 +- .../org/springframework/data/domain/Sort.java | 6 +- .../data/domain/TypedExample.java | 3 +- .../data/domain/TypedExampleMatcher.java | 6 +- .../springframework/data/domain/Unpaged.java | 2 +- .../data/domain/WindowImpl.java | 3 +- .../data/domain/jaxb/OrderAdapter.java | 9 +- .../data/domain/jaxb/PageAdapter.java | 9 +- .../data/domain/jaxb/PageableAdapter.java | 8 +- .../data/domain/jaxb/SortAdapter.java | 8 +- .../data/domain/jaxb/SpringDataJaxb.java | 3 +- .../data/domain/jaxb/package-info.java | 2 +- .../data/domain/package-info.java | 2 +- .../DefaultValueEvaluationContext.java | 3 +- .../data/expression/ExpressionExpression.java | 6 +- .../expression/PlaceholderExpression.java | 1 + ...eactiveValueEvaluationContextProvider.java | 3 +- .../expression/ValueEvaluationContext.java | 12 +- .../ValueEvaluationContextProvider.java | 3 +- .../data/expression/ValueExpression.java | 3 +- .../data/expression/package-info.java | 2 +- .../org/springframework/data/geo/Box.java | 3 +- .../org/springframework/data/geo/Circle.java | 3 +- .../springframework/data/geo/Distance.java | 3 +- .../org/springframework/data/geo/GeoPage.java | 3 +- .../springframework/data/geo/GeoResult.java | 3 +- .../springframework/data/geo/GeoResults.java | 3 +- .../org/springframework/data/geo/Point.java | 3 +- .../org/springframework/data/geo/Polygon.java | 3 +- .../data/geo/format/DistanceFormatter.java | 6 +- .../data/geo/format/PointFormatter.java | 5 +- .../data/geo/format/package-info.java | 2 +- .../data/geo/package-info.java | 2 +- .../data/history/Revision.java | 3 +- .../data/history/package-info.java | 2 +- .../data/mapping/AccessOptions.java | 27 ++-- .../springframework/data/mapping/Alias.java | 9 +- .../data/mapping/Association.java | 5 +- .../data/mapping/IdentifierAccessor.java | 2 +- .../data/mapping/MappingException.java | 2 +- .../data/mapping/Parameter.java | 11 +- .../data/mapping/PersistentEntity.java | 9 +- .../data/mapping/PersistentProperty.java | 3 +- .../mapping/PersistentPropertyAccessor.java | 3 +- .../data/mapping/PersistentPropertyPath.java | 3 +- .../PersistentPropertyPathAccessor.java | 3 +- .../data/mapping/PropertyPath.java | 12 +- .../mapping/PropertyReferenceException.java | 6 +- .../callback/EntityCallbackDiscoverer.java | 3 +- .../data/mapping/callback/package-info.java | 2 +- .../context/AbstractMappingContext.java | 3 +- .../DefaultPersistentPropertyPath.java | 7 +- .../InvalidPersistentPropertyPath.java | 3 +- .../data/mapping/context/MappingContext.java | 3 +- .../mapping/context/PersistentEntities.java | 9 +- .../PersistentPropertyPathFactory.java | 18 +-- .../data/mapping/context/package-info.java | 2 +- .../model/AbstractPersistentProperty.java | 43 +++--- .../AnnotationBasedPersistentProperty.java | 26 ++-- .../mapping/model/BasicPersistentEntity.java | 25 +++- .../data/mapping/model/BeanWrapper.java | 19 ++- ...achingValueExpressionEvaluatorFactory.java | 5 +- .../ClassGeneratingEntityInstantiator.java | 3 +- ...lassGeneratingPropertyAccessorFactory.java | 30 +++-- .../model/ConvertingPropertyAccessor.java | 3 +- .../model/IdPropertyIdentifierAccessor.java | 3 +- .../InstanceCreatorMetadataDiscoverer.java | 3 +- .../InstantiationAwarePropertyAccessor.java | 8 +- .../model/KotlinInstantiationDelegate.java | 10 +- .../data/mapping/model/KotlinValueUtils.java | 22 ++-- .../model/MappingInstantiationException.java | 58 ++++---- .../mapping/model/ParameterValueProvider.java | 6 +- .../model/PersistableIdentifierAccessor.java | 3 +- .../model/PersistentEntityIsNewStrategy.java | 3 +- ...ersistentEntityParameterValueProvider.java | 3 +- .../model/PreferredConstructorDiscoverer.java | 3 +- .../data/mapping/model/Property.java | 3 +- .../mapping/model/PropertyValueProvider.java | 3 +- .../SimplePersistentPropertyPathAccessor.java | 9 +- .../data/mapping/model/SpELContext.java | 3 +- .../model/ValueExpressionEvaluator.java | 5 +- ...ValueExpressionParameterValueProvider.java | 3 +- .../data/mapping/model/package-info.java | 2 +- .../data/mapping/package-info.java | 2 +- ...efaultMethodInvokingMethodInterceptor.java | 6 +- .../data/projection/EntityProjection.java | 6 +- .../EntityProjectionIntrospector.java | 3 +- .../MapAccessingMethodInterceptor.java | 5 +- .../ProjectingMethodInterceptor.java | 14 +- .../data/projection/ProjectionFactory.java | 5 +- .../PropertyAccessingMethodInterceptor.java | 5 +- .../projection/ProxyProjectionFactory.java | 6 +- .../SpelAwareProxyProjectionFactory.java | 2 +- .../SpelEvaluatingMethodInterceptor.java | 5 +- .../data/projection/TargetAware.java | 3 +- .../data/projection/package-info.java | 2 +- .../data/querydsl/QuerydslUtils.java | 3 +- .../data/querydsl/aot/QuerydslHints.java | 3 +- .../data/querydsl/aot/package-info.java | 2 +- .../querydsl/binding/PathInformation.java | 3 +- .../binding/PropertyPathInformation.java | 18 ++- .../querydsl/binding/QuerydslBindings.java | 3 +- .../binding/QuerydslPathInformation.java | 6 +- .../binding/QuerydslPredicateBuilder.java | 6 +- .../querydsl/binding/SingleValueBinding.java | 2 +- .../data/querydsl/binding/package-info.java | 2 +- .../data/querydsl/package-info.java | 2 +- .../aot/hint/RepositoryRuntimeHints.java | 3 +- .../repository/aot/hint/package-info.java | 2 +- .../repository/cdi/CdiRepositoryBean.java | 11 +- .../repository/cdi/CdiRepositoryContext.java | 6 +- .../data/repository/cdi/package-info.java | 2 +- ...notationRepositoryConfigurationSource.java | 8 +- .../config/DefaultAotRepositoryContext.java | 32 +++-- .../DefaultRepositoryConfiguration.java | 8 +- .../NamedQueriesBeanDefinitionBuilder.java | 5 +- .../NamedQueriesBeanDefinitionParser.java | 3 +- ...ropertiesBasedNamedQueriesFactoryBean.java | 6 +- .../RepositoryBeanDefinitionBuilder.java | 4 +- .../RepositoryBeanDefinitionParser.java | 4 +- .../RepositoryBeanDefinitionReader.java | 11 +- ...ositoryBeanDefinitionRegistrarSupport.java | 7 +- .../config/RepositoryComponentProvider.java | 5 +- .../config/RepositoryConfiguration.java | 3 +- .../RepositoryConfigurationAdapter.java | 3 +- .../RepositoryConfigurationDelegate.java | 5 +- .../RepositoryConfigurationExtension.java | 3 +- ...positoryConfigurationExtensionSupport.java | 6 +- .../config/RepositoryConfigurationSource.java | 3 +- .../RepositoryFragmentConfiguration.java | 3 +- ...RepositoryRegistrationAotContribution.java | 43 +++--- .../RepositoryRegistrationAotProcessor.java | 16 ++- ...positoryPopulatorBeanDefinitionParser.java | 3 +- .../XmlRepositoryConfigurationSource.java | 6 +- .../data/repository/config/package-info.java | 2 +- .../repository/core/EntityInformation.java | 3 +- .../core/RepositoryInformationSupport.java | 3 +- .../core/RepositoryMethodContextHolder.java | 6 +- .../data/repository/core/package-info.java | 2 +- .../support/DefaultRepositoryInformation.java | 6 +- .../support/DelegatingEntityInformation.java | 6 +- ...ublishingRepositoryProxyPostProcessor.java | 18 +-- .../support/MethodInvocationValidator.java | 7 +- .../repository/core/support/MethodLookup.java | 3 +- .../core/support/MethodLookups.java | 3 +- .../support/PersistentEntityInformation.java | 6 +- .../support/QueryExecutionResultHandler.java | 36 +++-- .../QueryExecutorMethodInterceptor.java | 11 +- .../ReactiveRepositoryFactorySupport.java | 4 +- .../core/support/RepositoryComposition.java | 31 +++-- .../support/RepositoryFactoryBeanSupport.java | 124 +++++++++++------- .../support/RepositoryFactorySupport.java | 32 +++-- .../core/support/RepositoryFragment.java | 3 +- .../RepositoryFragmentsFactoryBean.java | 15 ++- .../RepositoryInvocationMulticaster.java | 11 +- .../RepositoryMethodInvocationListener.java | 6 +- .../core/support/RepositoryMethodInvoker.java | 28 ++-- ...gTransactionDetectorMethodInterceptor.java | 5 +- ...sactionalRepositoryFactoryBeanSupport.java | 3 +- ...sactionalRepositoryProxyPostProcessor.java | 7 +- .../repository/core/support/package-info.java | 2 +- .../data/repository/history/package-info.java | 2 +- .../history/support/package-info.java | 2 +- ...bstractRepositoryPopulatorFactoryBean.java | 5 +- ...ackson2RepositoryPopulatorFactoryBean.java | 3 +- .../init/Jackson2ResourceReader.java | 3 +- .../init/RepositoriesPopulatedEvent.java | 3 +- .../data/repository/init/ResourceReader.java | 3 +- .../ResourceReaderRepositoryPopulator.java | 2 +- ...shallerRepositoryPopulatorFactoryBean.java | 3 +- .../init/UnmarshallingResourceReader.java | 3 +- .../data/repository/init/package-info.java | 2 +- .../data/repository/package-info.java | 2 +- .../data/repository/query/FluentQuery.java | 3 +- .../repository/query/ParameterAccessor.java | 3 +- .../query/ParametersParameterAccessor.java | 24 ++-- .../query/QueryCreationException.java | 9 +- .../repository/query/QueryLookupStrategy.java | 6 +- ...yMethodValueEvaluationContextAccessor.java | 19 +-- .../repository/query/RepositoryQuery.java | 2 +- .../repository/query/ResultProcessor.java | 17 +-- .../data/repository/query/ReturnedType.java | 10 +- .../query/ValueExpressionQueryRewriter.java | 26 ++-- .../data/repository/query/package-info.java | 2 +- .../query/parser/AbstractQueryCreator.java | 6 +- .../repository/query/parser/PartTree.java | 6 +- .../repository/query/parser/package-info.java | 2 +- .../repository/reactive/package-info.java | 2 +- .../support/AnnotationAttribute.java | 6 +- .../support/DomainClassConverter.java | 18 ++- .../repository/support/MethodParameters.java | 6 +- .../support/ReflectionRepositoryInvoker.java | 14 +- .../data/repository/support/package-info.java | 2 +- .../util/QueryExecutionConverters.java | 38 ++---- .../util/ReactiveWrapperConverters.java | 56 ++++++-- .../data/repository/util/package-info.java | 2 +- .../data/spel/EvaluationContextProvider.java | 3 +- ...tensionAwareEvaluationContextProvider.java | 25 ++-- .../ReactiveEvaluationContextProvider.java | 3 +- ...tensionAwareEvaluationContextProvider.java | 14 +- .../data/spel/package-info.java | 2 +- .../spel/spi/EvaluationContextExtension.java | 6 +- .../data/spel/spi/Function.java | 21 +-- .../data/spel/spi/package-info.java | 2 +- .../data/support/ExampleMatcherAccessor.java | 7 +- .../data/support/WindowIterator.java | 30 ++--- .../data/support/package-info.java | 2 +- .../ChainedTransactionManager.java | 8 +- .../transaction/MultiTransactionStatus.java | 33 ++++- .../data/transaction/package-info.java | 2 +- .../data/util/AnnotatedTypeScanner.java | 3 +- .../AnnotationDetectionFieldCallback.java | 9 +- .../AnnotationDetectionMethodCallback.java | 12 +- .../springframework/data/util/BeanLookup.java | 6 +- .../data/util/ClassTypeInformation.java | 2 - .../springframework/data/util/ClassUtils.java | 5 +- .../data/util/CustomCollections.java | 39 +++--- .../DirectFieldAccessFallbackBeanWrapper.java | 6 +- .../data/util/IteratorSpliterator.java | 8 +- .../data/util/KotlinBeanInfoFactory.java | 13 +- .../data/util/KotlinReflectionUtils.java | 6 +- .../org/springframework/data/util/Lazy.java | 13 +- .../data/util/MethodInvocationRecorder.java | 59 +++++---- .../data/util/NullableUtils.java | 26 ++-- .../data/util/NullableWrapper.java | 6 +- .../data/util/NullableWrapperConverters.java | 25 ++-- .../org/springframework/data/util/Pair.java | 3 +- .../data/util/ParameterTypes.java | 51 ++++--- .../data/util/QTypeContributor.java | 6 +- .../data/util/ReactiveWrappers.java | 3 +- .../data/util/ReflectionUtils.java | 17 +-- .../org/springframework/data/util/Sink.java | 6 +- .../data/util/StreamUtils.java | 3 +- .../data/util/TypeDiscoverer.java | 24 ++-- .../data/util/TypeInformation.java | 3 +- .../springframework/data/util/Version.java | 3 +- .../data/util/package-info.java | 2 +- ...PageableHandlerMethodArgumentResolver.java | 3 +- ...eoasSortHandlerMethodArgumentResolver.java | 3 +- ...sonProjectingMethodInterceptorFactory.java | 12 +- .../data/web/MapDataBinder.java | 11 +- .../OffsetScrollPositionArgumentResolver.java | 4 +- ...PositionHandlerMethodArgumentResolver.java | 5 +- ...nHandlerMethodArgumentResolverSupport.java | 3 +- .../data/web/PageableArgumentResolver.java | 5 +- ...PageableHandlerMethodArgumentResolver.java | 5 +- ...eHandlerMethodArgumentResolverSupport.java | 3 +- .../web/PageableMethodParameterUtils.java | 9 +- .../springframework/data/web/PagedModel.java | 6 +- .../data/web/PagedResourcesAssembler.java | 3 +- ...gedResourcesAssemblerArgumentResolver.java | 5 +- ...rojectingJackson2HttpMessageConverter.java | 3 +- ...PositionHandlerMethodArgumentResolver.java | 4 +- ...PageableHandlerMethodArgumentResolver.java | 3 +- ...tiveSortHandlerMethodArgumentResolver.java | 3 +- .../data/web/SlicedResourcesAssembler.java | 43 +++--- ...cedResourcesAssemblerArgumentResolver.java | 5 +- .../data/web/SortArgumentResolver.java | 5 +- .../SortHandlerMethodArgumentResolver.java | 5 +- ...tHandlerMethodArgumentResolverSupport.java | 3 +- .../data/web/SpringDataAnnotationUtils.java | 11 +- .../data/web/XmlBeamHttpMessageConverter.java | 4 +- .../data/web/aot/WebRuntimeHints.java | 3 +- .../SpringDataJacksonConfiguration.java | 6 +- .../config/SpringDataWebConfiguration.java | 3 +- .../data/web/config/package-info.java | 2 +- .../data/web/package-info.java | 2 +- .../QuerydslPredicateArgumentResolver.java | 6 +- ...rydslPredicateArgumentResolverSupport.java | 6 +- ...tiveQuerydslPredicateArgumentResolver.java | 6 +- .../data/web/querydsl/package-info.java | 2 +- .../data/aot/DeferredTypeBuilder.java | 3 +- ...ropertyValueConverterFactoryUnitTests.java | 2 +- ...pertyValueConverterRegistrarUnitTests.java | 2 +- .../expression/ValueEvaluationUnitTests.java | 2 +- .../callback/CapturingEntityCallback.java | 3 +- ...ationBasedPersistentPropertyUnitTests.java | 2 +- .../model/BasicPersistentEntityUnitTests.java | 2 +- ...GeneratingEntityInstantiatorUnitTests.java | 4 +- ...ReflectionEntityInstantiatorUnitTests.java | 4 +- ...RepositoryFactoryBeanSupportUnitTests.java | 4 +- .../RepositoryFactorySupportUnitTests.java | 2 +- .../RepositoryMethodInvokerUnitTests.java | 2 +- .../data/util/AbstractAuditable.java | 2 +- .../util/ClassTypeInformationUnitTests.java | 2 +- ...andlerMethodArgumentResolverUnitTests.java | 3 +- ...andlerMethodArgumentResolverUnitTests.java | 2 +- ...andlerMethodArgumentResolverUnitTests.java | 2 +- ...andlerMethodArgumentResolverUnitTests.java | 3 +- ...dslPredicateArgumentResolverUnitTests.java | 3 +- ...dslPredicateArgumentResolverUnitTests.java | 3 +- 344 files changed, 1515 insertions(+), 1234 deletions(-) diff --git a/src/main/java/org/springframework/data/annotation/AccessType.java b/src/main/java/org/springframework/data/annotation/AccessType.java index 560dc24deb..ee7140ac39 100644 --- a/src/main/java/org/springframework/data/annotation/AccessType.java +++ b/src/main/java/org/springframework/data/annotation/AccessType.java @@ -28,7 +28,7 @@ * @author Oliver Gierke */ @Documented -@Target({ ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, }) +@Target({ ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.FIELD, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) public @interface AccessType { @@ -40,4 +40,5 @@ enum Type { FIELD, PROPERTY; } + } diff --git a/src/main/java/org/springframework/data/annotation/package-info.java b/src/main/java/org/springframework/data/annotation/package-info.java index b22ea5403f..8306cfed05 100644 --- a/src/main/java/org/springframework/data/annotation/package-info.java +++ b/src/main/java/org/springframework/data/annotation/package-info.java @@ -1,5 +1,5 @@ /** * Core annotations being used by Spring Data. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.annotation; diff --git a/src/main/java/org/springframework/data/aot/AotContext.java b/src/main/java/org/springframework/data/aot/AotContext.java index 26cc61c90e..4d8c0baedc 100644 --- a/src/main/java/org/springframework/data/aot/AotContext.java +++ b/src/main/java/org/springframework/data/aot/AotContext.java @@ -22,6 +22,8 @@ import java.util.Set; import java.util.function.Consumer; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.BeanDefinition; @@ -29,7 +31,6 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.data.util.TypeScanner; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** diff --git a/src/main/java/org/springframework/data/aot/AuditingBeanRegistrationAotProcessor.java b/src/main/java/org/springframework/data/aot/AuditingBeanRegistrationAotProcessor.java index 9cc4ec8ee1..a3527e06f7 100644 --- a/src/main/java/org/springframework/data/aot/AuditingBeanRegistrationAotProcessor.java +++ b/src/main/java/org/springframework/data/aot/AuditingBeanRegistrationAotProcessor.java @@ -15,6 +15,8 @@ */ package org.springframework.data.aot; +import org.jspecify.annotations.Nullable; + import org.springframework.aop.SpringProxy; import org.springframework.aop.framework.Advised; import org.springframework.aot.hint.RuntimeHints; @@ -26,7 +28,6 @@ import org.springframework.data.domain.AuditorAware; import org.springframework.data.domain.ReactiveAuditorAware; import org.springframework.data.util.ReactiveWrappers; -import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; /** diff --git a/src/main/java/org/springframework/data/aot/DefaultAotContext.java b/src/main/java/org/springframework/data/aot/DefaultAotContext.java index 7c67e41c36..114da7673e 100644 --- a/src/main/java/org/springframework/data/aot/DefaultAotContext.java +++ b/src/main/java/org/springframework/data/aot/DefaultAotContext.java @@ -20,6 +20,8 @@ import java.util.List; import java.util.Optional; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.BeanDefinition; @@ -132,7 +134,7 @@ public RootBeanDefinition getRootBeanDefinition() throws NoSuchBeanDefinitionExc } @Override - public Class resolveType() { + public @Nullable Class resolveType() { return factory.getType(beanName, false); } } diff --git a/src/main/java/org/springframework/data/aot/ManagedTypesBeanFactoryInitializationAotProcessor.java b/src/main/java/org/springframework/data/aot/ManagedTypesBeanFactoryInitializationAotProcessor.java index 089c38f8ed..2d231ab401 100644 --- a/src/main/java/org/springframework/data/aot/ManagedTypesBeanFactoryInitializationAotProcessor.java +++ b/src/main/java/org/springframework/data/aot/ManagedTypesBeanFactoryInitializationAotProcessor.java @@ -20,6 +20,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution; import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor; @@ -30,7 +31,6 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.data.domain.ManagedTypes; import org.springframework.lang.Contract; -import org.springframework.lang.Nullable; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; @@ -48,9 +48,9 @@ public class ManagedTypesBeanFactoryInitializationAotProcessor implements BeanFa private static final Log logger = LogFactory.getLog(ManagedTypesBeanFactoryInitializationAotProcessor.class); @Override - @Nullable @Contract("_ -> null") - public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) { + public @Nullable BeanFactoryInitializationAotContribution processAheadOfTime( + ConfigurableListableBeanFactory beanFactory) { processManagedTypes(beanFactory); return null; @@ -82,12 +82,15 @@ private void postProcessManagedTypes(ConfigurableListableBeanFactory beanFactory } Object value = potentiallyWrapToIterable(supplier.get()); + String beanClassName = beanDefinition.getBeanClassName(); - BeanDefinition beanDefinitionReplacement = newManagedTypeBeanDefinition(beanDefinition.getBeanClassName(), - value); + if (beanClassName != null) { - registry.removeBeanDefinition(beanName); - registry.registerBeanDefinition(beanName, beanDefinitionReplacement); + BeanDefinition beanDefinitionReplacement = newManagedTypeBeanDefinition(beanClassName, value); + + registry.removeBeanDefinition(beanName); + registry.registerBeanDefinition(beanName, beanDefinitionReplacement); + } } } } diff --git a/src/main/java/org/springframework/data/aot/ManagedTypesBeanRegistrationAotProcessor.java b/src/main/java/org/springframework/data/aot/ManagedTypesBeanRegistrationAotProcessor.java index b82acc7a24..9495642b6b 100644 --- a/src/main/java/org/springframework/data/aot/ManagedTypesBeanRegistrationAotProcessor.java +++ b/src/main/java/org/springframework/data/aot/ManagedTypesBeanRegistrationAotProcessor.java @@ -21,6 +21,8 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; + import org.springframework.aot.generate.GenerationContext; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.BeanFactory; @@ -34,7 +36,6 @@ import org.springframework.data.util.QTypeContributor; import org.springframework.data.util.TypeContributor; import org.springframework.data.util.TypeUtils; -import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; @@ -61,7 +62,7 @@ public String getModuleIdentifier() { } @Override - public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) { + public @Nullable BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) { if (!isMatch(registeredBean.getBeanClass(), registeredBean.getBeanName())) { return null; diff --git a/src/main/java/org/springframework/data/aot/ManagedTypesRegistrationAotContribution.java b/src/main/java/org/springframework/data/aot/ManagedTypesRegistrationAotContribution.java index 31ddf0cbd7..1e59e7e852 100644 --- a/src/main/java/org/springframework/data/aot/ManagedTypesRegistrationAotContribution.java +++ b/src/main/java/org/springframework/data/aot/ManagedTypesRegistrationAotContribution.java @@ -22,6 +22,8 @@ import javax.lang.model.element.Modifier; +import org.jspecify.annotations.Nullable; + import org.springframework.aot.generate.AccessControl; import org.springframework.aot.generate.GeneratedMethod; import org.springframework.aot.generate.GenerationContext; @@ -41,7 +43,6 @@ import org.springframework.javapoet.ParameterizedTypeName; import org.springframework.javapoet.TypeName; import org.springframework.javapoet.WildcardTypeName; -import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.ReflectionUtils; diff --git a/src/main/java/org/springframework/data/aot/package-info.java b/src/main/java/org/springframework/data/aot/package-info.java index 85b86ff765..fdea25a3ca 100644 --- a/src/main/java/org/springframework/data/aot/package-info.java +++ b/src/main/java/org/springframework/data/aot/package-info.java @@ -2,5 +2,5 @@ * Support for registering the need for reflection, resources, java serialization and proxies at runtime for Ahead of * Time compilation. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.aot; diff --git a/src/main/java/org/springframework/data/auditing/AuditableBeanWrapper.java b/src/main/java/org/springframework/data/auditing/AuditableBeanWrapper.java index 0b738c34e1..bd0f140539 100644 --- a/src/main/java/org/springframework/data/auditing/AuditableBeanWrapper.java +++ b/src/main/java/org/springframework/data/auditing/AuditableBeanWrapper.java @@ -18,8 +18,9 @@ import java.time.temporal.TemporalAccessor; import java.util.Optional; +import org.jspecify.annotations.Nullable; + import org.springframework.lang.Contract; -import org.springframework.lang.Nullable; /** * Interface to abstract the ways setting the auditing information can be implemented. diff --git a/src/main/java/org/springframework/data/auditing/AuditingHandlerSupport.java b/src/main/java/org/springframework/data/auditing/AuditingHandlerSupport.java index d66997440a..d2e4ada5cc 100644 --- a/src/main/java/org/springframework/data/auditing/AuditingHandlerSupport.java +++ b/src/main/java/org/springframework/data/auditing/AuditingHandlerSupport.java @@ -20,11 +20,11 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.core.log.LogMessage; import org.springframework.data.domain.Auditable; import org.springframework.data.mapping.context.PersistentEntities; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** diff --git a/src/main/java/org/springframework/data/auditing/Auditor.java b/src/main/java/org/springframework/data/auditing/Auditor.java index ac8a01a454..7af41bae91 100644 --- a/src/main/java/org/springframework/data/auditing/Auditor.java +++ b/src/main/java/org/springframework/data/auditing/Auditor.java @@ -17,7 +17,8 @@ import java.util.Optional; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; + import org.springframework.util.ObjectUtils; /** diff --git a/src/main/java/org/springframework/data/auditing/DefaultAuditableBeanWrapperFactory.java b/src/main/java/org/springframework/data/auditing/DefaultAuditableBeanWrapperFactory.java index 925ffa8693..df8d7e603a 100644 --- a/src/main/java/org/springframework/data/auditing/DefaultAuditableBeanWrapperFactory.java +++ b/src/main/java/org/springframework/data/auditing/DefaultAuditableBeanWrapperFactory.java @@ -24,13 +24,14 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; + import org.springframework.core.ResolvableType; import org.springframework.core.convert.ConversionService; import org.springframework.data.convert.Jsr310Converters; import org.springframework.data.domain.Auditable; import org.springframework.data.util.ReflectionUtils; import org.springframework.format.support.DefaultFormattingConversionService; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -115,7 +116,7 @@ public AuditableInterfaceBeanWrapper(ConversionService conversionService, } @Override - public Object setCreatedBy(@Nullable Object value) { + public @Nullable Object setCreatedBy(@Nullable Object value) { auditable.setCreatedBy(value); return value; @@ -130,7 +131,7 @@ public TemporalAccessor setCreatedDate(TemporalAccessor value) { } @Override - public Object setLastModifiedBy(Object value) { + public @Nullable Object setLastModifiedBy(@Nullable Object value) { auditable.setLastModifiedBy(value); @@ -267,7 +268,7 @@ public ReflectionAuditingBeanWrapper(ConversionService conversionService, T targ } @Override - public Object setCreatedBy(@Nullable Object value) { + public @Nullable Object setCreatedBy(@Nullable Object value) { return setField(metadata.getCreatedByField(), value); } @@ -277,7 +278,7 @@ public TemporalAccessor setCreatedDate(TemporalAccessor value) { } @Override - public Object setLastModifiedBy(@Nullable Object value) { + public @Nullable Object setLastModifiedBy(@Nullable Object value) { return setField(metadata.getLastModifiedByField(), value); } diff --git a/src/main/java/org/springframework/data/auditing/MappingAuditableBeanWrapperFactory.java b/src/main/java/org/springframework/data/auditing/MappingAuditableBeanWrapperFactory.java index 9a7549adb2..2c11724dbe 100644 --- a/src/main/java/org/springframework/data/auditing/MappingAuditableBeanWrapperFactory.java +++ b/src/main/java/org/springframework/data/auditing/MappingAuditableBeanWrapperFactory.java @@ -23,6 +23,8 @@ import java.util.function.Predicate; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; + import org.springframework.core.convert.ConversionService; import org.springframework.data.annotation.CreatedBy; import org.springframework.data.annotation.CreatedDate; @@ -41,7 +43,6 @@ import org.springframework.data.mapping.context.PersistentEntities; import org.springframework.data.util.Lazy; import org.springframework.lang.Contract; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -195,7 +196,7 @@ public MappingMetadataAuditableBeanWrapper( } @Override - public Object setCreatedBy(Object value) { + public @Nullable Object setCreatedBy(@Nullable Object value) { return setProperty(metadata.createdByPaths, value); } @@ -205,7 +206,7 @@ public TemporalAccessor setCreatedDate(TemporalAccessor value) { } @Override - public Object setLastModifiedBy(@Nullable Object value) { + public @Nullable Object setLastModifiedBy(@Nullable Object value) { return setProperty(metadata.lastModifiedByPaths, value); } diff --git a/src/main/java/org/springframework/data/auditing/config/AuditingHandlerBeanDefinitionParser.java b/src/main/java/org/springframework/data/auditing/config/AuditingHandlerBeanDefinitionParser.java index 8479e102cb..3aa83379b8 100644 --- a/src/main/java/org/springframework/data/auditing/config/AuditingHandlerBeanDefinitionParser.java +++ b/src/main/java/org/springframework/data/auditing/config/AuditingHandlerBeanDefinitionParser.java @@ -17,6 +17,8 @@ import static org.springframework.beans.factory.support.BeanDefinitionBuilder.*; +import org.jspecify.annotations.Nullable; + import org.springframework.aop.framework.ProxyFactoryBean; import org.springframework.aop.target.LazyInitTargetSource; import org.springframework.beans.factory.config.BeanDefinition; @@ -45,7 +47,7 @@ public class AuditingHandlerBeanDefinitionParser extends AbstractSingleBeanDefin private static final String AUDITOR_AWARE_REF = "auditor-aware-ref"; private final String mappingContextBeanName; - private String resolvedBeanName; + private @Nullable String resolvedBeanName; /** * Creates a new {@link AuditingHandlerBeanDefinitionParser} to point to a {@link MappingContext} with the given bean @@ -65,7 +67,7 @@ public AuditingHandlerBeanDefinitionParser(String mappingContextBeanName) { * * @return the resolvedBeanName */ - public String getResolvedBeanName() { + public @Nullable String getResolvedBeanName() { return resolvedBeanName; } diff --git a/src/main/java/org/springframework/data/auditing/config/package-info.java b/src/main/java/org/springframework/data/auditing/config/package-info.java index 96a2208828..e0d505d717 100644 --- a/src/main/java/org/springframework/data/auditing/config/package-info.java +++ b/src/main/java/org/springframework/data/auditing/config/package-info.java @@ -1,5 +1,5 @@ /** * Types to abstract authentication concepts. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.auditing.config; diff --git a/src/main/java/org/springframework/data/auditing/package-info.java b/src/main/java/org/springframework/data/auditing/package-info.java index 07a8831925..16f821b7ba 100644 --- a/src/main/java/org/springframework/data/auditing/package-info.java +++ b/src/main/java/org/springframework/data/auditing/package-info.java @@ -1,5 +1,5 @@ /** * General support for entity auditing. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.auditing; diff --git a/src/main/java/org/springframework/data/config/ParsingUtils.java b/src/main/java/org/springframework/data/config/ParsingUtils.java index 68729070a1..6188c4ed71 100644 --- a/src/main/java/org/springframework/data/config/ParsingUtils.java +++ b/src/main/java/org/springframework/data/config/ParsingUtils.java @@ -15,15 +15,17 @@ */ package org.springframework.data.config; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; + import org.w3c.dom.Element; /** diff --git a/src/main/java/org/springframework/data/config/TypeFilterParser.java b/src/main/java/org/springframework/data/config/TypeFilterParser.java index 2e56ee0a1c..7e07ef4520 100644 --- a/src/main/java/org/springframework/data/config/TypeFilterParser.java +++ b/src/main/java/org/springframework/data/config/TypeFilterParser.java @@ -20,6 +20,8 @@ import java.util.HashSet; import java.util.regex.Pattern; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.BeanUtils; import org.springframework.beans.FatalBeanException; import org.springframework.beans.factory.parsing.ReaderContext; @@ -30,7 +32,6 @@ import org.springframework.core.type.filter.AssignableTypeFilter; import org.springframework.core.type.filter.RegexPatternTypeFilter; import org.springframework.core.type.filter.TypeFilter; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.w3c.dom.Element; @@ -101,7 +102,8 @@ public Collection parseTypeFilters(Element element, Type type) { try { filters.add(createTypeFilter(childElement, classLoader)); } catch (RuntimeException e) { - readerContext.error(e.getMessage(), readerContext.extractSource(element), e.getCause()); + readerContext.error("Failed creating type filter: " + e.getMessage(), readerContext.extractSource(element), + e.getCause()); } } diff --git a/src/main/java/org/springframework/data/config/package-info.java b/src/main/java/org/springframework/data/config/package-info.java index 1db339d5b2..977de6c641 100644 --- a/src/main/java/org/springframework/data/config/package-info.java +++ b/src/main/java/org/springframework/data/config/package-info.java @@ -1,5 +1,5 @@ /** * Basic support for creating custom Spring namespaces and JavaConfig. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.config; diff --git a/src/main/java/org/springframework/data/convert/AnnotatedPropertyValueConverterAccessor.java b/src/main/java/org/springframework/data/convert/AnnotatedPropertyValueConverterAccessor.java index 6a683ca430..1dd142ebb6 100644 --- a/src/main/java/org/springframework/data/convert/AnnotatedPropertyValueConverterAccessor.java +++ b/src/main/java/org/springframework/data/convert/AnnotatedPropertyValueConverterAccessor.java @@ -15,8 +15,9 @@ */ package org.springframework.data.convert; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.PersistentProperty; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -28,7 +29,7 @@ class AnnotatedPropertyValueConverterAccessor { private final String name; - private final ValueConverter annotation; + private final @Nullable ValueConverter annotation; public AnnotatedPropertyValueConverterAccessor(PersistentProperty property) { @@ -45,9 +46,8 @@ public AnnotatedPropertyValueConverterAccessor(PersistentProperty property) { * @return {@literal null} if none defined. Check {@link #hasValueConverter()} to check if the annotation is present * at all. */ - @Nullable @SuppressWarnings({ "unchecked", "rawtypes" }) - public Class>>> getValueConverterType() { + public @Nullable Class>>> getValueConverterType() { return annotation != null ? (Class) annotation.value() : null; } diff --git a/src/main/java/org/springframework/data/convert/ConfigurableTypeInformationMapper.java b/src/main/java/org/springframework/data/convert/ConfigurableTypeInformationMapper.java index f453ee2f84..7f27c58bc1 100644 --- a/src/main/java/org/springframework/data/convert/ConfigurableTypeInformationMapper.java +++ b/src/main/java/org/springframework/data/convert/ConfigurableTypeInformationMapper.java @@ -19,11 +19,12 @@ import java.util.Map; import java.util.Map.Entry; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.Alias; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -71,9 +72,8 @@ public Alias createAliasFor(TypeInformation type) { return typeToAlias.getOrDefault(type, Alias.NONE); } - @Nullable @Override - public TypeInformation resolveTypeFrom(Alias alias) { + public @Nullable TypeInformation resolveTypeFrom(Alias alias) { return aliasToType.get(alias); } } diff --git a/src/main/java/org/springframework/data/convert/CustomConversions.java b/src/main/java/org/springframework/data/convert/CustomConversions.java index abced91890..8e5dbd5837 100644 --- a/src/main/java/org/springframework/data/convert/CustomConversions.java +++ b/src/main/java/org/springframework/data/convert/CustomConversions.java @@ -23,6 +23,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.core.GenericTypeResolver; import org.springframework.core.annotation.AnnotationUtils; @@ -38,7 +39,6 @@ import org.springframework.data.util.CustomCollections; import org.springframework.data.util.Predicates; import org.springframework.data.util.Streamable; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -249,8 +249,7 @@ private void registerConverterIn(Object candidate, ConverterRegistry conversionS * data store does not support property value conversions. * @see PropertyValueConversions */ - @Nullable - public PropertyValueConversions getPropertyValueConversions() { + public @Nullable PropertyValueConversions getPropertyValueConversions() { return propertyValueConversions; } @@ -447,8 +446,7 @@ public boolean hasCustomReadTarget(Class sourceType, Class targetType) { * @param targetType must not be {@literal null}. * @return the actual target type for the given {@code sourceType} and {@code targetType}. */ - @Nullable - private Class getCustomReadTarget(Class sourceType, Class targetType) { + private @Nullable Class getCustomReadTarget(Class sourceType, Class targetType) { return customReadTargetTypes.computeIfAbsent(sourceType, targetType, getReadTarget); } @@ -461,8 +459,7 @@ private Class getCustomReadTarget(Class sourceType, Class targetType) { * @param pairs must not be {@literal null}. * @return the base {@link Class type} for the (requested) {@link Class target type} if present. */ - @Nullable - private Class getCustomTarget(Class sourceType, @Nullable Class targetType, + private @Nullable Class getCustomTarget(Class sourceType, @Nullable Class targetType, Collection pairs) { if (targetType != null && pairs.contains(new ConvertiblePair(sourceType, targetType))) { @@ -505,8 +502,8 @@ static class ConversionTargetsCache { * @param mappingFunction must not be {@literal null}. * @return the optional target type. */ - @Nullable - public Class computeIfAbsent(Class sourceType, Function> mappingFunction) { + public @Nullable Class computeIfAbsent(Class sourceType, + Function> mappingFunction) { return computeIfAbsent(sourceType, AbsentTargetTypeMarker.class, mappingFunction); } @@ -520,8 +517,7 @@ public Class computeIfAbsent(Class sourceType, Function computeIfAbsent(Class sourceType, Class targetType, + public @Nullable Class computeIfAbsent(Class sourceType, Class targetType, Function> mappingFunction) { TargetTypes targetTypes = customReadTargetTypes.get(sourceType); @@ -575,8 +571,8 @@ static class TargetTypes { * @param mappingFunction must not be {@literal null}. * @return the optional target type. */ - @Nullable - public Class computeIfAbsent(Class targetType, Function> mappingFunction) { + public @Nullable Class computeIfAbsent(Class targetType, + Function> mappingFunction) { Class optionalTarget = conversionTargets.get(targetType); @@ -927,7 +923,7 @@ protected static class ConverterConfiguration { private final StoreConversions storeConversions; private final List userConverters; private final Predicate converterRegistrationFilter; - private final PropertyValueConversions propertyValueConversions; + private final @Nullable PropertyValueConversions propertyValueConversions; /** * Create a new ConverterConfiguration holding the given {@link StoreConversions} and user defined converters. @@ -1004,8 +1000,7 @@ boolean shouldRegister(ConvertiblePair candidate) { * @return the configured {@link PropertyValueConversions} if set, {@literal null} otherwise. * @since 2.7 */ - @Nullable - public PropertyValueConversions getPropertyValueConversions() { + public @Nullable PropertyValueConversions getPropertyValueConversions() { return this.propertyValueConversions; } } diff --git a/src/main/java/org/springframework/data/convert/DefaultConverterBuilder.java b/src/main/java/org/springframework/data/convert/DefaultConverterBuilder.java index f421699ad1..3edde0aa85 100644 --- a/src/main/java/org/springframework/data/convert/DefaultConverterBuilder.java +++ b/src/main/java/org/springframework/data/convert/DefaultConverterBuilder.java @@ -21,6 +21,8 @@ import java.util.function.Function; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; + import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.GenericConverter; @@ -29,7 +31,6 @@ import org.springframework.data.convert.ConverterBuilder.ReadingConverterBuilder; import org.springframework.data.convert.ConverterBuilder.WritingConverterBuilder; import org.springframework.data.util.Optionals; -import org.springframework.lang.Nullable; import org.springframework.util.ObjectUtils; /** @@ -111,10 +112,9 @@ public ConfigurableGenericConverter(ConvertiblePair convertiblePair, Function accessor, }; } - @Nullable @Override - public TypeInformation readType(S source) { + public @Nullable TypeInformation readType(S source) { Assert.notNull(source, "Source object must not be null"); @@ -122,8 +122,7 @@ public TypeInformation readType(S source) { * @param alias * @return */ - @Nullable - private TypeInformation getFromCacheOrCreate(Alias alias) { + private @Nullable TypeInformation getFromCacheOrCreate(Alias alias) { return typeCache.computeIfAbsent(alias, getAlias).orElse(null); } @@ -160,8 +159,7 @@ public TypeInformation readType(S source, TypeInformation ba * @param source * @return */ - @Nullable - private Class getDefaultedTypeToBeUsed(S source) { + private @Nullable Class getDefaultedTypeToBeUsed(S source) { TypeInformation type = readType(source); type = type == null ? getFallbackTypeFor(source) : type; @@ -174,8 +172,7 @@ private Class getDefaultedTypeToBeUsed(S source) { * @param source will never be {@literal null}. * @return */ - @Nullable - protected TypeInformation getFallbackTypeFor(S source) { + protected @Nullable TypeInformation getFallbackTypeFor(S source) { return null; } diff --git a/src/main/java/org/springframework/data/convert/DtoInstantiatingConverter.java b/src/main/java/org/springframework/data/convert/DtoInstantiatingConverter.java index 33b29e4ebf..7fb5d7aae0 100644 --- a/src/main/java/org/springframework/data/convert/DtoInstantiatingConverter.java +++ b/src/main/java/org/springframework/data/convert/DtoInstantiatingConverter.java @@ -15,6 +15,8 @@ */ package org.springframework.data.convert; +import org.jspecify.annotations.Nullable; + import org.springframework.core.convert.converter.Converter; import org.springframework.data.mapping.InstanceCreatorMetadata; import org.springframework.data.mapping.Parameter; @@ -28,7 +30,6 @@ import org.springframework.data.mapping.model.EntityInstantiators; import org.springframework.data.mapping.model.ParameterValueProvider; import org.springframework.lang.Contract; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -81,9 +82,8 @@ public Object convert(Object source) { Object dto = instantiator.createInstance(targetEntity, new ParameterValueProvider() { @Override - @Nullable @SuppressWarnings({ "rawtypes" }) - public Object getParameterValue(Parameter parameter) { + public @Nullable Object getParameterValue(Parameter parameter) { String name = parameter.getName(); diff --git a/src/main/java/org/springframework/data/convert/Jsr310Converters.java b/src/main/java/org/springframework/data/convert/Jsr310Converters.java index 2e393ba006..be0e58d249 100644 --- a/src/main/java/org/springframework/data/convert/Jsr310Converters.java +++ b/src/main/java/org/springframework/data/convert/Jsr310Converters.java @@ -34,8 +34,9 @@ import java.util.Date; import java.util.List; +import org.jspecify.annotations.NonNull; + import org.springframework.core.convert.converter.Converter; -import org.springframework.lang.NonNull; /** * Helper class to register JSR-310 specific {@link Converter} implementations. diff --git a/src/main/java/org/springframework/data/convert/MappingContextTypeInformationMapper.java b/src/main/java/org/springframework/data/convert/MappingContextTypeInformationMapper.java index addef29f2e..545f1181bc 100644 --- a/src/main/java/org/springframework/data/convert/MappingContextTypeInformationMapper.java +++ b/src/main/java/org/springframework/data/convert/MappingContextTypeInformationMapper.java @@ -18,12 +18,13 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.Alias; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -109,9 +110,8 @@ private Alias verify(TypeInformation key, Alias alias) { return alias; } - @Nullable @Override - public TypeInformation resolveTypeFrom(Alias alias) { + public @Nullable TypeInformation resolveTypeFrom(Alias alias) { for (Map.Entry, Alias> entry : typeMap.entrySet()) { if (entry.getValue().hasSamePresentValueAs(alias)) { diff --git a/src/main/java/org/springframework/data/convert/PropertyValueConversionService.java b/src/main/java/org/springframework/data/convert/PropertyValueConversionService.java index ba8ab6c8d9..4de622ed61 100644 --- a/src/main/java/org/springframework/data/convert/PropertyValueConversionService.java +++ b/src/main/java/org/springframework/data/convert/PropertyValueConversionService.java @@ -15,8 +15,9 @@ */ package org.springframework.data.convert; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.PersistentProperty; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -74,8 +75,8 @@ public boolean hasConverter(PersistentProperty property) { * @param value conversion context type. * @return the value to be used in the domain model. Can be {@code null}. */ - @Nullable - public

, VCC extends ValueConversionContext

> Object read(@Nullable Object value, + public

, VCC extends ValueConversionContext

> @Nullable Object read( + @Nullable Object value, P property, VCC context) { PropertyValueConverter> converter = conversions @@ -95,8 +96,8 @@ public

, VCC extends ValueConversionContext

> * @param value conversion context type. * @return the value to be written to the data store. Can be {@code null}. */ - @Nullable - public

, VCC extends ValueConversionContext

> Object write(@Nullable Object value, + public

, VCC extends ValueConversionContext

> @Nullable Object write( + @Nullable Object value, P property, VCC context) { PropertyValueConverter> converter = conversions diff --git a/src/main/java/org/springframework/data/convert/PropertyValueConverter.java b/src/main/java/org/springframework/data/convert/PropertyValueConverter.java index e1e0c5c6ac..50594bb41c 100644 --- a/src/main/java/org/springframework/data/convert/PropertyValueConverter.java +++ b/src/main/java/org/springframework/data/convert/PropertyValueConverter.java @@ -17,8 +17,9 @@ import java.util.function.BiFunction; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.PersistentProperty; -import org.springframework.lang.Nullable; /** * {@link PropertyValueConverter} provides a symmetric way of converting certain properties from domain to @@ -87,8 +88,7 @@ default DV readNull(C context) { * never {@literal null}. * @return the converted value. Can be {@literal null}. */ - @Nullable - default SV writeNull(C context) { + default @Nullable SV writeNull(C context) { return null; } @@ -102,15 +102,13 @@ enum ObjectToObjectPropertyValueConverter implements PropertyValueConverter { INSTANCE; - @Nullable @Override - public Object read(@Nullable Object value, ValueConversionContext context) { + public @Nullable Object read(@Nullable Object value, ValueConversionContext context) { return value; } - @Nullable @Override - public Object write(@Nullable Object value, ValueConversionContext context) { + public @Nullable Object write(@Nullable Object value, ValueConversionContext context) { return value; } } @@ -133,25 +131,23 @@ public FunctionPropertyValueConverter(BiFunction, this.reader = reader; } - @Nullable @Override - public SV write(@Nullable DV value, ValueConversionContext

context) { + public @Nullable SV write(@Nullable DV value, ValueConversionContext

context) { return writer.apply(value, context); } @Override - public SV writeNull(ValueConversionContext

context) { + public @Nullable SV writeNull(ValueConversionContext

context) { return writer.apply(null, context); } - @Nullable @Override - public DV read(@Nullable SV value, ValueConversionContext

context) { + public @Nullable DV read(@Nullable SV value, ValueConversionContext

context) { return reader.apply(value, context); } @Override - public DV readNull(ValueConversionContext

context) { + public @Nullable DV readNull(ValueConversionContext

context) { return reader.apply(null, context); } } diff --git a/src/main/java/org/springframework/data/convert/PropertyValueConverterFactories.java b/src/main/java/org/springframework/data/convert/PropertyValueConverterFactories.java index 8c26f472a8..3db744e032 100644 --- a/src/main/java/org/springframework/data/convert/PropertyValueConverterFactories.java +++ b/src/main/java/org/springframework/data/convert/PropertyValueConverterFactories.java @@ -23,12 +23,13 @@ import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.data.mapping.PersistentProperty; import org.springframework.lang.Contract; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -57,10 +58,9 @@ static class ChainedPropertyValueConverterFactory implements PropertyValueConver this.delegates = Collections.unmodifiableList(delegates); } - @Nullable @Override @SuppressWarnings("unchecked") - public > PropertyValueConverter getConverter( + public > @Nullable PropertyValueConverter getConverter( PersistentProperty property) { return delegates.stream().map(it -> (PropertyValueConverter) it.getConverter(property)) @@ -68,7 +68,7 @@ public > PropertyValueConverter> PropertyValueConverter getConverter( + public > @Nullable PropertyValueConverter getConverter( Class> converterType) { return delegates.stream().filter(it -> it.getConverter(converterType) != null).findFirst() @@ -117,7 +117,7 @@ static class BeanFactoryAwarePropertyValueConverterFactory implements PropertyVa @Override @SuppressWarnings("unchecked") - public > PropertyValueConverter getConverter( + public > @Nullable PropertyValueConverter getConverter( Class> converterType) { Assert.notNull(converterType, "ConverterType must not be null"); @@ -151,10 +151,9 @@ static class ConfiguredInstanceServingValueConverterFactory implements PropertyV this.converterRegistry = converterRegistry; } - @Nullable @Override @SuppressWarnings("unchecked") - public > PropertyValueConverter getConverter( + public > @Nullable PropertyValueConverter getConverter( PersistentProperty property) { return (PropertyValueConverter) converterRegistry.getConverter(property.getOwner().getType(), @@ -162,7 +161,7 @@ public > PropertyValueConverter> PropertyValueConverter getConverter( + public > @Nullable PropertyValueConverter getConverter( Class> converterType) { return null; @@ -189,10 +188,9 @@ static class CachingPropertyValueConverterFactory implements PropertyValueConver this.delegate = delegate; } - @Nullable @Override @SuppressWarnings({ "rawtypes", "unchecked" }) - public > PropertyValueConverter getConverter( + public > @Nullable PropertyValueConverter getConverter( PersistentProperty property) { Optional>> converter = cache.get(property); @@ -203,7 +201,7 @@ public > PropertyValueConverter> PropertyValueConverter getConverter( + public > @Nullable PropertyValueConverter getConverter( Class> converterType) { Optional>> converter = cache.get(converterType); @@ -227,9 +225,9 @@ static class Cache { return typeCache.get(type); } - @Nullable @Contract("_, null -> null;_, !null -> !null") - > PropertyValueConverter cache(PersistentProperty property, + > @Nullable PropertyValueConverter cache( + PersistentProperty property, @Nullable PropertyValueConverter converter) { perPropertyCache.putIfAbsent(property, Optional.ofNullable(converter)); @@ -245,9 +243,8 @@ > PropertyValueConverter cach return converter; } - @Nullable @Contract("_, null -> null;_, !null -> !null") - > PropertyValueConverter cache(Class type, + > @Nullable PropertyValueConverter cache(Class type, @Nullable PropertyValueConverter converter) { typeCache.putIfAbsent(type, Optional.ofNullable(converter)); diff --git a/src/main/java/org/springframework/data/convert/PropertyValueConverterFactory.java b/src/main/java/org/springframework/data/convert/PropertyValueConverterFactory.java index e284ef8f2d..628f0c98d5 100644 --- a/src/main/java/org/springframework/data/convert/PropertyValueConverterFactory.java +++ b/src/main/java/org/springframework/data/convert/PropertyValueConverterFactory.java @@ -18,6 +18,8 @@ import java.util.Arrays; import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.BeanFactory; import org.springframework.data.convert.PropertyValueConverterFactories.BeanFactoryAwarePropertyValueConverterFactory; import org.springframework.data.convert.PropertyValueConverterFactories.CachingPropertyValueConverterFactory; @@ -25,7 +27,6 @@ import org.springframework.data.convert.PropertyValueConverterFactories.ConfiguredInstanceServingValueConverterFactory; import org.springframework.data.convert.PropertyValueConverterFactories.SimplePropertyConverterFactory; import org.springframework.data.mapping.PersistentProperty; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -50,8 +51,7 @@ public interface PropertyValueConverterFactory { * @return can be {@literal null}. */ @SuppressWarnings("unchecked") - @Nullable - default > PropertyValueConverter getConverter( + default > @Nullable PropertyValueConverter getConverter( PersistentProperty property) { AnnotatedPropertyValueConverterAccessor accessor = new AnnotatedPropertyValueConverterAccessor(property); @@ -72,8 +72,7 @@ default > PropertyValueConverter value conversion context to use. * @return can be {@literal null}. */ - @Nullable - > PropertyValueConverter getConverter( + > @Nullable PropertyValueConverter getConverter( Class> converterType); /** diff --git a/src/main/java/org/springframework/data/convert/SimplePropertyValueConversions.java b/src/main/java/org/springframework/data/convert/SimplePropertyValueConversions.java index 71e55f43bd..e69c354059 100644 --- a/src/main/java/org/springframework/data/convert/SimplePropertyValueConversions.java +++ b/src/main/java/org/springframework/data/convert/SimplePropertyValueConversions.java @@ -21,10 +21,11 @@ import java.util.Map; import java.util.Optional; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.InitializingBean; import org.springframework.data.convert.PropertyValueConverterFactories.ChainedPropertyValueConverterFactory; import org.springframework.data.mapping.PersistentProperty; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -60,12 +61,12 @@ enum NoOpConverter implements PropertyValueConverter { INSTANCE; @Override - public Object read(Object value, ValueConversionContext context) { + public @Nullable Object read(Object value, ValueConversionContext context) { return null; } @Override - public Object write(Object value, ValueConversionContext context) { + public @Nullable Object write(Object value, ValueConversionContext context) { return null; } } @@ -88,8 +89,7 @@ public void setConverterFactory(@Nullable PropertyValueConverterFactory converte * @return the configured {@link PropertyValueConverterFactory}; can be {@literal null}. * @see PropertyValueConverterFactory */ - @Nullable - public PropertyValueConverterFactory getConverterFactory() { + public @Nullable PropertyValueConverterFactory getConverterFactory() { return converterFactory; } @@ -122,8 +122,7 @@ public void setValueConverterRegistry(@Nullable ValueConverterRegistry valueC * @return the configured {@link ValueConverterRegistry}; can be {@literal null}. * @see ValueConverterRegistry */ - @Nullable - public ValueConverterRegistry getValueConverterRegistry() { + public @Nullable ValueConverterRegistry getValueConverterRegistry() { return valueConverterRegistry; } @@ -163,8 +162,7 @@ public , D extends ValueConversionContex } @SuppressWarnings("unchecked") - @Nullable - private , D extends ValueConversionContext

> PropertyValueConverter doGetConverter( + private , D extends ValueConversionContext

> @Nullable PropertyValueConverter doGetConverter( PersistentProperty property) { PropertyValueConverter converter = converterCache.get(property); diff --git a/src/main/java/org/springframework/data/convert/SimplePropertyValueConverterRegistry.java b/src/main/java/org/springframework/data/convert/SimplePropertyValueConverterRegistry.java index 855b09e1f8..924fb790ea 100644 --- a/src/main/java/org/springframework/data/convert/SimplePropertyValueConverterRegistry.java +++ b/src/main/java/org/springframework/data/convert/SimplePropertyValueConverterRegistry.java @@ -18,6 +18,8 @@ import java.util.LinkedHashMap; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.PersistentProperty; import org.springframework.util.ObjectUtils; @@ -68,7 +70,7 @@ public boolean containsConverterFor(Class type, String path) { @Override @SuppressWarnings("unchecked") - public PropertyValueConverter> getConverter(Class type, + public @Nullable PropertyValueConverter> getConverter(Class type, String path) { return (PropertyValueConverter>) converterRegistrationMap diff --git a/src/main/java/org/springframework/data/convert/SimpleTypeInformationMapper.java b/src/main/java/org/springframework/data/convert/SimpleTypeInformationMapper.java index 2132ba702e..cc2715cef1 100644 --- a/src/main/java/org/springframework/data/convert/SimpleTypeInformationMapper.java +++ b/src/main/java/org/springframework/data/convert/SimpleTypeInformationMapper.java @@ -19,10 +19,11 @@ import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.data.mapping.Alias; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; /** @@ -48,9 +49,8 @@ public class SimpleTypeInformationMapper implements TypeInformationMapper, BeanC * @return the type to be used for the given {@link String} representation or {@literal null} if nothing found or the * class cannot be loaded. */ - @Nullable @Override - public TypeInformation resolveTypeFrom(Alias alias) { + public @Nullable TypeInformation resolveTypeFrom(Alias alias) { String stringAlias = alias.mapTyped(String.class); diff --git a/src/main/java/org/springframework/data/convert/TypeInformationMapper.java b/src/main/java/org/springframework/data/convert/TypeInformationMapper.java index cdc4666403..8f00c4d27e 100644 --- a/src/main/java/org/springframework/data/convert/TypeInformationMapper.java +++ b/src/main/java/org/springframework/data/convert/TypeInformationMapper.java @@ -15,9 +15,10 @@ */ package org.springframework.data.convert; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.Alias; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; /** * Interface to abstract the mapping from a type alias to the actual type. diff --git a/src/main/java/org/springframework/data/convert/TypeMapper.java b/src/main/java/org/springframework/data/convert/TypeMapper.java index 9f4c66db1b..b8c2e228fe 100644 --- a/src/main/java/org/springframework/data/convert/TypeMapper.java +++ b/src/main/java/org/springframework/data/convert/TypeMapper.java @@ -15,8 +15,9 @@ */ package org.springframework.data.convert; +import org.jspecify.annotations.Nullable; + import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; /** * Interface to define strategies how to store type information in a store specific sink or source. diff --git a/src/main/java/org/springframework/data/convert/ValueConversionContext.java b/src/main/java/org/springframework/data/convert/ValueConversionContext.java index 1d51117469..a040c9aa0d 100644 --- a/src/main/java/org/springframework/data/convert/ValueConversionContext.java +++ b/src/main/java/org/springframework/data/convert/ValueConversionContext.java @@ -15,9 +15,10 @@ */ package org.springframework.data.convert; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; /** * The {@link ValueConversionContext} provides access to the store-specific {@link PersistentProperty} and allows to @@ -50,8 +51,7 @@ public interface ValueConversionContext

> { * @see PersistentProperty#getTypeInformation() * @see #write(Object, TypeInformation) */ - @Nullable - default Object write(@Nullable Object value) { + default @Nullable Object write(@Nullable Object value) { return write(value, getProperty().getTypeInformation()); } @@ -65,8 +65,7 @@ default Object write(@Nullable Object value) { * @see #write(Object, TypeInformation) * @see TypeInformation */ - @Nullable - default T write(@Nullable Object value, Class target) { + default @Nullable T write(@Nullable Object value, Class target) { return write(value, TypeInformation.of(target)); } @@ -79,8 +78,7 @@ default T write(@Nullable Object value, Class target) { * @throws IllegalStateException if value cannot be written as an instance of {@link TypeInformation type}. * @see TypeInformation */ - @Nullable - default T write(@Nullable Object value, TypeInformation target) { + default @Nullable T write(@Nullable Object value, TypeInformation target) { if (value == null || target.getType().isInstance(value)) { return target.getType().cast(value); @@ -100,8 +98,7 @@ default T write(@Nullable Object value, TypeInformation target) { * @see PersistentProperty#getTypeInformation() * @see #read(Object, TypeInformation) */ - @Nullable - default Object read(@Nullable Object value) { + default @Nullable Object read(@Nullable Object value) { return read(value, getProperty().getTypeInformation()); } @@ -115,8 +112,7 @@ default Object read(@Nullable Object value) { * @see #read(Object, TypeInformation) * @see TypeInformation */ - @Nullable - default T read(@Nullable Object value, Class target) { + default @Nullable T read(@Nullable Object value, Class target) { return read(value, TypeInformation.of(target)); } @@ -129,8 +125,7 @@ default T read(@Nullable Object value, Class target) { * @throws IllegalStateException if value cannot be read as an instance of {@link TypeInformation type}. * @see TypeInformation */ - @Nullable - default T read(@Nullable Object value, TypeInformation target) { + default @Nullable T read(@Nullable Object value, TypeInformation target) { if (value == null || target.getType().isInstance(value)) { return target.getType().cast(value); diff --git a/src/main/java/org/springframework/data/convert/ValueConverterRegistry.java b/src/main/java/org/springframework/data/convert/ValueConverterRegistry.java index 09822f6945..32cd73a391 100644 --- a/src/main/java/org/springframework/data/convert/ValueConverterRegistry.java +++ b/src/main/java/org/springframework/data/convert/ValueConverterRegistry.java @@ -15,8 +15,9 @@ */ package org.springframework.data.convert; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.PersistentProperty; -import org.springframework.lang.Nullable; /** * A registry of {@link PersistentProperty property-specific} {@link PropertyValueConverter value converters} @@ -48,8 +49,8 @@ void registerConverter(Class type, String path, * @param store-specific type. * @return {@literal null} if no converter present for the given type/path combination. */ - @Nullable - PropertyValueConverter> getConverter(Class type, String path); + @Nullable PropertyValueConverter> getConverter(Class type, + String path); /** * Check if a converter is registered for the given type, path combination. diff --git a/src/main/java/org/springframework/data/convert/package-info.java b/src/main/java/org/springframework/data/convert/package-info.java index 52f5d4b16e..04faa8fce7 100644 --- a/src/main/java/org/springframework/data/convert/package-info.java +++ b/src/main/java/org/springframework/data/convert/package-info.java @@ -3,5 +3,5 @@ * * @see org.springframework.data.convert.EntityConverter */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.convert; diff --git a/src/main/java/org/springframework/data/crossstore/ChangeSet.java b/src/main/java/org/springframework/data/crossstore/ChangeSet.java index dcd6a52d76..a8039bea33 100644 --- a/src/main/java/org/springframework/data/crossstore/ChangeSet.java +++ b/src/main/java/org/springframework/data/crossstore/ChangeSet.java @@ -17,8 +17,9 @@ import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.core.convert.ConversionService; -import org.springframework.lang.Nullable; /** * Interface representing the set of changes in an entity. @@ -28,8 +29,7 @@ */ public interface ChangeSet { - @Nullable - T get(String key, Class requiredClass, ConversionService cs); + @Nullable T get(String key, Class requiredClass, ConversionService cs); void set(String key, Object o); diff --git a/src/main/java/org/springframework/data/crossstore/HashMapChangeSet.java b/src/main/java/org/springframework/data/crossstore/HashMapChangeSet.java index 9eb6fafe7d..cec4e510bd 100644 --- a/src/main/java/org/springframework/data/crossstore/HashMapChangeSet.java +++ b/src/main/java/org/springframework/data/crossstore/HashMapChangeSet.java @@ -19,8 +19,9 @@ import java.util.HashMap; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.core.convert.ConversionService; -import org.springframework.lang.Nullable; /** * Simple ChangeSet implementation backed by a HashMap. @@ -56,14 +57,12 @@ public Map getValues() { } @Override - @Nullable - public Object removeProperty(String k) { + public @Nullable Object removeProperty(String k) { return this.values.remove(k); } @Override - @Nullable - public T get(String key, Class requiredClass, ConversionService conversionService) { + public @Nullable T get(String key, Class requiredClass, ConversionService conversionService) { Object value = values.get(key); diff --git a/src/main/java/org/springframework/data/crossstore/package-info.java b/src/main/java/org/springframework/data/crossstore/package-info.java index 824d8bb8fd..14f7048c09 100644 --- a/src/main/java/org/springframework/data/crossstore/package-info.java +++ b/src/main/java/org/springframework/data/crossstore/package-info.java @@ -1,5 +1,5 @@ /** * Support for cross-store persistence. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.crossstore; diff --git a/src/main/java/org/springframework/data/domain/Auditable.java b/src/main/java/org/springframework/data/domain/Auditable.java index d59823a15d..0175572835 100644 --- a/src/main/java/org/springframework/data/domain/Auditable.java +++ b/src/main/java/org/springframework/data/domain/Auditable.java @@ -18,7 +18,7 @@ import java.time.temporal.TemporalAccessor; import java.util.Optional; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** * Interface for auditable entities. Allows storing and retrieving creation and modification information. The changing diff --git a/src/main/java/org/springframework/data/domain/ExampleMatcher.java b/src/main/java/org/springframework/data/domain/ExampleMatcher.java index c65b191ab3..e59698a719 100644 --- a/src/main/java/org/springframework/data/domain/ExampleMatcher.java +++ b/src/main/java/org/springframework/data/domain/ExampleMatcher.java @@ -22,9 +22,10 @@ import java.util.Set; import java.util.function.Function; +import org.jspecify.annotations.Nullable; + import org.springframework.lang.CheckReturnValue; import org.springframework.lang.Contract; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -608,7 +609,7 @@ public Optional apply(Optional source) { * @author Mark Paluch * @since 1.12 */ - class PropertySpecifier { + static class PropertySpecifier { private final String path; private final @Nullable StringMatcher stringMatcher; @@ -692,16 +693,14 @@ public String getPath() { * * @return can be {@literal null}. */ - @Nullable - public StringMatcher getStringMatcher() { + public @Nullable StringMatcher getStringMatcher() { return stringMatcher; } /** * @return {@literal null} if not set. */ - @Nullable - public Boolean getIgnoreCase() { + public @Nullable Boolean getIgnoreCase() { return ignoreCase; } @@ -711,7 +710,7 @@ public Boolean getIgnoreCase() { * @return never {@literal null}. */ public PropertyValueTransformer getPropertyValueTransformer() { - return valueTransformer == null ? NoOpPropertyValueTransformer.INSTANCE : valueTransformer; + return valueTransformer; } /** @@ -772,7 +771,7 @@ class PropertySpecifiers { private final Map propertySpecifiers; PropertySpecifiers() { - this. propertySpecifiers = new LinkedHashMap<>(); + this.propertySpecifiers = new LinkedHashMap<>(); } PropertySpecifiers(PropertySpecifiers propertySpecifiers) { @@ -789,10 +788,21 @@ public boolean hasSpecifierForPath(String path) { return propertySpecifiers.containsKey(path); } - public PropertySpecifier getForPath(String path) { + public @Nullable PropertySpecifier getForPath(String path) { return propertySpecifiers.get(path); } + public PropertySpecifier getRequiredForPath(String path) { + + PropertySpecifier specifier = getForPath(path); + + if (specifier == null) { + throw new IllegalArgumentException("No PropertySpecifier found for path '%s'".formatted(path)); + } + + return specifier; + } + public boolean hasValues() { return !propertySpecifiers.isEmpty(); } diff --git a/src/main/java/org/springframework/data/domain/KeysetScrollPosition.java b/src/main/java/org/springframework/data/domain/KeysetScrollPosition.java index 3e8b14c7dc..aaecebc51b 100644 --- a/src/main/java/org/springframework/data/domain/KeysetScrollPosition.java +++ b/src/main/java/org/springframework/data/domain/KeysetScrollPosition.java @@ -20,7 +20,8 @@ import java.util.Map; import java.util.Objects; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; diff --git a/src/main/java/org/springframework/data/domain/Limit.java b/src/main/java/org/springframework/data/domain/Limit.java index 0d56e33916..6fb94b8ae5 100644 --- a/src/main/java/org/springframework/data/domain/Limit.java +++ b/src/main/java/org/springframework/data/domain/Limit.java @@ -15,9 +15,10 @@ */ package org.springframework.data.domain; +import org.jspecify.annotations.Nullable; + import org.springframework.data.domain.Limit.Limited; import org.springframework.data.domain.Limit.Unlimited; -import org.springframework.lang.Nullable; /** * {@link Limit} represents the maximum value up to which an operation should continue processing. It may be used for diff --git a/src/main/java/org/springframework/data/domain/OffsetScrollPosition.java b/src/main/java/org/springframework/data/domain/OffsetScrollPosition.java index 4c58bbc5ab..f0d68e8499 100644 --- a/src/main/java/org/springframework/data/domain/OffsetScrollPosition.java +++ b/src/main/java/org/springframework/data/domain/OffsetScrollPosition.java @@ -18,7 +18,8 @@ import java.util.Objects; import java.util.function.IntFunction; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; /** diff --git a/src/main/java/org/springframework/data/domain/PageImpl.java b/src/main/java/org/springframework/data/domain/PageImpl.java index 06c077ae86..ef8323a555 100644 --- a/src/main/java/org/springframework/data/domain/PageImpl.java +++ b/src/main/java/org/springframework/data/domain/PageImpl.java @@ -19,7 +19,8 @@ import java.util.List; import java.util.function.Function; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; + import org.springframework.util.CollectionUtils; /** diff --git a/src/main/java/org/springframework/data/domain/PageRequest.java b/src/main/java/org/springframework/data/domain/PageRequest.java index b5e1263ea9..597f9f71d9 100644 --- a/src/main/java/org/springframework/data/domain/PageRequest.java +++ b/src/main/java/org/springframework/data/domain/PageRequest.java @@ -20,7 +20,6 @@ import org.springframework.data.domain.Sort.Direction; import org.springframework.lang.CheckReturnValue; import org.springframework.lang.Contract; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; diff --git a/src/main/java/org/springframework/data/domain/Pageable.java b/src/main/java/org/springframework/data/domain/Pageable.java index 9b77694b5c..6bb6e65b23 100644 --- a/src/main/java/org/springframework/data/domain/Pageable.java +++ b/src/main/java/org/springframework/data/domain/Pageable.java @@ -130,7 +130,7 @@ default Sort getSortOr(Sort sort) { * * @return the {@link Pageable} requesting the next {@link Page}. */ - @Contract("_ -> new") + @Contract("-> new") @CheckReturnValue Pageable next(); @@ -139,7 +139,7 @@ default Sort getSortOr(Sort sort) { * * @return the previous {@link Pageable} or the first {@link Pageable} if the current one already is the first one. */ - @Contract("_ -> new") + @Contract("-> new") @CheckReturnValue Pageable previousOrFirst(); @@ -148,7 +148,7 @@ default Sort getSortOr(Sort sort) { * * @return the {@link Pageable} requesting the first page. */ - @Contract("_ -> new") + @Contract("-> new") @CheckReturnValue Pageable first(); diff --git a/src/main/java/org/springframework/data/domain/Persistable.java b/src/main/java/org/springframework/data/domain/Persistable.java index 641b8ccdb9..f88969f46c 100644 --- a/src/main/java/org/springframework/data/domain/Persistable.java +++ b/src/main/java/org/springframework/data/domain/Persistable.java @@ -15,7 +15,7 @@ */ package org.springframework.data.domain; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** * Simple interface for entities. diff --git a/src/main/java/org/springframework/data/domain/Range.java b/src/main/java/org/springframework/data/domain/Range.java index 6634115af8..fb3aa165dc 100644 --- a/src/main/java/org/springframework/data/domain/Range.java +++ b/src/main/java/org/springframework/data/domain/Range.java @@ -19,7 +19,8 @@ import java.util.Optional; import java.util.function.Function; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; diff --git a/src/main/java/org/springframework/data/domain/SliceImpl.java b/src/main/java/org/springframework/data/domain/SliceImpl.java index a21c30382b..1ec2fc08e1 100644 --- a/src/main/java/org/springframework/data/domain/SliceImpl.java +++ b/src/main/java/org/springframework/data/domain/SliceImpl.java @@ -19,7 +19,7 @@ import java.util.List; import java.util.function.Function; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** * Default implementation of {@link Slice}. diff --git a/src/main/java/org/springframework/data/domain/Sort.java b/src/main/java/org/springframework/data/domain/Sort.java index d414812856..f3d39640dd 100644 --- a/src/main/java/org/springframework/data/domain/Sort.java +++ b/src/main/java/org/springframework/data/domain/Sort.java @@ -27,12 +27,13 @@ import java.util.function.Function; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; + import org.springframework.data.util.MethodInvocationRecorder; import org.springframework.data.util.MethodInvocationRecorder.Recorded; import org.springframework.data.util.Streamable; import org.springframework.lang.CheckReturnValue; import org.springframework.lang.Contract; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; @@ -251,8 +252,7 @@ protected List doReverse() { * @param property name of the property that should be sorted. * @return the sort {@link Order} or {@literal null} if the property is not sorted by. */ - @Nullable - public Order getOrderFor(String property) { + public @Nullable Order getOrderFor(String property) { for (Order order : this) { if (order.getProperty().equals(property)) { diff --git a/src/main/java/org/springframework/data/domain/TypedExample.java b/src/main/java/org/springframework/data/domain/TypedExample.java index d908a5037f..d558a0f79e 100644 --- a/src/main/java/org/springframework/data/domain/TypedExample.java +++ b/src/main/java/org/springframework/data/domain/TypedExample.java @@ -15,7 +15,8 @@ */ package org.springframework.data.domain; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; diff --git a/src/main/java/org/springframework/data/domain/TypedExampleMatcher.java b/src/main/java/org/springframework/data/domain/TypedExampleMatcher.java index 26eafec19b..0d0cd95e23 100644 --- a/src/main/java/org/springframework/data/domain/TypedExampleMatcher.java +++ b/src/main/java/org/springframework/data/domain/TypedExampleMatcher.java @@ -20,7 +20,8 @@ import java.util.LinkedHashSet; import java.util.Set; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -188,13 +189,12 @@ TypedExampleMatcher withMode(MatchMode mode) { private PropertySpecifier getOrCreatePropertySpecifier(String propertyPath, PropertySpecifiers propertySpecifiers) { if (propertySpecifiers.hasSpecifierForPath(propertyPath)) { - return propertySpecifiers.getForPath(propertyPath); + return propertySpecifiers.getRequiredForPath(propertyPath); } return new PropertySpecifier(propertyPath); } - @Override public boolean equals(@Nullable Object o) { diff --git a/src/main/java/org/springframework/data/domain/Unpaged.java b/src/main/java/org/springframework/data/domain/Unpaged.java index 103375d1ab..c6a838f2e8 100644 --- a/src/main/java/org/springframework/data/domain/Unpaged.java +++ b/src/main/java/org/springframework/data/domain/Unpaged.java @@ -15,7 +15,7 @@ */ package org.springframework.data.domain; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** * {@link Pageable} implementation to represent the absence of pagination information. diff --git a/src/main/java/org/springframework/data/domain/WindowImpl.java b/src/main/java/org/springframework/data/domain/WindowImpl.java index 1dc3dfb5d7..9b992ba721 100644 --- a/src/main/java/org/springframework/data/domain/WindowImpl.java +++ b/src/main/java/org/springframework/data/domain/WindowImpl.java @@ -21,9 +21,8 @@ import java.util.function.IntFunction; import java.util.stream.Collectors; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.Nullable; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; diff --git a/src/main/java/org/springframework/data/domain/jaxb/OrderAdapter.java b/src/main/java/org/springframework/data/domain/jaxb/OrderAdapter.java index 8d639a2a0b..204d445eff 100644 --- a/src/main/java/org/springframework/data/domain/jaxb/OrderAdapter.java +++ b/src/main/java/org/springframework/data/domain/jaxb/OrderAdapter.java @@ -17,11 +17,12 @@ import jakarta.xml.bind.annotation.adapters.XmlAdapter; +import org.jspecify.annotations.Nullable; + import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Order; import org.springframework.data.domain.jaxb.SpringDataJaxb.OrderDto; import org.springframework.lang.Contract; -import org.springframework.lang.Nullable; /** * XmlAdapter to convert {@link Order} instances into {@link OrderDto}s and vice versa. @@ -32,9 +33,8 @@ public class OrderAdapter extends XmlAdapter { public static final OrderAdapter INSTANCE = new OrderAdapter(); - @Nullable @Override - public OrderDto marshal(@Nullable Order order) { + public @Nullable OrderDto marshal(@Nullable Order order) { if (order == null) { return null; @@ -46,10 +46,9 @@ public OrderDto marshal(@Nullable Order order) { return dto; } - @Nullable @Contract("null -> null") @Override - public Order unmarshal(@Nullable OrderDto source) { + public @Nullable Order unmarshal(@Nullable OrderDto source) { if (source == null) { return null; diff --git a/src/main/java/org/springframework/data/domain/jaxb/PageAdapter.java b/src/main/java/org/springframework/data/domain/jaxb/PageAdapter.java index e74dc569b8..8983600075 100644 --- a/src/main/java/org/springframework/data/domain/jaxb/PageAdapter.java +++ b/src/main/java/org/springframework/data/domain/jaxb/PageAdapter.java @@ -20,11 +20,12 @@ import java.util.Collections; import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.data.domain.Page; import org.springframework.data.domain.jaxb.SpringDataJaxb.PageDto; import org.springframework.hateoas.Link; import org.springframework.lang.Contract; -import org.springframework.lang.Nullable; /** * {@link XmlAdapter} to convert {@link Page} instances into {@link PageDto} instances and vice versa. @@ -33,10 +34,9 @@ */ public class PageAdapter extends XmlAdapter> { - @Nullable @Contract("null -> null; !null -> !null") @Override - public PageDto marshal(@Nullable Page source) { + public @Nullable PageDto marshal(@Nullable Page source) { if (source == null) { return null; @@ -49,10 +49,9 @@ public PageDto marshal(@Nullable Page source) { return dto; } - @Nullable @Contract("_ -> null") @Override - public Page unmarshal(@Nullable PageDto v) { + public @Nullable Page unmarshal(@Nullable PageDto v) { return null; } diff --git a/src/main/java/org/springframework/data/domain/jaxb/PageableAdapter.java b/src/main/java/org/springframework/data/domain/jaxb/PageableAdapter.java index 1d20f5bf6c..79172dae90 100644 --- a/src/main/java/org/springframework/data/domain/jaxb/PageableAdapter.java +++ b/src/main/java/org/springframework/data/domain/jaxb/PageableAdapter.java @@ -19,12 +19,13 @@ import java.util.Collections; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.jaxb.SpringDataJaxb.PageRequestDto; import org.springframework.data.domain.jaxb.SpringDataJaxb.SortDto; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; /** * {@link XmlAdapter} to convert {@link Pageable} instances int a {@link PageRequestDto} and vice versa. @@ -34,9 +35,8 @@ */ class PageableAdapter extends XmlAdapter { - @Nullable @Override - public PageRequestDto marshal(@Nullable Pageable request) { + public @Nullable PageRequestDto marshal(@Nullable Pageable request) { if (request == null) { return null; diff --git a/src/main/java/org/springframework/data/domain/jaxb/SortAdapter.java b/src/main/java/org/springframework/data/domain/jaxb/SortAdapter.java index 10c121bd31..ef8b3a401a 100644 --- a/src/main/java/org/springframework/data/domain/jaxb/SortAdapter.java +++ b/src/main/java/org/springframework/data/domain/jaxb/SortAdapter.java @@ -17,11 +17,12 @@ import jakarta.xml.bind.annotation.adapters.XmlAdapter; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + import org.springframework.data.domain.Sort; import org.springframework.data.domain.jaxb.SpringDataJaxb.SortDto; import org.springframework.lang.Contract; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; /** * {@link XmlAdapter} to convert {@link Sort} instances into {@link SortDto} instances and vice versa. @@ -32,10 +33,9 @@ public class SortAdapter extends XmlAdapter { public static final SortAdapter INSTANCE = new SortAdapter(); - @Nullable @Contract("null -> null; !null -> !null") @Override - public SortDto marshal(@Nullable Sort source) { + public @Nullable SortDto marshal(@Nullable Sort source) { if (source == null) { return null; diff --git a/src/main/java/org/springframework/data/domain/jaxb/SpringDataJaxb.java b/src/main/java/org/springframework/data/domain/jaxb/SpringDataJaxb.java index 2d33e4d2c9..cefe047572 100644 --- a/src/main/java/org/springframework/data/domain/jaxb/SpringDataJaxb.java +++ b/src/main/java/org/springframework/data/domain/jaxb/SpringDataJaxb.java @@ -29,6 +29,8 @@ import java.util.Collections; import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -36,7 +38,6 @@ import org.springframework.data.domain.Sort.Direction; import org.springframework.data.domain.Sort.Order; import org.springframework.hateoas.RepresentationModel; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** diff --git a/src/main/java/org/springframework/data/domain/jaxb/package-info.java b/src/main/java/org/springframework/data/domain/jaxb/package-info.java index 5bbdd590d2..a373707b29 100644 --- a/src/main/java/org/springframework/data/domain/jaxb/package-info.java +++ b/src/main/java/org/springframework/data/domain/jaxb/package-info.java @@ -10,7 +10,7 @@ @XmlJavaTypeAdapter(value = org.springframework.data.domain.jaxb.PageableAdapter.class, type = Pageable.class), @XmlJavaTypeAdapter(value = org.springframework.data.domain.jaxb.SortAdapter.class, type = Sort.class), @XmlJavaTypeAdapter(value = org.springframework.data.domain.jaxb.PageAdapter.class, type = Page.class) }) -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.domain.jaxb; import jakarta.xml.bind.annotation.XmlNs; diff --git a/src/main/java/org/springframework/data/domain/package-info.java b/src/main/java/org/springframework/data/domain/package-info.java index 1dc24ce770..e6b89a375a 100644 --- a/src/main/java/org/springframework/data/domain/package-info.java +++ b/src/main/java/org/springframework/data/domain/package-info.java @@ -4,5 +4,5 @@ * * @see org.springframework.data.repository.Repository */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.domain; diff --git a/src/main/java/org/springframework/data/expression/DefaultValueEvaluationContext.java b/src/main/java/org/springframework/data/expression/DefaultValueEvaluationContext.java index e39175404a..bf743d6b99 100644 --- a/src/main/java/org/springframework/data/expression/DefaultValueEvaluationContext.java +++ b/src/main/java/org/springframework/data/expression/DefaultValueEvaluationContext.java @@ -17,7 +17,6 @@ import org.springframework.core.env.Environment; import org.springframework.expression.EvaluationContext; -import org.springframework.lang.Nullable; /** * Default {@link ValueEvaluationContext}. @@ -25,7 +24,7 @@ * @author Mark Paluch * @since 3.3 */ -record DefaultValueEvaluationContext(@Nullable Environment environment, +record DefaultValueEvaluationContext(Environment environment, EvaluationContext evaluationContext) implements ValueEvaluationContext { @Override diff --git a/src/main/java/org/springframework/data/expression/ExpressionExpression.java b/src/main/java/org/springframework/data/expression/ExpressionExpression.java index f46dc496bc..a22fc90a2e 100644 --- a/src/main/java/org/springframework/data/expression/ExpressionExpression.java +++ b/src/main/java/org/springframework/data/expression/ExpressionExpression.java @@ -15,6 +15,8 @@ */ package org.springframework.data.expression; +import org.jspecify.annotations.Nullable; + import org.springframework.data.spel.ExpressionDependencies; import org.springframework.expression.EvaluationContext; import org.springframework.expression.Expression; @@ -44,14 +46,14 @@ public boolean isLiteral() { } @Override - public Object evaluate(ValueEvaluationContext context) { + public @Nullable Object evaluate(ValueEvaluationContext context) { EvaluationContext evaluationContext = context.getEvaluationContext(); return evaluationContext != null ? expression.getValue(evaluationContext) : expression.getValue(); } @Override - public Class getValueType(ValueEvaluationContext context) { + public @Nullable Class getValueType(ValueEvaluationContext context) { EvaluationContext evaluationContext = context.getEvaluationContext(); return evaluationContext != null ? expression.getValueType(evaluationContext) : expression.getValueType(); diff --git a/src/main/java/org/springframework/data/expression/PlaceholderExpression.java b/src/main/java/org/springframework/data/expression/PlaceholderExpression.java index f1123b6e9e..666a05e672 100644 --- a/src/main/java/org/springframework/data/expression/PlaceholderExpression.java +++ b/src/main/java/org/springframework/data/expression/PlaceholderExpression.java @@ -38,6 +38,7 @@ public boolean isLiteral() { } @Override + @SuppressWarnings("NullAway") public String evaluate(ValueEvaluationContext context) { Environment environment = context.getEnvironment(); diff --git a/src/main/java/org/springframework/data/expression/ReactiveValueEvaluationContextProvider.java b/src/main/java/org/springframework/data/expression/ReactiveValueEvaluationContextProvider.java index d2f6a4408e..f35f4888d1 100644 --- a/src/main/java/org/springframework/data/expression/ReactiveValueEvaluationContextProvider.java +++ b/src/main/java/org/springframework/data/expression/ReactiveValueEvaluationContextProvider.java @@ -17,8 +17,9 @@ import reactor.core.publisher.Mono; +import org.jspecify.annotations.Nullable; + import org.springframework.data.spel.ExpressionDependencies; -import org.springframework.lang.Nullable; /** * Reactive extension to {@link ValueEvaluationContext} for obtaining a {@link ValueEvaluationContext} that participates diff --git a/src/main/java/org/springframework/data/expression/ValueEvaluationContext.java b/src/main/java/org/springframework/data/expression/ValueEvaluationContext.java index 3fc2568582..feb26f14c0 100644 --- a/src/main/java/org/springframework/data/expression/ValueEvaluationContext.java +++ b/src/main/java/org/springframework/data/expression/ValueEvaluationContext.java @@ -17,7 +17,6 @@ import org.springframework.core.env.Environment; import org.springframework.expression.EvaluationContext; -import org.springframework.lang.Nullable; /** * Expressions are executed in an evaluation context. It is in this context that references are resolved when @@ -36,24 +35,22 @@ public interface ValueEvaluationContext { * @param evaluationContext * @return a new {@link ValueEvaluationContext} for the given environment and evaluation context. */ - static ValueEvaluationContext of(@Nullable Environment environment, EvaluationContext evaluationContext) { + static ValueEvaluationContext of(Environment environment, EvaluationContext evaluationContext) { return new DefaultValueEvaluationContext(environment, evaluationContext); } /** * Returns the {@link Environment} if provided. * - * @return the {@link Environment} or {@literal null}. + * @return the {@link Environment}. */ - @Nullable Environment getEnvironment(); /** * Returns the {@link EvaluationContext} if provided. * - * @return the {@link EvaluationContext} or {@literal null} if not set. + * @return the {@link EvaluationContext}. */ - @Nullable EvaluationContext getEvaluationContext(); /** @@ -62,7 +59,10 @@ static ValueEvaluationContext of(@Nullable Environment environment, EvaluationCo * * @return the {@link EvaluationContext}. * @since 3.4 + * @deprecated since 4.0, EvaluationContext is always provided. */ + @Deprecated + @SuppressWarnings("ConstantValue") default EvaluationContext getRequiredEvaluationContext() { EvaluationContext evaluationContext = getEvaluationContext(); diff --git a/src/main/java/org/springframework/data/expression/ValueEvaluationContextProvider.java b/src/main/java/org/springframework/data/expression/ValueEvaluationContextProvider.java index 4d380bbe09..f6b7600fa1 100644 --- a/src/main/java/org/springframework/data/expression/ValueEvaluationContextProvider.java +++ b/src/main/java/org/springframework/data/expression/ValueEvaluationContextProvider.java @@ -15,9 +15,10 @@ */ package org.springframework.data.expression; +import org.jspecify.annotations.Nullable; + import org.springframework.data.spel.ExpressionDependencies; import org.springframework.expression.EvaluationContext; -import org.springframework.lang.Nullable; /** * SPI to provide to access a centrally defined potentially shared {@link ValueEvaluationContext}. diff --git a/src/main/java/org/springframework/data/expression/ValueExpression.java b/src/main/java/org/springframework/data/expression/ValueExpression.java index d40d8b17cb..c490e8a3ad 100644 --- a/src/main/java/org/springframework/data/expression/ValueExpression.java +++ b/src/main/java/org/springframework/data/expression/ValueExpression.java @@ -15,9 +15,10 @@ */ package org.springframework.data.expression; +import org.jspecify.annotations.Nullable; + import org.springframework.data.spel.ExpressionDependencies; import org.springframework.expression.EvaluationException; -import org.springframework.lang.Nullable; /** * An expression capable of evaluating itself against context objects. Encapsulates the details of a previously parsed diff --git a/src/main/java/org/springframework/data/expression/package-info.java b/src/main/java/org/springframework/data/expression/package-info.java index 35ebb9ed7b..761a9067af 100644 --- a/src/main/java/org/springframework/data/expression/package-info.java +++ b/src/main/java/org/springframework/data/expression/package-info.java @@ -1,5 +1,5 @@ /** * Value Expression implementation. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.expression; diff --git a/src/main/java/org/springframework/data/geo/Box.java b/src/main/java/org/springframework/data/geo/Box.java index d1b3baf0d7..d2f36a8cc1 100644 --- a/src/main/java/org/springframework/data/geo/Box.java +++ b/src/main/java/org/springframework/data/geo/Box.java @@ -17,7 +17,8 @@ import java.io.Serial; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; diff --git a/src/main/java/org/springframework/data/geo/Circle.java b/src/main/java/org/springframework/data/geo/Circle.java index cc15cf45f0..c29449b61f 100644 --- a/src/main/java/org/springframework/data/geo/Circle.java +++ b/src/main/java/org/springframework/data/geo/Circle.java @@ -17,8 +17,9 @@ import java.io.Serial; +import org.jspecify.annotations.Nullable; + import org.springframework.data.annotation.PersistenceCreator; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; diff --git a/src/main/java/org/springframework/data/geo/Distance.java b/src/main/java/org/springframework/data/geo/Distance.java index 869cf8ef7c..612f905219 100644 --- a/src/main/java/org/springframework/data/geo/Distance.java +++ b/src/main/java/org/springframework/data/geo/Distance.java @@ -18,11 +18,12 @@ import java.io.Serial; import java.io.Serializable; +import org.jspecify.annotations.Nullable; + import org.springframework.data.domain.Range; import org.springframework.data.domain.Range.Bound; import org.springframework.lang.CheckReturnValue; import org.springframework.lang.Contract; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; diff --git a/src/main/java/org/springframework/data/geo/GeoPage.java b/src/main/java/org/springframework/data/geo/GeoPage.java index 328d7f1044..28d183ac42 100644 --- a/src/main/java/org/springframework/data/geo/GeoPage.java +++ b/src/main/java/org/springframework/data/geo/GeoPage.java @@ -17,10 +17,11 @@ import java.io.Serial; +import org.jspecify.annotations.Nullable; + import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; -import org.springframework.lang.Nullable; import org.springframework.util.ObjectUtils; /** diff --git a/src/main/java/org/springframework/data/geo/GeoResult.java b/src/main/java/org/springframework/data/geo/GeoResult.java index dc1718ad3c..ae9fa180ac 100644 --- a/src/main/java/org/springframework/data/geo/GeoResult.java +++ b/src/main/java/org/springframework/data/geo/GeoResult.java @@ -18,7 +18,8 @@ import java.io.Serial; import java.io.Serializable; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; diff --git a/src/main/java/org/springframework/data/geo/GeoResults.java b/src/main/java/org/springframework/data/geo/GeoResults.java index a271c46b33..a22b75ec75 100644 --- a/src/main/java/org/springframework/data/geo/GeoResults.java +++ b/src/main/java/org/springframework/data/geo/GeoResults.java @@ -22,8 +22,9 @@ import java.util.Iterator; import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.data.annotation.PersistenceCreator; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; diff --git a/src/main/java/org/springframework/data/geo/Point.java b/src/main/java/org/springframework/data/geo/Point.java index bc474e0adc..e66d0d99b2 100644 --- a/src/main/java/org/springframework/data/geo/Point.java +++ b/src/main/java/org/springframework/data/geo/Point.java @@ -19,8 +19,9 @@ import java.io.Serializable; import java.util.Locale; +import org.jspecify.annotations.Nullable; + import org.springframework.data.annotation.PersistenceCreator; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; diff --git a/src/main/java/org/springframework/data/geo/Polygon.java b/src/main/java/org/springframework/data/geo/Polygon.java index 289bfb1e1b..3491e91b36 100644 --- a/src/main/java/org/springframework/data/geo/Polygon.java +++ b/src/main/java/org/springframework/data/geo/Polygon.java @@ -23,8 +23,9 @@ import java.util.Iterator; import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.data.annotation.PersistenceCreator; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; diff --git a/src/main/java/org/springframework/data/geo/format/DistanceFormatter.java b/src/main/java/org/springframework/data/geo/format/DistanceFormatter.java index 753d38e4c7..3ce2cf4077 100644 --- a/src/main/java/org/springframework/data/geo/format/DistanceFormatter.java +++ b/src/main/java/org/springframework/data/geo/format/DistanceFormatter.java @@ -22,13 +22,14 @@ import java.util.Map; import java.util.Map.Entry; +import org.jspecify.annotations.Nullable; + import org.springframework.core.convert.converter.Converter; import org.springframework.data.geo.Distance; import org.springframework.data.geo.Metric; import org.springframework.data.geo.Metrics; import org.springframework.format.Formatter; import org.springframework.lang.Contract; -import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; /** @@ -59,9 +60,8 @@ public enum DistanceFormatter implements Converter, Formatter< } @Contract("null -> null; !null -> !null") - @Nullable @Override - public final Distance convert(@Nullable String source) { + public final @Nullable Distance convert(@Nullable String source) { return source == null ? null : doConvert(source.trim().toLowerCase(Locale.US)); } diff --git a/src/main/java/org/springframework/data/geo/format/PointFormatter.java b/src/main/java/org/springframework/data/geo/format/PointFormatter.java index 95f5c70ae9..2ebf1341cd 100644 --- a/src/main/java/org/springframework/data/geo/format/PointFormatter.java +++ b/src/main/java/org/springframework/data/geo/format/PointFormatter.java @@ -18,12 +18,13 @@ import java.text.ParseException; import java.util.Locale; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.GenericConverter.ConvertiblePair; import org.springframework.data.geo.Point; import org.springframework.format.Formatter; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; /** * Converter to parse two comma-separated doubles into a {@link Point}. diff --git a/src/main/java/org/springframework/data/geo/format/package-info.java b/src/main/java/org/springframework/data/geo/format/package-info.java index 3b0a6ba70f..ff80d60bb1 100644 --- a/src/main/java/org/springframework/data/geo/format/package-info.java +++ b/src/main/java/org/springframework/data/geo/format/package-info.java @@ -4,5 +4,5 @@ * @author Oliver Gierke * @since 1.8 */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.geo.format; diff --git a/src/main/java/org/springframework/data/geo/package-info.java b/src/main/java/org/springframework/data/geo/package-info.java index f2b340c266..b8bce43b4c 100644 --- a/src/main/java/org/springframework/data/geo/package-info.java +++ b/src/main/java/org/springframework/data/geo/package-info.java @@ -5,5 +5,5 @@ * @author Oliver Gierke * @since 1.8 */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.geo; diff --git a/src/main/java/org/springframework/data/history/Revision.java b/src/main/java/org/springframework/data/history/Revision.java index 87aaa676f6..325cf4008c 100755 --- a/src/main/java/org/springframework/data/history/Revision.java +++ b/src/main/java/org/springframework/data/history/Revision.java @@ -20,7 +20,8 @@ import java.time.Instant; import java.util.Optional; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; + import org.springframework.util.ObjectUtils; /** diff --git a/src/main/java/org/springframework/data/history/package-info.java b/src/main/java/org/springframework/data/history/package-info.java index 03ba13327d..2170dc7d23 100644 --- a/src/main/java/org/springframework/data/history/package-info.java +++ b/src/main/java/org/springframework/data/history/package-info.java @@ -1,5 +1,5 @@ /** * Basic interfaces and value objects for histography API. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.history; diff --git a/src/main/java/org/springframework/data/mapping/AccessOptions.java b/src/main/java/org/springframework/data/mapping/AccessOptions.java index 18846958b8..cf13a28e22 100644 --- a/src/main/java/org/springframework/data/mapping/AccessOptions.java +++ b/src/main/java/org/springframework/data/mapping/AccessOptions.java @@ -22,8 +22,9 @@ import java.util.Set; import java.util.function.Function; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.AccessOptions.SetOptions.SetNulls; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -34,6 +35,7 @@ * @author Oliver Drotbohm * @since 2.3 */ +@SuppressWarnings("NullAway") public class AccessOptions { /** @@ -64,10 +66,11 @@ public static class GetOptions { private static final GetOptions DEFAULT = new GetOptions(new HashMap<>(), GetNulls.REJECT); - private final Map, Function> handlers; + private final Map, Function<@Nullable Object, @Nullable Object>> handlers; private final GetNulls nullValues; - public GetOptions(Map, Function> handlers, GetNulls nullValues) { + public GetOptions(Map, Function<@Nullable Object, @Nullable Object>> handlers, + GetNulls nullValues) { this.handlers = handlers; this.nullValues = nullValues; @@ -110,12 +113,13 @@ public SetOptions.SetNulls toNullHandling() { * @param handler must not be {@literal null}. * @return */ - public GetOptions registerHandler(PersistentProperty property, Function handler) { + public GetOptions registerHandler(PersistentProperty property, + Function<@Nullable Object, @Nullable Object> handler) { Assert.notNull(property, "Property must not be null"); Assert.notNull(handler, "Handler must not be null"); - Map, Function> newHandlers = new HashMap<>(handlers); + Map, Function<@Nullable Object, @Nullable Object>> newHandlers = new HashMap<>(handlers); newHandlers.put(property, handler); return new GetOptions(newHandlers, nullValues); @@ -130,7 +134,7 @@ public GetOptions registerHandler(PersistentProperty property, Function property, - Function, Object> handler) { + Function, @Nullable Object> handler) { return registerHandler(property, Collection.class, (Function) handler); } @@ -142,7 +146,8 @@ public GetOptions registerCollectionHandler(PersistentProperty property, * @return */ @SuppressWarnings("unchecked") - public GetOptions registerListHandler(PersistentProperty property, Function, Object> handler) { + public GetOptions registerListHandler(PersistentProperty property, + Function, @Nullable Object> handler) { return registerHandler(property, List.class, (Function) handler); } @@ -154,7 +159,8 @@ public GetOptions registerListHandler(PersistentProperty property, Function property, Function, Object> handler) { + public GetOptions registerSetHandler(PersistentProperty property, + Function, @Nullable Object> handler) { return registerHandler(property, Set.class, (Function) handler); } @@ -166,7 +172,8 @@ public GetOptions registerSetHandler(PersistentProperty property, Function property, Function, Object> handler) { + public GetOptions registerMapHandler(PersistentProperty property, + Function, @Nullable Object> handler) { return registerHandler(property, Map.class, (Function) handler); } @@ -201,7 +208,7 @@ public GetOptions registerHandler(PersistentProperty property, Class t @Nullable Object postProcess(PersistentProperty property, @Nullable Object value) { - Function handler = handlers.get(property); + Function<@Nullable Object, @Nullable Object> handler = handlers.get(property); return handler == null ? value : handler.apply(value); } diff --git a/src/main/java/org/springframework/data/mapping/Alias.java b/src/main/java/org/springframework/data/mapping/Alias.java index 81afd53d15..b4db1c8691 100644 --- a/src/main/java/org/springframework/data/mapping/Alias.java +++ b/src/main/java/org/springframework/data/mapping/Alias.java @@ -18,7 +18,8 @@ import java.util.NoSuchElementException; import java.util.Objects; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; /** @@ -87,6 +88,7 @@ public static Alias empty() { * @param other must not be {@literal null}. * @return {@literal true} if this value is present but different from the {@code other} value. */ + @SuppressWarnings("NullAway") public boolean isPresentButDifferent(Alias other) { Assert.notNull(other, "Other alias must not be null"); @@ -100,8 +102,9 @@ public boolean isPresentButDifferent(Alias other) { * @param that the other value, may be {@literal null}. * @return {@literal true} if this alias has a value and it equals to {@code that}. */ + @SuppressWarnings("NullAway") public boolean hasValue(Object that) { - return value != null && value.equals(that); + return isPresent() && value.equals(that); } /** @@ -110,6 +113,7 @@ public boolean hasValue(Object that) { * @param other the other {@link Alias} * @return {@literal true} if there's an alias value present and its equal to the one in the given {@link Alias}. */ + @SuppressWarnings("NullAway") public boolean hasSamePresentValueAs(Alias other) { return isPresent() && value.equals(other.value); } @@ -185,6 +189,7 @@ public int hashCode() { } @Override + @SuppressWarnings("NullAway") public String toString() { return isPresent() ? value.toString() : "NONE"; } diff --git a/src/main/java/org/springframework/data/mapping/Association.java b/src/main/java/org/springframework/data/mapping/Association.java index 9e6d979ad9..c0878e30e2 100644 --- a/src/main/java/org/springframework/data/mapping/Association.java +++ b/src/main/java/org/springframework/data/mapping/Association.java @@ -15,7 +15,7 @@ */ package org.springframework.data.mapping; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** * Value object to capture {@link Association}s. @@ -44,8 +44,7 @@ public P getInverse() { return inverse; } - @Nullable - public P getObverse() { + public @Nullable P getObverse() { return obverse; } } diff --git a/src/main/java/org/springframework/data/mapping/IdentifierAccessor.java b/src/main/java/org/springframework/data/mapping/IdentifierAccessor.java index f17dd1c2b2..506d13457a 100644 --- a/src/main/java/org/springframework/data/mapping/IdentifierAccessor.java +++ b/src/main/java/org/springframework/data/mapping/IdentifierAccessor.java @@ -15,7 +15,7 @@ */ package org.springframework.data.mapping; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** * Interface for a component allowing the access of identifier values. diff --git a/src/main/java/org/springframework/data/mapping/MappingException.java b/src/main/java/org/springframework/data/mapping/MappingException.java index 5fba4d4a6e..ff777769b4 100644 --- a/src/main/java/org/springframework/data/mapping/MappingException.java +++ b/src/main/java/org/springframework/data/mapping/MappingException.java @@ -17,7 +17,7 @@ import java.io.Serial; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** * @author Jon Brisbin diff --git a/src/main/java/org/springframework/data/mapping/Parameter.java b/src/main/java/org/springframework/data/mapping/Parameter.java index 740f40a3ad..16407b4cfa 100644 --- a/src/main/java/org/springframework/data/mapping/Parameter.java +++ b/src/main/java/org/springframework/data/mapping/Parameter.java @@ -18,11 +18,12 @@ import java.lang.annotation.Annotation; import java.util.Objects; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.annotation.Value; import org.springframework.core.annotation.MergedAnnotations; import org.springframework.data.util.Lazy; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; @@ -80,8 +81,7 @@ public Parameter(@Nullable String name, TypeInformation type, Annotation[] an this.hasExpression = Lazy.of(() -> StringUtils.hasText(getValueExpression())); } - @Nullable - private static String getValue(MergedAnnotations annotations) { + private static @Nullable String getValue(MergedAnnotations annotations) { return annotations.get(Value.class) // .getValue("value", String.class) // @@ -94,8 +94,7 @@ private static String getValue(MergedAnnotations annotations) { * * @return */ - @Nullable - public String getName() { + public @Nullable String getName() { return name; } @@ -155,7 +154,7 @@ public String getValueExpression() { * @return the expression to be used when looking up a source data structure. * @since 3.3 */ - @SuppressWarnings("DataFlowIssue") + @SuppressWarnings({ "DataFlowIssue", "NullAway" }) public String getRequiredValueExpression() { if (!hasValueExpression()) { diff --git a/src/main/java/org/springframework/data/mapping/PersistentEntity.java b/src/main/java/org/springframework/data/mapping/PersistentEntity.java index 2cb8dbd345..88721f685a 100644 --- a/src/main/java/org/springframework/data/mapping/PersistentEntity.java +++ b/src/main/java/org/springframework/data/mapping/PersistentEntity.java @@ -18,9 +18,10 @@ import java.lang.annotation.Annotation; import java.util.Iterator; +import org.jspecify.annotations.Nullable; + import org.springframework.data.annotation.Immutable; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -170,8 +171,7 @@ default P getRequiredPersistentProperty(String name) { * @return {@literal null} if no property found with given annotation type. * @since 1.8 */ - @Nullable - default P getPersistentProperty(Class annotationType) { + default @Nullable P getPersistentProperty(Class annotationType) { Iterator

it = getPersistentProperties(annotationType).iterator(); return it.hasNext() ? it.next() : null; @@ -279,8 +279,7 @@ default void doWithAll(PropertyHandler

handler) { * @return {@literal null} if not found. * @since 1.8 */ - @Nullable - A findAnnotation(Class annotationType); + @Nullable A findAnnotation(Class annotationType); /** * Returns the required annotation of the given type on the {@link PersistentEntity}. diff --git a/src/main/java/org/springframework/data/mapping/PersistentProperty.java b/src/main/java/org/springframework/data/mapping/PersistentProperty.java index b61d1e1a8e..e34a1a9e78 100644 --- a/src/main/java/org/springframework/data/mapping/PersistentProperty.java +++ b/src/main/java/org/springframework/data/mapping/PersistentProperty.java @@ -21,10 +21,11 @@ import java.util.Collection; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** diff --git a/src/main/java/org/springframework/data/mapping/PersistentPropertyAccessor.java b/src/main/java/org/springframework/data/mapping/PersistentPropertyAccessor.java index 2cc52e4e58..5d50df819d 100644 --- a/src/main/java/org/springframework/data/mapping/PersistentPropertyAccessor.java +++ b/src/main/java/org/springframework/data/mapping/PersistentPropertyAccessor.java @@ -15,8 +15,9 @@ */ package org.springframework.data.mapping; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.model.ConvertingPropertyAccessor; -import org.springframework.lang.Nullable; /** * Domain service to allow accessing and setting {@link PersistentProperty}s of an entity. Usually obtained through diff --git a/src/main/java/org/springframework/data/mapping/PersistentPropertyPath.java b/src/main/java/org/springframework/data/mapping/PersistentPropertyPath.java index c0c20e04ad..73403272c3 100644 --- a/src/main/java/org/springframework/data/mapping/PersistentPropertyPath.java +++ b/src/main/java/org/springframework/data/mapping/PersistentPropertyPath.java @@ -15,9 +15,10 @@ */ package org.springframework.data.mapping; +import org.jspecify.annotations.Nullable; + import org.springframework.core.convert.converter.Converter; import org.springframework.data.util.Streamable; -import org.springframework.lang.Nullable; /** * Abstraction of a path of {@link PersistentProperty}s. diff --git a/src/main/java/org/springframework/data/mapping/PersistentPropertyPathAccessor.java b/src/main/java/org/springframework/data/mapping/PersistentPropertyPathAccessor.java index fd21629c0a..2b12bb3195 100644 --- a/src/main/java/org/springframework/data/mapping/PersistentPropertyPathAccessor.java +++ b/src/main/java/org/springframework/data/mapping/PersistentPropertyPathAccessor.java @@ -15,9 +15,10 @@ */ package org.springframework.data.mapping; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.AccessOptions.GetOptions; import org.springframework.data.mapping.AccessOptions.SetOptions; -import org.springframework.lang.Nullable; /** * Extension of {@link PersistentPropertyAccessor} that is also able to obtain and set values for diff --git a/src/main/java/org/springframework/data/mapping/PropertyPath.java b/src/main/java/org/springframework/data/mapping/PropertyPath.java index e2d7c77cb7..da10c72273 100644 --- a/src/main/java/org/springframework/data/mapping/PropertyPath.java +++ b/src/main/java/org/springframework/data/mapping/PropertyPath.java @@ -26,9 +26,10 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.jspecify.annotations.Nullable; + import org.springframework.data.util.Streamable; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ConcurrentReferenceHashMap; import org.springframework.util.StringUtils; @@ -102,8 +103,7 @@ public class PropertyPath implements Streamable { : this.typeInformation.getRequiredActualType(); } - @Nullable - private static Property lookupProperty(TypeInformation owningType, String name) { + private static @Nullable Property lookupProperty(TypeInformation owningType, String name) { TypeInformation propertyType = owningType.getProperty(name); @@ -185,8 +185,7 @@ public TypeInformation getTypeInformation() { * @return the next nested {@link PropertyPath} or {@literal null} if no nested {@link PropertyPath} available. * @see #hasNext() */ - @Nullable - public PropertyPath next() { + public @Nullable PropertyPath next() { return next; } @@ -268,8 +267,7 @@ public boolean hasNext() { } @Override - @Nullable - public PropertyPath next() { + public @Nullable PropertyPath next() { PropertyPath result = current; diff --git a/src/main/java/org/springframework/data/mapping/PropertyReferenceException.java b/src/main/java/org/springframework/data/mapping/PropertyReferenceException.java index 24d6a49ab6..68a6a06eab 100644 --- a/src/main/java/org/springframework/data/mapping/PropertyReferenceException.java +++ b/src/main/java/org/springframework/data/mapping/PropertyReferenceException.java @@ -22,10 +22,11 @@ import java.util.List; import java.util.Set; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.PropertyMatches; import org.springframework.data.util.Lazy; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -121,8 +122,7 @@ public String getMessage() { * * @return */ - @Nullable - public PropertyPath getBaseProperty() { + public @Nullable PropertyPath getBaseProperty() { return alreadyResolvedPath.isEmpty() ? null : alreadyResolvedPath.get(alreadyResolvedPath.size() - 1); } diff --git a/src/main/java/org/springframework/data/mapping/callback/EntityCallbackDiscoverer.java b/src/main/java/org/springframework/data/mapping/callback/EntityCallbackDiscoverer.java index bfadb5c6a6..d313491d38 100644 --- a/src/main/java/org/springframework/data/mapping/callback/EntityCallbackDiscoverer.java +++ b/src/main/java/org/springframework/data/mapping/callback/EntityCallbackDiscoverer.java @@ -28,6 +28,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiFunction; +import org.jspecify.annotations.Nullable; + import org.springframework.aop.framework.AopProxyUtils; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.config.BeanDefinition; @@ -35,7 +37,6 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.core.ResolvableType; import org.springframework.core.annotation.AnnotationAwareOrderComparator; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; diff --git a/src/main/java/org/springframework/data/mapping/callback/package-info.java b/src/main/java/org/springframework/data/mapping/callback/package-info.java index ade249bfc7..cae514eafe 100644 --- a/src/main/java/org/springframework/data/mapping/callback/package-info.java +++ b/src/main/java/org/springframework/data/mapping/callback/package-info.java @@ -1,5 +1,5 @@ /** * Mapping callback API and implementation base classes. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.mapping.callback; diff --git a/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java b/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java index e1b59c149a..5ba05b4a02 100644 --- a/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java +++ b/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java @@ -33,6 +33,8 @@ 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; import org.springframework.beans.factory.BeanFactory; @@ -70,7 +72,6 @@ import org.springframework.data.util.Optionals; import org.springframework.data.util.Streamable; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils.FieldCallback; diff --git a/src/main/java/org/springframework/data/mapping/context/DefaultPersistentPropertyPath.java b/src/main/java/org/springframework/data/mapping/context/DefaultPersistentPropertyPath.java index 9a4a2b9c72..0591d291bc 100644 --- a/src/main/java/org/springframework/data/mapping/context/DefaultPersistentPropertyPath.java +++ b/src/main/java/org/springframework/data/mapping/context/DefaultPersistentPropertyPath.java @@ -20,12 +20,13 @@ import java.util.Iterator; import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.core.convert.converter.Converter; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.PersistentPropertyPath; import org.springframework.data.util.TypeInformation; import org.springframework.lang.Contract; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -182,9 +183,8 @@ public PersistentPropertyPath

getExtensionForBaseOf(PersistentPropertyPath

return new DefaultPersistentPropertyPath<>(properties.subList(base.getLength(), getLength())); } - @Nullable @Override - public PersistentPropertyPath

getParentPath() { + public @Nullable PersistentPropertyPath

getParentPath() { int size = properties.size(); @@ -243,7 +243,6 @@ public int hashCode() { } @Override - @Nullable public String toString() { return toDotPath(); } diff --git a/src/main/java/org/springframework/data/mapping/context/InvalidPersistentPropertyPath.java b/src/main/java/org/springframework/data/mapping/context/InvalidPersistentPropertyPath.java index ab096ee1cf..65ac608086 100644 --- a/src/main/java/org/springframework/data/mapping/context/InvalidPersistentPropertyPath.java +++ b/src/main/java/org/springframework/data/mapping/context/InvalidPersistentPropertyPath.java @@ -20,12 +20,13 @@ import java.util.HashSet; import java.util.Set; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.PropertyMatches; import org.springframework.data.mapping.MappingException; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.PersistentPropertyPath; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; diff --git a/src/main/java/org/springframework/data/mapping/context/MappingContext.java b/src/main/java/org/springframework/data/mapping/context/MappingContext.java index 94671f4253..45279f48a4 100644 --- a/src/main/java/org/springframework/data/mapping/context/MappingContext.java +++ b/src/main/java/org/springframework/data/mapping/context/MappingContext.java @@ -18,6 +18,8 @@ import java.util.Collection; import java.util.function.Predicate; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.MappingException; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; @@ -25,7 +27,6 @@ import org.springframework.data.mapping.PersistentPropertyPaths; import org.springframework.data.mapping.PropertyPath; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; /** * This interface defines the overall context including all known PersistentEntity instances and methods to obtain diff --git a/src/main/java/org/springframework/data/mapping/context/PersistentEntities.java b/src/main/java/org/springframework/data/mapping/context/PersistentEntities.java index ff46d4cfc7..8db69f1b3b 100644 --- a/src/main/java/org/springframework/data/mapping/context/PersistentEntities.java +++ b/src/main/java/org/springframework/data/mapping/context/PersistentEntities.java @@ -27,12 +27,13 @@ import java.util.stream.Collectors; import java.util.stream.StreamSupport; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.MappingException; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.util.Streamable; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -189,8 +190,7 @@ public Streamable> getManagedTypes() { * @return * @since 2.1 */ - @Nullable - public PersistentEntity getEntityUltimatelyReferredToBy(PersistentProperty property) { + public @Nullable PersistentEntity getEntityUltimatelyReferredToBy(PersistentProperty property) { TypeInformation propertyType = property.getTypeInformation().getActualType(); @@ -231,8 +231,7 @@ public TypeInformation getTypeUltimatelyReferredToBy(PersistentProperty pr * @throws IllegalStateException if the entity cannot be detected uniquely as multiple ones might share the same * identifier. */ - @Nullable - private PersistentEntity getEntityIdentifiedBy(TypeInformation type) { + private @Nullable PersistentEntity getEntityIdentifiedBy(TypeInformation type) { Collection> entities = new ArrayList<>(); for (MappingContext> context : contexts) { diff --git a/src/main/java/org/springframework/data/mapping/context/PersistentPropertyPathFactory.java b/src/main/java/org/springframework/data/mapping/context/PersistentPropertyPathFactory.java index 1cffe89ee2..5cabdd8dbb 100644 --- a/src/main/java/org/springframework/data/mapping/context/PersistentPropertyPathFactory.java +++ b/src/main/java/org/springframework/data/mapping/context/PersistentPropertyPathFactory.java @@ -22,6 +22,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.AssociationHandler; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; @@ -32,7 +34,6 @@ import org.springframework.data.util.Pair; import org.springframework.data.util.StreamUtils; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -210,8 +211,7 @@ private PathResolution createPersistentPropertyPath(String propertyPath, TypeInf return PathResolution.resolved(path); } - @Nullable - private Pair, E> getPair(DefaultPersistentPropertyPath

path, + private @Nullable Pair, E> getPair(DefaultPersistentPropertyPath

path, Iterator iterator, String segment, E entity) { P property = entity.getPersistentProperty(segment); @@ -263,8 +263,7 @@ private Collection> from(E entity, Predicate handler = association -> propertyTester - .doWithPersistentProperty(association.getInverse()); + AssociationHandler

handler = association -> propertyTester.doWithPersistentProperty(association.getInverse()); entity.doWithAssociations(handler); return properties; @@ -303,8 +302,7 @@ public boolean equals(@Nullable Object obj) { return false; } - return Objects.equals(this.type, that.type) - && Objects.equals(this.path, that.path); + return Objects.equals(this.type, that.type) && Objects.equals(this.path, that.path); } @Override @@ -315,9 +313,7 @@ public int hashCode() { @Override public String toString() { - return "TypeAndPath[" + - "type=" + type + ", " + - "path=" + path + ']'; + return "TypeAndPath[" + "type=" + type + ", " + "path=" + path + ']'; } } @@ -473,7 +469,7 @@ static PathResolution resolved(PersistentPropertyPath path) { * @return the path if available. * @throws InvalidPersistentPropertyPath when the path could not be resolved to an actual property */ - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "NullAway" })

> PersistentPropertyPath

getResolvedPath() { if (resolvable) { diff --git a/src/main/java/org/springframework/data/mapping/context/package-info.java b/src/main/java/org/springframework/data/mapping/context/package-info.java index 6ffe039ff6..5e274dfb53 100644 --- a/src/main/java/org/springframework/data/mapping/context/package-info.java +++ b/src/main/java/org/springframework/data/mapping/context/package-info.java @@ -1,5 +1,5 @@ /** * Mapping context API and implementation base classes. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.mapping.context; diff --git a/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java b/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java index b200908a16..f378fe0d35 100644 --- a/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java +++ b/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java @@ -24,6 +24,8 @@ import java.util.Set; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.Association; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; @@ -32,7 +34,6 @@ import org.springframework.data.util.Lazy; import org.springframework.data.util.ReflectionUtils; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -46,7 +47,7 @@ public abstract class AbstractPersistentProperty

> implements PersistentProperty

{ private static final Field CAUSE_FIELD; - private static final Class ASSOCIATION_TYPE; + private static final @Nullable Class ASSOCIATION_TYPE; static { @@ -68,10 +69,10 @@ public abstract class AbstractPersistentProperty

private final Lazy isAssociation; private final Lazy> associationTargetType; - private final Method getter; - private final Method setter; - private final Field field; - private final Method wither; + private final @Nullable Method getter; + private final @Nullable Method setter; + private final @Nullable Field field; + private final @Nullable Method wither; private final Lazy readable; private final boolean immutable; @@ -161,33 +162,28 @@ public Iterable> getPersistentEntityTypeInformation return entityTypeInformation.get(); } - @Nullable @Override - public Method getGetter() { + public @Nullable Method getGetter() { return this.getter; } - @Nullable @Override - public Method getSetter() { + public @Nullable Method getSetter() { return this.setter; } - @Nullable @Override - public Method getWither() { + public @Nullable Method getWither() { return this.wither; } - @Nullable @Override - public Field getField() { + public @Nullable Field getField() { return this.field; } @Override - @Nullable - public String getSpelExpression() { + public @Nullable String getSpelExpression() { return null; } @@ -216,24 +212,21 @@ public boolean isAssociation() { return isAssociation.get(); } - @Nullable @Override - public Association

getAssociation() { + public @Nullable Association

getAssociation() { return association.orElse(null); } - @Nullable @Override - public Class getAssociationTargetType() { + public @Nullable Class getAssociationTargetType() { TypeInformation result = getAssociationTargetTypeInformation(); return result != null ? result.getType() : null; } - @Nullable @Override - public TypeInformation getAssociationTargetTypeInformation() { + public @Nullable TypeInformation getAssociationTargetTypeInformation() { return associationTargetType.getNullable(); } @@ -257,15 +250,13 @@ public boolean isEntity() { return !isTransient() && !entityTypeInformation.get().isEmpty(); } - @Nullable @Override - public Class getComponentType() { + public @Nullable Class getComponentType() { return isMap() || isCollectionLike() ? information.getRequiredComponentType().getType() : null; } - @Nullable @Override - public Class getMapValueType() { + public @Nullable Class getMapValueType() { if (isMap()) { diff --git a/src/main/java/org/springframework/data/mapping/model/AnnotationBasedPersistentProperty.java b/src/main/java/org/springframework/data/mapping/model/AnnotationBasedPersistentProperty.java index 810909c123..0bd4a7e402 100644 --- a/src/main/java/org/springframework/data/mapping/model/AnnotationBasedPersistentProperty.java +++ b/src/main/java/org/springframework/data/mapping/model/AnnotationBasedPersistentProperty.java @@ -23,6 +23,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.annotation.AnnotatedElementUtils; @@ -42,7 +44,6 @@ import org.springframework.data.util.Optionals; import org.springframework.data.util.StreamUtils; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -56,7 +57,7 @@ public abstract class AnnotationBasedPersistentProperty

{ private static final String SPRING_DATA_PACKAGE = "org.springframework.data"; - private static final Class IDENTITY_TYPE = loadIdentityType(); + private static final @Nullable Class IDENTITY_TYPE = loadIdentityType(); private final @Nullable String value; private final Map, Optional> annotationCache = new ConcurrentHashMap<>(); @@ -116,6 +117,7 @@ public AnnotationBasedPersistentProperty(Property property, PersistentEntity { @@ -123,7 +125,6 @@ private void populateAnnotationCache(Property property) { for (Annotation annotation : it.getAnnotations()) { Class annotationType = annotation.annotationType(); - Annotation mergedAnnotation = AnnotatedElementUtils.getMergedAnnotation(it, annotationType); validateAnnotation(mergedAnnotation, @@ -131,7 +132,7 @@ private void populateAnnotationCache(Property property) { + "multiple times on accessor methods of property %s in class %s", annotationType.getSimpleName(), getName(), getOwner().getType().getSimpleName()); - annotationCache.put(annotationType, Optional.of(mergedAnnotation)); + annotationCache.put(annotationType, Optional.ofNullable(mergedAnnotation)); } }); @@ -146,7 +147,7 @@ private void populateAnnotationCache(Property property) { "Ambiguous mapping; Annotation %s configured " + "on field %s and one of its accessor methods in class %s", annotationType.getSimpleName(), it.getName(), getOwner().getType().getSimpleName()); - annotationCache.put(annotationType, Optional.of(mergedAnnotation)); + annotationCache.put(annotationType, Optional.ofNullable(mergedAnnotation)); } }); } @@ -179,9 +180,8 @@ private void validateAnnotation(Annotation candidate, String message, Object... * * @see org.springframework.data.mapping.model.AbstractPersistentProperty#getSpelExpression() */ - @Nullable @Override - public String getSpelExpression() { + public @Nullable String getSpelExpression() { return value; } @@ -228,8 +228,7 @@ public boolean isWritable() { * @return {@literal null} if annotation type not found on property. */ @Override - @Nullable - public A findAnnotation(Class annotationType) { + public @Nullable A findAnnotation(Class annotationType) { Assert.notNull(annotationType, "Annotation type must not be null"); @@ -254,9 +253,8 @@ private Optional doFindAnnotation(Class annotationT }); } - @Nullable @Override - public A findPropertyOrOwnerAnnotation(Class annotationType) { + public @Nullable A findPropertyOrOwnerAnnotation(Class annotationType) { A annotation = findAnnotation(annotationType); @@ -279,9 +277,8 @@ public boolean usePropertyAccess() { return usePropertyAccess.get(); } - @Nullable @Override - public TypeInformation getAssociationTargetTypeInformation() { + public @Nullable TypeInformation getAssociationTargetTypeInformation() { return associationTargetType.getNullable(); } @@ -312,9 +309,8 @@ private Stream getAccessors() { * * @return can be {@literal null}. */ - @Nullable @SuppressWarnings("unchecked") - private static Class loadIdentityType() { + private static @Nullable Class loadIdentityType() { return (Class) ClassUtils.loadIfPresent("org.jmolecules.ddd.annotation.Identity", AbstractPersistentProperty.class.getClassLoader()); diff --git a/src/main/java/org/springframework/data/mapping/model/BasicPersistentEntity.java b/src/main/java/org/springframework/data/mapping/model/BasicPersistentEntity.java index 93b69d354d..320cec6f66 100644 --- a/src/main/java/org/springframework/data/mapping/model/BasicPersistentEntity.java +++ b/src/main/java/org/springframework/data/mapping/model/BasicPersistentEntity.java @@ -30,8 +30,12 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; + import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.env.Environment; +import org.springframework.core.env.EnvironmentCapable; +import org.springframework.core.env.StandardEnvironment; import org.springframework.data.annotation.Immutable; import org.springframework.data.annotation.TypeAlias; import org.springframework.data.domain.Persistable; @@ -44,7 +48,6 @@ import org.springframework.data.util.Lazy; import org.springframework.data.util.TypeInformation; import org.springframework.expression.EvaluationContext; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.MultiValueMap; @@ -61,7 +64,8 @@ * @author Mark Paluch * @author Johannes Englmeier */ -public class BasicPersistentEntity> implements MutablePersistentEntity { +public class BasicPersistentEntity> + implements MutablePersistentEntity, EnvironmentCapable { private static final String TYPE_MISMATCH = "Target bean of type %s is not of type of the persistent entity (%s)"; @@ -229,14 +233,23 @@ public void setEnvironment(Environment environment) { this.environment = environment; } + @Override + public Environment getEnvironment() { + + if (this.environment == null) { + this.environment = new StandardEnvironment(); + } + + return this.environment; + } + /** * Returns the given property if it is a better candidate for the id property than the current id property. * * @param property the new id property candidate, will never be {@literal null}. * @return the given id property or {@literal null} if the given property is not an id property. */ - @Nullable - protected P returnPropertyIfBetterIdPropertyCandidateOrNull(P property) { + protected @Nullable P returnPropertyIfBetterIdPropertyCandidateOrNull(P property) { if (!property.isIdProperty()) { return null; @@ -468,7 +481,7 @@ protected EvaluationContext getEvaluationContext(Object rootObject, ExpressionDe * @since 3.3 */ protected ValueEvaluationContext getValueEvaluationContext(Object rootObject) { - return ValueEvaluationContext.of(this.environment, getEvaluationContext(rootObject)); + return ValueEvaluationContext.of(getEnvironment(), getEvaluationContext(rootObject)); } /** @@ -480,7 +493,7 @@ protected ValueEvaluationContext getValueEvaluationContext(Object rootObject) { * @since 3.3 */ protected ValueEvaluationContext getValueEvaluationContext(Object rootObject, ExpressionDependencies dependencies) { - return ValueEvaluationContext.of(this.environment, getEvaluationContext(rootObject, dependencies)); + return ValueEvaluationContext.of(getEnvironment(), getEvaluationContext(rootObject, dependencies)); } /** diff --git a/src/main/java/org/springframework/data/mapping/model/BeanWrapper.java b/src/main/java/org/springframework/data/mapping/model/BeanWrapper.java index d1bd40f89d..98e72ec6a0 100644 --- a/src/main/java/org/springframework/data/mapping/model/BeanWrapper.java +++ b/src/main/java/org/springframework/data/mapping/model/BeanWrapper.java @@ -25,12 +25,13 @@ import java.util.List; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.core.KotlinDetector; import org.springframework.data.mapping.MappingException; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.PersistentPropertyAccessor; import org.springframework.data.util.KotlinReflectionUtils; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ReflectionUtils; @@ -71,7 +72,13 @@ public void setProperty(PersistentProperty property, @Nullable Object value) if (wither != null) { ReflectionUtils.makeAccessible(wither); - this.bean = (T) ReflectionUtils.invokeMethod(wither, bean, value); + T newBean = (T) ReflectionUtils.invokeMethod(wither, bean, value); + + if (newBean == null) { + throw new IllegalStateException("Wither method '%s' returned null".formatted(wither)); + } + + this.bean = newBean; return; } @@ -82,7 +89,7 @@ public void setProperty(PersistentProperty property, @Nullable Object value) } throw new UnsupportedOperationException( - String.format("Cannot set immutable property %s.%s ", property.getOwner().getName(), property.getName())); + String.format("Cannot set immutable property '%s.%s'", property.getOwner().getName(), property.getName())); } if (!property.usePropertyAccess()) { @@ -100,7 +107,8 @@ public void setProperty(PersistentProperty property, @Nullable Object value) ReflectionUtils.invokeMethod(setter, bean, value); } catch (IllegalStateException e) { - throw new MappingException("Could not set object property", e); + throw new MappingException( + "Could not set object property '%s.%s'".formatted(property.getOwner().getName(), property.getName()), e); } } @@ -140,8 +148,7 @@ public Object getProperty(PersistentProperty property, Class return ReflectionUtils.invokeMethod(getter, bean); } catch (IllegalStateException e) { - throw new MappingException( - String.format("Could not read property %s of %s", property, bean.toString()), e); + throw new MappingException(String.format("Could not read property %s of %s", property, bean.toString()), e); } } diff --git a/src/main/java/org/springframework/data/mapping/model/CachingValueExpressionEvaluatorFactory.java b/src/main/java/org/springframework/data/mapping/model/CachingValueExpressionEvaluatorFactory.java index 8a9a1a572b..1ff4ec39df 100644 --- a/src/main/java/org/springframework/data/mapping/model/CachingValueExpressionEvaluatorFactory.java +++ b/src/main/java/org/springframework/data/mapping/model/CachingValueExpressionEvaluatorFactory.java @@ -15,6 +15,8 @@ */ package org.springframework.data.mapping.model; +import org.jspecify.annotations.Nullable; + import org.springframework.core.env.EnvironmentCapable; import org.springframework.data.expression.ValueEvaluationContext; import org.springframework.data.expression.ValueEvaluationContextProvider; @@ -23,7 +25,6 @@ import org.springframework.data.spel.EvaluationContextProvider; import org.springframework.data.spel.ExpressionDependencies; import org.springframework.expression.ExpressionParser; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ConcurrentLruCache; @@ -97,7 +98,7 @@ public ValueExpressionEvaluator create(Object source) { return new ValueExpressionEvaluator() { @SuppressWarnings("unchecked") @Override - public T evaluate(String expression) { + public @Nullable T evaluate(String expression) { ValueExpression valueExpression = expressionCache.get(expression); return (T) valueExpression.evaluate(getEvaluationContext(source, valueExpression.getExpressionDependencies())); } diff --git a/src/main/java/org/springframework/data/mapping/model/ClassGeneratingEntityInstantiator.java b/src/main/java/org/springframework/data/mapping/model/ClassGeneratingEntityInstantiator.java index 883f19d08b..952fa0e9a6 100644 --- a/src/main/java/org/springframework/data/mapping/model/ClassGeneratingEntityInstantiator.java +++ b/src/main/java/org/springframework/data/mapping/model/ClassGeneratingEntityInstantiator.java @@ -27,6 +27,8 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; + import org.springframework.asm.ClassWriter; import org.springframework.asm.MethodVisitor; import org.springframework.asm.Opcodes; @@ -42,7 +44,6 @@ import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.PreferredConstructor; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; diff --git a/src/main/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactory.java b/src/main/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactory.java index ce27969fc9..0e6047d7aa 100644 --- a/src/main/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactory.java +++ b/src/main/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactory.java @@ -40,6 +40,8 @@ import java.util.function.Function; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; + import org.springframework.asm.ClassWriter; import org.springframework.asm.Label; import org.springframework.asm.MethodVisitor; @@ -56,7 +58,6 @@ import org.springframework.data.mapping.model.KotlinValueUtils.ValueBoxing; import org.springframework.data.util.Optionals; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ConcurrentLruCache; @@ -84,7 +85,7 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert private volatile Map, Class>> propertyAccessorClasses = new HashMap<>( 32); - private final ConcurrentLruCache, Function> wrapperCache = new ConcurrentLruCache<>( + private final ConcurrentLruCache, Function<@Nullable Object, @Nullable Object>> wrapperCache = new ConcurrentLruCache<>( 256, KotlinValueBoxingAdapter::getWrapper); @Override @@ -834,7 +835,12 @@ private static void visitGetPropertySwitch(PersistentEntity entity, for (PersistentProperty property : persistentProperties) { - mv.visitLabel(propertyStackMap.get(property.getName()).label); + PropertyStackAddress propertyStackAddress = propertyStackMap.get(property.getName()); + if (propertyStackAddress == null) { + throw new IllegalStateException( + "No PropertyStackAddress found for property %s".formatted(property.getName())); + } + mv.visitLabel(propertyStackAddress.label); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); if (property.getGetter() != null || property.getField() != null) { @@ -996,7 +1002,15 @@ private static void visitSetPropertySwitch(PersistentEntity entity, mv.visitLookupSwitchInsn(dfltLabel, hashes, switchJumpLabels); for (PersistentProperty property : persistentProperties) { - mv.visitLabel(propertyStackMap.get(property.getName()).label); + + PropertyStackAddress propertyStackAddress = propertyStackMap.get(property.getName()); + + if (propertyStackAddress == null) { + throw new IllegalStateException( + "No PropertyStackAddress found for property %s".formatted(property.getName())); + } + + mv.visitLabel(propertyStackAddress.label); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); if (supportsMutation(property)) { @@ -1439,8 +1453,8 @@ static boolean supportsMutation(PersistentProperty property) { * @param * @since 3.2 */ - record KotlinValueBoxingAdapter (PersistentEntity entity, PersistentPropertyAccessor delegate, - ConcurrentLruCache, Function> wrapperCache) + record KotlinValueBoxingAdapter(PersistentEntity entity, PersistentPropertyAccessor delegate, + ConcurrentLruCache, Function<@Nullable Object, @Nullable Object>> wrapperCache) implements PersistentPropertyAccessor { @@ -1457,7 +1471,7 @@ public void setProperty(PersistentProperty property, @Nullable Object value) * {@link Function#identity()} if wrapping is not necessary. * @see KotlinValueUtils#getCopyValueHierarchy(KParameter) */ - static Function getWrapper(PersistentProperty property) { + static Function<@Nullable Object, @Nullable Object> getWrapper(PersistentProperty property) { Optional kotlinCopyMethod = KotlinCopyMethod.findCopyMethod(property.getOwner().getType()) .filter(it -> it.supportsProperty(property)); @@ -1486,7 +1500,7 @@ static Function getWrapper(PersistentProperty property) { } @Override - public Object getProperty(PersistentProperty property) { + public @Nullable Object getProperty(PersistentProperty property) { return delegate.getProperty(property); } diff --git a/src/main/java/org/springframework/data/mapping/model/ConvertingPropertyAccessor.java b/src/main/java/org/springframework/data/mapping/model/ConvertingPropertyAccessor.java index 0425cfcf63..8fe99a5126 100644 --- a/src/main/java/org/springframework/data/mapping/model/ConvertingPropertyAccessor.java +++ b/src/main/java/org/springframework/data/mapping/model/ConvertingPropertyAccessor.java @@ -15,12 +15,13 @@ */ package org.springframework.data.mapping.model; +import org.jspecify.annotations.Nullable; + import org.springframework.core.convert.ConversionService; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.PersistentPropertyAccessor; import org.springframework.data.mapping.PersistentPropertyPath; import org.springframework.lang.Contract; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; diff --git a/src/main/java/org/springframework/data/mapping/model/IdPropertyIdentifierAccessor.java b/src/main/java/org/springframework/data/mapping/model/IdPropertyIdentifierAccessor.java index d70d7b7ab9..b106461a5e 100644 --- a/src/main/java/org/springframework/data/mapping/model/IdPropertyIdentifierAccessor.java +++ b/src/main/java/org/springframework/data/mapping/model/IdPropertyIdentifierAccessor.java @@ -15,12 +15,13 @@ */ package org.springframework.data.mapping.model; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.IdentifierAccessor; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.PersistentPropertyAccessor; import org.springframework.data.mapping.TargetAwareIdentifierAccessor; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** diff --git a/src/main/java/org/springframework/data/mapping/model/InstanceCreatorMetadataDiscoverer.java b/src/main/java/org/springframework/data/mapping/model/InstanceCreatorMetadataDiscoverer.java index 7a97065f92..8bf00261b5 100644 --- a/src/main/java/org/springframework/data/mapping/model/InstanceCreatorMetadataDiscoverer.java +++ b/src/main/java/org/springframework/data/mapping/model/InstanceCreatorMetadataDiscoverer.java @@ -28,6 +28,8 @@ import java.util.ArrayList; import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.core.KotlinDetector; import org.springframework.core.ParameterNameDiscoverer; @@ -40,7 +42,6 @@ import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; /** * Discoverer for factory methods and persistence constructors. diff --git a/src/main/java/org/springframework/data/mapping/model/InstantiationAwarePropertyAccessor.java b/src/main/java/org/springframework/data/mapping/model/InstantiationAwarePropertyAccessor.java index 53a0a1aec5..96a92e0cd1 100644 --- a/src/main/java/org/springframework/data/mapping/model/InstantiationAwarePropertyAccessor.java +++ b/src/main/java/org/springframework/data/mapping/model/InstantiationAwarePropertyAccessor.java @@ -17,12 +17,13 @@ import java.util.function.Function; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.InstanceCreatorMetadata; import org.springframework.data.mapping.Parameter; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.PersistentPropertyAccessor; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -106,9 +107,8 @@ public void setProperty(PersistentProperty property, @Nullable Object value) this.bean = (T) instantiator.createInstance(owner, new ParameterValueProvider() { @Override - @Nullable - @SuppressWarnings("null") - public Object getParameterValue(Parameter parameter) { + @SuppressWarnings("NullAway") + public @Nullable Object getParameterValue(Parameter parameter) { return property.getName().equals(parameter.getName()) // ? value diff --git a/src/main/java/org/springframework/data/mapping/model/KotlinInstantiationDelegate.java b/src/main/java/org/springframework/data/mapping/model/KotlinInstantiationDelegate.java index 21bba049e6..579548ca8e 100644 --- a/src/main/java/org/springframework/data/mapping/model/KotlinInstantiationDelegate.java +++ b/src/main/java/org/springframework/data/mapping/model/KotlinInstantiationDelegate.java @@ -27,13 +27,14 @@ import java.util.function.Function; import java.util.stream.IntStream; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.InstanceCreatorMetadata; import org.springframework.data.mapping.Parameter; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.PreferredConstructor; import org.springframework.data.mapping.model.KotlinValueUtils.ValueBoxing; import org.springframework.data.util.ReflectionUtils; -import org.springframework.lang.Nullable; /** * Delegate to allocate instantiation arguments and to resolve the actual constructor to call for inline/value class @@ -50,7 +51,7 @@ class KotlinInstantiationDelegate { private final KFunction constructor; private final List kParameters; private final Map indexByKParameter; - private final List> wrappers = new ArrayList<>(); + private final List> wrappers = new ArrayList<>(); private final Constructor constructorToInvoke; private final boolean hasDefaultConstructorMarker; @@ -102,7 +103,8 @@ public int getRequiredParameterCount() { /** * Extract the actual construction arguments for a direct constructor call. */ - public

> void extractInvocationArguments(Object[] params, + @SuppressWarnings("NullAway") + public

> void extractInvocationArguments(@Nullable Object[] params, @Nullable InstanceCreatorMetadata

entityCreator, ParameterValueProvider

provider) { if (entityCreator == null) { @@ -204,7 +206,7 @@ private static Constructor doResolveKotlinConstructor(Constructor detected if ((detectedConstructor.getParameterCount() + syntheticParameters) != candidate.getParameterCount()) { continue; } - } else { + } else if (kotlinFunction != null) { int optionalParameterCount = (int) kotlinFunction.getParameters().stream().filter(KParameter::isOptional) .count(); diff --git a/src/main/java/org/springframework/data/mapping/model/KotlinValueUtils.java b/src/main/java/org/springframework/data/mapping/model/KotlinValueUtils.java index aebe7ec7ff..525906df0d 100644 --- a/src/main/java/org/springframework/data/mapping/model/KotlinValueUtils.java +++ b/src/main/java/org/springframework/data/mapping/model/KotlinValueUtils.java @@ -35,7 +35,8 @@ import java.util.List; import java.util.function.BiFunction; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; /** @@ -204,9 +205,9 @@ static class ValueBoxing { private final KClass kClass; - private final KFunction wrapperConstructor; + private final @Nullable KFunction wrapperConstructor; - private final KProperty valueProperty; + private final @Nullable KProperty valueProperty; private final boolean applyBoxing; @@ -341,7 +342,7 @@ public Class getActualType() { public Class getParameterType() { if (hasNext() && getNext().appliesBoxing()) { - return next.getParameterType(); + return getNext().getParameterType(); } return JvmClassMappingKt.getJavaClass(kClass); @@ -387,8 +388,7 @@ public ValueBoxing getNext() { * @param o * @return */ - @Nullable - public Object wrap(@Nullable Object o) { + public @Nullable Object wrap(@Nullable Object o) { return doWrap(o, false, ValueBoxing::wrap); } @@ -410,18 +410,20 @@ Object applyWrapping(@Nullable Object o) { * pass on the result into {@code nextWrapStage}. */ @Nullable - Object doWrap(@Nullable Object o, boolean unwrap, BiFunction nextWrapStage) { + Object doWrap(@Nullable Object o, boolean unwrap, + BiFunction nextWrapStage) { if (applyBoxing) { - return o == null || kClass.isInstance(o) ? o : wrapperConstructor.call(nextWrapStage.apply(next, o)); + return o == null || kClass.isInstance(o) || wrapperConstructor == null ? o + : wrapperConstructor.call(nextWrapStage.apply(getNext(), o)); } else if (unwrap && kClass.isValue()) { - if (o != null && kClass.isInstance(o)) { + if (o != null && kClass.isInstance(o) && valueProperty != null) { o = valueProperty.getGetter().call(o); } } if (hasNext()) { - return nextWrapStage.apply(next, o); + return nextWrapStage.apply(getNext(), o); } return o; diff --git a/src/main/java/org/springframework/data/mapping/model/MappingInstantiationException.java b/src/main/java/org/springframework/data/mapping/model/MappingInstantiationException.java index f47e0ef017..63a697d7d0 100644 --- a/src/main/java/org/springframework/data/mapping/model/MappingInstantiationException.java +++ b/src/main/java/org/springframework/data/mapping/model/MappingInstantiationException.java @@ -23,7 +23,8 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; -import java.util.Optional; + +import org.jspecify.annotations.Nullable; import org.springframework.core.KotlinDetector; import org.springframework.data.mapping.FactoryMethod; @@ -31,7 +32,6 @@ import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PreferredConstructor; import org.springframework.data.util.KotlinReflectionUtils; -import org.springframework.lang.Nullable; import org.springframework.util.ObjectUtils; /** @@ -47,8 +47,8 @@ public class MappingInstantiationException extends RuntimeException { private static final @Serial long serialVersionUID = 822211065035487628L; private static final String TEXT_TEMPLATE = "Failed to instantiate %s using constructor %s with arguments %s"; - private final Class entityType; - private final InstanceCreatorMetadata entityCreator; + private final @Nullable Class entityType; + private final @Nullable InstanceCreatorMetadata entityCreator; private final List constructorArguments; /** @@ -59,8 +59,9 @@ public class MappingInstantiationException extends RuntimeException { * @param arguments * @param cause */ - public MappingInstantiationException(PersistentEntity entity, List arguments, Exception cause) { - this(Optional.ofNullable(entity), arguments, null, cause); + public MappingInstantiationException(@Nullable PersistentEntity entity, List arguments, + Exception cause) { + this(entity, arguments, null, cause); } /** @@ -70,36 +71,37 @@ public MappingInstantiationException(PersistentEntity entity, List * @param cause */ public MappingInstantiationException(List arguments, Exception cause) { - this(Optional.empty(), arguments, null, cause); + this(null, arguments, null, cause); } - private MappingInstantiationException(Optional> entity, List arguments, + private MappingInstantiationException(@Nullable PersistentEntity entity, List arguments, @Nullable String message, Exception cause) { super(buildExceptionMessage(entity, arguments, message), cause); - this.entityType = entity.map(PersistentEntity::getType).orElse(null); - this.entityCreator = entity.map(PersistentEntity::getInstanceCreatorMetadata).orElse(null); + this.entityType = entity != null ? entity.getType() : null; + this.entityCreator = entity != null ? entity.getInstanceCreatorMetadata() : null; this.constructorArguments = arguments; } - private static String buildExceptionMessage(Optional> entity, List arguments, + private static @Nullable String buildExceptionMessage(@Nullable PersistentEntity entity, List arguments, @Nullable String defaultMessage) { - return entity.map(it -> { + if (entity == null) { + return defaultMessage; + } - Optional> constructor = Optional.ofNullable(it.getInstanceCreatorMetadata()); - List toStringArgs = new ArrayList<>(arguments.size()); + InstanceCreatorMetadata constructor = entity.getInstanceCreatorMetadata(); + List toStringArgs = new ArrayList<>(arguments.size()); - for (Object o : arguments) { - toStringArgs.add(ObjectUtils.nullSafeToString(o)); - } + for (Object o : arguments) { + toStringArgs.add(ObjectUtils.nullSafeToString(o)); + } - return String.format(TEXT_TEMPLATE, it.getType().getName(), - constructor.map(MappingInstantiationException::toString).orElse("NO_CONSTRUCTOR"), // - String.join(",", toStringArgs)); + return String.format(TEXT_TEMPLATE, entity.getType().getName(), + constructor != null ? toString(constructor) : "NO_CONSTRUCTOR", // + String.join(",", toStringArgs)); - }).orElse(defaultMessage); } private static String toString(InstanceCreatorMetadata creator) { @@ -119,7 +121,8 @@ private static String toString(PreferredConstructor preferredConstructor) Constructor constructor = preferredConstructor.getConstructor(); - if (KotlinDetector.isKotlinPresent() && KotlinReflectionUtils.isSupportedKotlinClass(constructor.getDeclaringClass())) { + if (KotlinDetector.isKotlinPresent() + && KotlinReflectionUtils.isSupportedKotlinClass(constructor.getDeclaringClass())) { KFunction kotlinFunction = ReflectJvmMapping.getKotlinFunction(constructor); @@ -135,7 +138,8 @@ private static String toString(FactoryMethod factoryMethod) { Method constructor = factoryMethod.getFactoryMethod(); - if (KotlinDetector.isKotlinPresent() && KotlinReflectionUtils.isSupportedKotlinClass(constructor.getDeclaringClass())) { + if (KotlinDetector.isKotlinPresent() + && KotlinReflectionUtils.isSupportedKotlinClass(constructor.getDeclaringClass())) { KFunction kotlinFunction = ReflectJvmMapping.getKotlinFunction(constructor); @@ -152,8 +156,8 @@ private static String toString(FactoryMethod factoryMethod) { * * @return the entityType */ - public Optional> getEntityType() { - return Optional.ofNullable(entityType); + public @Nullable Class getEntityType() { + return entityType; } /** @@ -162,8 +166,8 @@ public Optional> getEntityType() { * @return the entity creator * @since 3.0 */ - public Optional> getEntityCreator() { - return Optional.ofNullable(entityCreator); + public @Nullable InstanceCreatorMetadata getEntityCreator() { + return entityCreator; } /** diff --git a/src/main/java/org/springframework/data/mapping/model/ParameterValueProvider.java b/src/main/java/org/springframework/data/mapping/model/ParameterValueProvider.java index b30511720d..79770b6953 100644 --- a/src/main/java/org/springframework/data/mapping/model/ParameterValueProvider.java +++ b/src/main/java/org/springframework/data/mapping/model/ParameterValueProvider.java @@ -15,9 +15,10 @@ */ package org.springframework.data.mapping.model; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.Parameter; import org.springframework.data.mapping.PersistentProperty; -import org.springframework.lang.Nullable; /** * Callback interface to lookup values for a given {@link Parameter}. @@ -32,6 +33,5 @@ public interface ParameterValueProvider

> { * @param parameter must not be {@literal null}. * @return the property value. Can be {@literal null}. */ - @Nullable - T getParameterValue(Parameter parameter); + @Nullable T getParameterValue(Parameter parameter); } diff --git a/src/main/java/org/springframework/data/mapping/model/PersistableIdentifierAccessor.java b/src/main/java/org/springframework/data/mapping/model/PersistableIdentifierAccessor.java index d369ceac38..85e514185f 100644 --- a/src/main/java/org/springframework/data/mapping/model/PersistableIdentifierAccessor.java +++ b/src/main/java/org/springframework/data/mapping/model/PersistableIdentifierAccessor.java @@ -15,10 +15,11 @@ */ package org.springframework.data.mapping.model; +import org.jspecify.annotations.Nullable; + import org.springframework.data.domain.Persistable; import org.springframework.data.mapping.IdentifierAccessor; import org.springframework.data.mapping.TargetAwareIdentifierAccessor; -import org.springframework.lang.Nullable; /** * {@link IdentifierAccessor} that invokes {@link Persistable#getId()}. diff --git a/src/main/java/org/springframework/data/mapping/model/PersistentEntityIsNewStrategy.java b/src/main/java/org/springframework/data/mapping/model/PersistentEntityIsNewStrategy.java index 22e1573e4b..82f8c1d0e5 100644 --- a/src/main/java/org/springframework/data/mapping/model/PersistentEntityIsNewStrategy.java +++ b/src/main/java/org/springframework/data/mapping/model/PersistentEntityIsNewStrategy.java @@ -17,9 +17,10 @@ import java.util.function.Function; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.support.IsNewStrategy; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; diff --git a/src/main/java/org/springframework/data/mapping/model/PersistentEntityParameterValueProvider.java b/src/main/java/org/springframework/data/mapping/model/PersistentEntityParameterValueProvider.java index 67913a2d9a..8690743a77 100644 --- a/src/main/java/org/springframework/data/mapping/model/PersistentEntityParameterValueProvider.java +++ b/src/main/java/org/springframework/data/mapping/model/PersistentEntityParameterValueProvider.java @@ -15,12 +15,13 @@ */ package org.springframework.data.mapping.model; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.InstanceCreatorMetadata; import org.springframework.data.mapping.MappingException; import org.springframework.data.mapping.Parameter; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; -import org.springframework.lang.Nullable; /** * {@link ParameterValueProvider} based on a {@link PersistentEntity} to use a {@link PropertyValueProvider} to lookup diff --git a/src/main/java/org/springframework/data/mapping/model/PreferredConstructorDiscoverer.java b/src/main/java/org/springframework/data/mapping/model/PreferredConstructorDiscoverer.java index 1d4ae5c55d..3f6f923930 100644 --- a/src/main/java/org/springframework/data/mapping/model/PreferredConstructorDiscoverer.java +++ b/src/main/java/org/springframework/data/mapping/model/PreferredConstructorDiscoverer.java @@ -28,6 +28,8 @@ import java.util.List; import java.util.Optional; +import org.jspecify.annotations.Nullable; + import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.core.KotlinDetector; import org.springframework.core.ParameterNameDiscoverer; @@ -39,7 +41,6 @@ import org.springframework.data.mapping.PreferredConstructor; import org.springframework.data.util.KotlinReflectionUtils; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; diff --git a/src/main/java/org/springframework/data/mapping/model/Property.java b/src/main/java/org/springframework/data/mapping/model/Property.java index 208398275c..e39a629842 100644 --- a/src/main/java/org/springframework/data/mapping/model/Property.java +++ b/src/main/java/org/springframework/data/mapping/model/Property.java @@ -23,10 +23,11 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; +import org.jspecify.annotations.Nullable; + import org.springframework.data.util.Lazy; import org.springframework.data.util.Optionals; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; diff --git a/src/main/java/org/springframework/data/mapping/model/PropertyValueProvider.java b/src/main/java/org/springframework/data/mapping/model/PropertyValueProvider.java index 1432148841..602fbe7a01 100644 --- a/src/main/java/org/springframework/data/mapping/model/PropertyValueProvider.java +++ b/src/main/java/org/springframework/data/mapping/model/PropertyValueProvider.java @@ -15,8 +15,9 @@ */ package org.springframework.data.mapping.model; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.PersistentProperty; -import org.springframework.lang.Nullable; /** * SPI for components to provide values for as {@link PersistentProperty}. diff --git a/src/main/java/org/springframework/data/mapping/model/SimplePersistentPropertyPathAccessor.java b/src/main/java/org/springframework/data/mapping/model/SimplePersistentPropertyPathAccessor.java index 3307addfda..63a3cf0dd9 100644 --- a/src/main/java/org/springframework/data/mapping/model/SimplePersistentPropertyPathAccessor.java +++ b/src/main/java/org/springframework/data/mapping/model/SimplePersistentPropertyPathAccessor.java @@ -24,6 +24,8 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; + import org.springframework.core.CollectionFactory; import org.springframework.data.mapping.AccessOptions; import org.springframework.data.mapping.AccessOptions.GetOptions; @@ -36,7 +38,6 @@ import org.springframework.data.mapping.PersistentPropertyAccessor; import org.springframework.data.mapping.PersistentPropertyPath; import org.springframework.data.mapping.PersistentPropertyPathAccessor; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -65,9 +66,8 @@ public T getBean() { return delegate.getBean(); } - @Nullable @Override - public Object getProperty(PersistentProperty property) { + public @Nullable Object getProperty(PersistentProperty property) { return delegate.getProperty(property); } @@ -214,7 +214,8 @@ private Object handleNull(PersistentPropertyPath PersistentPropertyPath> parentPath = path.getParentPath(); - throw new MappingException(String.format(nullIntermediateMessage, parentPath.getLeafProperty(), path.toDotPath(), + throw new MappingException(String.format(nullIntermediateMessage, + parentPath != null ? parentPath.getLeafProperty() : path.getLeafProperty(), path.toDotPath(), getBean().getClass().getName())); } diff --git a/src/main/java/org/springframework/data/mapping/model/SpELContext.java b/src/main/java/org/springframework/data/mapping/model/SpELContext.java index 6281554d61..a064ee91df 100644 --- a/src/main/java/org/springframework/data/mapping/model/SpELContext.java +++ b/src/main/java/org/springframework/data/mapping/model/SpELContext.java @@ -15,6 +15,8 @@ */ package org.springframework.data.mapping.model; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.BeanFactory; import org.springframework.context.expression.BeanFactoryResolver; import org.springframework.data.spel.EvaluationContextProvider; @@ -23,7 +25,6 @@ import org.springframework.expression.PropertyAccessor; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** diff --git a/src/main/java/org/springframework/data/mapping/model/ValueExpressionEvaluator.java b/src/main/java/org/springframework/data/mapping/model/ValueExpressionEvaluator.java index 02902d5015..994b7f8300 100644 --- a/src/main/java/org/springframework/data/mapping/model/ValueExpressionEvaluator.java +++ b/src/main/java/org/springframework/data/mapping/model/ValueExpressionEvaluator.java @@ -15,7 +15,7 @@ */ package org.springframework.data.mapping.model; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** * SPI for components that can evaluate Value expressions. @@ -31,6 +31,5 @@ public interface ValueExpressionEvaluator { * @param expression * @return */ - @Nullable - T evaluate(String expression); + @Nullable T evaluate(String expression); } diff --git a/src/main/java/org/springframework/data/mapping/model/ValueExpressionParameterValueProvider.java b/src/main/java/org/springframework/data/mapping/model/ValueExpressionParameterValueProvider.java index 43ed677db9..ace3317bc9 100644 --- a/src/main/java/org/springframework/data/mapping/model/ValueExpressionParameterValueProvider.java +++ b/src/main/java/org/springframework/data/mapping/model/ValueExpressionParameterValueProvider.java @@ -15,10 +15,11 @@ */ package org.springframework.data.mapping.model; +import org.jspecify.annotations.Nullable; + import org.springframework.core.convert.ConversionService; import org.springframework.data.mapping.Parameter; import org.springframework.data.mapping.PersistentProperty; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** diff --git a/src/main/java/org/springframework/data/mapping/model/package-info.java b/src/main/java/org/springframework/data/mapping/model/package-info.java index d45487b532..3a4ad56807 100644 --- a/src/main/java/org/springframework/data/mapping/model/package-info.java +++ b/src/main/java/org/springframework/data/mapping/model/package-info.java @@ -1,5 +1,5 @@ /** * Core implementation of the mapping subsystem's model. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.mapping.model; diff --git a/src/main/java/org/springframework/data/mapping/package-info.java b/src/main/java/org/springframework/data/mapping/package-info.java index 74503fe6e2..f152a5ddff 100644 --- a/src/main/java/org/springframework/data/mapping/package-info.java +++ b/src/main/java/org/springframework/data/mapping/package-info.java @@ -1,5 +1,5 @@ /** * Base package for the mapping subsystem. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.mapping; diff --git a/src/main/java/org/springframework/data/projection/DefaultMethodInvokingMethodInterceptor.java b/src/main/java/org/springframework/data/projection/DefaultMethodInvokingMethodInterceptor.java index e460028702..7a5bef7666 100644 --- a/src/main/java/org/springframework/data/projection/DefaultMethodInvokingMethodInterceptor.java +++ b/src/main/java/org/springframework/data/projection/DefaultMethodInvokingMethodInterceptor.java @@ -27,8 +27,9 @@ import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; +import org.jspecify.annotations.Nullable; + import org.springframework.aop.ProxyMethodInvocation; -import org.springframework.lang.Nullable; import org.springframework.util.ReflectionUtils; /** @@ -59,9 +60,8 @@ public static boolean hasDefaultMethods(Class interfaceClass) { return atomicBoolean.get(); } - @Nullable @Override - public Object invoke(MethodInvocation invocation) throws Throwable { + public @Nullable Object invoke(MethodInvocation invocation) throws Throwable { Method method = invocation.getMethod(); diff --git a/src/main/java/org/springframework/data/projection/EntityProjection.java b/src/main/java/org/springframework/data/projection/EntityProjection.java index 28c98d2fcd..4542644e35 100644 --- a/src/main/java/org/springframework/data/projection/EntityProjection.java +++ b/src/main/java/org/springframework/data/projection/EntityProjection.java @@ -23,10 +23,11 @@ import java.util.Map; import java.util.function.Consumer; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.PropertyPath; import org.springframework.data.util.Streamable; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; /** * Descriptor for a top-level mapped type representing a view onto a domain type structure. The view may exactly match @@ -182,8 +183,7 @@ public boolean isClosedProjection() { * @param name the property name. * @return the type view, if the property is known; {@code null} otherwise. */ - @Nullable - public EntityProjection findProperty(String name) { + public @Nullable EntityProjection findProperty(String name) { for (PropertyProjection descriptor : properties) { diff --git a/src/main/java/org/springframework/data/projection/EntityProjectionIntrospector.java b/src/main/java/org/springframework/data/projection/EntityProjectionIntrospector.java index 1d8f01c426..52392601f1 100644 --- a/src/main/java/org/springframework/data/projection/EntityProjectionIntrospector.java +++ b/src/main/java/org/springframework/data/projection/EntityProjectionIntrospector.java @@ -22,13 +22,14 @@ import java.util.List; import java.util.Set; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.PropertyPath; import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.projection.EntityProjection.ProjectionType; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** diff --git a/src/main/java/org/springframework/data/projection/MapAccessingMethodInterceptor.java b/src/main/java/org/springframework/data/projection/MapAccessingMethodInterceptor.java index b28567dda3..04f44c7a6c 100644 --- a/src/main/java/org/springframework/data/projection/MapAccessingMethodInterceptor.java +++ b/src/main/java/org/springframework/data/projection/MapAccessingMethodInterceptor.java @@ -20,8 +20,8 @@ import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; +import org.jspecify.annotations.Nullable; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ReflectionUtils; @@ -43,9 +43,8 @@ class MapAccessingMethodInterceptor implements MethodInterceptor { this.map = map; } - @Nullable @Override - public Object invoke(@SuppressWarnings("null") MethodInvocation invocation) throws Throwable { + public @Nullable Object invoke(@SuppressWarnings("null") MethodInvocation invocation) throws Throwable { Method method = invocation.getMethod(); diff --git a/src/main/java/org/springframework/data/projection/ProjectingMethodInterceptor.java b/src/main/java/org/springframework/data/projection/ProjectingMethodInterceptor.java index a6ea4f4e81..fa1b6aa8bf 100644 --- a/src/main/java/org/springframework/data/projection/ProjectingMethodInterceptor.java +++ b/src/main/java/org/springframework/data/projection/ProjectingMethodInterceptor.java @@ -25,14 +25,15 @@ import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + import org.springframework.core.CollectionFactory; import org.springframework.core.convert.ConversionService; import org.springframework.data.util.NullableWrapper; import org.springframework.data.util.NullableWrapperConverters; import org.springframework.data.util.TypeInformation; import org.springframework.lang.Contract; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; @@ -61,9 +62,8 @@ class ProjectingMethodInterceptor implements MethodInterceptor { this.conversionService = conversionService; } - @Nullable @Override - public Object invoke(@SuppressWarnings("null") @NonNull MethodInvocation invocation) throws Throwable { + public @Nullable Object invoke(@SuppressWarnings("null") @NonNull MethodInvocation invocation) throws Throwable { TypeInformation type = TypeInformation.fromReturnTypeOf(invocation.getMethod()); TypeInformation resultType = type; @@ -87,8 +87,7 @@ public Object invoke(@SuppressWarnings("null") @NonNull MethodInvocation invocat return result; } - @Nullable - protected Object potentiallyConvertResult(TypeInformation type, @Nullable Object result) { + protected @Nullable Object potentiallyConvertResult(TypeInformation type, @Nullable Object result) { if (result == null) { return null; @@ -158,9 +157,8 @@ private Map projectMapValues(Map sources, TypeInformation< return result; } - @Nullable @Contract("null, _ -> null") - private Object getProjection(@Nullable Object result, Class returnType) { + private @Nullable Object getProjection(@Nullable Object result, Class returnType) { return (result == null) || ClassUtils.isAssignable(returnType, result.getClass()) ? result : factory.createProjection(returnType, result); } diff --git a/src/main/java/org/springframework/data/projection/ProjectionFactory.java b/src/main/java/org/springframework/data/projection/ProjectionFactory.java index 08a5400f19..836c854577 100644 --- a/src/main/java/org/springframework/data/projection/ProjectionFactory.java +++ b/src/main/java/org/springframework/data/projection/ProjectionFactory.java @@ -15,7 +15,7 @@ */ package org.springframework.data.projection; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** * A factory to create projecting instances for other objects usually used to allow easy creation of representation @@ -43,8 +43,7 @@ public interface ProjectionFactory { * @param source can be {@literal null}. * @return */ - @Nullable - default T createNullableProjection(Class projectionType, @Nullable Object source) { + default @Nullable T createNullableProjection(Class projectionType, @Nullable Object source) { return source == null ? null : createProjection(projectionType, source); } diff --git a/src/main/java/org/springframework/data/projection/PropertyAccessingMethodInterceptor.java b/src/main/java/org/springframework/data/projection/PropertyAccessingMethodInterceptor.java index 4c793e3b1c..7fbeb77881 100644 --- a/src/main/java/org/springframework/data/projection/PropertyAccessingMethodInterceptor.java +++ b/src/main/java/org/springframework/data/projection/PropertyAccessingMethodInterceptor.java @@ -20,12 +20,12 @@ import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; +import org.jspecify.annotations.Nullable; import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanWrapper; import org.springframework.core.BridgeMethodResolver; import org.springframework.data.util.DirectFieldAccessFallbackBeanWrapper; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ReflectionUtils; @@ -53,9 +53,8 @@ public PropertyAccessingMethodInterceptor(Object target) { this.target = new DirectFieldAccessFallbackBeanWrapper(target); } - @Nullable @Override - public Object invoke(@SuppressWarnings("null") MethodInvocation invocation) throws Throwable { + public @Nullable Object invoke(@SuppressWarnings("null") MethodInvocation invocation) throws Throwable { if (ReflectionUtils.isObjectMethod(invocation.getMethod())) { return invocation.proceed(); diff --git a/src/main/java/org/springframework/data/projection/ProxyProjectionFactory.java b/src/main/java/org/springframework/data/projection/ProxyProjectionFactory.java index b52b2a9aa5..1efd20f125 100644 --- a/src/main/java/org/springframework/data/projection/ProxyProjectionFactory.java +++ b/src/main/java/org/springframework/data/projection/ProxyProjectionFactory.java @@ -24,6 +24,8 @@ import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; +import org.jspecify.annotations.Nullable; + import org.springframework.aop.framework.Advised; import org.springframework.aop.framework.ProxyFactory; import org.springframework.beans.factory.BeanClassLoaderAware; @@ -32,7 +34,6 @@ import org.springframework.data.convert.Jsr310Converters; import org.springframework.data.util.Lazy; import org.springframework.data.util.NullableWrapperConverters; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -230,9 +231,8 @@ private record TargetAwareMethodInterceptor(Class targetType) implements Meth Assert.notNull(targetType, "Target type must not be null"); } - @Nullable @Override - public Object invoke(@SuppressWarnings("null") MethodInvocation invocation) throws Throwable { + public @Nullable Object invoke(@SuppressWarnings("null") MethodInvocation invocation) throws Throwable { if (invocation.getMethod().equals(GET_TARGET_CLASS_METHOD)) { return targetType; diff --git a/src/main/java/org/springframework/data/projection/SpelAwareProxyProjectionFactory.java b/src/main/java/org/springframework/data/projection/SpelAwareProxyProjectionFactory.java index c79fbc4dd5..92fccd6035 100644 --- a/src/main/java/org/springframework/data/projection/SpelAwareProxyProjectionFactory.java +++ b/src/main/java/org/springframework/data/projection/SpelAwareProxyProjectionFactory.java @@ -21,6 +21,7 @@ import java.util.concurrent.ConcurrentHashMap; import org.aopalliance.intercept.MethodInterceptor; +import org.jspecify.annotations.Nullable; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; @@ -30,7 +31,6 @@ import org.springframework.data.util.AnnotationDetectionMethodCallback; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ReflectionUtils; diff --git a/src/main/java/org/springframework/data/projection/SpelEvaluatingMethodInterceptor.java b/src/main/java/org/springframework/data/projection/SpelEvaluatingMethodInterceptor.java index e1e1d371e3..f677812eeb 100644 --- a/src/main/java/org/springframework/data/projection/SpelEvaluatingMethodInterceptor.java +++ b/src/main/java/org/springframework/data/projection/SpelEvaluatingMethodInterceptor.java @@ -23,6 +23,7 @@ import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.annotation.Value; @@ -35,7 +36,6 @@ import org.springframework.expression.ParserContext; import org.springframework.expression.common.TemplateParserContext; import org.springframework.expression.spel.support.StandardEvaluationContext; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; @@ -128,9 +128,8 @@ private static Map potentiallyCreateExpressionsForMethodsOn return Collections.unmodifiableMap(expressions); } - @Nullable @Override - public Object invoke(@SuppressWarnings("null") MethodInvocation invocation) throws Throwable { + public @Nullable Object invoke(@SuppressWarnings("null") MethodInvocation invocation) throws Throwable { Expression expression = expressions.get(invocation.getMethod().hashCode()); diff --git a/src/main/java/org/springframework/data/projection/TargetAware.java b/src/main/java/org/springframework/data/projection/TargetAware.java index a091eff7a9..1c217861f5 100644 --- a/src/main/java/org/springframework/data/projection/TargetAware.java +++ b/src/main/java/org/springframework/data/projection/TargetAware.java @@ -15,9 +15,10 @@ */ package org.springframework.data.projection; +import org.jspecify.annotations.Nullable; + import org.springframework.aop.RawTargetAccess; import org.springframework.core.DecoratingProxy; -import org.springframework.lang.Nullable; import com.fasterxml.jackson.annotation.JsonIgnore; diff --git a/src/main/java/org/springframework/data/projection/package-info.java b/src/main/java/org/springframework/data/projection/package-info.java index 75a3a75fa1..db805a7101 100644 --- a/src/main/java/org/springframework/data/projection/package-info.java +++ b/src/main/java/org/springframework/data/projection/package-info.java @@ -1,5 +1,5 @@ /** * Projection subsystem. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.projection; diff --git a/src/main/java/org/springframework/data/querydsl/QuerydslUtils.java b/src/main/java/org/springframework/data/querydsl/QuerydslUtils.java index fdfb08a19a..d6032e5712 100644 --- a/src/main/java/org/springframework/data/querydsl/QuerydslUtils.java +++ b/src/main/java/org/springframework/data/querydsl/QuerydslUtils.java @@ -15,7 +15,8 @@ */ package org.springframework.data.querydsl; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; + import org.springframework.util.StringUtils; import com.querydsl.core.types.Path; diff --git a/src/main/java/org/springframework/data/querydsl/aot/QuerydslHints.java b/src/main/java/org/springframework/data/querydsl/aot/QuerydslHints.java index aa362f6ee1..46e225cb6b 100644 --- a/src/main/java/org/springframework/data/querydsl/aot/QuerydslHints.java +++ b/src/main/java/org/springframework/data/querydsl/aot/QuerydslHints.java @@ -17,6 +17,8 @@ import java.util.Arrays; +import org.jspecify.annotations.Nullable; + import org.springframework.aot.hint.MemberCategory; import org.springframework.aot.hint.RuntimeHints; import org.springframework.aot.hint.RuntimeHintsRegistrar; @@ -25,7 +27,6 @@ import org.springframework.data.querydsl.QuerydslUtils; import org.springframework.data.querydsl.ReactiveQuerydslPredicateExecutor; import org.springframework.data.util.ReactiveWrappers; -import org.springframework.lang.Nullable; import com.querydsl.core.types.Predicate; diff --git a/src/main/java/org/springframework/data/querydsl/aot/package-info.java b/src/main/java/org/springframework/data/querydsl/aot/package-info.java index 664427e22a..54492cb511 100644 --- a/src/main/java/org/springframework/data/querydsl/aot/package-info.java +++ b/src/main/java/org/springframework/data/querydsl/aot/package-info.java @@ -1,5 +1,5 @@ /** * Querydsl AOT hints. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.querydsl.aot; diff --git a/src/main/java/org/springframework/data/querydsl/binding/PathInformation.java b/src/main/java/org/springframework/data/querydsl/binding/PathInformation.java index 008e0f856d..175397a769 100644 --- a/src/main/java/org/springframework/data/querydsl/binding/PathInformation.java +++ b/src/main/java/org/springframework/data/querydsl/binding/PathInformation.java @@ -17,9 +17,10 @@ import java.beans.PropertyDescriptor; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.PropertyPath; import org.springframework.data.querydsl.EntityPathResolver; -import org.springframework.lang.Nullable; import com.querydsl.core.types.Path; diff --git a/src/main/java/org/springframework/data/querydsl/binding/PropertyPathInformation.java b/src/main/java/org/springframework/data/querydsl/binding/PropertyPathInformation.java index 308ad1a314..719a4ba09f 100644 --- a/src/main/java/org/springframework/data/querydsl/binding/PropertyPathInformation.java +++ b/src/main/java/org/springframework/data/querydsl/binding/PropertyPathInformation.java @@ -18,11 +18,12 @@ import java.beans.PropertyDescriptor; import java.lang.reflect.Field; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.BeanUtils; import org.springframework.data.mapping.PropertyPath; import org.springframework.data.querydsl.EntityPathResolver; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; import org.springframework.util.ObjectUtils; import org.springframework.util.ReflectionUtils; @@ -85,9 +86,8 @@ public String getLeafProperty() { return path.getLeafProperty().getSegment(); } - @Nullable @Override - public PropertyDescriptor getLeafPropertyDescriptor() { + public @Nullable PropertyDescriptor getLeafPropertyDescriptor() { return BeanUtils.getPropertyDescriptor(getLeafParentType(), getLeafProperty()); } @@ -101,7 +101,7 @@ public Path reifyPath(EntityPathResolver resolver) { return reifyPath(resolver, path, null); } - @SuppressWarnings("ConstantConditions") + @SuppressWarnings({ "ConstantConditions", "NullAway" }) private static Path reifyPath(EntityPathResolver resolver, PropertyPath path, @Nullable Path base) { if (base instanceof CollectionPathBase) { @@ -111,8 +111,18 @@ private static Path reifyPath(EntityPathResolver resolver, PropertyPath path, Path entityPath = base != null ? base : resolver.createPath(path.getOwningType().getType()); Field field = ReflectionUtils.findField(entityPath.getClass(), path.getSegment()); + if (field == null) { + throw new IllegalArgumentException("Unable to find field describing property '%s' in '%s'" + .formatted(path.getSegment(), entityPath.getClass().getName())); + } + Object value = ReflectionUtils.getField(field, entityPath); + if (value == null) { + throw new IllegalArgumentException( + "Model describing '%s' in '%s' returned null".formatted(path.getSegment(), entityPath.getClass().getName())); + } + if (path.hasNext()) { return reifyPath(resolver, path.next(), (Path) value); } diff --git a/src/main/java/org/springframework/data/querydsl/binding/QuerydslBindings.java b/src/main/java/org/springframework/data/querydsl/binding/QuerydslBindings.java index b5b9bd76c3..683b0a037f 100644 --- a/src/main/java/org/springframework/data/querydsl/binding/QuerydslBindings.java +++ b/src/main/java/org/springframework/data/querydsl/binding/QuerydslBindings.java @@ -23,11 +23,12 @@ import java.util.Optional; import java.util.Set; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.PropertyPath; import org.springframework.data.mapping.PropertyReferenceException; import org.springframework.data.util.Optionals; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; diff --git a/src/main/java/org/springframework/data/querydsl/binding/QuerydslPathInformation.java b/src/main/java/org/springframework/data/querydsl/binding/QuerydslPathInformation.java index e82cbbf135..f8578f13fc 100644 --- a/src/main/java/org/springframework/data/querydsl/binding/QuerydslPathInformation.java +++ b/src/main/java/org/springframework/data/querydsl/binding/QuerydslPathInformation.java @@ -17,10 +17,11 @@ import java.beans.PropertyDescriptor; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.BeanUtils; import org.springframework.data.querydsl.EntityPathResolver; import org.springframework.data.querydsl.QuerydslUtils; -import org.springframework.lang.Nullable; import org.springframework.util.ObjectUtils; import com.querydsl.core.types.Path; @@ -72,9 +73,8 @@ public String getLeafProperty() { return path.getMetadata().getElement().toString(); } - @Nullable @Override - public PropertyDescriptor getLeafPropertyDescriptor() { + public @Nullable PropertyDescriptor getLeafPropertyDescriptor() { return BeanUtils.getPropertyDescriptor(getLeafParentType(), getLeafProperty()); } diff --git a/src/main/java/org/springframework/data/querydsl/binding/QuerydslPredicateBuilder.java b/src/main/java/org/springframework/data/querydsl/binding/QuerydslPredicateBuilder.java index 5a95aad97b..7607b80d1d 100644 --- a/src/main/java/org/springframework/data/querydsl/binding/QuerydslPredicateBuilder.java +++ b/src/main/java/org/springframework/data/querydsl/binding/QuerydslPredicateBuilder.java @@ -24,6 +24,8 @@ import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.PropertyValues; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.Property; @@ -31,7 +33,6 @@ import org.springframework.data.mapping.PropertyPath; import org.springframework.data.querydsl.EntityPathResolver; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.MultiValueMap; @@ -189,8 +190,7 @@ private Collection convertToPropertyPathSpecificType(List source, Pat return target; } - @Nullable - private Object getValue(TypeDescriptor targetType, Object value) { + private @Nullable Object getValue(TypeDescriptor targetType, Object value) { if (ClassUtils.isAssignableValue(targetType.getType(), value)) { return value; diff --git a/src/main/java/org/springframework/data/querydsl/binding/SingleValueBinding.java b/src/main/java/org/springframework/data/querydsl/binding/SingleValueBinding.java index 972ab89b28..66f01c0c46 100644 --- a/src/main/java/org/springframework/data/querydsl/binding/SingleValueBinding.java +++ b/src/main/java/org/springframework/data/querydsl/binding/SingleValueBinding.java @@ -15,7 +15,7 @@ */ package org.springframework.data.querydsl.binding; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; import com.querydsl.core.types.Path; import com.querydsl.core.types.Predicate; diff --git a/src/main/java/org/springframework/data/querydsl/binding/package-info.java b/src/main/java/org/springframework/data/querydsl/binding/package-info.java index 414d2a8b9f..a7512e502a 100644 --- a/src/main/java/org/springframework/data/querydsl/binding/package-info.java +++ b/src/main/java/org/springframework/data/querydsl/binding/package-info.java @@ -1,5 +1,5 @@ /** * Base classes to implement CDI support for repositories. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.querydsl.binding; diff --git a/src/main/java/org/springframework/data/querydsl/package-info.java b/src/main/java/org/springframework/data/querydsl/package-info.java index 3083151776..9acb2a1861 100644 --- a/src/main/java/org/springframework/data/querydsl/package-info.java +++ b/src/main/java/org/springframework/data/querydsl/package-info.java @@ -3,5 +3,5 @@ * * @see http://www.querydsl.com */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.querydsl; diff --git a/src/main/java/org/springframework/data/repository/aot/hint/RepositoryRuntimeHints.java b/src/main/java/org/springframework/data/repository/aot/hint/RepositoryRuntimeHints.java index 72531484f6..6b660c5cb5 100644 --- a/src/main/java/org/springframework/data/repository/aot/hint/RepositoryRuntimeHints.java +++ b/src/main/java/org/springframework/data/repository/aot/hint/RepositoryRuntimeHints.java @@ -18,6 +18,8 @@ import java.util.Arrays; import java.util.Properties; +import org.jspecify.annotations.Nullable; + import org.springframework.aop.SpringProxy; import org.springframework.aop.framework.Advised; import org.springframework.aot.hint.MemberCategory; @@ -40,7 +42,6 @@ import org.springframework.data.repository.query.QueryByExampleExecutor; import org.springframework.data.repository.query.ReactiveQueryByExampleExecutor; import org.springframework.data.util.ReactiveWrappers; -import org.springframework.lang.Nullable; /** * {@link RuntimeHintsRegistrar} holding required hints to bootstrap data repositories.
diff --git a/src/main/java/org/springframework/data/repository/aot/hint/package-info.java b/src/main/java/org/springframework/data/repository/aot/hint/package-info.java index ec11352699..ef81328964 100644 --- a/src/main/java/org/springframework/data/repository/aot/hint/package-info.java +++ b/src/main/java/org/springframework/data/repository/aot/hint/package-info.java @@ -1,5 +1,5 @@ /** * Predefined Runtime Hints. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.repository.aot.hint; diff --git a/src/main/java/org/springframework/data/repository/cdi/CdiRepositoryBean.java b/src/main/java/org/springframework/data/repository/cdi/CdiRepositoryBean.java index 3cc608c8e6..1bb349340d 100644 --- a/src/main/java/org/springframework/data/repository/cdi/CdiRepositoryBean.java +++ b/src/main/java/org/springframework/data/repository/cdi/CdiRepositoryBean.java @@ -39,6 +39,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.log.LogMessage; @@ -48,7 +49,6 @@ import org.springframework.data.repository.core.support.RepositoryFactorySupport; import org.springframework.data.repository.core.support.RepositoryFragment; import org.springframework.data.util.Optionals; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -208,7 +208,8 @@ public final T create(@SuppressWarnings("null") CreationalContext creationalC T repoInstance = this.repoInstance; if (repoInstance != null) { - logger.debug(LogMessage.format("Returning eagerly created CDI repository instance for %s.", repositoryType.getName())); + logger.debug( + LogMessage.format("Returning eagerly created CDI repository instance for %s.", repositoryType.getName())); return repoInstance; } @@ -351,7 +352,7 @@ private List> findRepositoryFragments(Class repositoryT Stream fragmentConfigurations = context .getRepositoryFragments(cdiRepositoryConfiguration, repositoryType); - return fragmentConfigurations.flatMap(it -> { + return fragmentConfigurations.filter(it -> it.getInterfaceName() != null).flatMap(it -> { Class interfaceClass = (Class) lookupFragmentInterface(repositoryType, it.getInterfaceName()); Class implementationClass = context.loadClass(it.getClassName()); @@ -368,8 +369,8 @@ private static Class lookupFragmentInterface(Class repositoryType, String return Arrays.stream(repositoryType.getInterfaces()) // .filter(it -> it.getName().equals(interfaceName)) // .findFirst() // - .orElseThrow(() -> new IllegalArgumentException(String.format("Did not find type %s in %s", interfaceName, - Arrays.asList(repositoryType.getInterfaces())))); + .orElseThrow(() -> new IllegalArgumentException( + String.format("Did not find type %s in %s", interfaceName, Arrays.asList(repositoryType.getInterfaces())))); } /** diff --git a/src/main/java/org/springframework/data/repository/cdi/CdiRepositoryContext.java b/src/main/java/org/springframework/data/repository/cdi/CdiRepositoryContext.java index 5950a9321e..c408afb984 100644 --- a/src/main/java/org/springframework/data/repository/cdi/CdiRepositoryContext.java +++ b/src/main/java/org/springframework/data/repository/cdi/CdiRepositoryContext.java @@ -20,6 +20,8 @@ import java.util.Optional; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.core.env.StandardEnvironment; import org.springframework.core.io.ResourceLoader; @@ -34,7 +36,6 @@ import org.springframework.data.repository.config.RepositoryFragmentConfiguration; import org.springframework.data.util.Optionals; import org.springframework.data.util.Streamable; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -151,8 +152,7 @@ private Optional detectRepositoryFragmentConfig return beanDefinition.map(bd -> new RepositoryFragmentConfiguration(fragmentInterfaceName, bd)); } - @Nullable - private Class loadBeanClass(AbstractBeanDefinition definition) { + private @Nullable Class loadBeanClass(AbstractBeanDefinition definition) { String beanClassName = definition.getBeanClassName(); diff --git a/src/main/java/org/springframework/data/repository/cdi/package-info.java b/src/main/java/org/springframework/data/repository/cdi/package-info.java index 69bebbc537..1be95af5be 100644 --- a/src/main/java/org/springframework/data/repository/cdi/package-info.java +++ b/src/main/java/org/springframework/data/repository/cdi/package-info.java @@ -1,5 +1,5 @@ /** * Base classes to implement CDI support for repositories. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.repository.cdi; diff --git a/src/main/java/org/springframework/data/repository/config/AnnotationRepositoryConfigurationSource.java b/src/main/java/org/springframework/data/repository/config/AnnotationRepositoryConfigurationSource.java index 753a93ffa5..f143cbb2a1 100644 --- a/src/main/java/org/springframework/data/repository/config/AnnotationRepositoryConfigurationSource.java +++ b/src/main/java/org/springframework/data/repository/config/AnnotationRepositoryConfigurationSource.java @@ -24,6 +24,9 @@ import java.util.function.Function; import java.util.stream.Stream; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanNameGenerator; @@ -37,8 +40,6 @@ import org.springframework.core.type.filter.TypeFilter; import org.springframework.data.config.ConfigurationUtils; import org.springframework.data.util.Streamable; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; @@ -333,9 +334,8 @@ private static BeanNameGenerator defaultBeanNameGenerator(@Nullable BeanNameGene * configured as String instead of a Class instance. * @return the bean name generator or {@literal null} if not configured. */ - @Nullable @SuppressWarnings("unchecked") - private static BeanNameGenerator getConfiguredBeanNameGenerator(AnnotationMetadata metadata, + private static @Nullable BeanNameGenerator getConfiguredBeanNameGenerator(AnnotationMetadata metadata, Class annotation, ClassLoader beanClassLoader) { Map annotationAttributes = metadata.getAnnotationAttributes(annotation.getName()); diff --git a/src/main/java/org/springframework/data/repository/config/DefaultAotRepositoryContext.java b/src/main/java/org/springframework/data/repository/config/DefaultAotRepositoryContext.java index 74e8ad1c17..3c6b8cccbb 100644 --- a/src/main/java/org/springframework/data/repository/config/DefaultAotRepositoryContext.java +++ b/src/main/java/org/springframework/data/repository/config/DefaultAotRepositoryContext.java @@ -16,10 +16,13 @@ package org.springframework.data.repository.config; import java.lang.annotation.Annotation; +import java.util.Collections; import java.util.LinkedHashSet; import java.util.Set; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.core.annotation.MergedAnnotation; import org.springframework.data.aot.AotContext; @@ -36,16 +39,17 @@ * @see AotRepositoryContext * @since 3.0 */ +@SuppressWarnings("NullAway") // TODO class DefaultAotRepositoryContext implements AotRepositoryContext { private final AotContext aotContext; private final Lazy>> resolvedAnnotations = Lazy.of(this::discoverAnnotations); private final Lazy>> managedTypes = Lazy.of(this::discoverTypes); - private RepositoryInformation repositoryInformation; - private Set basePackages; - private Set> identifyingAnnotations; - private String beanName; + private @Nullable RepositoryInformation repositoryInformation; + private @Nullable Set basePackages; + private @Nullable Set> identifyingAnnotations; + private @Nullable String beanName; public DefaultAotRepositoryContext(AotContext aotContext) { this.aotContext = aotContext; @@ -62,7 +66,7 @@ public ConfigurableListableBeanFactory getBeanFactory() { @Override public Set getBasePackages() { - return basePackages; + return basePackages == null ? Collections.emptySet() : basePackages; } public void setBasePackages(Set basePackages) { @@ -80,7 +84,7 @@ public void setBeanName(String beanName) { @Override public Set> getIdentifyingAnnotations() { - return identifyingAnnotations; + return identifyingAnnotations == null ? Collections.emptySet() : identifyingAnnotations; } public void setIdentifyingAnnotations(Set> identifyingAnnotations) { @@ -122,18 +126,24 @@ protected Set> discoverAnnotations() { .flatMap(type -> TypeUtils.resolveUsedAnnotations(type).stream()) .collect(Collectors.toCollection(LinkedHashSet::new)); - annotations.addAll(TypeUtils.resolveUsedAnnotations(repositoryInformation.getRepositoryInterface())); + if (repositoryInformation != null) { + annotations.addAll(TypeUtils.resolveUsedAnnotations(repositoryInformation.getRepositoryInterface())); + } return annotations; } protected Set> discoverTypes() { - Set> types = new LinkedHashSet<>(TypeCollector.inspect(repositoryInformation.getDomainType()).list()); + Set> types = new LinkedHashSet<>(); - repositoryInformation.getQueryMethods() - .flatMap(it -> TypeUtils.resolveTypesInSignature(repositoryInformation.getRepositoryInterface(), it).stream()) - .flatMap(it -> TypeCollector.inspect(it).list().stream()).forEach(types::add); + if (repositoryInformation != null) { + types.addAll(TypeCollector.inspect(repositoryInformation.getDomainType()).list()); + + repositoryInformation.getQueryMethods() + .flatMap(it -> TypeUtils.resolveTypesInSignature(repositoryInformation.getRepositoryInterface(), it).stream()) + .flatMap(it -> TypeCollector.inspect(it).list().stream()).forEach(types::add); + } if (!getIdentifyingAnnotations().isEmpty()) { diff --git a/src/main/java/org/springframework/data/repository/config/DefaultRepositoryConfiguration.java b/src/main/java/org/springframework/data/repository/config/DefaultRepositoryConfiguration.java index a18af66eb4..1ebdb1c907 100644 --- a/src/main/java/org/springframework/data/repository/config/DefaultRepositoryConfiguration.java +++ b/src/main/java/org/springframework/data/repository/config/DefaultRepositoryConfiguration.java @@ -17,6 +17,8 @@ import java.util.Optional; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.filter.TypeFilter; @@ -24,7 +26,6 @@ import org.springframework.data.repository.query.QueryLookupStrategy.Key; import org.springframework.data.util.Lazy; import org.springframework.data.util.Streamable; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; @@ -101,9 +102,8 @@ public String getImplementationBeanName() { return beanName.get() + configurationSource.getRepositoryImplementationPostfix().orElse("Impl"); } - @Nullable @Override - public Object getSource() { + public @Nullable Object getSource() { return configurationSource.getSource(); } @@ -161,7 +161,7 @@ public ImplementationLookupConfiguration toLookupConfiguration(MetadataReaderFac } @Override - @org.springframework.lang.NonNull + @org.jspecify.annotations.NonNull public String getResourceDescription() { return String.format("%s defined in %s", getRepositoryInterface(), configurationSource.getResourceDescription()); } diff --git a/src/main/java/org/springframework/data/repository/config/NamedQueriesBeanDefinitionBuilder.java b/src/main/java/org/springframework/data/repository/config/NamedQueriesBeanDefinitionBuilder.java index 7b6da6bea7..9bb0706d15 100644 --- a/src/main/java/org/springframework/data/repository/config/NamedQueriesBeanDefinitionBuilder.java +++ b/src/main/java/org/springframework/data/repository/config/NamedQueriesBeanDefinitionBuilder.java @@ -15,11 +15,12 @@ */ package org.springframework.data.repository.config; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.data.repository.core.NamedQueries; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -32,7 +33,7 @@ public class NamedQueriesBeanDefinitionBuilder { private final String defaultLocation; - private String locations; + private @Nullable String locations; /** * Creates a new {@link NamedQueriesBeanDefinitionBuilder} using the given default location. diff --git a/src/main/java/org/springframework/data/repository/config/NamedQueriesBeanDefinitionParser.java b/src/main/java/org/springframework/data/repository/config/NamedQueriesBeanDefinitionParser.java index 0cdde07032..3dfb4ff167 100644 --- a/src/main/java/org/springframework/data/repository/config/NamedQueriesBeanDefinitionParser.java +++ b/src/main/java/org/springframework/data/repository/config/NamedQueriesBeanDefinitionParser.java @@ -17,13 +17,14 @@ import java.util.Properties; +import org.jspecify.annotations.NonNull; + import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.data.repository.core.NamedQueries; -import org.springframework.lang.NonNull; import org.springframework.util.Assert; import org.springframework.util.StringUtils; diff --git a/src/main/java/org/springframework/data/repository/config/PropertiesBasedNamedQueriesFactoryBean.java b/src/main/java/org/springframework/data/repository/config/PropertiesBasedNamedQueriesFactoryBean.java index 9036af9a38..e5921a38c9 100644 --- a/src/main/java/org/springframework/data/repository/config/PropertiesBasedNamedQueriesFactoryBean.java +++ b/src/main/java/org/springframework/data/repository/config/PropertiesBasedNamedQueriesFactoryBean.java @@ -18,11 +18,12 @@ import java.io.IOException; import java.util.Properties; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.core.io.support.PropertiesLoaderSupport; import org.springframework.data.repository.core.support.PropertiesBasedNamedQueries; -import org.springframework.lang.Nullable; /** * Factory bean to create {@link PropertiesBasedNamedQueries}. @@ -66,8 +67,7 @@ public void afterPropertiesSet() throws IOException { } @Override - @Nullable - public PropertiesBasedNamedQueries getObject() throws IOException { + public @Nullable PropertiesBasedNamedQueries getObject() throws IOException { if (this.singleton) { return this.singletonInstance; } else { diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionBuilder.java b/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionBuilder.java index 29b759407d..ada478eb9b 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionBuilder.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionBuilder.java @@ -29,6 +29,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition; import org.springframework.beans.factory.config.BeanDefinition; @@ -47,7 +48,6 @@ import org.springframework.data.repository.core.support.RepositoryFragment; import org.springframework.data.repository.core.support.RepositoryFragmentsFactoryBean; import org.springframework.data.util.Optionals; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; @@ -149,6 +149,7 @@ public BeanDefinitionBuilder build(RepositoryConfiguration configuration) { // TODO: merge that with the one that creates the BD // TODO: Add support for fragments discovered from spring.factories + @SuppressWarnings("NullAway") RepositoryConfigurationAdapter buildMetadata(RepositoryConfiguration configuration) { ImplementationDetectionConfiguration config = configuration @@ -165,6 +166,7 @@ RepositoryConfigurationAdapter buildMetadata(RepositoryConfiguration confi Optional beanDefinition = implementationDetector.detectCustomImplementation(lookup); if (beanDefinition.isPresent()) { + repositoryFragmentConfigurationStream = new ArrayList<>(1); List interfaceNames = fragmentMetadata.getFragmentInterfaces(configuration.getRepositoryInterface()) diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionParser.java b/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionParser.java index 168e28c8c1..dd6103173a 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionParser.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionParser.java @@ -17,6 +17,8 @@ import static org.springframework.beans.factory.support.BeanDefinitionReaderUtils.*; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.parsing.BeanComponentDefinition; import org.springframework.beans.factory.parsing.ReaderContext; @@ -27,7 +29,6 @@ import org.springframework.core.env.Environment; import org.springframework.core.io.ResourceLoader; import org.springframework.data.config.ConfigurationUtils; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.w3c.dom.Element; @@ -84,6 +85,7 @@ public BeanDefinition parse(Element element, ParserContext parser) { return null; } + @SuppressWarnings("NullAway") private void handleError(Exception e, Element source, ReaderContext reader) { reader.error(e.getMessage(), reader.extractSource(source), e); } diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionReader.java b/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionReader.java index c733cbf1bd..0ac1ae991a 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionReader.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionReader.java @@ -55,9 +55,11 @@ private static Supplier>> fragments(RepositoryC List> fragments = new ArrayList<>(1); - // TODO: Implemented accepts an Object, not a class. fragments.add(RepositoryFragment.implemented(forName(it.getClassName(), beanFactory))); - fragments.add(RepositoryFragment.structural(forName(it.getInterfaceName(), beanFactory))); + + if (it.getInterfaceName() != null) { + fragments.add(RepositoryFragment.structural(forName(it.getInterfaceName(), beanFactory))); + } return fragments.stream(); }).collect(Collectors.toList()); @@ -72,10 +74,7 @@ private static Supplier> repositoryBaseClass(RepositoryConfiguration me ConfigurableListableBeanFactory beanFactory) { return Lazy.of(() -> (Class) metadata.getRepositoryBaseClassName().map(it -> forName(it.toString(), beanFactory)) - .orElseGet(() -> { - // TODO: retrieve the default without loading the actual RepositoryBeanFactory - return Object.class; - })); + .orElse(Object.class)); } private static Supplier metadataSupplier( diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionRegistrarSupport.java b/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionRegistrarSupport.java index 8acf8dc5a1..837dd081d9 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionRegistrarSupport.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionRegistrarSupport.java @@ -17,6 +17,8 @@ import java.lang.annotation.Annotation; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanNameGenerator; @@ -37,8 +39,8 @@ public abstract class RepositoryBeanDefinitionRegistrarSupport implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware { - private ResourceLoader resourceLoader; - private Environment environment; + private @Nullable ResourceLoader resourceLoader; + private @Nullable Environment environment; @Override public void setResourceLoader(ResourceLoader resourceLoader) { @@ -75,6 +77,7 @@ public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionR Assert.notNull(metadata, "AnnotationMetadata must not be null"); Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); Assert.notNull(resourceLoader, "ResourceLoader must not be null"); + Assert.state(environment != null, "Environment must not be null"); // Guard against calls for sub-classes if (metadata.getAnnotationAttributes(getAnnotation().getName()) == null) { diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryComponentProvider.java b/src/main/java/org/springframework/data/repository/config/RepositoryComponentProvider.java index c298061c83..c7538b3ff6 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryComponentProvider.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryComponentProvider.java @@ -20,6 +20,9 @@ import java.util.List; import java.util.Set; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionRegistry; @@ -33,8 +36,6 @@ import org.springframework.data.repository.NoRepositoryBean; import org.springframework.data.repository.Repository; import org.springframework.data.repository.RepositoryDefinition; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryConfiguration.java b/src/main/java/org/springframework/data/repository/config/RepositoryConfiguration.java index 874f965e4b..0a42dcd108 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryConfiguration.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryConfiguration.java @@ -17,11 +17,12 @@ import java.util.Optional; +import org.jspecify.annotations.Nullable; + import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.filter.TypeFilter; import org.springframework.data.repository.query.QueryLookupStrategy; import org.springframework.data.util.Streamable; -import org.springframework.lang.Nullable; /** * Configuration information for a single repository instance. diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationAdapter.java b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationAdapter.java index f455187b45..e8bdaee78f 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationAdapter.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationAdapter.java @@ -18,10 +18,11 @@ import java.util.List; import java.util.Optional; +import org.jspecify.annotations.Nullable; + import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.filter.TypeFilter; import org.springframework.data.util.Streamable; -import org.springframework.lang.Nullable; /** * @author Christoph Strobl diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationDelegate.java b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationDelegate.java index a8577ad751..45338837ef 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationDelegate.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationDelegate.java @@ -26,6 +26,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableBeanFactory; @@ -53,7 +54,6 @@ import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport; import org.springframework.data.repository.core.support.RepositoryFactorySupport; import org.springframework.data.util.ClassUtils; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StopWatch; @@ -316,8 +316,7 @@ private static ApplicationStartup getStartup(BeanDefinitionRegistry registry) { * @param configuration must not be {@literal null}. * @return can be {@literal null}. */ - @Nullable - private ResolvableType getRepositoryFactoryBeanType(RepositoryConfiguration configuration) { + private @Nullable ResolvableType getRepositoryFactoryBeanType(RepositoryConfiguration configuration) { String interfaceName = configuration.getRepositoryInterface(); ClassLoader classLoader = resourceLoader.getClassLoader() == null diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationExtension.java b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationExtension.java index 30eac982b0..1b9531da35 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationExtension.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationExtension.java @@ -18,12 +18,13 @@ import java.util.Collection; import java.util.Locale; +import org.jspecify.annotations.NonNull; + import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.core.io.ResourceLoader; -import org.springframework.lang.NonNull; /** * SPI to implement store specific extension to the repository bean definition registration process. diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationExtensionSupport.java b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationExtensionSupport.java index e29a476528..5917e05c5c 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationExtensionSupport.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationExtensionSupport.java @@ -15,8 +15,7 @@ */ package org.springframework.data.repository.config; -import static org.springframework.beans.factory.support.BeanDefinitionReaderUtils.GENERATED_BEAN_NAME_SEPARATOR; -import static org.springframework.beans.factory.support.BeanDefinitionReaderUtils.generateBeanName; +import static org.springframework.beans.factory.support.BeanDefinitionReaderUtils.*; import java.lang.annotation.Annotation; import java.util.Collection; @@ -28,6 +27,8 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; @@ -38,7 +39,6 @@ import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.repository.core.support.AbstractRepositoryMetadata; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationSource.java b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationSource.java index c5f872e217..af1dec7a65 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationSource.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationSource.java @@ -17,13 +17,14 @@ import java.util.Optional; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.core.io.ResourceLoader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.filter.TypeFilter; import org.springframework.data.repository.query.QueryLookupStrategy; import org.springframework.data.util.Streamable; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryFragmentConfiguration.java b/src/main/java/org/springframework/data/repository/config/RepositoryFragmentConfiguration.java index 8b5937ab82..1fde822833 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryFragmentConfiguration.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryFragmentConfiguration.java @@ -18,9 +18,10 @@ import java.beans.Introspector; import java.util.Optional; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.data.config.ConfigurationUtils; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryRegistrationAotContribution.java b/src/main/java/org/springframework/data/repository/config/RepositoryRegistrationAotContribution.java index 4274c9d086..0e3319b164 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryRegistrationAotContribution.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryRegistrationAotContribution.java @@ -27,6 +27,8 @@ import java.util.function.BiConsumer; import java.util.function.Predicate; +import org.jspecify.annotations.Nullable; + import org.springframework.aop.SpringProxy; import org.springframework.aop.framework.Advised; import org.springframework.aot.generate.GenerationContext; @@ -48,7 +50,6 @@ import org.springframework.data.util.QTypeContributor; import org.springframework.data.util.TypeContributor; import org.springframework.data.util.TypeUtils; -import org.springframework.lang.Nullable; import org.springframework.stereotype.Component; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -63,25 +64,9 @@ public class RepositoryRegistrationAotContribution implements BeanRegistrationAo private static final String KOTLIN_COROUTINE_REPOSITORY_TYPE_NAME = "org.springframework.data.repository.kotlin.CoroutineCrudRepository"; - /** - * Factory method used to construct a new instance of {@link RepositoryRegistrationAotContribution} initialized with - * the given, required {@link RepositoryRegistrationAotProcessor} from which this contribution was created. - * - * @param repositoryRegistrationAotProcessor reference back to the {@link RepositoryRegistrationAotProcessor} from - * which this contribution was created. - * @return a new instance of {@link RepositoryRegistrationAotContribution}. - * @throws IllegalArgumentException if the {@link RepositoryRegistrationAotProcessor} is {@literal null}. - * @see RepositoryRegistrationAotProcessor - */ - public static RepositoryRegistrationAotContribution fromProcessor( - RepositoryRegistrationAotProcessor repositoryRegistrationAotProcessor) { - - return new RepositoryRegistrationAotContribution(repositoryRegistrationAotProcessor); - } + private @Nullable AotRepositoryContext repositoryContext; - private AotRepositoryContext repositoryContext; - - private BiConsumer moduleContribution; + private @Nullable BiConsumer moduleContribution; private final RepositoryRegistrationAotProcessor repositoryRegistrationAotProcessor; @@ -102,6 +87,21 @@ protected RepositoryRegistrationAotContribution( this.repositoryRegistrationAotProcessor = repositoryRegistrationAotProcessor; } + /** + * Factory method used to construct a new instance of {@link RepositoryRegistrationAotContribution} initialized with + * the given, required {@link RepositoryRegistrationAotProcessor} from which this contribution was created. + * + * @param repositoryRegistrationAotProcessor reference back to the {@link RepositoryRegistrationAotProcessor} from + * which this contribution was created. + * @return a new instance of {@link RepositoryRegistrationAotContribution}. + * @throws IllegalArgumentException if the {@link RepositoryRegistrationAotProcessor} is {@literal null}. + * @see RepositoryRegistrationAotProcessor + */ + public static RepositoryRegistrationAotContribution fromProcessor( + RepositoryRegistrationAotProcessor repositoryRegistrationAotProcessor) { + return new RepositoryRegistrationAotContribution(repositoryRegistrationAotProcessor); + } + protected ConfigurableListableBeanFactory getBeanFactory() { return getRepositoryRegistrationAotProcessor().getBeanFactory(); } @@ -147,6 +147,8 @@ public RepositoryRegistrationAotContribution forBean(RegisteredBean repositoryBe RepositoryConfiguration repositoryMetadata = getRepositoryRegistrationAotProcessor() .getRepositoryMetadata(repositoryBean); + Assert.state(repositoryMetadata != null, "The RepositoryConfiguration for the repository must not be null"); + this.repositoryContext = buildAotRepositoryContext(repositoryBean, repositoryMetadata); return this; @@ -213,6 +215,9 @@ public RepositoryRegistrationAotContribution withModuleContribution( @Override public void applyTo(GenerationContext generationContext, BeanRegistrationCode beanRegistrationCode) { + Assert.state(this.repositoryContext != null, + "RepositoryContext cannot be null. Make sure to initialize this class with forBean(…)."); + contributeRepositoryInfo(this.repositoryContext, generationContext); getModuleContribution().ifPresent(it -> it.accept(getRepositoryContext(), generationContext)); } diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryRegistrationAotProcessor.java b/src/main/java/org/springframework/data/repository/config/RepositoryRegistrationAotProcessor.java index 42e57e7d26..0f9caaadd5 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryRegistrationAotProcessor.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryRegistrationAotProcessor.java @@ -26,6 +26,8 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; + import org.springframework.aot.generate.GenerationContext; import org.springframework.aot.hint.RuntimeHints; import org.springframework.aot.hint.annotation.Reflective; @@ -43,7 +45,6 @@ import org.springframework.data.repository.core.RepositoryInformation; import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport; import org.springframework.data.util.TypeContributor; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -70,15 +71,14 @@ */ public class RepositoryRegistrationAotProcessor implements BeanRegistrationAotProcessor, BeanFactoryAware { - private ConfigurableListableBeanFactory beanFactory; + private @Nullable ConfigurableListableBeanFactory beanFactory; private final Log logger = LogFactory.getLog(getClass()); - private Map> configMap; + private @Nullable Map> configMap; - @Nullable @Override - public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean bean) { + public @Nullable BeanRegistrationAotContribution processAheadOfTime(RegisteredBean bean) { return isRepositoryBean(bean) ? newRepositoryRegistrationAotContribution(bean) : null; } @@ -140,6 +140,9 @@ public void setBeanFactory(BeanFactory beanFactory) throws BeansException { } protected ConfigurableListableBeanFactory getBeanFactory() { + + Assert.state(this.beanFactory != null, "BeanFactory must not be null"); + return this.beanFactory; } @@ -155,8 +158,7 @@ private Map nullSafeMap(@Nullable Map map) { return map != null ? map : Collections.emptyMap(); } - @Nullable - protected RepositoryConfiguration getRepositoryMetadata(RegisteredBean bean) { + protected @Nullable RepositoryConfiguration getRepositoryMetadata(RegisteredBean bean) { return getConfigMap().get(nullSafeBeanName(bean)); } diff --git a/src/main/java/org/springframework/data/repository/config/ResourceReaderRepositoryPopulatorBeanDefinitionParser.java b/src/main/java/org/springframework/data/repository/config/ResourceReaderRepositoryPopulatorBeanDefinitionParser.java index 00c74b2f38..5fd07b39c2 100644 --- a/src/main/java/org/springframework/data/repository/config/ResourceReaderRepositoryPopulatorBeanDefinitionParser.java +++ b/src/main/java/org/springframework/data/repository/config/ResourceReaderRepositoryPopulatorBeanDefinitionParser.java @@ -17,12 +17,13 @@ import java.util.Arrays; +import org.jspecify.annotations.NonNull; + import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.data.repository.init.Jackson2RepositoryPopulatorFactoryBean; import org.springframework.data.repository.init.UnmarshallerRepositoryPopulatorFactoryBean; -import org.springframework.lang.NonNull; import org.springframework.util.StringUtils; import org.w3c.dom.Element; diff --git a/src/main/java/org/springframework/data/repository/config/XmlRepositoryConfigurationSource.java b/src/main/java/org/springframework/data/repository/config/XmlRepositoryConfigurationSource.java index 87e5465243..5573613c7d 100644 --- a/src/main/java/org/springframework/data/repository/config/XmlRepositoryConfigurationSource.java +++ b/src/main/java/org/springframework/data/repository/config/XmlRepositoryConfigurationSource.java @@ -19,6 +19,9 @@ import java.util.Locale; import java.util.Optional; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.beans.factory.support.DefaultBeanNameGenerator; import org.springframework.beans.factory.xml.ParserContext; @@ -31,10 +34,9 @@ import org.springframework.data.repository.query.QueryLookupStrategy.Key; import org.springframework.data.util.ParsingUtils; import org.springframework.data.util.Streamable; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; + import org.w3c.dom.Element; /** diff --git a/src/main/java/org/springframework/data/repository/config/package-info.java b/src/main/java/org/springframework/data/repository/config/package-info.java index 2e133ab5e5..6436bafff2 100644 --- a/src/main/java/org/springframework/data/repository/config/package-info.java +++ b/src/main/java/org/springframework/data/repository/config/package-info.java @@ -1,5 +1,5 @@ /** * Support classes for repository namespace and JavaConfig integration. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.repository.config; diff --git a/src/main/java/org/springframework/data/repository/core/EntityInformation.java b/src/main/java/org/springframework/data/repository/core/EntityInformation.java index 7cac165601..b5458d44d6 100644 --- a/src/main/java/org/springframework/data/repository/core/EntityInformation.java +++ b/src/main/java/org/springframework/data/repository/core/EntityInformation.java @@ -15,7 +15,8 @@ */ package org.springframework.data.repository.core; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; /** diff --git a/src/main/java/org/springframework/data/repository/core/RepositoryInformationSupport.java b/src/main/java/org/springframework/data/repository/core/RepositoryInformationSupport.java index 7ccc7a6b6a..298ec61415 100644 --- a/src/main/java/org/springframework/data/repository/core/RepositoryInformationSupport.java +++ b/src/main/java/org/springframework/data/repository/core/RepositoryInformationSupport.java @@ -21,6 +21,8 @@ import java.util.Set; import java.util.function.Supplier; +import org.jspecify.annotations.Nullable; + import org.springframework.core.annotation.AnnotationUtils; import org.springframework.data.annotation.QueryAnnotation; import org.springframework.data.repository.Repository; @@ -28,7 +30,6 @@ import org.springframework.data.util.Streamable; import org.springframework.data.util.TypeInformation; import org.springframework.lang.Contract; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; diff --git a/src/main/java/org/springframework/data/repository/core/RepositoryMethodContextHolder.java b/src/main/java/org/springframework/data/repository/core/RepositoryMethodContextHolder.java index 6b6aac5639..fe64c7a117 100644 --- a/src/main/java/org/springframework/data/repository/core/RepositoryMethodContextHolder.java +++ b/src/main/java/org/springframework/data/repository/core/RepositoryMethodContextHolder.java @@ -15,8 +15,9 @@ */ package org.springframework.data.repository.core; +import org.jspecify.annotations.Nullable; + import org.springframework.core.NamedThreadLocal; -import org.springframework.lang.Nullable; /** * Associates a given {@link RepositoryMethodContext} with the current execution thread. @@ -48,8 +49,7 @@ public class RepositoryMethodContextHolder { * @return the old metadata, which may be {@code null} if none was bound * @see #getContext() */ - @Nullable - public static RepositoryMethodContext setContext(@Nullable RepositoryMethodContext context) { + public static @Nullable RepositoryMethodContext setContext(@Nullable RepositoryMethodContext context) { RepositoryMethodContext old = currentMethod.get(); if (context != null) { diff --git a/src/main/java/org/springframework/data/repository/core/package-info.java b/src/main/java/org/springframework/data/repository/core/package-info.java index 1ff4a7832a..f0d968cc2d 100644 --- a/src/main/java/org/springframework/data/repository/core/package-info.java +++ b/src/main/java/org/springframework/data/repository/core/package-info.java @@ -1,5 +1,5 @@ /** * Core abstractions for repository implementation. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.repository.core; diff --git a/src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryInformation.java b/src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryInformation.java index 51c5e6a9e2..71d118587b 100644 --- a/src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryInformation.java +++ b/src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryInformation.java @@ -20,11 +20,12 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import org.jspecify.annotations.Nullable; + import org.springframework.data.repository.core.RepositoryInformation; import org.springframework.data.repository.core.RepositoryInformationSupport; import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.lang.Contract; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ReflectionUtils; @@ -79,9 +80,8 @@ public Method getTargetClassMethod(Method method) { return cacheAndReturn(method, baseComposition.findMethod(method).orElse(method)); } - @Nullable @Contract("_, null -> null; _, !null -> !null") - private Method cacheAndReturn(Method key, @Nullable Method value) { + private @Nullable Method cacheAndReturn(Method key, @Nullable Method value) { if (value != null) { ReflectionUtils.makeAccessible(value); diff --git a/src/main/java/org/springframework/data/repository/core/support/DelegatingEntityInformation.java b/src/main/java/org/springframework/data/repository/core/support/DelegatingEntityInformation.java index 9b3f9c0820..cbf532c60e 100644 --- a/src/main/java/org/springframework/data/repository/core/support/DelegatingEntityInformation.java +++ b/src/main/java/org/springframework/data/repository/core/support/DelegatingEntityInformation.java @@ -15,8 +15,9 @@ */ package org.springframework.data.repository.core.support; +import org.jspecify.annotations.Nullable; + import org.springframework.data.repository.core.EntityInformation; -import org.springframework.lang.Nullable; /** * Useful base class to implement custom {@link EntityInformation}s and delegate execution of standard methods from @@ -42,9 +43,8 @@ public boolean isNew(T entity) { return delegate.isNew(entity); } - @Nullable @Override - public ID getId(T entity) { + public @Nullable ID getId(T entity) { return delegate.getId(entity); } diff --git a/src/main/java/org/springframework/data/repository/core/support/EventPublishingRepositoryProxyPostProcessor.java b/src/main/java/org/springframework/data/repository/core/support/EventPublishingRepositoryProxyPostProcessor.java index 3d9698a98d..084b1ab2b7 100644 --- a/src/main/java/org/springframework/data/repository/core/support/EventPublishingRepositoryProxyPostProcessor.java +++ b/src/main/java/org/springframework/data/repository/core/support/EventPublishingRepositoryProxyPostProcessor.java @@ -25,6 +25,8 @@ import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; +import org.jspecify.annotations.Nullable; + import org.springframework.aop.framework.ProxyFactory; import org.springframework.context.ApplicationEventPublisher; import org.springframework.data.domain.AfterDomainEventPublication; @@ -32,7 +34,6 @@ import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.core.RepositoryInformation; import org.springframework.data.util.AnnotationDetectionMethodCallback; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ConcurrentReferenceHashMap; import org.springframework.util.ReflectionUtils; @@ -103,8 +104,7 @@ public static EventPublishingMethodInterceptor of(EventPublishingMethod eventMet } @Override - @Nullable - public Object invoke(MethodInvocation invocation) throws Throwable { + public @Nullable Object invoke(MethodInvocation invocation) throws Throwable { Object result = invocation.proceed(); @@ -168,8 +168,7 @@ static class EventPublishingMethod { * @return an {@link EventPublishingMethod} for the given type or {@literal null} in case the given type does not * expose an event publishing method. */ - @Nullable - public static EventPublishingMethod of(Class type) { + public static @Nullable EventPublishingMethod of(Class type) { Assert.notNull(type, "Type must not be null"); @@ -231,8 +230,7 @@ public void publishEventsFrom(@Nullable Iterable aggregates, ApplicationEvent * * @return */ - @Nullable - private EventPublishingMethod orNull() { + private @Nullable EventPublishingMethod orNull() { return this == EventPublishingMethod.NONE ? null : this; } @@ -272,8 +270,7 @@ private static EventPublishingMethod from(Class type, AnnotationDetectionMeth * @param clearing must not be {@literal null}. * @return */ - @Nullable - private static Method getClearingMethod(AnnotationDetectionMethodCallback clearing) { + private static @Nullable Method getClearingMethod(AnnotationDetectionMethodCallback clearing) { if (!clearing.hasFoundAnnotation()) { return null; @@ -314,9 +311,8 @@ private static Collection asCollection(@Nullable Object source) { * @param source can be {@literal null}. * @return will never be {@literal null}. */ - @Nullable @SuppressWarnings("unchecked") - private static Iterable asIterable(@Nullable Object source, @Nullable Method method) { + private static @Nullable Iterable asIterable(@Nullable Object source, @Nullable Method method) { return method != null && method.getName().startsWith("saveAll") ? (Iterable) source diff --git a/src/main/java/org/springframework/data/repository/core/support/MethodInvocationValidator.java b/src/main/java/org/springframework/data/repository/core/support/MethodInvocationValidator.java index 61ac758ce6..f2af7b4a0a 100644 --- a/src/main/java/org/springframework/data/repository/core/support/MethodInvocationValidator.java +++ b/src/main/java/org/springframework/data/repository/core/support/MethodInvocationValidator.java @@ -24,6 +24,7 @@ import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.core.KotlinDetector; @@ -34,7 +35,6 @@ import org.springframework.data.util.KotlinReflectionUtils; import org.springframework.data.util.NullableUtils; import org.springframework.data.util.ReflectionUtils; -import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; @@ -45,7 +45,7 @@ * @author Mark Paluch * @author Johannes Englmeier * @since 2.0 - * @see org.springframework.lang.NonNull + * @see org.jspecify.annotations.NonNull * @see ReflectionUtils#isNullable(MethodParameter) * @see NullableUtils */ @@ -73,9 +73,8 @@ public static boolean supports(Class repositoryInterface) { || NullableUtils.isNonNull(repositoryInterface, ElementType.PARAMETER); } - @Nullable @Override - public Object invoke(@SuppressWarnings("null") MethodInvocation invocation) throws Throwable { + public @Nullable Object invoke(@SuppressWarnings("null") MethodInvocation invocation) throws Throwable { Method method = invocation.getMethod(); Nullability nullability = nullabilityCache.get(method); diff --git a/src/main/java/org/springframework/data/repository/core/support/MethodLookup.java b/src/main/java/org/springframework/data/repository/core/support/MethodLookup.java index 9cbc2f13e1..a51c55419f 100644 --- a/src/main/java/org/springframework/data/repository/core/support/MethodLookup.java +++ b/src/main/java/org/springframework/data/repository/core/support/MethodLookup.java @@ -21,9 +21,10 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; + import org.springframework.lang.CheckReturnValue; import org.springframework.lang.Contract; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; diff --git a/src/main/java/org/springframework/data/repository/core/support/MethodLookups.java b/src/main/java/org/springframework/data/repository/core/support/MethodLookups.java index e2d60e9fbc..66ee773111 100644 --- a/src/main/java/org/springframework/data/repository/core/support/MethodLookups.java +++ b/src/main/java/org/springframework/data/repository/core/support/MethodLookups.java @@ -29,6 +29,8 @@ import java.util.stream.IntStream; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.core.ResolvableType; import org.springframework.data.repository.Repository; @@ -37,7 +39,6 @@ import org.springframework.data.repository.util.QueryExecutionConverters; import org.springframework.data.repository.util.ReactiveWrapperConverters; import org.springframework.data.util.ReactiveWrappers; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; diff --git a/src/main/java/org/springframework/data/repository/core/support/PersistentEntityInformation.java b/src/main/java/org/springframework/data/repository/core/support/PersistentEntityInformation.java index c84443ecb3..f8a0556fa0 100644 --- a/src/main/java/org/springframework/data/repository/core/support/PersistentEntityInformation.java +++ b/src/main/java/org/springframework/data/repository/core/support/PersistentEntityInformation.java @@ -15,10 +15,11 @@ */ package org.springframework.data.repository.core.support; +import org.jspecify.annotations.Nullable; + import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.repository.core.EntityInformation; -import org.springframework.lang.Nullable; /** * {@link EntityInformation} implementation that uses a {@link PersistentEntity} to obtain id type information and uses @@ -40,10 +41,9 @@ public boolean isNew(T entity) { return persistentEntity.isNew(entity); } - @Nullable @Override @SuppressWarnings("unchecked") - public ID getId(T entity) { + public @Nullable ID getId(T entity) { return (ID) persistentEntity.getIdentifierAccessor(entity).getIdentifier(); } diff --git a/src/main/java/org/springframework/data/repository/core/support/QueryExecutionResultHandler.java b/src/main/java/org/springframework/data/repository/core/support/QueryExecutionResultHandler.java index 1ae5826eb1..b4c170f5cf 100644 --- a/src/main/java/org/springframework/data/repository/core/support/QueryExecutionResultHandler.java +++ b/src/main/java/org/springframework/data/repository/core/support/QueryExecutionResultHandler.java @@ -15,12 +15,15 @@ */ package org.springframework.data.repository.core.support; +import java.lang.reflect.Method; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Optional; +import org.jspecify.annotations.Nullable; + import org.springframework.core.CollectionFactory; import org.springframework.core.KotlinDetector; import org.springframework.core.MethodParameter; @@ -32,7 +35,6 @@ import org.springframework.data.util.NullableWrapper; import org.springframework.data.util.ReactiveWrappers; import org.springframework.data.util.Streamable; -import org.springframework.lang.Nullable; /** * Simple domain service to convert query results into a dedicated type. @@ -45,7 +47,7 @@ class QueryExecutionResultHandler { private static final TypeDescriptor WRAPPER_TYPE = TypeDescriptor.valueOf(NullableWrapper.class); - private static final Class FLOW_TYPE = loadIfPresent("kotlinx.coroutines.flow.Flow"); + private static final @Nullable Class FLOW_TYPE = loadIfPresent("kotlinx.coroutines.flow.Flow"); private final GenericConversionService conversionService; @@ -61,9 +63,8 @@ class QueryExecutionResultHandler { this.conversionService = conversionService; } - @Nullable @SuppressWarnings("unchecked") - public static Class loadIfPresent(String type) { + public @Nullable static Class loadIfPresent(String type) { try { return (Class) org.springframework.util.ClassUtils.forName(type, @@ -231,16 +232,15 @@ private boolean conversionRequired(TypeDescriptor source, TypeDescriptor target) * @param source can be {@literal null}. * @return */ - @Nullable @SuppressWarnings("unchecked") - private static Object unwrapOptional(@Nullable Object source) { + private static @Nullable Object unwrapOptional(@Nullable Object source) { if (source == null) { return null; } - return Optional.class.isInstance(source) // - ? Optional.class.cast(source).orElse(null) // + return source instanceof Optional op// + ? op.orElse(null) // : source; } @@ -255,8 +255,9 @@ private static boolean processingRequired(@Nullable Object source, MethodParamet Class targetType = methodParameter.getParameterType(); - if (source != null && ReactiveWrappers.KOTLIN_COROUTINES_PRESENT - && KotlinDetector.isSuspendingFunction(methodParameter.getMethod())) { + Method method = methodParameter.getMethod(); + if (source != null && method != null && ReactiveWrappers.KOTLIN_COROUTINES_PRESENT + && KotlinDetector.isSuspendingFunction(method)) { // Spring's AOP invoker handles Publisher to Flow conversion, so we have to exempt these from post-processing. if (FLOW_TYPE != null && FLOW_TYPE.isAssignableFrom(targetType)) { @@ -275,7 +276,7 @@ private static boolean processingRequired(@Nullable Object source, MethodParamet static class ReturnTypeDescriptor { private final MethodParameter methodParameter; - private final TypeDescriptor typeDescriptor; + private final @Nullable TypeDescriptor typeDescriptor; private final @Nullable TypeDescriptor nestedTypeDescriptor; private ReturnTypeDescriptor(MethodParameter methodParameter) { @@ -308,14 +309,11 @@ TypeDescriptor getReturnTypeDescriptor(int nestingLevel) { // optimizing for nesting level 0 and 1 (Optional, List) // nesting level 2 (Optional>) uses the slow path. - switch (nestingLevel) { - case 0: - return typeDescriptor; - case 1: - return nestedTypeDescriptor; - default: - return TypeDescriptor.nested(this.methodParameter, nestingLevel); - } + return switch (nestingLevel) { + case 0 -> typeDescriptor; + case 1 -> nestedTypeDescriptor; + default -> TypeDescriptor.nested(this.methodParameter, nestingLevel); + }; } } } diff --git a/src/main/java/org/springframework/data/repository/core/support/QueryExecutorMethodInterceptor.java b/src/main/java/org/springframework/data/repository/core/support/QueryExecutorMethodInterceptor.java index dc80c2a8f6..e9ebaf992e 100644 --- a/src/main/java/org/springframework/data/repository/core/support/QueryExecutorMethodInterceptor.java +++ b/src/main/java/org/springframework/data/repository/core/support/QueryExecutorMethodInterceptor.java @@ -25,6 +25,7 @@ import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; +import org.jspecify.annotations.Nullable; import org.springframework.core.MethodParameter; import org.springframework.core.ResolvableType; @@ -39,7 +40,6 @@ import org.springframework.data.repository.query.RepositoryQuery; import org.springframework.data.repository.util.QueryExecutionConverters; import org.springframework.data.util.Pair; -import org.springframework.lang.Nullable; import org.springframework.util.ConcurrentReferenceHashMap; /** @@ -129,15 +129,14 @@ private void invokeListeners(RepositoryQuery query) { ResolvableType typeArgument = ResolvableType.forClass(QueryCreationListener.class, listener.getClass()) .getGeneric(0); - if (typeArgument != null && typeArgument.isAssignableFrom(ResolvableType.forClass(query.getClass()))) { + if (typeArgument.isAssignableFrom(ResolvableType.forClass(query.getClass()))) { listener.onCreation(query); } } } @Override - @Nullable - public Object invoke(@SuppressWarnings("null") MethodInvocation invocation) throws Throwable { + public @Nullable Object invoke(MethodInvocation invocation) throws Throwable { Method method = invocation.getMethod(); MethodParameter returnType = returnTypeMap.computeIfAbsent(method, it -> new MethodParameter(it, -1)); @@ -153,8 +152,8 @@ public Object invoke(@SuppressWarnings("null") MethodInvocation invocation) thro .apply(() -> resultHandler.postProcessInvocationResult(doInvoke(invocation), returnType)); } - @Nullable - private Object doInvoke(MethodInvocation invocation) throws Throwable { + @SuppressWarnings("NullAway") + private @Nullable Object doInvoke(MethodInvocation invocation) throws Throwable { Method method = invocation.getMethod(); diff --git a/src/main/java/org/springframework/data/repository/core/support/ReactiveRepositoryFactorySupport.java b/src/main/java/org/springframework/data/repository/core/support/ReactiveRepositoryFactorySupport.java index 5e6e2dbfdc..6a91f12343 100644 --- a/src/main/java/org/springframework/data/repository/core/support/ReactiveRepositoryFactorySupport.java +++ b/src/main/java/org/springframework/data/repository/core/support/ReactiveRepositoryFactorySupport.java @@ -19,6 +19,7 @@ import java.util.Arrays; import java.util.Optional; +import org.jspecify.annotations.Nullable; import org.reactivestreams.Publisher; import org.springframework.dao.InvalidDataAccessApiUsageException; @@ -27,7 +28,6 @@ import org.springframework.data.repository.query.ValueExpressionDelegate; import org.springframework.data.repository.util.ReactiveWrapperConverters; import org.springframework.data.util.ReactiveWrappers; -import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; /** @@ -68,7 +68,7 @@ protected void validate(RepositoryMetadata repositoryMetadata) { * @since 3.4 */ @Override - protected Optional getQueryLookupStrategy(@Nullable QueryLookupStrategy.Key key, + protected Optional getQueryLookupStrategy(QueryLookupStrategy.@Nullable Key key, ValueExpressionDelegate valueExpressionDelegate) { return Optional.empty(); } diff --git a/src/main/java/org/springframework/data/repository/core/support/RepositoryComposition.java b/src/main/java/org/springframework/data/repository/core/support/RepositoryComposition.java index 038b7560ea..df5eb20073 100644 --- a/src/main/java/org/springframework/data/repository/core/support/RepositoryComposition.java +++ b/src/main/java/org/springframework/data/repository/core/support/RepositoryComposition.java @@ -29,6 +29,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; + import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.repository.core.support.MethodLookup.InvokedMethod; import org.springframework.data.repository.core.support.RepositoryInvocationMulticaster.NoOpRepositoryInvocationMulticaster; @@ -37,7 +39,6 @@ import org.springframework.data.util.Streamable; import org.springframework.lang.CheckReturnValue; import org.springframework.lang.Contract; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; @@ -266,8 +267,7 @@ public boolean isEmpty() { /** * Invoke a method on the repository by routing the invocation to the appropriate {@link RepositoryFragment}. */ - @Nullable - public Object invoke(Method method, Object... args) throws Throwable { + public @Nullable Object invoke(Method method, Object... args) throws Throwable { return invoke(NoOpRepositoryInvocationMulticaster.INSTANCE, method, args); } @@ -361,8 +361,8 @@ public int hashCode() { public BiFunction getArgumentConverter() { return this.argumentConverter; } - public static class RepositoryFragments implements Streamable> { + public static class RepositoryFragments implements Streamable> { static final RepositoryFragments EMPTY = new RepositoryFragments(Collections.emptyList()); @@ -426,6 +426,11 @@ public static RepositoryFragments from(List> fragments) { return new RepositoryFragments(new ArrayList<>(fragments)); } + @Override + public boolean isEmpty() { + return this.fragments.isEmpty(); + } + /** * Create new {@link RepositoryFragments} from the current content appending {@link RepositoryFragment}. * @@ -455,6 +460,10 @@ public RepositoryFragments append(RepositoryFragments fragments) { Assert.notNull(fragments, "RepositoryFragments must not be null"); + if (fragments.isEmpty()) { + return this; + } + return concat(stream(), fragments.stream()); } @@ -477,8 +486,9 @@ public Stream methods() { /** * Invoke {@link Method} by resolving the fragment that implements a suitable method. */ - @Nullable - public Object invoke(Method invokedMethod, Method methodToCall, Object[] args) throws Throwable { + @Deprecated(forRemoval = true) + @SuppressWarnings("NullAway") + public @Nullable Object invoke(Method invokedMethod, Method methodToCall, Object[] args) throws Throwable { return invoke(null, NoOpRepositoryInvocationMulticaster.INSTANCE, invokedMethod, methodToCall, args); } @@ -486,8 +496,8 @@ public Object invoke(Method invokedMethod, Method methodToCall, Object[] args) t * Invoke {@link Method} by resolving the fragment that implements a suitable method. */ @Nullable - Object invoke(Class repositoryInterface, RepositoryInvocationMulticaster listener, Method invokedMethod, - Method methodToCall, Object[] args) throws Throwable { + Object invoke(@Nullable Class repositoryInterface, RepositoryInvocationMulticaster listener, + Method invokedMethod, Method methodToCall, Object[] args) throws Throwable { RepositoryFragment fragment = fragmentCache.computeIfAbsent(methodToCall, this::findImplementationFragment); Optional optional = fragment.getImplementation(); @@ -505,6 +515,8 @@ Object invoke(Class repositoryInterface, RepositoryInvocationMulticaster list invocationMetadataCache.put(invokedMethod, repositoryMethodInvoker); } + Assert.notNull(repositoryInterface, "Repository interface must not be null"); + return repositoryMethodInvoker.invoke(repositoryInterface, listener, args); } @@ -516,8 +528,7 @@ private RepositoryFragment findImplementationFragment(Method key) { .orElseThrow(() -> new IllegalArgumentException(String.format("No fragment found for method %s", key))); } - @Nullable - private static Method findMethod(InvokedMethod invokedMethod, MethodLookup lookup, + private static @Nullable Method findMethod(InvokedMethod invokedMethod, MethodLookup lookup, Supplier> methodStreamSupplier) { for (MethodLookup.MethodPredicate methodPredicate : lookup.getLookups()) { diff --git a/src/main/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupport.java b/src/main/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupport.java index e63f511fe8..b637ce27a4 100644 --- a/src/main/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupport.java +++ b/src/main/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupport.java @@ -17,7 +17,9 @@ import java.util.ArrayList; import java.util.List; -import java.util.Optional; + +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanClassLoaderAware; @@ -44,7 +46,6 @@ import org.springframework.data.repository.query.QueryMethodValueEvaluationContextAccessor; import org.springframework.data.spel.EvaluationContextProvider; import org.springframework.data.util.Lazy; -import org.springframework.lang.NonNull; import org.springframework.util.Assert; /** @@ -70,25 +71,23 @@ public abstract class RepositoryFactoryBeanSupport, private final Class repositoryInterface; - private RepositoryFactorySupport factory; + private @Nullable RepositoryFactorySupport factory; private boolean exposeMetadata; - private Key queryLookupStrategyKey; - private Optional> repositoryBaseClass = Optional.empty(); - private Optional customImplementation = Optional.empty(); - private Optional repositoryFragments = Optional.empty(); + private @Nullable Key queryLookupStrategyKey; + private @Nullable Class repositoryBaseClass; + private @Nullable Object customImplementation; + private RepositoryFragments repositoryFragments = RepositoryFragments.empty(); private NamedQueries namedQueries = PropertiesBasedNamedQueries.EMPTY; - private Optional> mappingContext = Optional.empty(); - private ClassLoader classLoader; - private ApplicationEventPublisher publisher; - private BeanFactory beanFactory; - private Environment environment; + private @Nullable MappingContext mappingContext; + private @Nullable ClassLoader classLoader; + private @Nullable ApplicationEventPublisher publisher; + private @Nullable BeanFactory beanFactory; + private @Nullable Environment environment; private boolean lazyInit = false; - private Optional evaluationContextProvider = Optional.empty(); + private @Nullable EvaluationContextProvider evaluationContextProvider; private final List repositoryFactoryCustomizers = new ArrayList<>(); - - private Lazy repository; - - private RepositoryMetadata repositoryMetadata; + private @Nullable Lazy repository; + private @Nullable RepositoryMetadata repositoryMetadata; /** * Creates a new {@link RepositoryFactoryBeanSupport} for the given repository interface. @@ -108,7 +107,7 @@ protected RepositoryFactoryBeanSupport(Class repositoryInterface) { * @since 1.11 */ public void setRepositoryBaseClass(Class repositoryBaseClass) { - this.repositoryBaseClass = Optional.ofNullable(repositoryBaseClass); + this.repositoryBaseClass = repositoryBaseClass; } /** @@ -140,7 +139,7 @@ public void setQueryLookupStrategyKey(Key queryLookupStrategyKey) { * @param customImplementation */ public void setCustomImplementation(Object customImplementation) { - this.customImplementation = Optional.of(customImplementation); + this.customImplementation = customImplementation; } /** @@ -149,7 +148,7 @@ public void setCustomImplementation(Object customImplementation) { * @param repositoryFragments */ public void setRepositoryFragments(RepositoryFragments repositoryFragments) { - this.repositoryFragments = Optional.of(repositoryFragments); + this.repositoryFragments = repositoryFragments; } /** @@ -168,7 +167,7 @@ public void setNamedQueries(NamedQueries namedQueries) { * @param mappingContext */ protected void setMappingContext(MappingContext mappingContext) { - this.mappingContext = Optional.of(mappingContext); + this.mappingContext = mappingContext; } /** @@ -178,7 +177,7 @@ protected void setMappingContext(MappingContext mappingContext) { * @since 3.4 */ public void setEvaluationContextProvider(EvaluationContextProvider evaluationContextProvider) { - this.evaluationContextProvider = Optional.of(evaluationContextProvider); + this.evaluationContextProvider = evaluationContextProvider; } /** @@ -213,7 +212,7 @@ public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; - if (this.evaluationContextProvider.isEmpty() && beanFactory instanceof ListableBeanFactory lbf) { + if (this.evaluationContextProvider == null && beanFactory instanceof ListableBeanFactory lbf) { this.evaluationContextProvider = createDefaultEvaluationContextProvider(lbf); } } @@ -227,12 +226,12 @@ public void setEnvironment(Environment environment) { * Create a default {@link EvaluationContextProvider} (or subclass) from {@link ListableBeanFactory}. * * @param beanFactory the bean factory to use. - * @return the default instance. May be {@link Optional#empty()}. + * @return the default instance. May be {@code null}. * @since 3.4 */ - protected Optional createDefaultEvaluationContextProvider( + protected @Nullable EvaluationContextProvider createDefaultEvaluationContextProvider( ListableBeanFactory beanFactory) { - return Optional.of(QueryMethodValueEvaluationContextAccessor.createEvaluationContextProvider(beanFactory)); + return QueryMethodValueEvaluationContextAccessor.createEvaluationContextProvider(beanFactory); } @Override @@ -243,53 +242,74 @@ public void setApplicationEventPublisher(ApplicationEventPublisher publisher) { @Override @SuppressWarnings("unchecked") public EntityInformation getEntityInformation() { - return (EntityInformation) factory.getEntityInformation(repositoryMetadata.getDomainType()); + return (EntityInformation) getRequiredFactory() + .getEntityInformation(getRequiredRepositoryMetadata().getDomainType()); } @Override public RepositoryInformation getRepositoryInformation() { - RepositoryFragments fragments = customImplementation.map(RepositoryFragments::just)// - .orElse(RepositoryFragments.empty()); + RepositoryFragments fragments = customImplementation != null ? RepositoryFragments.just(customImplementation) + : RepositoryFragments.empty(); - return factory.getRepositoryInformation(repositoryMetadata, fragments); + return getRequiredFactory().getRepositoryInformation(getRequiredRepositoryMetadata(), fragments); } @Override public PersistentEntity getPersistentEntity() { - return mappingContext.orElseThrow(() -> new IllegalStateException("No MappingContext available")) - .getRequiredPersistentEntity(repositoryMetadata.getDomainType()); + Assert.state(mappingContext != null, "No MappingContext available"); + + return mappingContext.getRequiredPersistentEntity(getRequiredRepositoryMetadata().getDomainType()); } @Override public List getQueryMethods() { - return factory.getQueryMethods(); + return getRequiredFactory().getQueryMethods(); } @Override - @NonNull - public T getObject() { + public @NonNull T getObject() { + + Assert.state(repository != null, "RepositoryFactory is not initialized"); + return this.repository.get(); } @Override - @NonNull - public Class getObjectType() { + public @NonNull Class getObjectType() { return repositoryInterface; } + RepositoryFactorySupport getRequiredFactory() { + + Assert.state(factory != null, "RepositoryFactory is not initialized"); + + return factory; + } + + RepositoryMetadata getRequiredRepositoryMetadata() { + + Assert.state(repositoryMetadata != null, "RepositoryMetadata is not initialized"); + + return repositoryMetadata; + } + @Override public void afterPropertiesSet() { + this.factory = createRepositoryFactory(); this.factory.setExposeMetadata(exposeMetadata); this.factory.setQueryLookupStrategyKey(queryLookupStrategyKey); this.factory.setNamedQueries(namedQueries); - this.factory.setEvaluationContextProvider( - evaluationContextProvider.orElse(QueryMethodValueEvaluationContextAccessor.DEFAULT_CONTEXT_PROVIDER)); + this.factory.setEvaluationContextProvider(evaluationContextProvider != null ? evaluationContextProvider + : QueryMethodValueEvaluationContextAccessor.DEFAULT_CONTEXT_PROVIDER); this.factory.setBeanClassLoader(classLoader); - this.factory.setBeanFactory(beanFactory); + + if (beanFactory != null) { + this.factory.setBeanFactory(beanFactory); + } if (this.publisher != null) { this.factory.addRepositoryProxyPostProcessor(new EventPublishingRepositoryProxyPostProcessor(publisher)); @@ -299,24 +319,25 @@ public void afterPropertiesSet() { this.factory.setEnvironment(this.environment); } - repositoryBaseClass.ifPresent(this.factory::setRepositoryBaseClass); + if (repositoryBaseClass != null) { + this.factory.setRepositoryBaseClass(repositoryBaseClass); + } this.repositoryFactoryCustomizers.forEach(customizer -> customizer.customize(this.factory)); - RepositoryFragments customImplementationFragment = customImplementation // - .map(RepositoryFragments::just) // - .orElseGet(RepositoryFragments::empty); + RepositoryFragments customImplementationFragment = customImplementation != null ? // + RepositoryFragments.just(customImplementation) : RepositoryFragments.empty(); - RepositoryFragments repositoryFragmentsToUse = this.repositoryFragments // - .orElseGet(RepositoryFragments::empty) // - .append(customImplementationFragment); + RepositoryFragments repositoryFragmentsToUse = repositoryFragments.append(customImplementationFragment); this.repositoryMetadata = this.factory.getRepositoryMetadata(repositoryInterface); - - this.repository = Lazy.of(() -> this.factory.getRepository(repositoryInterface, repositoryFragmentsToUse)); + this.repository = Lazy.of(() -> getRequiredFactory().getRepository(repositoryInterface, repositoryFragmentsToUse)); // Make sure the aggregate root type is present in the MappingContext (e.g. for auditing) - this.mappingContext.ifPresent(it -> it.getPersistentEntity(repositoryMetadata.getDomainType())); + + if (this.mappingContext != null) { + this.mappingContext.getPersistentEntity(repositoryMetadata.getDomainType()); + } if (!lazyInit) { this.repository.get(); @@ -326,7 +347,8 @@ public void afterPropertiesSet() { /** * Create the actual {@link RepositoryFactorySupport} instance. * - * @return + * @return the repository factory. */ protected abstract RepositoryFactorySupport createRepositoryFactory(); + } diff --git a/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java b/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java index e00c5d185c..49cc4ad203 100644 --- a/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java +++ b/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java @@ -31,6 +31,7 @@ import org.aopalliance.intercept.MethodInvocation; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.interceptor.ExposeInvocationInterceptor; @@ -75,7 +76,6 @@ import org.springframework.data.util.ReflectionUtils; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; -import org.springframework.lang.Nullable; import org.springframework.transaction.interceptor.TransactionalProxy; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -112,19 +112,18 @@ public abstract class RepositoryFactorySupport private @Nullable Class repositoryBaseClass; private boolean exposeMetadata; - private @Nullable QueryLookupStrategy.Key queryLookupStrategyKey; + private QueryLookupStrategy.@Nullable Key queryLookupStrategyKey; private final List> queryPostProcessors; private final List methodInvocationListeners; private NamedQueries namedQueries; - private ClassLoader classLoader; + private @Nullable ClassLoader classLoader; private EvaluationContextProvider evaluationContextProvider; - private BeanFactory beanFactory; - private Environment environment; + private @Nullable BeanFactory beanFactory; + private @Nullable Environment environment; private Lazy projectionFactory; private final QueryCollectingQueryCreationListener collectingListener = new QueryCollectingQueryCreationListener(); - @SuppressWarnings("null") public RepositoryFactorySupport() { this.repositoryInformationCache = new HashMap<>(16); @@ -168,7 +167,7 @@ public void setExposeMetadata(boolean exposeMetadata) { * * @param key */ - public void setQueryLookupStrategyKey(Key key) { + public void setQueryLookupStrategyKey(@Nullable Key key) { this.queryLookupStrategyKey = key; } @@ -448,11 +447,18 @@ public T getRepository(Class repositoryInterface, RepositoryFragments fra * @param beanFactory will never be {@literal null}. * @return will never be {@literal null}. */ - protected ProjectionFactory getProjectionFactory(ClassLoader classLoader, BeanFactory beanFactory) { + protected ProjectionFactory getProjectionFactory(@Nullable ClassLoader classLoader, + @Nullable BeanFactory beanFactory) { SpelAwareProxyProjectionFactory factory = new SpelAwareProxyProjectionFactory(EXPRESSION_PARSER); - factory.setBeanClassLoader(classLoader); - factory.setBeanFactory(beanFactory); + + if (classLoader != null) { + factory.setBeanClassLoader(classLoader); + } + + if (beanFactory != null) { + factory.setBeanFactory(beanFactory); + } return factory; } @@ -691,9 +697,8 @@ public ImplementationMethodExecutionInterceptor(RepositoryInformation informatio : new DefaultRepositoryInvocationMulticaster(methodInvocationListeners); } - @Nullable @Override - public Object invoke(@SuppressWarnings("null") MethodInvocation invocation) throws Throwable { + public @Nullable Object invoke(@SuppressWarnings("null") MethodInvocation invocation) throws Throwable { Method method = invocation.getMethod(); Object[] arguments = invocation.getArguments(); @@ -722,9 +727,8 @@ public ExposeMetadataInterceptor(RepositoryMetadata repositoryMetadata) { this.repositoryMetadata = repositoryMetadata; } - @Nullable @Override - public Object invoke(MethodInvocation invocation) throws Throwable { + public @Nullable Object invoke(MethodInvocation invocation) throws Throwable { RepositoryMethodContext oldMetadata = null; diff --git a/src/main/java/org/springframework/data/repository/core/support/RepositoryFragment.java b/src/main/java/org/springframework/data/repository/core/support/RepositoryFragment.java index 48047ae661..63013371a2 100644 --- a/src/main/java/org/springframework/data/repository/core/support/RepositoryFragment.java +++ b/src/main/java/org/springframework/data/repository/core/support/RepositoryFragment.java @@ -20,7 +20,8 @@ import java.util.Optional; import java.util.stream.Stream; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; diff --git a/src/main/java/org/springframework/data/repository/core/support/RepositoryFragmentsFactoryBean.java b/src/main/java/org/springframework/data/repository/core/support/RepositoryFragmentsFactoryBean.java index 319faddd4a..0652229ec5 100644 --- a/src/main/java/org/springframework/data/repository/core/support/RepositoryFragmentsFactoryBean.java +++ b/src/main/java/org/springframework/data/repository/core/support/RepositoryFragmentsFactoryBean.java @@ -18,13 +18,15 @@ import java.util.List; import java.util.stream.Collectors; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.data.repository.core.support.RepositoryComposition.RepositoryFragments; -import org.springframework.lang.NonNull; import org.springframework.util.Assert; /** @@ -40,7 +42,7 @@ public class RepositoryFragmentsFactoryBean private final List fragmentBeanNames; - private BeanFactory beanFactory; + private @Nullable BeanFactory beanFactory; private RepositoryFragments repositoryFragments = RepositoryFragments.empty(); /** @@ -64,6 +66,8 @@ public void setBeanFactory(BeanFactory beanFactory) throws BeansException { @SuppressWarnings({ "unchecked", "rawtypes" }) public void afterPropertiesSet() { + Assert.notNull(beanFactory, "BeanFactory must not be null"); + List> fragments = (List) fragmentBeanNames.stream() // .map(it -> beanFactory.getBean(it, RepositoryFragment.class)) // .collect(Collectors.toList()); @@ -71,15 +75,14 @@ public void afterPropertiesSet() { this.repositoryFragments = RepositoryFragments.from(fragments); } - @NonNull @Override - public RepositoryFragments getObject() throws Exception { + public @NonNull RepositoryFragments getObject() { return this.repositoryFragments; } - @NonNull @Override - public Class getObjectType() { + public @NonNull Class getObjectType() { return RepositoryComposition.class; } + } diff --git a/src/main/java/org/springframework/data/repository/core/support/RepositoryInvocationMulticaster.java b/src/main/java/org/springframework/data/repository/core/support/RepositoryInvocationMulticaster.java index 9aafe20f6f..80cfc1a988 100644 --- a/src/main/java/org/springframework/data/repository/core/support/RepositoryInvocationMulticaster.java +++ b/src/main/java/org/springframework/data/repository/core/support/RepositoryInvocationMulticaster.java @@ -18,8 +18,9 @@ import java.lang.reflect.Method; import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.data.repository.core.support.RepositoryMethodInvocationListener.RepositoryMethodInvocation; -import org.springframework.data.repository.core.support.RepositoryMethodInvocationListener.RepositoryMethodInvocationResult; /** * Interface to be implemented by repository method listeners. Listeners are notified with the called {@link Method}, @@ -37,7 +38,7 @@ interface RepositoryInvocationMulticaster { * @param args * @param result */ - void notifyListeners(Method method, Object[] args, RepositoryMethodInvocation result); + void notifyListeners(Method method, @Nullable Object[] args, RepositoryMethodInvocation result); /** * {@link RepositoryInvocationMulticaster} that does nothing upon invocation. @@ -49,14 +50,14 @@ enum NoOpRepositoryInvocationMulticaster implements RepositoryInvocationMulticas INSTANCE; @Override - public void notifyListeners(Method method, Object[] args, RepositoryMethodInvocation result) { + public void notifyListeners(Method method, @Nullable Object[] args, RepositoryMethodInvocation result) { } } /** * {@link RepositoryInvocationMulticaster} implementation that notifies {@link RepositoryMethodInvocationListener} - * upon {@link #notifyListeners(Method, Object[], RepositoryMethodInvocationResult)}. + * upon {@link #notifyListeners(Method, Object[], RepositoryMethodInvocation)}. * * @author Mark Paluch */ @@ -70,7 +71,7 @@ class DefaultRepositoryInvocationMulticaster implements RepositoryInvocationMult } @Override - public void notifyListeners(Method method, Object[] args, RepositoryMethodInvocation result) { + public void notifyListeners(Method method, @Nullable Object[] args, RepositoryMethodInvocation result) { for (RepositoryMethodInvocationListener methodInvocationListener : methodInvocationListeners) { methodInvocationListener.afterInvocation(result); diff --git a/src/main/java/org/springframework/data/repository/core/support/RepositoryMethodInvocationListener.java b/src/main/java/org/springframework/data/repository/core/support/RepositoryMethodInvocationListener.java index ca8ca08e49..350973e5dc 100644 --- a/src/main/java/org/springframework/data/repository/core/support/RepositoryMethodInvocationListener.java +++ b/src/main/java/org/springframework/data/repository/core/support/RepositoryMethodInvocationListener.java @@ -19,7 +19,8 @@ import java.util.Arrays; import java.util.concurrent.TimeUnit; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -81,8 +82,7 @@ public Method getMethod() { return method; } - @Nullable - public RepositoryMethodInvocationResult getResult() { + public @Nullable RepositoryMethodInvocationResult getResult() { return result; } diff --git a/src/main/java/org/springframework/data/repository/core/support/RepositoryMethodInvoker.java b/src/main/java/org/springframework/data/repository/core/support/RepositoryMethodInvoker.java index f17aad05af..110966fed1 100644 --- a/src/main/java/org/springframework/data/repository/core/support/RepositoryMethodInvoker.java +++ b/src/main/java/org/springframework/data/repository/core/support/RepositoryMethodInvoker.java @@ -26,7 +26,9 @@ import java.util.Collection; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.reactivestreams.Publisher; + import org.springframework.aop.support.AopUtils; import org.springframework.core.KotlinDetector; import org.springframework.data.repository.core.support.RepositoryMethodInvocationListener.RepositoryMethodInvocation; @@ -36,7 +38,6 @@ import org.springframework.data.repository.util.ReactiveWrapperConverters; import org.springframework.data.util.KotlinReflectionUtils; import org.springframework.data.util.ReactiveWrappers; -import org.springframework.lang.Nullable; /** * Invoker for repository methods. Used to invoke query methods and fragment methods. This invoker considers Kotlin @@ -77,7 +78,7 @@ protected RepositoryMethodInvoker(Method method, Invokable invokable) { Object result = invokable.invoke(args); - if (returnedType == Unit.class) { + if (returnedType == Unit.class && result != null) { if (result instanceof Mono m) { return m.then(); @@ -87,7 +88,7 @@ protected RepositoryMethodInvoker(Method method, Invokable invokable) { return flux.then(); } - if (returnedType != Flow.class) { + if (returnedType != Flow.class && result != null) { if (result instanceof Mono m) { return m; @@ -152,15 +153,13 @@ public static boolean canInvoke(Method declaredMethod, Method baseClassMethod) { * @return * @throws Exception */ - @Nullable - public Object invoke(Class repositoryInterface, RepositoryInvocationMulticaster multicaster, Object[] args) - throws Exception { + public @Nullable Object invoke(Class repositoryInterface, RepositoryInvocationMulticaster multicaster, + @Nullable Object[] args) throws Exception { return doInvoke(repositoryInterface, multicaster, args); } - @Nullable - private Object doInvoke(Class repositoryInterface, RepositoryInvocationMulticaster multicaster, Object[] args) - throws Exception { + private @Nullable Object doInvoke(Class repositoryInterface, RepositoryInvocationMulticaster multicaster, + @Nullable Object[] args) throws Exception { RepositoryMethodInvocationCaptor invocationResultCaptor = RepositoryMethodInvocationCaptor .captureInvocationOn(repositoryInterface); @@ -195,7 +194,7 @@ private RepositoryMethodInvocation computeInvocationResult(RepositoryMethodInvoc interface Invokable { @Nullable - Object invoke(Object[] args) throws Exception; + Object invoke(@Nullable Object[] args) throws Exception; } /** @@ -212,7 +211,9 @@ public RepositoryQueryMethodInvoker(Method method, RepositoryQuery repositoryQue */ class ReactiveInvocationListenerDecorator { - Publisher decorate(Class repositoryInterface, RepositoryInvocationMulticaster multicaster, Object[] args, + @SuppressWarnings("unchecked") + Publisher decorate(Class repositoryInterface, RepositoryInvocationMulticaster multicaster, + @Nullable Object[] args, Object result) { if (result instanceof Mono) { @@ -361,11 +362,12 @@ private static class RepositoryMethodInvocationCaptor { private final Class repositoryInterface; private long startTime; - private @Nullable Long endTime; + private final @Nullable Long endTime; private final State state; private final @Nullable Throwable error; - protected RepositoryMethodInvocationCaptor(Class repositoryInterface, long startTime, Long endTime, State state, + protected RepositoryMethodInvocationCaptor(Class repositoryInterface, long startTime, @Nullable Long endTime, + State state, @Nullable Throwable exception) { this.repositoryInterface = repositoryInterface; diff --git a/src/main/java/org/springframework/data/repository/core/support/SurroundingTransactionDetectorMethodInterceptor.java b/src/main/java/org/springframework/data/repository/core/support/SurroundingTransactionDetectorMethodInterceptor.java index 655c894221..8147e211b7 100644 --- a/src/main/java/org/springframework/data/repository/core/support/SurroundingTransactionDetectorMethodInterceptor.java +++ b/src/main/java/org/springframework/data/repository/core/support/SurroundingTransactionDetectorMethodInterceptor.java @@ -17,8 +17,8 @@ import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; +import org.jspecify.annotations.Nullable; -import org.springframework.lang.Nullable; import org.springframework.transaction.support.TransactionSynchronizationManager; /** @@ -47,9 +47,8 @@ public boolean isSurroundingTransactionActive() { return Boolean.TRUE == SURROUNDING_TX_ACTIVE.get(); } - @Nullable @Override - public Object invoke(@SuppressWarnings("null") MethodInvocation invocation) throws Throwable { + public @Nullable Object invoke(@SuppressWarnings("null") MethodInvocation invocation) throws Throwable { SURROUNDING_TX_ACTIVE.set(TransactionSynchronizationManager.isActualTransactionActive()); diff --git a/src/main/java/org/springframework/data/repository/core/support/TransactionalRepositoryFactoryBeanSupport.java b/src/main/java/org/springframework/data/repository/core/support/TransactionalRepositoryFactoryBeanSupport.java index 1bf8bfb37a..ed77247233 100644 --- a/src/main/java/org/springframework/data/repository/core/support/TransactionalRepositoryFactoryBeanSupport.java +++ b/src/main/java/org/springframework/data/repository/core/support/TransactionalRepositoryFactoryBeanSupport.java @@ -15,12 +15,13 @@ */ package org.springframework.data.repository.core.support; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.data.repository.Repository; import org.springframework.data.repository.util.TxUtils; -import org.springframework.lang.Nullable; import org.springframework.transaction.interceptor.TransactionInterceptor; import org.springframework.util.Assert; diff --git a/src/main/java/org/springframework/data/repository/core/support/TransactionalRepositoryProxyPostProcessor.java b/src/main/java/org/springframework/data/repository/core/support/TransactionalRepositoryProxyPostProcessor.java index deb073cf2b..255b1c161a 100644 --- a/src/main/java/org/springframework/data/repository/core/support/TransactionalRepositoryProxyPostProcessor.java +++ b/src/main/java/org/springframework/data/repository/core/support/TransactionalRepositoryProxyPostProcessor.java @@ -19,6 +19,8 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import org.jspecify.annotations.Nullable; + import org.springframework.aop.framework.ProxyFactory; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.ListableBeanFactory; @@ -26,7 +28,6 @@ import org.springframework.dao.support.PersistenceExceptionTranslationInterceptor; import org.springframework.data.repository.core.RepositoryInformation; import org.springframework.data.util.ProxyUtils; -import org.springframework.lang.Nullable; import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource; import org.springframework.transaction.interceptor.TransactionAttribute; import org.springframework.transaction.interceptor.TransactionInterceptor; @@ -115,8 +116,8 @@ public RepositoryAnnotationTransactionAttributeSource(RepositoryInformation repo } @Override - @Nullable - protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class targetClass) { + protected @Nullable TransactionAttribute computeTransactionAttribute(Method method, + @Nullable Class targetClass) { // Don't allow no-public methods as required. if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) { diff --git a/src/main/java/org/springframework/data/repository/core/support/package-info.java b/src/main/java/org/springframework/data/repository/core/support/package-info.java index 27c80182ec..d129dabdb2 100644 --- a/src/main/java/org/springframework/data/repository/core/support/package-info.java +++ b/src/main/java/org/springframework/data/repository/core/support/package-info.java @@ -1,5 +1,5 @@ /** * Base classes to implement repositories for various data stores. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.repository.core.support; diff --git a/src/main/java/org/springframework/data/repository/history/package-info.java b/src/main/java/org/springframework/data/repository/history/package-info.java index 7741e536ee..f95e624018 100644 --- a/src/main/java/org/springframework/data/repository/history/package-info.java +++ b/src/main/java/org/springframework/data/repository/history/package-info.java @@ -1,5 +1,5 @@ /** * API for repositories using historiography. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.repository.history; diff --git a/src/main/java/org/springframework/data/repository/history/support/package-info.java b/src/main/java/org/springframework/data/repository/history/support/package-info.java index e8de1607a5..d9a41242bc 100644 --- a/src/main/java/org/springframework/data/repository/history/support/package-info.java +++ b/src/main/java/org/springframework/data/repository/history/support/package-info.java @@ -1,5 +1,5 @@ /** * Value objects to implement core repository interfaces for historiography. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.repository.history.support; diff --git a/src/main/java/org/springframework/data/repository/init/AbstractRepositoryPopulatorFactoryBean.java b/src/main/java/org/springframework/data/repository/init/AbstractRepositoryPopulatorFactoryBean.java index 3a1c33f7bd..3f28aacf9a 100644 --- a/src/main/java/org/springframework/data/repository/init/AbstractRepositoryPopulatorFactoryBean.java +++ b/src/main/java/org/springframework/data/repository/init/AbstractRepositoryPopulatorFactoryBean.java @@ -15,6 +15,9 @@ */ package org.springframework.data.repository.init; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.config.AbstractFactoryBean; import org.springframework.context.ApplicationContext; @@ -23,8 +26,6 @@ import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.core.io.Resource; import org.springframework.data.repository.support.Repositories; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** diff --git a/src/main/java/org/springframework/data/repository/init/Jackson2RepositoryPopulatorFactoryBean.java b/src/main/java/org/springframework/data/repository/init/Jackson2RepositoryPopulatorFactoryBean.java index 412bd2186e..75b08c3145 100644 --- a/src/main/java/org/springframework/data/repository/init/Jackson2RepositoryPopulatorFactoryBean.java +++ b/src/main/java/org/springframework/data/repository/init/Jackson2RepositoryPopulatorFactoryBean.java @@ -15,8 +15,9 @@ */ package org.springframework.data.repository.init; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.FactoryBean; -import org.springframework.lang.Nullable; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/src/main/java/org/springframework/data/repository/init/Jackson2ResourceReader.java b/src/main/java/org/springframework/data/repository/init/Jackson2ResourceReader.java index 04a0ab8d04..783fa9ec7d 100644 --- a/src/main/java/org/springframework/data/repository/init/Jackson2ResourceReader.java +++ b/src/main/java/org/springframework/data/repository/init/Jackson2ResourceReader.java @@ -23,8 +23,9 @@ import java.util.Iterator; import java.util.List; +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.ClassUtils; diff --git a/src/main/java/org/springframework/data/repository/init/RepositoriesPopulatedEvent.java b/src/main/java/org/springframework/data/repository/init/RepositoriesPopulatedEvent.java index 061dc21f9c..6e815b6ec8 100644 --- a/src/main/java/org/springframework/data/repository/init/RepositoriesPopulatedEvent.java +++ b/src/main/java/org/springframework/data/repository/init/RepositoriesPopulatedEvent.java @@ -17,10 +17,11 @@ import java.io.Serial; +import org.jspecify.annotations.Nullable; + import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationEvent; import org.springframework.data.repository.support.Repositories; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** diff --git a/src/main/java/org/springframework/data/repository/init/ResourceReader.java b/src/main/java/org/springframework/data/repository/init/ResourceReader.java index cfe4204185..e083f8bf71 100644 --- a/src/main/java/org/springframework/data/repository/init/ResourceReader.java +++ b/src/main/java/org/springframework/data/repository/init/ResourceReader.java @@ -15,8 +15,9 @@ */ package org.springframework.data.repository.init; +import org.jspecify.annotations.Nullable; + import org.springframework.core.io.Resource; -import org.springframework.lang.Nullable; /** * @author Oliver Gierke diff --git a/src/main/java/org/springframework/data/repository/init/ResourceReaderRepositoryPopulator.java b/src/main/java/org/springframework/data/repository/init/ResourceReaderRepositoryPopulator.java index 457703e087..ba17727c2e 100644 --- a/src/main/java/org/springframework/data/repository/init/ResourceReaderRepositoryPopulator.java +++ b/src/main/java/org/springframework/data/repository/init/ResourceReaderRepositoryPopulator.java @@ -22,6 +22,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; @@ -32,7 +33,6 @@ import org.springframework.data.repository.support.Repositories; import org.springframework.data.repository.support.RepositoryInvoker; import org.springframework.data.repository.support.RepositoryInvokerFactory; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** diff --git a/src/main/java/org/springframework/data/repository/init/UnmarshallerRepositoryPopulatorFactoryBean.java b/src/main/java/org/springframework/data/repository/init/UnmarshallerRepositoryPopulatorFactoryBean.java index 2c5fd1f8da..4af51c9593 100644 --- a/src/main/java/org/springframework/data/repository/init/UnmarshallerRepositoryPopulatorFactoryBean.java +++ b/src/main/java/org/springframework/data/repository/init/UnmarshallerRepositoryPopulatorFactoryBean.java @@ -15,8 +15,9 @@ */ package org.springframework.data.repository.init; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.FactoryBean; -import org.springframework.lang.Nullable; import org.springframework.oxm.Unmarshaller; import org.springframework.util.Assert; diff --git a/src/main/java/org/springframework/data/repository/init/UnmarshallingResourceReader.java b/src/main/java/org/springframework/data/repository/init/UnmarshallingResourceReader.java index 7a7f954404..fafc22ee40 100644 --- a/src/main/java/org/springframework/data/repository/init/UnmarshallingResourceReader.java +++ b/src/main/java/org/springframework/data/repository/init/UnmarshallingResourceReader.java @@ -19,8 +19,9 @@ import javax.xml.transform.stream.StreamSource; +import org.jspecify.annotations.Nullable; + import org.springframework.core.io.Resource; -import org.springframework.lang.Nullable; import org.springframework.oxm.Unmarshaller; import org.springframework.util.Assert; diff --git a/src/main/java/org/springframework/data/repository/init/package-info.java b/src/main/java/org/springframework/data/repository/init/package-info.java index 23931ebe62..fa678af39b 100644 --- a/src/main/java/org/springframework/data/repository/init/package-info.java +++ b/src/main/java/org/springframework/data/repository/init/package-info.java @@ -1,5 +1,5 @@ /** * Support for repository initialization using XML and JSON. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.repository.init; diff --git a/src/main/java/org/springframework/data/repository/package-info.java b/src/main/java/org/springframework/data/repository/package-info.java index bad4a37e05..ae925608f5 100644 --- a/src/main/java/org/springframework/data/repository/package-info.java +++ b/src/main/java/org/springframework/data/repository/package-info.java @@ -1,5 +1,5 @@ /** * Central interfaces for repository abstraction. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.repository; diff --git a/src/main/java/org/springframework/data/repository/query/FluentQuery.java b/src/main/java/org/springframework/data/repository/query/FluentQuery.java index 86e1848781..506cb01bcd 100644 --- a/src/main/java/org/springframework/data/repository/query/FluentQuery.java +++ b/src/main/java/org/springframework/data/repository/query/FluentQuery.java @@ -24,6 +24,8 @@ import java.util.Optional; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; + import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.ScrollPosition; @@ -31,7 +33,6 @@ import org.springframework.data.domain.Window; import org.springframework.lang.CheckReturnValue; import org.springframework.lang.Contract; -import org.springframework.lang.Nullable; /** * Fluent interface to define and run a query along with projection and sorting and. Instances of {@link FluentQuery} diff --git a/src/main/java/org/springframework/data/repository/query/ParameterAccessor.java b/src/main/java/org/springframework/data/repository/query/ParameterAccessor.java index b4cc076f86..d8a406d909 100644 --- a/src/main/java/org/springframework/data/repository/query/ParameterAccessor.java +++ b/src/main/java/org/springframework/data/repository/query/ParameterAccessor.java @@ -17,11 +17,12 @@ import java.util.Iterator; +import org.jspecify.annotations.Nullable; + import org.springframework.data.domain.Limit; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.ScrollPosition; import org.springframework.data.domain.Sort; -import org.springframework.lang.Nullable; /** * Interface to access method parameters. Allows dedicated access to parameters of special types diff --git a/src/main/java/org/springframework/data/repository/query/ParametersParameterAccessor.java b/src/main/java/org/springframework/data/repository/query/ParametersParameterAccessor.java index 747eb765d6..49815e4ca0 100644 --- a/src/main/java/org/springframework/data/repository/query/ParametersParameterAccessor.java +++ b/src/main/java/org/springframework/data/repository/query/ParametersParameterAccessor.java @@ -17,6 +17,8 @@ import java.util.Iterator; +import org.jspecify.annotations.Nullable; + import org.springframework.data.domain.Limit; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -24,7 +26,6 @@ import org.springframework.data.domain.Sort; import org.springframework.data.repository.util.QueryExecutionConverters; import org.springframework.data.repository.util.ReactiveWrapperConverters; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -36,7 +37,7 @@ public class ParametersParameterAccessor implements ParameterAccessor { private final Parameters parameters; - private final Object[] values; + private final @Nullable Object[] values; /** * Creates a new {@link ParametersParameterAccessor}. @@ -44,7 +45,7 @@ public class ParametersParameterAccessor implements ParameterAccessor { * @param parameters must not be {@literal null}. * @param values must not be {@literal null}. */ - public ParametersParameterAccessor(Parameters parameters, Object[] values) { + public ParametersParameterAccessor(Parameters parameters, @Nullable Object[] values) { Assert.notNull(parameters, "Parameters must not be null"); Assert.notNull(values, "Values must not be null"); @@ -64,7 +65,7 @@ public ParametersParameterAccessor(Parameters parameters, Object[] values) } } - private static boolean requiresUnwrapping(Object[] values) { + private static boolean requiresUnwrapping(@Nullable Object[] values) { for (Object value : values) { if (value != null && (QueryExecutionConverters.supports(value.getClass()) @@ -90,12 +91,12 @@ private static boolean requiresUnwrapping(Object[] values) { * * @return */ - protected Object[] getValues() { + protected @Nullable Object[] getValues() { return this.values; } @Override - public ScrollPosition getScrollPosition() { + public @Nullable ScrollPosition getScrollPosition() { if (!parameters.hasScrollPositionParameter()) { @@ -146,6 +147,7 @@ public Sort getSort() { } @Override + @SuppressWarnings("NullAway") public Limit getLimit() { if (parameters.hasLimitParameter()) { @@ -184,13 +186,12 @@ public Class findDynamicProjection() { * @return */ @SuppressWarnings("unchecked") - @Nullable - protected T getValue(int index) { + protected @Nullable T getValue(int index) { return (T) values[index]; } @Override - public Object getBindableValue(int index) { + public @Nullable Object getBindableValue(int index) { return values[parameters.getBindableParameter(index).getIndex()]; } @@ -207,7 +208,7 @@ public boolean hasBindableNullValue() { } @Override - public BindableParameterIterator iterator() { + public Iterator iterator() { return new BindableParameterIterator(this); } @@ -241,9 +242,8 @@ public BindableParameterIterator(ParametersParameterAccessor accessor) { * * @return */ - @Nullable @Override - public Object next() { + public @Nullable Object next() { return accessor.getBindableValue(currentIndex++); } diff --git a/src/main/java/org/springframework/data/repository/query/QueryCreationException.java b/src/main/java/org/springframework/data/repository/query/QueryCreationException.java index 53b37599d0..739cb7c5e3 100644 --- a/src/main/java/org/springframework/data/repository/query/QueryCreationException.java +++ b/src/main/java/org/springframework/data/repository/query/QueryCreationException.java @@ -18,6 +18,8 @@ import java.io.Serial; import java.lang.reflect.Method; +import org.jspecify.annotations.Nullable; + import org.springframework.data.repository.core.RepositoryCreationException; /** @@ -60,8 +62,8 @@ private QueryCreationException(String message, Throwable cause, Class reposit */ public static QueryCreationException invalidProperty(QueryMethod method, String propertyName) { - return new QueryCreationException(String.format(MESSAGE_TEMPLATE, method, propertyName, method.getDomainClass() - .getName()), method); + return new QueryCreationException( + String.format(MESSAGE_TEMPLATE, method, propertyName, method.getDomainClass().getName()), method); } /** @@ -84,6 +86,7 @@ public static QueryCreationException create(QueryMethod method, String message) * @param cause * @return */ + @SuppressWarnings("NullAway") public static QueryCreationException create(QueryMethod method, Throwable cause) { return new QueryCreationException(cause.getMessage(), cause, method.getMetadata().getRepositoryInterface(), method.getMethod()); @@ -97,7 +100,7 @@ public static QueryCreationException create(QueryMethod method, Throwable cause) * @return * @since 2.5 */ - public static QueryCreationException create(String message, Throwable cause, Class repositoryInterface, + public static QueryCreationException create(@Nullable String message, Throwable cause, Class repositoryInterface, Method method) { return new QueryCreationException(String.format("Could not create query for %s; Reason: %s", method, message), cause, repositoryInterface, method); diff --git a/src/main/java/org/springframework/data/repository/query/QueryLookupStrategy.java b/src/main/java/org/springframework/data/repository/query/QueryLookupStrategy.java index 8191488c86..c69d20869d 100644 --- a/src/main/java/org/springframework/data/repository/query/QueryLookupStrategy.java +++ b/src/main/java/org/springframework/data/repository/query/QueryLookupStrategy.java @@ -18,10 +18,11 @@ import java.lang.reflect.Method; import java.util.Locale; +import org.jspecify.annotations.Nullable; + import org.springframework.data.projection.ProjectionFactory; import org.springframework.data.repository.core.NamedQueries; import org.springframework.data.repository.core.RepositoryMetadata; -import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; /** @@ -41,8 +42,7 @@ public static enum Key { * @param xml * @return a strategy key from the given XML value */ - @Nullable - public static Key create(String xml) { + public static @Nullable Key create(String xml) { if (!StringUtils.hasText(xml)) { return null; diff --git a/src/main/java/org/springframework/data/repository/query/QueryMethodValueEvaluationContextAccessor.java b/src/main/java/org/springframework/data/repository/query/QueryMethodValueEvaluationContextAccessor.java index 168938689b..5b8fa7ee88 100644 --- a/src/main/java/org/springframework/data/repository/query/QueryMethodValueEvaluationContextAccessor.java +++ b/src/main/java/org/springframework/data/repository/query/QueryMethodValueEvaluationContextAccessor.java @@ -22,6 +22,8 @@ import java.util.HashMap; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.core.env.Environment; @@ -38,7 +40,6 @@ import org.springframework.data.spel.spi.ExtensionIdAware; import org.springframework.data.util.ReactiveWrappers; import org.springframework.expression.EvaluationContext; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -56,7 +57,7 @@ public class QueryMethodValueEvaluationContextAccessor { static final StandardEnvironment ENVIRONMENT = new StandardEnvironment(); - private final @Nullable Environment environment; + private final Environment environment; private final EvaluationContextProvider evaluationContextProvider; /** @@ -79,7 +80,7 @@ public QueryMethodValueEvaluationContextAccessor(ApplicationContext context) { * @param environment * @param beanFactory the bean factory to use, must not be {@literal null}. */ - public QueryMethodValueEvaluationContextAccessor(@Nullable Environment environment, ListableBeanFactory beanFactory) { + public QueryMethodValueEvaluationContextAccessor(Environment environment, ListableBeanFactory beanFactory) { this(environment, createEvaluationContextProvider(beanFactory)); } @@ -91,9 +92,10 @@ public QueryMethodValueEvaluationContextAccessor(@Nullable Environment environme * @param evaluationContextProvider the underlying {@link EvaluationContextProvider} to use, must not be * {@literal null}. */ - public QueryMethodValueEvaluationContextAccessor(@Nullable Environment environment, + public QueryMethodValueEvaluationContextAccessor(Environment environment, EvaluationContextProvider evaluationContextProvider) { + Assert.notNull(environment, "Environment must not be null"); Assert.notNull(evaluationContextProvider, "EvaluationContextProvider must not be null"); this.environment = environment; @@ -106,9 +108,10 @@ public QueryMethodValueEvaluationContextAccessor(@Nullable Environment environme * @param environment * @param extensions must not be {@literal null}. */ - public QueryMethodValueEvaluationContextAccessor(@Nullable Environment environment, + public QueryMethodValueEvaluationContextAccessor(Environment environment, Collection extensions) { + Assert.notNull(environment, "Environment must not be null"); Assert.notNull(extensions, "EvaluationContextExtensions must not be null"); this.environment = environment; @@ -206,11 +209,11 @@ static Map collectVariables(Parameters parameters, Object[ */ static class DefaultQueryMethodValueEvaluationContextProvider implements ValueEvaluationContextProvider { - final @Nullable Environment environment; + final Environment environment; final Parameters parameters; final EvaluationContextProvider delegate; - DefaultQueryMethodValueEvaluationContextProvider(@Nullable Environment environment, Parameters parameters, + DefaultQueryMethodValueEvaluationContextProvider(Environment environment, Parameters parameters, EvaluationContextProvider delegate) { this.environment = environment; this.parameters = parameters; @@ -248,7 +251,7 @@ static class DefaultReactiveQueryMethodValueEvaluationContextProvider private final ReactiveEvaluationContextProvider delegate; - DefaultReactiveQueryMethodValueEvaluationContextProvider(@Nullable Environment environment, + DefaultReactiveQueryMethodValueEvaluationContextProvider(Environment environment, Parameters parameters, ReactiveEvaluationContextProvider delegate) { super(environment, parameters, delegate); this.delegate = delegate; diff --git a/src/main/java/org/springframework/data/repository/query/RepositoryQuery.java b/src/main/java/org/springframework/data/repository/query/RepositoryQuery.java index 74244cc3e6..dfdcfa9666 100644 --- a/src/main/java/org/springframework/data/repository/query/RepositoryQuery.java +++ b/src/main/java/org/springframework/data/repository/query/RepositoryQuery.java @@ -15,7 +15,7 @@ */ package org.springframework.data.repository.query; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** * Interface for a query abstraction. diff --git a/src/main/java/org/springframework/data/repository/query/ResultProcessor.java b/src/main/java/org/springframework/data/repository/query/ResultProcessor.java index b798715b7f..499a5de4b9 100644 --- a/src/main/java/org/springframework/data/repository/query/ResultProcessor.java +++ b/src/main/java/org/springframework/data/repository/query/ResultProcessor.java @@ -22,6 +22,8 @@ import java.util.Map; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; + import org.springframework.core.CollectionFactory; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.converter.Converter; @@ -31,7 +33,6 @@ import org.springframework.data.projection.ProjectionFactory; import org.springframework.data.repository.util.ReactiveWrapperConverters; import org.springframework.lang.Contract; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -120,9 +121,8 @@ public ReturnedType getReturnedType() { * @param source can be {@literal null}. * @return */ - @Nullable @Contract("null -> null; !null -> !null") - public T processResult(@Nullable Object source) { + public @Nullable T processResult(@Nullable Object source) { return processResult(source, NoOpConverter.INSTANCE); } @@ -134,10 +134,9 @@ public T processResult(@Nullable Object source) { * @param preparingConverter must not be {@literal null}. * @return */ - @Nullable - @Contract("null -> null; !null -> !null") + @Contract("null, _ -> null; !null, _ -> !null") @SuppressWarnings("unchecked") - public T processResult(@Nullable Object source, Converter preparingConverter) { + public @Nullable T processResult(@Nullable Object source, Converter preparingConverter) { if (source == null || type.isInstance(source) || !type.isProjecting()) { return (T) source; @@ -237,9 +236,8 @@ public ChainingConverter and(final Converter converter) { }); } - @Nullable @Override - public Object convert(Object source) { + public @Nullable Object convert(Object source) { return delegate.convert(source); } } @@ -295,9 +293,8 @@ ProjectingConverter withType(ReturnedType type) { return new ProjectingConverter(type, factory, conversionService); } - @Nullable @Override - public Object convert(Object source) { + public @Nullable Object convert(Object source) { Class targetType = type.getReturnedType(); diff --git a/src/main/java/org/springframework/data/repository/query/ReturnedType.java b/src/main/java/org/springframework/data/repository/query/ReturnedType.java index 97e8b8a9d2..4195eaadc3 100644 --- a/src/main/java/org/springframework/data/repository/query/ReturnedType.java +++ b/src/main/java/org/springframework/data/repository/query/ReturnedType.java @@ -26,6 +26,8 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; import org.springframework.data.mapping.Parameter; import org.springframework.data.mapping.PreferredConstructor; @@ -33,8 +35,6 @@ import org.springframework.data.projection.ProjectionFactory; import org.springframework.data.projection.ProjectionInformation; import org.springframework.lang.Contract; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; @@ -131,8 +131,7 @@ public final boolean isInstance(@Nullable Object source) { * * @return */ - @Nullable - public abstract Class getTypeToRead(); + public abstract @Nullable Class getTypeToRead(); /** * Returns the properties required to be used to populate the result. @@ -210,9 +209,8 @@ public boolean isProjecting() { return !information.getType().isAssignableFrom(domainType); } - @Nullable @Override - public Class getTypeToRead() { + public @Nullable Class getTypeToRead() { return isProjecting() && information.isClosed() ? null : domainType; } diff --git a/src/main/java/org/springframework/data/repository/query/ValueExpressionQueryRewriter.java b/src/main/java/org/springframework/data/repository/query/ValueExpressionQueryRewriter.java index a49b6bd578..1df2162836 100644 --- a/src/main/java/org/springframework/data/repository/query/ValueExpressionQueryRewriter.java +++ b/src/main/java/org/springframework/data/repository/query/ValueExpressionQueryRewriter.java @@ -27,13 +27,14 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.jspecify.annotations.Nullable; + import org.springframework.data.domain.Range; import org.springframework.data.domain.Range.Bound; import org.springframework.data.expression.ValueEvaluationContext; import org.springframework.data.expression.ValueEvaluationContextProvider; import org.springframework.data.expression.ValueExpression; import org.springframework.data.expression.ValueExpressionParser; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -186,8 +187,8 @@ public static class EvaluatingValueExpressionQueryRewriter extends ValueExpressi * @param replacementSource must not be {@literal null}. */ private EvaluatingValueExpressionQueryRewriter(ValueExpressionParser expressionParser, - QueryMethodValueEvaluationContextAccessor factory, - BiFunction parameterNameSource, BiFunction replacementSource) { + QueryMethodValueEvaluationContextAccessor factory, BiFunction parameterNameSource, + BiFunction replacementSource) { super(expressionParser, parameterNameSource, replacementSource); @@ -303,7 +304,14 @@ public boolean isQuoted(int index) { } public ValueExpression getParameter(String name) { - return expressions.get(name); + + ValueExpression valueExpression = expressions.get(name); + + if (valueExpression == null) { + throw new IllegalArgumentException("No ValueExpression with name '%s' found in query.".formatted(name)); + } + + return valueExpression; } /** @@ -414,8 +422,7 @@ public class QueryExpressionEvaluator { private final ValueEvaluationContextProvider evaluationContextProvider; private final ParsedQuery detector; - public QueryExpressionEvaluator(ValueEvaluationContextProvider evaluationContextProvider, - ParsedQuery detector) { + public QueryExpressionEvaluator(ValueEvaluationContextProvider evaluationContextProvider, ParsedQuery detector) { this.evaluationContextProvider = evaluationContextProvider; this.detector = detector; } @@ -426,12 +433,12 @@ public QueryExpressionEvaluator(ValueEvaluationContextProvider evaluationContext * @param values Parameter values. Must not be {@literal null}. * @return a map from parameter name to evaluated value as of {@link ParsedQuery#getParameterMap()}. */ - public Map evaluate(Object[] values) { + public Map evaluate(Object[] values) { Assert.notNull(values, "Values must not be null."); Map parameterMap = detector.getParameterMap(); - Map results = new LinkedHashMap<>(parameterMap.size()); + Map results = new LinkedHashMap<>(parameterMap.size()); parameterMap.forEach((parameter, expression) -> results.put(parameter, evaluate(expression, values))); @@ -447,8 +454,7 @@ public String getQueryString() { return detector.getQueryString(); } - @Nullable - private Object evaluate(ValueExpression expression, Object[] values) { + private @Nullable Object evaluate(ValueExpression expression, Object[] values) { ValueEvaluationContext evaluationContext = evaluationContextProvider.getEvaluationContext(values, expression.getExpressionDependencies()); diff --git a/src/main/java/org/springframework/data/repository/query/package-info.java b/src/main/java/org/springframework/data/repository/query/package-info.java index 550101be17..61a8ab332f 100644 --- a/src/main/java/org/springframework/data/repository/query/package-info.java +++ b/src/main/java/org/springframework/data/repository/query/package-info.java @@ -1,5 +1,5 @@ /** * Support classes to work with query methods. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.repository.query; diff --git a/src/main/java/org/springframework/data/repository/query/parser/AbstractQueryCreator.java b/src/main/java/org/springframework/data/repository/query/parser/AbstractQueryCreator.java index 3822ac30db..e5da9739ba 100644 --- a/src/main/java/org/springframework/data/repository/query/parser/AbstractQueryCreator.java +++ b/src/main/java/org/springframework/data/repository/query/parser/AbstractQueryCreator.java @@ -19,10 +19,11 @@ import java.util.Iterator; import java.util.Optional; +import org.jspecify.annotations.Nullable; + import org.springframework.data.domain.Sort; import org.springframework.data.repository.query.ParameterAccessor; import org.springframework.data.repository.query.ParametersParameterAccessor; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -102,8 +103,7 @@ public T createQuery(Sort dynamicSort) { * @param tree must not be {@literal null}. * @return */ - @Nullable - private S createCriteria(PartTree tree) { + private @Nullable S createCriteria(PartTree tree) { S base = null; Iterator iterator = parameters.map(ParameterAccessor::iterator).orElse(Collections.emptyIterator()); diff --git a/src/main/java/org/springframework/data/repository/query/parser/PartTree.java b/src/main/java/org/springframework/data/repository/query/parser/PartTree.java index 108b5633c5..8882a76d81 100644 --- a/src/main/java/org/springframework/data/repository/query/parser/PartTree.java +++ b/src/main/java/org/springframework/data/repository/query/parser/PartTree.java @@ -23,12 +23,13 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; + import org.springframework.data.domain.Limit; import org.springframework.data.domain.Sort; import org.springframework.data.repository.query.parser.Part.Type; import org.springframework.data.repository.query.parser.PartTree.OrPart; import org.springframework.data.util.Streamable; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -172,8 +173,7 @@ public boolean isLimiting() { * @return {@literal null} if not restricted. * @since 1.9 */ - @Nullable - public Integer getMaxResults() { + public @Nullable Integer getMaxResults() { return subject.getMaxResults().orElse(null); } diff --git a/src/main/java/org/springframework/data/repository/query/parser/package-info.java b/src/main/java/org/springframework/data/repository/query/parser/package-info.java index a2db23ab75..76f90cc813 100644 --- a/src/main/java/org/springframework/data/repository/query/parser/package-info.java +++ b/src/main/java/org/springframework/data/repository/query/parser/package-info.java @@ -1,5 +1,5 @@ /** * Support classes for parsing queries from method names. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.repository.query.parser; diff --git a/src/main/java/org/springframework/data/repository/reactive/package-info.java b/src/main/java/org/springframework/data/repository/reactive/package-info.java index 26c6722845..f7bc4b82e1 100644 --- a/src/main/java/org/springframework/data/repository/reactive/package-info.java +++ b/src/main/java/org/springframework/data/repository/reactive/package-info.java @@ -1,5 +1,5 @@ /** * Support for reactive repositories. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.repository.reactive; diff --git a/src/main/java/org/springframework/data/repository/support/AnnotationAttribute.java b/src/main/java/org/springframework/data/repository/support/AnnotationAttribute.java index 3ae84a4899..7ef4acb7c7 100644 --- a/src/main/java/org/springframework/data/repository/support/AnnotationAttribute.java +++ b/src/main/java/org/springframework/data/repository/support/AnnotationAttribute.java @@ -19,9 +19,10 @@ import java.lang.reflect.AnnotatedElement; import java.util.Optional; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -97,8 +98,7 @@ public Optional getValueFrom(AnnotatedElement annotatedElement) { * @param annotation must not be {@literal null}. * @return */ - @Nullable - public Object getValueFrom(Annotation annotation) { + public @Nullable Object getValueFrom(Annotation annotation) { Assert.notNull(annotation, "Annotation must not be null"); return attributeName.map(it -> AnnotationUtils.getValue(annotation, it)) diff --git a/src/main/java/org/springframework/data/repository/support/DomainClassConverter.java b/src/main/java/org/springframework/data/repository/support/DomainClassConverter.java index 171107c200..a9d0163afc 100644 --- a/src/main/java/org/springframework/data/repository/support/DomainClassConverter.java +++ b/src/main/java/org/springframework/data/repository/support/DomainClassConverter.java @@ -19,6 +19,9 @@ import java.util.Optional; import java.util.Set; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.core.convert.ConversionService; @@ -30,8 +33,6 @@ import org.springframework.data.repository.core.RepositoryInformation; import org.springframework.data.util.Lazy; import org.springframework.lang.Contract; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -73,9 +74,8 @@ public Set getConvertibleTypes() { return Collections.singleton(new ConvertiblePair(Object.class, Object.class)); } - @Nullable @Override - public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + public @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { return getConverter(targetType).map(it -> it.convert(source, sourceType, targetType)).orElse(null); } @@ -137,10 +137,9 @@ public Set getConvertibleTypes() { return Collections.singleton(new ConvertiblePair(Object.class, Object.class)); } - @Nullable - @Contract("null -> null") + @Contract("null, _, _ -> null") @Override - public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + public @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { if (source == null || !StringUtils.hasText(source.toString())) { return null; @@ -209,10 +208,9 @@ public Set getConvertibleTypes() { return Collections.singleton(new ConvertiblePair(Object.class, Object.class)); } - @Nullable - @Contract("null -> null") + @Contract("null, _, _ -> null") @Override - public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + public @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { if (source == null || !StringUtils.hasText(source.toString())) { return null; diff --git a/src/main/java/org/springframework/data/repository/support/MethodParameters.java b/src/main/java/org/springframework/data/repository/support/MethodParameters.java index c345dcf13a..565cb20b36 100644 --- a/src/main/java/org/springframework/data/repository/support/MethodParameters.java +++ b/src/main/java/org/springframework/data/repository/support/MethodParameters.java @@ -22,11 +22,12 @@ import java.util.Optional; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; + import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.core.MethodParameter; import org.springframework.core.ParameterNameDiscoverer; import org.springframework.data.util.Lazy; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -153,9 +154,8 @@ public AnnotationNamingMethodParameter(Method method, int parameterIndex, Option orElseGet(super::getParameterName)); } - @Nullable @Override - public String getParameterName() { + public @Nullable String getParameterName() { return name.orElse(null); } } diff --git a/src/main/java/org/springframework/data/repository/support/ReflectionRepositoryInvoker.java b/src/main/java/org/springframework/data/repository/support/ReflectionRepositoryInvoker.java index 8967edcb0e..c56b9c3ff8 100644 --- a/src/main/java/org/springframework/data/repository/support/ReflectionRepositoryInvoker.java +++ b/src/main/java/org/springframework/data/repository/support/ReflectionRepositoryInvoker.java @@ -20,6 +20,8 @@ import java.util.List; import java.util.Optional; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.core.convert.ConversionException; import org.springframework.core.convert.ConversionService; @@ -32,7 +34,6 @@ import org.springframework.data.repository.util.QueryExecutionConverters; import org.springframework.data.util.TypeInformation; import org.springframework.lang.Contract; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.MultiValueMap; @@ -194,9 +195,8 @@ private Object[] prepareParameters(Method method, MultiValueMap rawPa return result; } - @Nullable @Contract("null, _ -> null") - private Object convert(@Nullable Object value, MethodParameter parameter) { + private @Nullable Object convert(@Nullable Object value, MethodParameter parameter) { if (value == null) { return value; @@ -216,13 +216,12 @@ private Object convert(@Nullable Object value, MethodParameter parameter) { * @param arguments * @return */ - @Nullable @SuppressWarnings("unchecked") - private T invoke(Method method, Object... arguments) { + private @Nullable T invoke(Method method, @Nullable Object... arguments) { return (T) ReflectionUtils.invokeMethod(method, repository, arguments); } - private T invokeForNonNullResult(Method method, Object... arguments) { + private T invokeForNonNullResult(Method method, @Nullable Object... arguments) { T result = invoke(method, arguments); @@ -304,8 +303,7 @@ protected Iterable invokeFindAllReflectively(Sort sort) { * @param source can be {@literal null}. * @return */ - @Nullable - private static Object unwrapSingleElement(@Nullable List source) { + private static @Nullable Object unwrapSingleElement(@Nullable List source) { return source == null ? null : source.size() == 1 ? source.get(0) : source; } } diff --git a/src/main/java/org/springframework/data/repository/support/package-info.java b/src/main/java/org/springframework/data/repository/support/package-info.java index 1413e89a59..35cb53879d 100644 --- a/src/main/java/org/springframework/data/repository/support/package-info.java +++ b/src/main/java/org/springframework/data/repository/support/package-info.java @@ -1,5 +1,5 @@ /** * Support classes for integration of the repository programming model with 3rd party frameworks. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.repository.support; diff --git a/src/main/java/org/springframework/data/repository/util/QueryExecutionConverters.java b/src/main/java/org/springframework/data/repository/util/QueryExecutionConverters.java index 1a72722675..a10d45c078 100644 --- a/src/main/java/org/springframework/data/repository/util/QueryExecutionConverters.java +++ b/src/main/java/org/springframework/data/repository/util/QueryExecutionConverters.java @@ -28,6 +28,8 @@ import java.util.function.Function; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; + import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.converter.ConditionalGenericConverter; @@ -46,7 +48,6 @@ import org.springframework.data.util.Streamable; import org.springframework.data.util.TypeInformation; import org.springframework.lang.Contract; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ConcurrentReferenceHashMap; @@ -104,7 +105,7 @@ public abstract class QueryExecutionConverters { CustomCollections.getCustomTypes().stream().map(WrapperType::multiValue).forEach(WRAPPER_TYPES::add); - CustomCollections.getPaginationReturnTypes().forEach(ALLOWED_PAGEABLE_TYPES::add); + ALLOWED_PAGEABLE_TYPES.addAll(CustomCollections.getPaginationReturnTypes()); if (VAVR_PRESENT) { @@ -210,9 +211,8 @@ public static void registerConvertersIn(ConfigurableConversionService conversion * @param source can be {@literal null}. * @return */ - @Nullable @Contract("null -> null") - public static Object unwrap(@Nullable Object source) { + public static @Nullable Object unwrap(@Nullable Object source) { source = NullableWrapperConverters.unwrap(source); @@ -276,8 +276,7 @@ public static TypeInformation unwrapWrapperTypes(TypeInformation type) { * @param returnType must not be {@literal null}. * @return can be {@literal null}. */ - @Nullable - public static ExecutionAdapter getExecutionAdapter(Class returnType) { + public static @Nullable ExecutionAdapter getExecutionAdapter(Class returnType) { Assert.notNull(returnType, "Return type must not be null"); @@ -285,10 +284,12 @@ public static ExecutionAdapter getExecutionAdapter(Class returnType) { } public interface ThrowingSupplier { + @Nullable Object get() throws Throwable; } public interface ExecutionAdapter { + @Nullable Object apply(ThrowingSupplier supplier) throws Throwable; } @@ -303,19 +304,6 @@ private static abstract class AbstractWrapperTypeConverter implements GenericCon private final Object nullValue; private final Iterable> wrapperTypes; - /** - * Creates a new {@link AbstractWrapperTypeConverter} using the given {@link ConversionService} and wrapper type. - * - * @param nullValue must not be {@literal null}. - */ - AbstractWrapperTypeConverter(Object nullValue) { - - Assert.notNull(nullValue, "Null value must not be null"); - - this.nullValue = nullValue; - this.wrapperTypes = Collections.singleton(nullValue.getClass()); - } - AbstractWrapperTypeConverter(Object nullValue, Iterable> wrapperTypes) { this.nullValue = nullValue; this.wrapperTypes = wrapperTypes; @@ -329,10 +317,10 @@ public Set getConvertibleTypes() { .stream().collect(StreamUtils.toUnmodifiableSet()); } - @Nullable - @Contract("null -> null") + @Contract("null, _, _ -> null") @Override - public final Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + public final @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, + TypeDescriptor targetType) { if (source == null) { return null; @@ -341,7 +329,6 @@ public final Object convert(@Nullable Object source, TypeDescriptor sourceType, NullableWrapper wrapper = (NullableWrapper) source; Object value = wrapper.getValue(); - // TODO: Add Recursive conversion once we move to Spring 4 return value == null ? nullValue : wrap(value); } @@ -412,10 +399,9 @@ public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { }); } - @SuppressWarnings("unchecked") - @Nullable + @SuppressWarnings({ "unchecked", "rawtypes" }) @Override - public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + public @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { Streamable streamable = source == null // ? Streamable.empty() // diff --git a/src/main/java/org/springframework/data/repository/util/ReactiveWrapperConverters.java b/src/main/java/org/springframework/data/repository/util/ReactiveWrapperConverters.java index 142f426ff3..554d9dbac2 100644 --- a/src/main/java/org/springframework/data/repository/util/ReactiveWrapperConverters.java +++ b/src/main/java/org/springframework/data/repository/util/ReactiveWrapperConverters.java @@ -26,6 +26,8 @@ import java.util.Optional; import java.util.function.Function; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; import org.reactivestreams.Publisher; import org.springframework.core.ReactiveAdapter; @@ -38,8 +40,6 @@ import org.springframework.core.convert.support.GenericConversionService; import org.springframework.data.util.ReactiveWrappers.ReactiveLibrary; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -166,7 +166,7 @@ public static TypeInformation unwrapWrapperTypes(TypeInformation type) { * @param targetWrapperType must not be {@literal null}. * @return */ - @SuppressWarnings({ "unchecked", "DataFlowIssue" }) + @SuppressWarnings({ "unchecked" }) public static T toWrapper(Object reactiveObject, Class targetWrapperType) { Assert.notNull(reactiveObject, "Reactive source object must not be null"); @@ -176,7 +176,13 @@ public static T toWrapper(Object reactiveObject, Class targetWr return (T) reactiveObject; } - return GENERIC_CONVERSION_SERVICE.convert(reactiveObject, targetWrapperType); + T convert = GENERIC_CONVERSION_SERVICE.convert(reactiveObject, targetWrapperType); + + if (convert == null) { + throw new IllegalStateException("Wait, what?"); + } + + return convert; } /** @@ -260,7 +266,7 @@ public Class> getWrapperClass() { @Override public Mono map(Object wrapper, Function function) { - return ((Mono) wrapper).map(function::apply); + return ((Mono) wrapper).map(function); } } @@ -529,13 +535,13 @@ public Converter getConverter(Class targetType) { return source -> { Publisher publisher = source instanceof Publisher ? (Publisher) source - : RegistryHolder.REACTIVE_ADAPTER_REGISTRY.getAdapter(Publisher.class, source).toPublisher(source); - - ReactiveAdapter adapter = RegistryHolder.REACTIVE_ADAPTER_REGISTRY.getAdapter(targetType); + : RegistryHolder.getAdapter(Publisher.class, source).toPublisher(source); + ReactiveAdapter adapter = RegistryHolder.getAdapter(targetType); return (T) adapter.fromPublisher(publisher); }; } + } /** @@ -556,5 +562,39 @@ static class RegistryHolder { REACTIVE_ADAPTER_REGISTRY = null; } } + + static ReactiveAdapterRegistry getReactiveAdapterRegistry() { + + if (REACTIVE_ADAPTER_REGISTRY == null) { + throw new IllegalStateException( + "ReactiveAdapterRegistry not available. Make sure to have Project Reactor on your classpath!"); + } + + return REACTIVE_ADAPTER_REGISTRY; + } + + public static ReactiveAdapter getAdapter(Class reactiveType, Object source) { + + ReactiveAdapter adapter = getReactiveAdapterRegistry().getAdapter(reactiveType, source); + + if (adapter == null) { + throw new IllegalArgumentException("Cannot convert Reactive Type '%s' (%s) to Publisher" + .formatted(reactiveType.getName(), source.getClass().getName())); + } + + return adapter; + } + + public static ReactiveAdapter getAdapter(Class reactiveType) { + + ReactiveAdapter adapter = getReactiveAdapterRegistry().getAdapter(reactiveType); + + if (adapter == null) { + throw new IllegalArgumentException( + "No ReactiveAdapter for '%s' conversion registered.".formatted(reactiveType.getName())); + } + + return adapter; + } } } diff --git a/src/main/java/org/springframework/data/repository/util/package-info.java b/src/main/java/org/springframework/data/repository/util/package-info.java index 0b6e96025d..dd3979c6b1 100644 --- a/src/main/java/org/springframework/data/repository/util/package-info.java +++ b/src/main/java/org/springframework/data/repository/util/package-info.java @@ -1,5 +1,5 @@ /** * Utility classes for repository implementations. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.repository.util; diff --git a/src/main/java/org/springframework/data/spel/EvaluationContextProvider.java b/src/main/java/org/springframework/data/spel/EvaluationContextProvider.java index d8282c64a4..85ecbf6615 100644 --- a/src/main/java/org/springframework/data/spel/EvaluationContextProvider.java +++ b/src/main/java/org/springframework/data/spel/EvaluationContextProvider.java @@ -15,9 +15,10 @@ */ package org.springframework.data.spel; +import org.jspecify.annotations.Nullable; + import org.springframework.expression.EvaluationContext; import org.springframework.expression.spel.support.StandardEvaluationContext; -import org.springframework.lang.Nullable; /** * Provides a way to access a centrally defined potentially shared {@link StandardEvaluationContext}. diff --git a/src/main/java/org/springframework/data/spel/ExtensionAwareEvaluationContextProvider.java b/src/main/java/org/springframework/data/spel/ExtensionAwareEvaluationContextProvider.java index b3d5eec7a1..2e2a54fc50 100644 --- a/src/main/java/org/springframework/data/spel/ExtensionAwareEvaluationContextProvider.java +++ b/src/main/java/org/springframework/data/spel/ExtensionAwareEvaluationContextProvider.java @@ -26,6 +26,8 @@ import java.util.function.Predicate; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.context.expression.BeanFactoryResolver; @@ -47,7 +49,6 @@ import org.springframework.expression.spel.SpelMessage; import org.springframework.expression.spel.support.ReflectivePropertyAccessor; import org.springframework.expression.spel.support.StandardEvaluationContext; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -67,7 +68,7 @@ public class ExtensionAwareEvaluationContextProvider implements EvaluationContex private final Map extensionInformationCache = new ConcurrentHashMap<>(); private final Lazy> extensions; - private ListableBeanFactory beanFactory; + private @Nullable ListableBeanFactory beanFactory; ExtensionAwareEvaluationContextProvider() { this(Collections.emptyList()); @@ -95,8 +96,7 @@ public ExtensionAwareEvaluationContextProvider(Collection> extensions) { + public ExtensionAwareEvaluationContextProvider(Lazy> extensions) { this.extensions = extensions; } @@ -273,9 +273,8 @@ public void write(EvaluationContext context, @Nullable Object target, String nam // noop } - @Nullable @Override - public Class[] getSpecificTargetClasses() { + public Class @Nullable [] getSpecificTargetClasses() { return null; } @@ -323,16 +322,11 @@ private TypedValue lookupPropertyFrom(EvaluationContextExtensionAdapter extensio * @author Oliver Gierke * @since 1.9 */ - private static class FunctionMethodExecutor implements MethodExecutor { - - private final Function function; - - public FunctionMethodExecutor(Function function) { - this.function = function; - } + private record FunctionMethodExecutor(Function function) implements MethodExecutor { @Override - public TypedValue execute(EvaluationContext context, Object target, Object... arguments) throws AccessException { + public TypedValue execute(EvaluationContext context, Object target, @Nullable Object... arguments) + throws AccessException { try { return new TypedValue(function.invoke(arguments)); @@ -354,7 +348,6 @@ public TypedValue execute(EvaluationContext context, Object target, Object... ar private static class EvaluationContextExtensionAdapter { private final EvaluationContextExtension extension; - private final Functions functions = new Functions(); private final Map properties; @@ -420,5 +413,7 @@ public Map getProperties() { public String toString() { return String.format("EvaluationContextExtensionAdapter for '%s'", getExtensionId()); } + } + } diff --git a/src/main/java/org/springframework/data/spel/ReactiveEvaluationContextProvider.java b/src/main/java/org/springframework/data/spel/ReactiveEvaluationContextProvider.java index 5ea24795a5..13cb2fc353 100644 --- a/src/main/java/org/springframework/data/spel/ReactiveEvaluationContextProvider.java +++ b/src/main/java/org/springframework/data/spel/ReactiveEvaluationContextProvider.java @@ -17,8 +17,9 @@ import reactor.core.publisher.Mono; +import org.jspecify.annotations.Nullable; + import org.springframework.expression.EvaluationContext; -import org.springframework.lang.Nullable; /** * Provides a way to access a centrally defined potentially shared {@link EvaluationContext}. diff --git a/src/main/java/org/springframework/data/spel/ReactiveExtensionAwareEvaluationContextProvider.java b/src/main/java/org/springframework/data/spel/ReactiveExtensionAwareEvaluationContextProvider.java index 73f0a319aa..39c04d28b2 100644 --- a/src/main/java/org/springframework/data/spel/ReactiveExtensionAwareEvaluationContextProvider.java +++ b/src/main/java/org/springframework/data/spel/ReactiveExtensionAwareEvaluationContextProvider.java @@ -22,6 +22,8 @@ import java.util.List; import java.util.function.Predicate; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.core.ResolvableType; import org.springframework.data.spel.spi.EvaluationContextExtension; @@ -31,7 +33,6 @@ import org.springframework.data.util.ReflectionUtils; import org.springframework.expression.EvaluationContext; import org.springframework.expression.spel.support.StandardEvaluationContext; -import org.springframework.lang.Nullable; /** * A reactive {@link EvaluationContextProvider} that assembles an {@link EvaluationContext} from a list of @@ -72,12 +73,12 @@ public ReactiveExtensionAwareEvaluationContextProvider(Collection> getExtensions( if (it instanceof ReactiveEvaluationContextExtension extension) { ResolvableType actualType = getExtensionType(it); + Class rawClass = actualType.getRawClass(); - if (actualType.equals(ResolvableType.NONE) || actualType.isAssignableFrom(GENERIC_EXTENSION_TYPE)) { + if (actualType.equals(ResolvableType.NONE) || actualType.isAssignableFrom(GENERIC_EXTENSION_TYPE) + || rawClass == null) { return extension.getExtension(); } - EvaluationContextExtensionInformation information = evaluationContextProvider - .getOrCreateInformation((Class) actualType.getRawClass()); + EvaluationContextExtensionInformation information = evaluationContextProvider.getOrCreateInformation(rawClass); if (extensionFilter.test(information)) { return extension.getExtension(); diff --git a/src/main/java/org/springframework/data/spel/package-info.java b/src/main/java/org/springframework/data/spel/package-info.java index d45330a59c..7b87be9397 100644 --- a/src/main/java/org/springframework/data/spel/package-info.java +++ b/src/main/java/org/springframework/data/spel/package-info.java @@ -1,5 +1,5 @@ /** * SpEL support. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.spel; diff --git a/src/main/java/org/springframework/data/spel/spi/EvaluationContextExtension.java b/src/main/java/org/springframework/data/spel/spi/EvaluationContextExtension.java index 3283a8a875..1f467ba38a 100644 --- a/src/main/java/org/springframework/data/spel/spi/EvaluationContextExtension.java +++ b/src/main/java/org/springframework/data/spel/spi/EvaluationContextExtension.java @@ -18,9 +18,10 @@ import java.util.Collections; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.data.spel.ExtensionAwareEvaluationContextProvider; import org.springframework.expression.EvaluationContext; -import org.springframework.lang.Nullable; /** * SPI to allow adding a set of properties and function definitions accessible via the root of an @@ -61,8 +62,7 @@ default Map getFunctions() { * * @return the root object to be exposed by the extension. */ - @Nullable - default Object getRootObject() { + default @Nullable Object getRootObject() { return null; } } diff --git a/src/main/java/org/springframework/data/spel/spi/Function.java b/src/main/java/org/springframework/data/spel/spi/Function.java index 33182e3c19..629bb9d9bc 100644 --- a/src/main/java/org/springframework/data/spel/spi/Function.java +++ b/src/main/java/org/springframework/data/spel/spi/Function.java @@ -22,9 +22,10 @@ import java.util.Arrays; import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.core.convert.TypeDescriptor; import org.springframework.data.util.ParameterTypes; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -77,7 +78,7 @@ public Function(Method method, @Nullable Object target) { * @return * @throws Exception */ - public Object invoke(Object[] arguments) throws Exception { + public @Nullable Object invoke(@Nullable Object[] arguments) throws Exception { if (method.getParameterCount() == arguments.length) { return method.invoke(target, arguments); @@ -88,15 +89,15 @@ public Object invoke(Object[] arguments) throws Exception { if (tailType.isArray()) { - List argumentsToUse = new ArrayList<>(types.length); + List<@Nullable Object> argumentsToUse = new ArrayList<>(types.length); // Add all arguments up until the last one - for (int i = 0; i < types.length - 1; i++) { - argumentsToUse.add(arguments[i]); - } + argumentsToUse.addAll(Arrays.asList(arguments).subList(0, types.length - 1)); // Gather all other arguments into an array of the tail type - Object[] varargs = (Object[]) Array.newInstance(tailType.getComponentType(), arguments.length - types.length + 1); + @Nullable + Object[] varargs = (@Nullable Object[]) Array.newInstance(tailType.getComponentType(), + arguments.length - types.length + 1); int count = 0; for (int i = types.length - 1; i < arguments.length; i++) { @@ -105,10 +106,12 @@ public Object invoke(Object[] arguments) throws Exception { argumentsToUse.add(varargs); - return method.invoke(target, argumentsToUse.size() == 1 ? argumentsToUse.get(0) : argumentsToUse.toArray()); + return method.invoke(target, + argumentsToUse.size() == 1 ? new @Nullable Object[] { argumentsToUse.get(0) } : argumentsToUse.toArray()); } - throw new IllegalStateException(String.format("Could not invoke method %s for arguments %s", method, arguments)); + throw new IllegalStateException( + String.format("Could not invoke method %s for arguments %s", method, Arrays.toString(arguments))); } /** diff --git a/src/main/java/org/springframework/data/spel/spi/package-info.java b/src/main/java/org/springframework/data/spel/spi/package-info.java index 64a9cc8ab7..c1017f5f99 100644 --- a/src/main/java/org/springframework/data/spel/spi/package-info.java +++ b/src/main/java/org/springframework/data/spel/spi/package-info.java @@ -1,5 +1,5 @@ /** * Service provider interfaces to extend the query execution mechanism. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.spel.spi; diff --git a/src/main/java/org/springframework/data/support/ExampleMatcherAccessor.java b/src/main/java/org/springframework/data/support/ExampleMatcherAccessor.java index 602da65559..bbbab55649 100644 --- a/src/main/java/org/springframework/data/support/ExampleMatcherAccessor.java +++ b/src/main/java/org/springframework/data/support/ExampleMatcherAccessor.java @@ -17,6 +17,8 @@ import java.util.Collection; +import org.jspecify.annotations.Nullable; + import org.springframework.data.domain.ExampleMatcher; import org.springframework.data.domain.ExampleMatcher.PropertySpecifier; @@ -63,7 +65,7 @@ public boolean hasPropertySpecifier(String path) { * @param path Dot-Path to property. * @return {@literal null} when no {@link ExampleMatcher.PropertySpecifier} defined for path. */ - public ExampleMatcher.PropertySpecifier getPropertySpecifier(String path) { + public ExampleMatcher.@Nullable PropertySpecifier getPropertySpecifier(String path) { return matcher.getPropertySpecifiers().getForPath(path); } @@ -80,6 +82,7 @@ public boolean hasPropertySpecifiers() { * @param path * @return never {@literal null}. */ + @SuppressWarnings("NullAway") public ExampleMatcher.StringMatcher getStringMatcherForPath(String path) { if (!hasPropertySpecifier(path)) { @@ -131,6 +134,7 @@ public boolean isIgnoredPath(String path) { * @param path * @return never {@literal null}. */ + @SuppressWarnings("NullAway") public boolean isIgnoreCaseForPath(String path) { if (!hasPropertySpecifier(path)) { @@ -150,6 +154,7 @@ public boolean isIgnoreCaseForPath(String path) { * @param path * @return never {@literal null}. */ + @SuppressWarnings("NullAway") public ExampleMatcher.PropertyValueTransformer getValueTransformerForPath(String path) { if (!hasPropertySpecifier(path)) { diff --git a/src/main/java/org/springframework/data/support/WindowIterator.java b/src/main/java/org/springframework/data/support/WindowIterator.java index 245ee39cef..36dc3caabc 100644 --- a/src/main/java/org/springframework/data/support/WindowIterator.java +++ b/src/main/java/org/springframework/data/support/WindowIterator.java @@ -21,10 +21,11 @@ import java.util.NoSuchElementException; import java.util.function.Function; +import org.jspecify.annotations.Nullable; + import org.springframework.data.domain.KeysetScrollPosition; import org.springframework.data.domain.ScrollPosition; import org.springframework.data.domain.Window; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -82,26 +83,20 @@ public boolean hasNext() { } if (currentIterator == null) { - if (currentWindow != null) { - currentIterator = isBackwardsScrolling(currentPosition) - ? new ReverseListIterator<>(currentWindow.getContent()) - : currentWindow.iterator(); - } + currentIterator = isBackwardsScrolling(currentPosition) ? new ReverseListIterator<>(currentWindow.getContent()) + : currentWindow.iterator(); } - if (currentIterator != null) { - - if (currentIterator.hasNext()) { - return true; - } + if (currentIterator.hasNext()) { + return true; + } - if (currentWindow != null && currentWindow.hasNext()) { + if (currentWindow != null && currentWindow.hasNext()) { - currentPosition = getNextPosition(currentPosition, currentWindow); - currentIterator = null; - currentWindow = null; - continue; - } + currentPosition = getNextPosition(currentPosition, currentWindow); + currentIterator = null; + currentWindow = null; + continue; } return false; @@ -109,6 +104,7 @@ public boolean hasNext() { } @Override + @SuppressWarnings("NullAway") public T next() { if (!hasNext()) { diff --git a/src/main/java/org/springframework/data/support/package-info.java b/src/main/java/org/springframework/data/support/package-info.java index e6f7d23b54..35ab4c7415 100644 --- a/src/main/java/org/springframework/data/support/package-info.java +++ b/src/main/java/org/springframework/data/support/package-info.java @@ -1,5 +1,5 @@ /** * Core support classes. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.support; diff --git a/src/main/java/org/springframework/data/transaction/ChainedTransactionManager.java b/src/main/java/org/springframework/data/transaction/ChainedTransactionManager.java index 85329b2c8e..83f5496260 100644 --- a/src/main/java/org/springframework/data/transaction/ChainedTransactionManager.java +++ b/src/main/java/org/springframework/data/transaction/ChainedTransactionManager.java @@ -25,8 +25,8 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; -import org.springframework.lang.Nullable; import org.springframework.transaction.CannotCreateTransactionException; import org.springframework.transaction.HeuristicCompletionException; import org.springframework.transaction.PlatformTransactionManager; @@ -102,7 +102,9 @@ public ChainedTransactionManager(PlatformTransactionManager... transactionManage this.transactionManagers = asList(transactionManagers); } - public MultiTransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException { + @SuppressWarnings("NullAway") + @Override + public TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException { MultiTransactionStatus mts = new MultiTransactionStatus(transactionManagers.get(0)); @@ -145,6 +147,7 @@ public MultiTransactionStatus getTransaction(@Nullable TransactionDefinition def return mts; } + @Override public void commit(TransactionStatus status) throws TransactionException { MultiTransactionStatus multiTransactionStatus = (MultiTransactionStatus) status; @@ -189,6 +192,7 @@ public void commit(TransactionStatus status) throws TransactionException { } } + @Override public void rollback(TransactionStatus status) throws TransactionException { Exception rollbackException = null; diff --git a/src/main/java/org/springframework/data/transaction/MultiTransactionStatus.java b/src/main/java/org/springframework/data/transaction/MultiTransactionStatus.java index ea6c3a3209..e808feffb9 100644 --- a/src/main/java/org/springframework/data/transaction/MultiTransactionStatus.java +++ b/src/main/java/org/springframework/data/transaction/MultiTransactionStatus.java @@ -65,7 +65,8 @@ public boolean isNewSynchonization() { return newSynchonization; } - public void registerTransactionManager(TransactionDefinition definition, PlatformTransactionManager transactionManager) { + public void registerTransactionManager(TransactionDefinition definition, + PlatformTransactionManager transactionManager) { getTransactionStatuses().put(transactionManager, transactionManager.getTransaction(definition)); } @@ -83,28 +84,34 @@ public void rollback(PlatformTransactionManager transactionManager) { transactionManager.rollback(getTransactionStatus(transactionManager)); } + @Override public boolean isRollbackOnly() { return getMainTransactionStatus().isRollbackOnly(); } + @Override public boolean isCompleted() { return getMainTransactionStatus().isCompleted(); } + @Override public boolean isNewTransaction() { return getMainTransactionStatus().isNewTransaction(); } + @Override public boolean hasSavepoint() { return getMainTransactionStatus().hasSavepoint(); } + @Override public void setRollbackOnly() { for (TransactionStatus ts : transactionStatuses.values()) { ts.setRollbackOnly(); } } + @Override public Object createSavepoint() throws TransactionException { SavePoints savePoints = new SavePoints(); @@ -115,15 +122,18 @@ public Object createSavepoint() throws TransactionException { return savePoints; } + @Override public void rollbackToSavepoint(Object savepoint) throws TransactionException { SavePoints savePoints = (SavePoints) savepoint; savePoints.rollback(); } + @Override public void releaseSavepoint(Object savepoint) throws TransactionException { ((SavePoints) savepoint).release(); } + @Override public void flush() { for (TransactionStatus transactionStatus : transactionStatuses.values()) { transactionStatus.flush(); @@ -131,11 +141,21 @@ public void flush() { } private TransactionStatus getMainTransactionStatus() { - return transactionStatuses.get(mainTransactionManager); + + TransactionStatus status = transactionStatuses.get(mainTransactionManager); + + Assert.state(status != null, "No TransactionStatus for main transaction manager found"); + + return status; } private TransactionStatus getTransactionStatus(PlatformTransactionManager transactionManager) { - return this.getTransactionStatuses().get(transactionManager); + + TransactionStatus status = getTransactionStatuses().get(transactionManager); + + Assert.state(status != null, "No TransactionStatus for transaction manager %s found".formatted(transactionManager)); + + return status; } private static class SavePoints { @@ -160,7 +180,12 @@ public void rollback() { } private Object savepointFor(TransactionStatus transactionStatus) { - return savepoints.get(transactionStatus); + + Object savepoint = savepoints.get(transactionStatus); + + Assert.state(savepoint != null, "No SavePoint for transaction status %s found".formatted(transactionStatus)); + + return savepoint; } public void release() { diff --git a/src/main/java/org/springframework/data/transaction/package-info.java b/src/main/java/org/springframework/data/transaction/package-info.java index 48e56615b9..e15133d1b6 100644 --- a/src/main/java/org/springframework/data/transaction/package-info.java +++ b/src/main/java/org/springframework/data/transaction/package-info.java @@ -3,5 +3,5 @@ * * @see org.springframework.data.transaction.ChainedTransactionManager */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.transaction; diff --git a/src/main/java/org/springframework/data/util/AnnotatedTypeScanner.java b/src/main/java/org/springframework/data/util/AnnotatedTypeScanner.java index 777f03a591..bd647bbe17 100644 --- a/src/main/java/org/springframework/data/util/AnnotatedTypeScanner.java +++ b/src/main/java/org/springframework/data/util/AnnotatedTypeScanner.java @@ -23,6 +23,8 @@ import java.util.function.Consumer; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.EnvironmentAware; @@ -32,7 +34,6 @@ import org.springframework.core.io.ResourceLoader; import org.springframework.core.type.filter.AnnotationTypeFilter; import org.springframework.core.type.filter.TypeFilter; -import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; /** diff --git a/src/main/java/org/springframework/data/util/AnnotationDetectionFieldCallback.java b/src/main/java/org/springframework/data/util/AnnotationDetectionFieldCallback.java index a37eb21b49..79d6c10378 100755 --- a/src/main/java/org/springframework/data/util/AnnotationDetectionFieldCallback.java +++ b/src/main/java/org/springframework/data/util/AnnotationDetectionFieldCallback.java @@ -18,8 +18,9 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Field; +import org.jspecify.annotations.Nullable; + import org.springframework.core.annotation.AnnotatedElementUtils; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils.FieldCallback; @@ -67,8 +68,7 @@ public void doWith(Field field) throws IllegalArgumentException, IllegalAccessEx * * @return the field */ - @Nullable - public Field getField() { + public @Nullable Field getField() { return field; } @@ -94,8 +94,7 @@ public Field getRequiredField() { * * @return */ - @Nullable - public Class getType() { + public @Nullable Class getType() { Field field = this.field; diff --git a/src/main/java/org/springframework/data/util/AnnotationDetectionMethodCallback.java b/src/main/java/org/springframework/data/util/AnnotationDetectionMethodCallback.java index df1e7af618..14567b4b10 100644 --- a/src/main/java/org/springframework/data/util/AnnotationDetectionMethodCallback.java +++ b/src/main/java/org/springframework/data/util/AnnotationDetectionMethodCallback.java @@ -18,8 +18,9 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Method; +import org.jspecify.annotations.Nullable; + import org.springframework.core.annotation.AnnotatedElementUtils; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils.MethodCallback; @@ -68,8 +69,7 @@ public AnnotationDetectionMethodCallback(Class annotationType, boolean enforc /** * @return the method */ - @Nullable - public Method getMethod() { + public @Nullable Method getMethod() { return foundMethod; } @@ -93,8 +93,7 @@ public Method getRequiredMethod() { /** * @return the annotation */ - @Nullable - public A getAnnotation() { + public @Nullable A getAnnotation() { return annotation; } @@ -136,9 +135,8 @@ public void doWith(Method method) throws IllegalArgumentException, IllegalAccess * @return * @since 2.7 */ - @Nullable @SuppressWarnings("unchecked") - public T invoke(@Nullable Object target, Object... args) { + public @Nullable T invoke(@Nullable Object target, Object... args) { Method method = this.foundMethod; diff --git a/src/main/java/org/springframework/data/util/BeanLookup.java b/src/main/java/org/springframework/data/util/BeanLookup.java index b858933c73..66e32e7084 100644 --- a/src/main/java/org/springframework/data/util/BeanLookup.java +++ b/src/main/java/org/springframework/data/util/BeanLookup.java @@ -17,10 +17,11 @@ import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.NoUniqueBeanDefinitionException; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -60,8 +61,7 @@ public static Lazy lazyIfAvailable(Class type, BeanFactory beanFactory * @param beanFactory must not be {@literal null}. * @return */ - @Nullable - private static T lookupBean(Class type, ListableBeanFactory beanFactory) { + private static @Nullable T lookupBean(Class type, ListableBeanFactory beanFactory) { Map names = beanFactory.getBeansOfType(type, false, false); diff --git a/src/main/java/org/springframework/data/util/ClassTypeInformation.java b/src/main/java/org/springframework/data/util/ClassTypeInformation.java index 21d588df5b..c70b8cbf45 100644 --- a/src/main/java/org/springframework/data/util/ClassTypeInformation.java +++ b/src/main/java/org/springframework/data/util/ClassTypeInformation.java @@ -15,14 +15,12 @@ */ package org.springframework.data.util; -import java.lang.reflect.Method; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import org.springframework.core.ResolvableType; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ConcurrentLruCache; diff --git a/src/main/java/org/springframework/data/util/ClassUtils.java b/src/main/java/org/springframework/data/util/ClassUtils.java index f2cb717990..2dce18fdc8 100644 --- a/src/main/java/org/springframework/data/util/ClassUtils.java +++ b/src/main/java/org/springframework/data/util/ClassUtils.java @@ -17,7 +17,7 @@ import java.util.function.Consumer; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** * Utility class to work with classes. @@ -65,8 +65,7 @@ public static void ifPresent(String className, @Nullable ClassLoader classLoader * @param classLoader the class loader to use (can be {@literal null}, which indicates the default class loader). * @return the {@link Class} or {@literal null} in case the class can't be loaded for any reason. */ - @Nullable - public static Class loadIfPresent(String name, @Nullable ClassLoader classLoader) { + public static @Nullable Class loadIfPresent(String name, @Nullable ClassLoader classLoader) { try { return org.springframework.util.ClassUtils.forName(name, classLoader); diff --git a/src/main/java/org/springframework/data/util/CustomCollections.java b/src/main/java/org/springframework/data/util/CustomCollections.java index 0ccc19ecd1..a7b5e75b54 100644 --- a/src/main/java/org/springframework/data/util/CustomCollections.java +++ b/src/main/java/org/springframework/data/util/CustomCollections.java @@ -48,6 +48,9 @@ import org.eclipse.collections.api.map.MutableMap; import org.eclipse.collections.api.set.ImmutableSet; import org.eclipse.collections.api.set.MutableSet; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.converter.ConditionalConverter; import org.springframework.core.convert.converter.ConditionalGenericConverter; @@ -55,8 +58,6 @@ import org.springframework.core.convert.converter.ConverterRegistry; import org.springframework.core.io.support.SpringFactoriesLoader; import org.springframework.lang.Contract; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -290,7 +291,9 @@ private static Function, Class> rejectNull(Supplier message) return candidate; }; + } + } static class VavrCollections implements CustomCollectionRegistrar { @@ -355,10 +358,9 @@ public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { && COLLECTIONS_AND_MAP.contains(targetType.getType()); } - @Nullable - @Contract("null -> null; !null -> !null") + @Contract("null, _, _ -> null; !null, _, _ -> !null") @Override - public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + public @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { if (source == null) { return null; @@ -378,6 +380,7 @@ public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDe throw new IllegalArgumentException("Unsupported Vavr collection " + source.getClass()); } + } private enum JavaToVavrCollectionConverter implements ConditionalGenericConverter { @@ -395,9 +398,9 @@ private enum JavaToVavrCollectionConverter implements ConditionalGenericConverte CONVERTIBLE_PAIRS = Collections.unmodifiableSet(pairs); } - @NonNull + @Override - public java.util.Set getConvertibleTypes() { + public java.util.@NonNull Set getConvertibleTypes() { return CONVERTIBLE_PAIRS; } @@ -418,9 +421,10 @@ public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { return true; } - @Nullable + @Contract("null, _, _ -> null; !null, _, _ -> !null") @Override - public Object convert(@Nullable Object source, TypeDescriptor sourceDescriptor, TypeDescriptor targetDescriptor) { + public @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceDescriptor, + TypeDescriptor targetDescriptor) { var targetType = targetDescriptor.getType(); @@ -453,7 +457,9 @@ public Object convert(@Nullable Object source, TypeDescriptor sourceDescriptor, return source; } + } + } static class EclipseCollections implements CustomCollectionRegistrar { @@ -508,10 +514,9 @@ public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { && COLLECTIONS_AND_MAP.contains(targetType.getType()); } - @Nullable @Contract("null -> null; !null -> !null") @Override - public Object convert(@Nullable Object source) { + public @Nullable Object convert(@Nullable Object source) { if (source instanceof ImmutableList) { return ((ImmutableList) source).toList(); @@ -531,6 +536,7 @@ public Object convert(@Nullable Object source) { return source; } + } enum JavaToEclipseConverter implements ConditionalGenericConverter { @@ -559,9 +565,8 @@ enum JavaToEclipseConverter implements ConditionalGenericConverter { CONVERTIBLE_PAIRS = Collections.unmodifiableSet(pairs); } - @NonNull @Override - public Set getConvertibleTypes() { + public @NonNull Set getConvertibleTypes() { return CONVERTIBLE_PAIRS; } @@ -583,10 +588,10 @@ public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { return true; } - @Nullable - @Contract("null -> null; !null -> !null") + @Contract("null, _, _ -> null; !null, _ , _ -> !null") @Override - public Object convert(@Nullable Object source, TypeDescriptor sourceDescriptor, TypeDescriptor targetDescriptor) { + public @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceDescriptor, + TypeDescriptor targetDescriptor) { var targetType = targetDescriptor.getType(); @@ -640,5 +645,7 @@ public Object convert(@Nullable Object source, TypeDescriptor sourceDescriptor, return source; } } + } + } diff --git a/src/main/java/org/springframework/data/util/DirectFieldAccessFallbackBeanWrapper.java b/src/main/java/org/springframework/data/util/DirectFieldAccessFallbackBeanWrapper.java index 1371ce1157..be557ec152 100644 --- a/src/main/java/org/springframework/data/util/DirectFieldAccessFallbackBeanWrapper.java +++ b/src/main/java/org/springframework/data/util/DirectFieldAccessFallbackBeanWrapper.java @@ -19,10 +19,11 @@ import java.lang.reflect.Field; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.BeanWrapperImpl; import org.springframework.beans.NotReadablePropertyException; import org.springframework.beans.NotWritablePropertyException; -import org.springframework.lang.Nullable; /** * Custom extension of {@link BeanWrapperImpl} that falls back to direct field access in case the object or type being @@ -42,8 +43,7 @@ public DirectFieldAccessFallbackBeanWrapper(Class type) { } @Override - @Nullable - public Object getPropertyValue(String propertyName) { + public @Nullable Object getPropertyValue(String propertyName) { try { return super.getPropertyValue(propertyName); diff --git a/src/main/java/org/springframework/data/util/IteratorSpliterator.java b/src/main/java/org/springframework/data/util/IteratorSpliterator.java index 098b218b55..587dfaf909 100644 --- a/src/main/java/org/springframework/data/util/IteratorSpliterator.java +++ b/src/main/java/org/springframework/data/util/IteratorSpliterator.java @@ -21,7 +21,7 @@ import java.util.Spliterators; import java.util.function.Consumer; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** * A Spliterator using a given Iterator for element operations. The spliterator implements {@code trySplit} to permit @@ -46,9 +46,8 @@ public IteratorSpliterator(Iterator iterator) { this.est = Long.MAX_VALUE; } - @Nullable @Override - public Spliterator trySplit() { + public @Nullable Spliterator trySplit() { /* * Split into arrays of arithmetically increasing batch * sizes. This will only improve parallel performance if @@ -110,9 +109,8 @@ public int characteristics() { return 0; } - @Nullable @Override - public Comparator getComparator() { + public @Nullable Comparator getComparator() { if (hasCharacteristics(Spliterator.SORTED)) { return null; } diff --git a/src/main/java/org/springframework/data/util/KotlinBeanInfoFactory.java b/src/main/java/org/springframework/data/util/KotlinBeanInfoFactory.java index da262b56d2..cd814c7f7e 100644 --- a/src/main/java/org/springframework/data/util/KotlinBeanInfoFactory.java +++ b/src/main/java/org/springframework/data/util/KotlinBeanInfoFactory.java @@ -34,12 +34,13 @@ import java.util.LinkedHashMap; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.BeanInfoFactory; import org.springframework.beans.BeanUtils; import org.springframework.core.KotlinDetector; import org.springframework.core.Ordered; import org.springframework.lang.Contract; -import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.ReflectionUtils; @@ -56,7 +57,7 @@ public class KotlinBeanInfoFactory implements BeanInfoFactory, Ordered { @Override - public BeanInfo getBeanInfo(Class beanClass) throws IntrospectionException { + public @Nullable BeanInfo getBeanInfo(Class beanClass) throws IntrospectionException { if (beanClass.isInterface() || beanClass.isEnum()) { return null; // back-off to leave interface-based properties to the default mechanism. @@ -151,9 +152,8 @@ private static void collectBasicJavaProperties(Class beanClass, Map null, _, !null -> !null") - private static Method specialize(Class beanClass, @Nullable Method method) { + @Contract("_, null -> null; _, !null -> !null") + private static @Nullable Method specialize(Class beanClass, @Nullable Method method) { if (method == null) { return method; @@ -191,8 +191,7 @@ public void setReadMethod(@Nullable Method readMethod) { } @Override - @Nullable - public Method getReadMethod() { + public @Nullable Method getReadMethod() { return this.readMethod; } diff --git a/src/main/java/org/springframework/data/util/KotlinReflectionUtils.java b/src/main/java/org/springframework/data/util/KotlinReflectionUtils.java index 25e99628ee..7e62331866 100644 --- a/src/main/java/org/springframework/data/util/KotlinReflectionUtils.java +++ b/src/main/java/org/springframework/data/util/KotlinReflectionUtils.java @@ -30,10 +30,11 @@ import java.util.Optional; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; + import org.springframework.core.KotlinDetector; import org.springframework.core.MethodParameter; import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.lang.Nullable; /** * Reflection utility methods specific to Kotlin reflection. Requires Kotlin classes to be present to avoid linkage @@ -90,8 +91,7 @@ public static boolean isDataClass(Class type) { * @param method the method to look up. * @return the {@link KFunction} or {@code null} if the method cannot be looked up. */ - @Nullable - public static KFunction findKotlinFunction(Method method) { + public static @Nullable KFunction findKotlinFunction(Method method) { KFunction kotlinFunction = ReflectJvmMapping.getKotlinFunction(method); diff --git a/src/main/java/org/springframework/data/util/Lazy.java b/src/main/java/org/springframework/data/util/Lazy.java index 748e4e6681..643ecbc95c 100644 --- a/src/main/java/org/springframework/data/util/Lazy.java +++ b/src/main/java/org/springframework/data/util/Lazy.java @@ -19,7 +19,8 @@ import java.util.function.Function; import java.util.function.Supplier; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -42,12 +43,12 @@ public class Lazy implements Supplier { private static final Lazy EMPTY = new Lazy<>(() -> null, null, true); static final String UNRESOLVED = "[Unresolved]"; - private final Supplier supplier; + private final Supplier supplier; private @Nullable T value; private volatile boolean resolved; - private Lazy(Supplier supplier) { + private Lazy(Supplier supplier) { this(supplier, null, false); } @@ -58,7 +59,7 @@ private Lazy(Supplier supplier) { * @param value can be {@literal null}. * @param resolved whether the value handed into the constructor represents a resolved value. */ - private Lazy(Supplier supplier, @Nullable T value, boolean resolved) { + private Lazy(Supplier supplier, @Nullable T value, boolean resolved) { this.supplier = supplier; this.value = value; @@ -72,7 +73,7 @@ private Lazy(Supplier supplier, @Nullable T value, boolean resolved * @param supplier the {@link Supplier} to create the object lazily. * @return a {@code Lazy} wrapping the given {@link Supplier}. */ - public static Lazy of(Supplier supplier) { + public static Lazy of(Supplier supplier) { return new Lazy<>(supplier); } @@ -199,7 +200,7 @@ public T orElse(@Nullable T other) { * @return the value, if present, otherwise the result produced by the supplying function. */ @Nullable - public T orElseGet(Supplier supplier) { + public T orElseGet(Supplier supplier) { Assert.notNull(supplier, "Default value supplier must not be null"); diff --git a/src/main/java/org/springframework/data/util/MethodInvocationRecorder.java b/src/main/java/org/springframework/data/util/MethodInvocationRecorder.java index c8a502ff88..37a4404d03 100644 --- a/src/main/java/org/springframework/data/util/MethodInvocationRecorder.java +++ b/src/main/java/org/springframework/data/util/MethodInvocationRecorder.java @@ -18,19 +18,20 @@ import java.lang.reflect.Array; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.Function; +import java.util.stream.Stream; import org.aopalliance.intercept.MethodInvocation; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + import org.springframework.aop.framework.ProxyFactory; import org.springframework.core.CollectionFactory; import org.springframework.core.ResolvableType; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.util.ReflectionUtils; @@ -48,17 +49,17 @@ public class MethodInvocationRecorder { public static PropertyNameDetectionStrategy DEFAULT = DefaultPropertyNameDetectionStrategy.INSTANCE; - private final Optional interceptor; + private final @Nullable RecordingMethodInterceptor interceptor; /** * Creates a new {@link MethodInvocationRecorder}. For ad-hoc instantation prefer the static * {@link #forProxyOf(Class)}. */ private MethodInvocationRecorder() { - this(Optional.empty()); + this(null); } - private MethodInvocationRecorder(Optional interceptor) { + private MethodInvocationRecorder(@Nullable RecordingMethodInterceptor interceptor) { this.interceptor = interceptor; } @@ -99,11 +100,16 @@ private Recorded create(Class type) { T proxy = (T) proxyFactory.getProxy(type.getClassLoader()); - return new Recorded<>(proxy, new MethodInvocationRecorder(Optional.ofNullable(interceptor))); + return new Recorded<>(proxy, new MethodInvocationRecorder(interceptor)); } - private Optional getPropertyPath(List strategies) { - return interceptor.flatMap(it -> it.getPropertyPath(strategies)); + private @Nullable String getPropertyPath(List strategies) { + + if (interceptor != null) { + return interceptor.getPropertyPath(strategies); + } + + return null; } private class RecordingMethodInterceptor implements org.aopalliance.intercept.MethodInterceptor { @@ -112,9 +118,10 @@ private class RecordingMethodInterceptor implements org.aopalliance.intercept.Me @Override @SuppressWarnings("null") - public Object invoke(MethodInvocation invocation) throws Throwable { + public @Nullable Object invoke(MethodInvocation invocation) throws Throwable { Method method = invocation.getMethod(); + @Nullable Object[] arguments = invocation.getArguments(); if (ReflectionUtils.isObjectMethod(method)) { @@ -131,7 +138,10 @@ public Object invoke(MethodInvocation invocation) throws Throwable { InvocationInformation information = registerInvocation(method, clazz); Collection collection = CollectionFactory.createCollection(rawType, 1); - collection.add(information.getCurrentInstance()); + + if (information.getCurrentInstance() != null) { + collection.add(information.getCurrentInstance()); + } return collection; } @@ -142,7 +152,10 @@ public Object invoke(MethodInvocation invocation) throws Throwable { InvocationInformation information = registerInvocation(method, clazz); Map map = CollectionFactory.createMap(rawType, 1); - map.put("_key_", information.getCurrentInstance()); + + if (information.getCurrentInstance() != null) { + map.put("_key_", information.getCurrentInstance()); + } return map; } @@ -150,7 +163,7 @@ public Object invoke(MethodInvocation invocation) throws Throwable { return registerInvocation(method, rawType).getCurrentInstance(); } - private Optional getPropertyPath(List strategies) { + private @Nullable String getPropertyPath(List strategies) { return this.information.getPropertyPath(strategies); } @@ -183,36 +196,36 @@ Object getCurrentInstance() { return recorded.currentInstance; } - Optional getPropertyPath(List strategies) { + @Nullable + String getPropertyPath(List strategies) { Method invokedMethod = this.invokedMethod; if (invokedMethod == null) { - return Optional.empty(); + return null; } String propertyName = getPropertyName(invokedMethod, strategies); Optional next = recorded.getPropertyPath(strategies); return Optionals.firstNonEmpty(() -> next.map(it -> propertyName.concat(".").concat(it)), // - () -> Optional.of(propertyName)); + () -> Optional.of(propertyName)).orElse(null); } private static String getPropertyName(Method invokedMethod, List strategies) { return strategies.stream() // - .map(it -> it.getPropertyName(invokedMethod)) // + .flatMap(it -> Stream.ofNullable(it.getPropertyName(invokedMethod))) // .findFirst() // - .orElseThrow(() -> new IllegalArgumentException( - String.format("No property name found for method %s", invokedMethod))); + .orElseThrow( + () -> new IllegalArgumentException(String.format("No property name found for method %s", invokedMethod))); } public Recorded getRecorded() { return this.recorded; } - @Nullable - public Method getInvokedMethod() { + public @Nullable Method getInvokedMethod() { return this.invokedMethod; } @@ -299,14 +312,14 @@ public Optional getPropertyPath(PropertyNameDetectionStrategy strategy) MethodInvocationRecorder recorder = this.recorder; - return recorder == null ? Optional.empty() : recorder.getPropertyPath(Arrays.asList(strategy)); + return Optional.ofNullable(recorder == null ? null : recorder.getPropertyPath(List.of(strategy))); } public Optional getPropertyPath(List strategies) { MethodInvocationRecorder recorder = this.recorder; - return recorder == null ? Optional.empty() : recorder.getPropertyPath(strategies); + return Optional.ofNullable(recorder == null ? null : recorder.getPropertyPath(strategies)); } /** diff --git a/src/main/java/org/springframework/data/util/NullableUtils.java b/src/main/java/org/springframework/data/util/NullableUtils.java index c0604c4510..5ff82a663e 100644 --- a/src/main/java/org/springframework/data/util/NullableUtils.java +++ b/src/main/java/org/springframework/data/util/NullableUtils.java @@ -29,12 +29,13 @@ import java.util.function.Predicate; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.MergedAnnotations; import org.springframework.lang.NonNullApi; -import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; import org.springframework.util.MultiValueMap; @@ -48,7 +49,7 @@ * package rule. Subpackages do not inherit nullability rules and must be annotated themself. * *
- * @org.springframework.lang.NonNullApi
+ * @org.jspecify.annotations.NullMarked
  * package com.example;
  * 
* @@ -157,8 +158,7 @@ private static boolean isNonNull(Annotation annotation, ElementType elementType) return true; } - if (!MergedAnnotations.from(annotation.annotationType()).isPresent(annotationClass) - || !isNonNull(annotation)) { + if (!MergedAnnotations.from(annotation.annotationType()).isPresent(annotationClass) || !isNonNull(annotation)) { return false; } @@ -227,26 +227,28 @@ private static boolean test(Annotation annotation, String metaAnnotationName if (annotation.annotationType().getName().equals(metaAnnotationName)) { - Map attributes = AnnotationUtils.getAnnotationAttributes(annotation); - + Map attributes = AnnotationUtils.getAnnotationAttributes(annotation); return !attributes.isEmpty() && filter.test((T) attributes.get(attribute)); } - MultiValueMap attributes = AnnotatedElementUtils + MultiValueMap attributes = AnnotatedElementUtils .getAllAnnotationAttributes(annotation.annotationType(), metaAnnotationName); - if (attributes == null || attributes.isEmpty()) { + if (attributes.isEmpty()) { return false; } - List elementTypes = attributes.get(attribute); + List<@Nullable Object> elementTypes = attributes.get(attribute); - for (Object value : elementTypes) { + if (elementTypes != null) { + for (Object value : elementTypes) { - if (filter.test((T) value)) { - return true; + if (filter.test((T) value)) { + return true; + } } } + return false; } diff --git a/src/main/java/org/springframework/data/util/NullableWrapper.java b/src/main/java/org/springframework/data/util/NullableWrapper.java index 6f4d4cb408..d46cc8b0eb 100644 --- a/src/main/java/org/springframework/data/util/NullableWrapper.java +++ b/src/main/java/org/springframework/data/util/NullableWrapper.java @@ -15,8 +15,9 @@ */ package org.springframework.data.util; +import org.jspecify.annotations.Nullable; + import org.springframework.core.convert.converter.Converter; -import org.springframework.lang.Nullable; /** * Simple value object to wrap a nullable delegate. Used to be able to write {@link Converter} implementations that @@ -57,8 +58,7 @@ public Class getValueType() { * * @return the value can be {@literal null}. */ - @Nullable - public Object getValue() { + public @Nullable Object getValue() { return value; } } diff --git a/src/main/java/org/springframework/data/util/NullableWrapperConverters.java b/src/main/java/org/springframework/data/util/NullableWrapperConverters.java index 31ae8f1658..252dbf4a2a 100644 --- a/src/main/java/org/springframework/data/util/NullableWrapperConverters.java +++ b/src/main/java/org/springframework/data/util/NullableWrapperConverters.java @@ -25,12 +25,13 @@ import java.util.Set; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; + import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.ConverterRegistry; import org.springframework.core.convert.converter.GenericConverter; import org.springframework.lang.Contract; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ConcurrentReferenceHashMap; @@ -178,9 +179,8 @@ public static void registerConvertersIn(ConverterRegistry registry) { * @param source can be {@literal null}. * @return */ - @Nullable @Contract("null -> null") - public static Object unwrap(@Nullable Object source) { + public static @Nullable Object unwrap(@Nullable Object source) { if (source == null || !supports(source.getClass())) { return source; @@ -253,9 +253,9 @@ public Set getConvertibleTypes() { .stream().collect(StreamUtils.toUnmodifiableSet()); } - @Nullable @Override - public final Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + public final @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, + TypeDescriptor targetType) { if (source == null) { return null; @@ -378,9 +378,8 @@ private enum GuavaOptionalUnwrapper implements Converter { INSTANCE; - @Nullable @Override - public Object convert(Object source) { + public @Nullable Object convert(Object source) { return source instanceof Optional ? ((Optional) source).orNull() : source; } } @@ -394,9 +393,8 @@ private enum Jdk8OptionalUnwrapper implements Converter { INSTANCE; - @Nullable @Override - public Object convert(Object source) { + public @Nullable Object convert(Object source) { return source instanceof java.util.Optional ? ((java.util.Optional) source).orElse(null) : source; } } @@ -414,16 +412,14 @@ private enum ScalOptionUnwrapper implements Converter { private final Function0 alternative = new AbstractFunction0<>() { - @Nullable @Override - public Option apply() { + public @Nullable Option apply() { return null; } }; - @Nullable @Override - public Object convert(Object source) { + public @Nullable Object convert(Object source) { return source instanceof Option ? ((Option) source).getOrElse(alternative) : source; } } @@ -438,10 +434,9 @@ private enum VavrOptionUnwrapper implements Converter { INSTANCE; - @Nullable @Override @SuppressWarnings("unchecked") - public Object convert(Object source) { + public @Nullable Object convert(Object source) { if (source instanceof io.vavr.control.Option) { return ((io.vavr.control.Option) source).getOrElse(() -> null); diff --git a/src/main/java/org/springframework/data/util/Pair.java b/src/main/java/org/springframework/data/util/Pair.java index b041b69bc0..37fda3b9a8 100644 --- a/src/main/java/org/springframework/data/util/Pair.java +++ b/src/main/java/org/springframework/data/util/Pair.java @@ -20,7 +20,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; diff --git a/src/main/java/org/springframework/data/util/ParameterTypes.java b/src/main/java/org/springframework/data/util/ParameterTypes.java index 03f7b8dd97..db1fbea103 100644 --- a/src/main/java/org/springframework/data/util/ParameterTypes.java +++ b/src/main/java/org/springframework/data/util/ParameterTypes.java @@ -21,12 +21,12 @@ import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.Optional; import java.util.concurrent.ConcurrentMap; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; + import org.springframework.core.convert.TypeDescriptor; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ConcurrentReferenceHashMap; import org.springframework.util.ObjectUtils; @@ -58,7 +58,7 @@ public class ParameterTypes { private ParameterTypes(List types) { this.types = types; - this.alternatives = Lazy.of(() -> getAlternatives()); + this.alternatives = Lazy.of(this::getAlternatives); } public ParameterTypes(List types, Lazy> alternatives) { @@ -123,8 +123,13 @@ public boolean areValidFor(Method method) { */ private boolean hasValidAlternativeFor(Method method) { - return alternatives.get().stream().anyMatch(it -> it.areValidTypes(method)) // - || getParent().map(parent -> parent.hasValidAlternativeFor(method)).orElse(false); + if (alternatives.get().stream().anyMatch(it -> it.areValidTypes(method))) { + return true; + } + + ParameterTypes parent = getParent(); + + return parent != null && parent.hasValidAlternativeFor(method); } /** @@ -137,7 +142,10 @@ List getAllAlternatives() { List result = new ArrayList<>(); result.addAll(alternatives.get()); - getParent().ifPresent(it -> result.addAll(it.getAllAlternatives())); + ParameterTypes parent = getParent(); + if (parent != null) { + result.addAll(parent.getAllAlternatives()); + } return result; } @@ -154,7 +162,7 @@ boolean hasTypes(Class... types) { return Arrays.stream(types) // .map(TypeDescriptor::valueOf) // - .collect(Collectors.toList())// + .toList()// .equals(this.types); } @@ -191,24 +199,24 @@ public String toString() { .collect(Collectors.joining(", ", "(", ")")); } - protected Optional getParent() { - return types.isEmpty() ? Optional.empty() : getParent(getTail()); + protected @Nullable ParameterTypes getParent() { + return types.isEmpty() ? null : getParent(getTail()); } - protected final Optional getParent(TypeDescriptor tail) { + protected final @Nullable ParameterTypes getParent(TypeDescriptor tail) { return types.size() <= 1 // - ? Optional.empty() // - : Optional.of(ParentParameterTypes.of(types.subList(0, types.size() - 1), tail)); + ? null // + : ParentParameterTypes.of(types.subList(0, types.size() - 1), tail); } - protected Optional withLastVarArgs() { + protected @Nullable ParameterTypes withLastVarArgs() { TypeDescriptor lastDescriptor = types.get(types.size() - 1); return lastDescriptor.isArray() // - ? Optional.empty() // - : Optional.ofNullable(withVarArgs(lastDescriptor)); + ? null // + : withVarArgs(lastDescriptor); } @SuppressWarnings("null") @@ -216,7 +224,7 @@ private ParameterTypes withVarArgs(TypeDescriptor descriptor) { TypeDescriptor lastDescriptor = types.get(types.size() - 1); - if (lastDescriptor.isArray() && lastDescriptor.getElementTypeDescriptor().equals(descriptor)) { + if (lastDescriptor.isArray() && descriptor.equals(lastDescriptor.getElementTypeDescriptor())) { return this; } @@ -234,7 +242,10 @@ private Collection getAlternatives() { List alternatives = new ArrayList<>(); - withLastVarArgs().ifPresent(alternatives::add); + ParameterTypes parameterTypes = withLastVarArgs(); + if (parameterTypes != null) { + alternatives.add(parameterTypes); + } ParameterTypes objectVarArgs = withVarArgs(OBJECT_DESCRIPTOR); @@ -314,15 +325,15 @@ public static ParentParameterTypes of(List types, TypeDescriptor } @Override - protected Optional getParent() { + protected @Nullable ParameterTypes getParent() { return super.getParent(tail); } @Override - protected Optional withLastVarArgs() { + protected @Nullable ParameterTypes withLastVarArgs() { return !tail.isAssignableTo(super.getTail()) // - ? Optional.empty() // + ? null // : super.withLastVarArgs(); } diff --git a/src/main/java/org/springframework/data/util/QTypeContributor.java b/src/main/java/org/springframework/data/util/QTypeContributor.java index bc69d62970..8447a35973 100644 --- a/src/main/java/org/springframework/data/util/QTypeContributor.java +++ b/src/main/java/org/springframework/data/util/QTypeContributor.java @@ -17,10 +17,11 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; + import org.springframework.aot.generate.GenerationContext; import org.springframework.aot.hint.MemberCategory; import org.springframework.aot.hint.TypeReference; -import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; /** @@ -59,8 +60,7 @@ public static void contributeEntityPath(Class type, GenerationContext context } } - @Nullable - private static Class getEntityPathType(@Nullable ClassLoader classLoader) throws ClassNotFoundException { + private @Nullable static Class getEntityPathType(@Nullable ClassLoader classLoader) throws ClassNotFoundException { String entityPathClassName = "com.querydsl.core.types.EntityPath"; if (!ClassUtils.isPresent(entityPathClassName, classLoader)) { diff --git a/src/main/java/org/springframework/data/util/ReactiveWrappers.java b/src/main/java/org/springframework/data/util/ReactiveWrappers.java index 98a353e2b9..f82d575ef9 100644 --- a/src/main/java/org/springframework/data/util/ReactiveWrappers.java +++ b/src/main/java/org/springframework/data/util/ReactiveWrappers.java @@ -22,10 +22,11 @@ import java.util.Map; import java.util.Optional; +import org.jspecify.annotations.Nullable; + import org.springframework.core.ReactiveAdapter; import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.core.ReactiveTypeDescriptor; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ConcurrentReferenceHashMap; diff --git a/src/main/java/org/springframework/data/util/ReflectionUtils.java b/src/main/java/org/springframework/data/util/ReflectionUtils.java index b36a6a5ac8..c0c2f908db 100644 --- a/src/main/java/org/springframework/data/util/ReflectionUtils.java +++ b/src/main/java/org/springframework/data/util/ReflectionUtils.java @@ -28,12 +28,12 @@ import java.util.stream.Stream; import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.Nullable; import org.springframework.core.KotlinDetector; import org.springframework.core.MethodParameter; import org.springframework.core.ResolvableType; import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils.FieldFilter; @@ -168,8 +168,7 @@ public String getDescription() { * @param filter must not be {@literal null}. * @return the field matching the filter or {@literal null} in case no field could be found. */ - @Nullable - public static Field findField(Class type, FieldFilter filter) { + public @Nullable static Field findField(Class type, FieldFilter filter) { return findField(type, new DescribedFieldFilter() { @@ -195,8 +194,7 @@ public String getDescription() { * @return the field matching the given {@link DescribedFieldFilter} or {@literal null} if none found. * @throws IllegalStateException in case more than one matching field is found */ - @Nullable - public static Field findField(Class type, DescribedFieldFilter filter) { + public @Nullable static Field findField(Class type, DescribedFieldFilter filter) { return findField(type, filter, true); } @@ -210,8 +208,7 @@ public static Field findField(Class type, DescribedFieldFilter filter) { * @return the field matching the given {@link DescribedFieldFilter} or {@literal null} if none found. * @throws IllegalStateException if enforceUniqueness is true and more than one matching field is found */ - @Nullable - public static Field findField(Class type, DescribedFieldFilter filter, boolean enforceUniqueness) { + public @Nullable static Field findField(Class type, DescribedFieldFilter filter, boolean enforceUniqueness) { Assert.notNull(type, "Type must not be null"); Assert.notNull(filter, "Filter must not be null"); @@ -284,9 +281,8 @@ public static void setField(Field field, Object target, @Nullable Object value) * @param constructorArguments must not be {@literal null}. * @return a {@link Constructor} that is compatible with the given arguments. */ - @Nullable @SuppressWarnings("unchecked") - public static Constructor findConstructor(Class type, Object... constructorArguments) { + public static @Nullable Constructor findConstructor(Class type, Object... constructorArguments) { Assert.notNull(type, "Target type must not be null"); Assert.notNull(constructorArguments, "Constructor arguments must not be null"); @@ -391,8 +387,7 @@ public static Stream> returnTypeAndParameters(Method method) { * @return the required method. * @since 3.5 */ - @Nullable - public static Method findMethod(Class type, String name, ResolvableType... parameterTypes) { + public static @Nullable Method findMethod(Class type, String name, ResolvableType... parameterTypes) { Assert.notNull(type, "Type must not be null"); Assert.hasText(name, "Name must not be null or empty"); diff --git a/src/main/java/org/springframework/data/util/Sink.java b/src/main/java/org/springframework/data/util/Sink.java index afdcb52979..4a0005e944 100644 --- a/src/main/java/org/springframework/data/util/Sink.java +++ b/src/main/java/org/springframework/data/util/Sink.java @@ -2,7 +2,7 @@ import java.util.function.Consumer; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** * A simple {@link Consumer} that captures the instance handed into it. @@ -12,14 +12,14 @@ */ class Sink implements Consumer { - private T value; + private @Nullable T value; /** * Returns the value captured. * * @return */ - public T getValue() { + public @Nullable T getValue() { return value; } diff --git a/src/main/java/org/springframework/data/util/StreamUtils.java b/src/main/java/org/springframework/data/util/StreamUtils.java index a4fc62b2a3..8bd438a95b 100644 --- a/src/main/java/org/springframework/data/util/StreamUtils.java +++ b/src/main/java/org/springframework/data/util/StreamUtils.java @@ -31,7 +31,8 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; import org.springframework.util.MultiValueMap; diff --git a/src/main/java/org/springframework/data/util/TypeDiscoverer.java b/src/main/java/org/springframework/data/util/TypeDiscoverer.java index 68c787ddec..48c75e0cee 100644 --- a/src/main/java/org/springframework/data/util/TypeDiscoverer.java +++ b/src/main/java/org/springframework/data/util/TypeDiscoverer.java @@ -28,11 +28,12 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.BeanUtils; import org.springframework.core.MethodParameter; import org.springframework.core.ResolvableType; import org.springframework.core.convert.TypeDescriptor; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ConcurrentLruCache; import org.springframework.util.ObjectUtils; @@ -110,9 +111,8 @@ public List> getParameterTypes(Constructor constructor) { }); } - @Nullable @Override - public TypeInformation getProperty(String name) { + public @Nullable TypeInformation getProperty(String name) { var separatorIndex = name.indexOf('.'); @@ -138,14 +138,12 @@ public boolean isCollectionLike() { return isCollectionLike.get(); } - @Nullable @Override - public TypeInformation getComponentType() { + public @Nullable TypeInformation getComponentType() { return componentType.orElse(null); } - @Nullable - protected TypeInformation doGetComponentType() { + protected @Nullable TypeInformation doGetComponentType() { if (resolvableType.isArray()) { return TypeInformation.of(resolvableType.getComponentType()); @@ -179,14 +177,12 @@ public boolean isMap() { return isMap.get(); } - @Nullable @Override - public TypeInformation getMapValueType() { + public @Nullable TypeInformation getMapValueType() { return valueType.orElse(null); } - @Nullable - protected TypeInformation doGetMapValueType() { + protected @Nullable TypeInformation doGetMapValueType() { return isMap() // ? getTypeArgument(CustomCollections.getMapBaseType(getType()), 1) @@ -209,9 +205,8 @@ public TypeInformation getRawTypeInformation() { return new ClassTypeInformation<>(ResolvableType.forRawClass(resolvableType.toClass())); } - @Nullable @Override - public TypeInformation getActualType() { + public @Nullable TypeInformation getActualType() { if (isMap()) { return getMapValueType(); @@ -246,9 +241,8 @@ public List> getParameterTypes(Method method) { } - @Nullable @Override - public TypeInformation getSuperTypeInformation(Class superType) { + public @Nullable TypeInformation getSuperTypeInformation(Class superType) { Class rawType = getType(); diff --git a/src/main/java/org/springframework/data/util/TypeInformation.java b/src/main/java/org/springframework/data/util/TypeInformation.java index 2005d84fb5..175ed92ce5 100644 --- a/src/main/java/org/springframework/data/util/TypeInformation.java +++ b/src/main/java/org/springframework/data/util/TypeInformation.java @@ -23,10 +23,11 @@ import java.util.Map; import java.util.Set; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.core.ResolvableType; import org.springframework.core.convert.TypeDescriptor; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** diff --git a/src/main/java/org/springframework/data/util/Version.java b/src/main/java/org/springframework/data/util/Version.java index 0a02d6d38c..f578a8cf15 100644 --- a/src/main/java/org/springframework/data/util/Version.java +++ b/src/main/java/org/springframework/data/util/Version.java @@ -18,7 +18,8 @@ import java.util.ArrayList; import java.util.List; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; import org.springframework.util.StringUtils; diff --git a/src/main/java/org/springframework/data/util/package-info.java b/src/main/java/org/springframework/data/util/package-info.java index 04a8e670cc..c6847f5a4d 100644 --- a/src/main/java/org/springframework/data/util/package-info.java +++ b/src/main/java/org/springframework/data/util/package-info.java @@ -1,5 +1,5 @@ /** * Core utility APIs such as a type information framework to resolve generic types. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.util; diff --git a/src/main/java/org/springframework/data/web/HateoasPageableHandlerMethodArgumentResolver.java b/src/main/java/org/springframework/data/web/HateoasPageableHandlerMethodArgumentResolver.java index 312b2946f1..b4a073fd1f 100644 --- a/src/main/java/org/springframework/data/web/HateoasPageableHandlerMethodArgumentResolver.java +++ b/src/main/java/org/springframework/data/web/HateoasPageableHandlerMethodArgumentResolver.java @@ -21,12 +21,13 @@ import java.util.Arrays; import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.data.domain.Pageable; import org.springframework.hateoas.TemplateVariable; import org.springframework.hateoas.TemplateVariables; import org.springframework.hateoas.server.mvc.UriComponentsContributor; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.MultiValueMap; import org.springframework.web.util.UriComponents; diff --git a/src/main/java/org/springframework/data/web/HateoasSortHandlerMethodArgumentResolver.java b/src/main/java/org/springframework/data/web/HateoasSortHandlerMethodArgumentResolver.java index 179eeaf2f0..c9adb12797 100644 --- a/src/main/java/org/springframework/data/web/HateoasSortHandlerMethodArgumentResolver.java +++ b/src/main/java/org/springframework/data/web/HateoasSortHandlerMethodArgumentResolver.java @@ -17,12 +17,13 @@ import static org.springframework.hateoas.TemplateVariable.VariableType.*; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.data.domain.Sort; import org.springframework.hateoas.TemplateVariable; import org.springframework.hateoas.TemplateVariables; import org.springframework.hateoas.server.mvc.UriComponentsContributor; -import org.springframework.lang.Nullable; import org.springframework.util.MultiValueMap; import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; diff --git a/src/main/java/org/springframework/data/web/JsonProjectingMethodInterceptorFactory.java b/src/main/java/org/springframework/data/web/JsonProjectingMethodInterceptorFactory.java index d3569f18f8..20c7b86d78 100644 --- a/src/main/java/org/springframework/data/web/JsonProjectingMethodInterceptorFactory.java +++ b/src/main/java/org/springframework/data/web/JsonProjectingMethodInterceptorFactory.java @@ -29,12 +29,13 @@ import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; +import org.jspecify.annotations.Nullable; + import org.springframework.core.ResolvableType; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.data.projection.Accessor; import org.springframework.data.projection.MethodInterceptorFactory; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import com.jayway.jsonpath.Configuration; @@ -138,14 +139,13 @@ public InputMessageProjecting(DocumentContext context) { this.context = context; } - @Nullable @Override - public Object invoke(MethodInvocation invocation) throws Throwable { + public @Nullable Object invoke(MethodInvocation invocation) throws Throwable { Method method = invocation.getMethod(); TypeInformation returnType = TypeInformation.fromReturnTypeOf(method); ResolvableType type = ResolvableType.forMethodReturnType(method); - boolean isCollectionResult = Collection.class.isAssignableFrom(type.getRawClass()); + boolean isCollectionResult = type.getRawClass() != null && Collection.class.isAssignableFrom(type.getRawClass()); type = isCollectionResult ? type : ResolvableType.forClassWithGenerics(List.class, type); Iterable jsonPaths = getJsonPaths(method); @@ -163,9 +163,7 @@ public Object invoke(MethodInvocation invocation) throws Throwable { } boolean definitePath = JsonPath.isPathDefinite(jsonPath); - type = isCollectionResult && definitePath - ? ResolvableType.forClassWithGenerics(List.class, type) - : type; + type = isCollectionResult && definitePath ? ResolvableType.forClassWithGenerics(List.class, type) : type; List result = (List) context.read(jsonPath, new ResolvableTypeRef(type)); diff --git a/src/main/java/org/springframework/data/web/MapDataBinder.java b/src/main/java/org/springframework/data/web/MapDataBinder.java index 20f28b1c1f..074ec4c25c 100644 --- a/src/main/java/org/springframework/data/web/MapDataBinder.java +++ b/src/main/java/org/springframework/data/web/MapDataBinder.java @@ -20,6 +20,9 @@ import java.util.List; import java.util.Map; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.AbstractPropertyAccessor; import org.springframework.beans.BeanUtils; import org.springframework.beans.BeansException; @@ -42,8 +45,6 @@ import org.springframework.expression.spel.SpelParserConfiguration; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.SimpleEvaluationContext; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.web.bind.WebDataBinder; @@ -131,15 +132,13 @@ public boolean isWritableProperty(String propertyName) { } } - @Nullable @Override - public TypeDescriptor getPropertyTypeDescriptor(String propertyName) throws BeansException { + public @Nullable TypeDescriptor getPropertyTypeDescriptor(String propertyName) throws BeansException { throw new UnsupportedOperationException(); } - @Nullable @Override - public Object getPropertyValue(String propertyName) throws BeansException { + public @Nullable Object getPropertyValue(String propertyName) throws BeansException { throw new UnsupportedOperationException(); } diff --git a/src/main/java/org/springframework/data/web/OffsetScrollPositionArgumentResolver.java b/src/main/java/org/springframework/data/web/OffsetScrollPositionArgumentResolver.java index 025d1f32cd..48d19e26ae 100644 --- a/src/main/java/org/springframework/data/web/OffsetScrollPositionArgumentResolver.java +++ b/src/main/java/org/springframework/data/web/OffsetScrollPositionArgumentResolver.java @@ -15,9 +15,10 @@ */ package org.springframework.data.web; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.data.domain.OffsetScrollPosition; -import org.springframework.lang.Nullable; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; @@ -51,6 +52,7 @@ public interface OffsetScrollPositionArgumentResolver extends HandlerMethodArgum * within Optional or Optional.empty(). */ @Override + @Nullable Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory); } diff --git a/src/main/java/org/springframework/data/web/OffsetScrollPositionHandlerMethodArgumentResolver.java b/src/main/java/org/springframework/data/web/OffsetScrollPositionHandlerMethodArgumentResolver.java index ecd507a62e..ac36bb41ef 100644 --- a/src/main/java/org/springframework/data/web/OffsetScrollPositionHandlerMethodArgumentResolver.java +++ b/src/main/java/org/springframework/data/web/OffsetScrollPositionHandlerMethodArgumentResolver.java @@ -17,9 +17,10 @@ import java.util.Arrays; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.data.domain.OffsetScrollPosition; -import org.springframework.lang.Nullable; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; @@ -41,7 +42,7 @@ public boolean supportsParameter(MethodParameter parameter) { } @Override - public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, + public @Nullable Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) { String[] offsetParameter = webRequest.getParameterValues(getOffsetParameter(parameter.nestedIfOptional())); diff --git a/src/main/java/org/springframework/data/web/OffsetScrollPositionHandlerMethodArgumentResolverSupport.java b/src/main/java/org/springframework/data/web/OffsetScrollPositionHandlerMethodArgumentResolverSupport.java index 8cd33ac57d..affd85f543 100644 --- a/src/main/java/org/springframework/data/web/OffsetScrollPositionHandlerMethodArgumentResolverSupport.java +++ b/src/main/java/org/springframework/data/web/OffsetScrollPositionHandlerMethodArgumentResolverSupport.java @@ -18,10 +18,11 @@ import java.util.List; import java.util.Optional; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.data.domain.OffsetScrollPosition; import org.springframework.data.domain.ScrollPosition; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; diff --git a/src/main/java/org/springframework/data/web/PageableArgumentResolver.java b/src/main/java/org/springframework/data/web/PageableArgumentResolver.java index 58c34a1130..a78a52c0d8 100644 --- a/src/main/java/org/springframework/data/web/PageableArgumentResolver.java +++ b/src/main/java/org/springframework/data/web/PageableArgumentResolver.java @@ -15,10 +15,11 @@ */ package org.springframework.data.web; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.data.domain.Pageable; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; diff --git a/src/main/java/org/springframework/data/web/PageableHandlerMethodArgumentResolver.java b/src/main/java/org/springframework/data/web/PageableHandlerMethodArgumentResolver.java index a4b518c485..d5f2d4090a 100644 --- a/src/main/java/org/springframework/data/web/PageableHandlerMethodArgumentResolver.java +++ b/src/main/java/org/springframework/data/web/PageableHandlerMethodArgumentResolver.java @@ -15,12 +15,13 @@ */ package org.springframework.data.web; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.ModelAndViewContainer; diff --git a/src/main/java/org/springframework/data/web/PageableHandlerMethodArgumentResolverSupport.java b/src/main/java/org/springframework/data/web/PageableHandlerMethodArgumentResolverSupport.java index 636199c990..05969521e0 100644 --- a/src/main/java/org/springframework/data/web/PageableHandlerMethodArgumentResolverSupport.java +++ b/src/main/java/org/springframework/data/web/PageableHandlerMethodArgumentResolverSupport.java @@ -20,6 +20,8 @@ import java.lang.reflect.Method; import java.util.Optional; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.core.MethodParameter; import org.springframework.core.annotation.MergedAnnotation; @@ -27,7 +29,6 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; diff --git a/src/main/java/org/springframework/data/web/PageableMethodParameterUtils.java b/src/main/java/org/springframework/data/web/PageableMethodParameterUtils.java index a46551e52f..bf5fd9c000 100644 --- a/src/main/java/org/springframework/data/web/PageableMethodParameterUtils.java +++ b/src/main/java/org/springframework/data/web/PageableMethodParameterUtils.java @@ -20,13 +20,14 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.core.MethodParameter; import org.springframework.core.log.LogMessage; import org.springframework.data.domain.Pageable; import org.springframework.hateoas.server.core.MethodParameters; import org.springframework.lang.Contract; -import org.springframework.lang.Nullable; /** * Utility methods to obtain a {@link MethodParameter} of type {@link Pageable} with the same {@link Qualifier}. @@ -49,8 +50,7 @@ class PageableMethodParameterUtils { * @param parameter must not be {@literal null}. * @return can be {@literal null}. */ - @Nullable - static MethodParameter findMatchingPageableParameter(MethodParameter parameter) { + static @Nullable MethodParameter findMatchingPageableParameter(MethodParameter parameter) { Method method = parameter.getMethod(); @@ -95,9 +95,8 @@ static MethodParameter findMatchingPageableParameter(MethodParameter parameter) throw new IllegalStateException(PARAMETER_AMBIGUITY); } - @Nullable @Contract("_, null -> null") - private static MethodParameter returnIfQualifiersMatch(MethodParameter pageableParameter, + private static @Nullable MethodParameter returnIfQualifiersMatch(MethodParameter pageableParameter, @Nullable Qualifier assemblerQualifier) { if (assemblerQualifier == null) { diff --git a/src/main/java/org/springframework/data/web/PagedModel.java b/src/main/java/org/springframework/data/web/PagedModel.java index 20910acb61..97faa42a6f 100644 --- a/src/main/java/org/springframework/data/web/PagedModel.java +++ b/src/main/java/org/springframework/data/web/PagedModel.java @@ -18,8 +18,9 @@ import java.util.List; import java.util.Objects; +import org.jspecify.annotations.Nullable; + import org.springframework.data.domain.Page; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import com.fasterxml.jackson.annotation.JsonProperty; @@ -56,9 +57,8 @@ public List getContent() { return page.getContent(); } - @Nullable @JsonProperty("page") - public PageMetadata getMetadata() { + public @Nullable PageMetadata getMetadata() { return new PageMetadata(page.getSize(), page.getNumber(), page.getTotalElements(), page.getTotalPages()); } diff --git a/src/main/java/org/springframework/data/web/PagedResourcesAssembler.java b/src/main/java/org/springframework/data/web/PagedResourcesAssembler.java index ca3f13bb41..0488fd6aaf 100644 --- a/src/main/java/org/springframework/data/web/PagedResourcesAssembler.java +++ b/src/main/java/org/springframework/data/web/PagedResourcesAssembler.java @@ -22,6 +22,8 @@ import java.util.List; import java.util.Optional; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -37,7 +39,6 @@ import org.springframework.hateoas.server.RepresentationModelAssembler; import org.springframework.hateoas.server.core.EmbeddedWrapper; import org.springframework.hateoas.server.core.EmbeddedWrappers; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; import org.springframework.web.util.UriComponents; diff --git a/src/main/java/org/springframework/data/web/PagedResourcesAssemblerArgumentResolver.java b/src/main/java/org/springframework/data/web/PagedResourcesAssemblerArgumentResolver.java index 1eee4d3b18..05771f805a 100644 --- a/src/main/java/org/springframework/data/web/PagedResourcesAssemblerArgumentResolver.java +++ b/src/main/java/org/springframework/data/web/PagedResourcesAssemblerArgumentResolver.java @@ -15,9 +15,10 @@ */ package org.springframework.data.web; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; diff --git a/src/main/java/org/springframework/data/web/ProjectingJackson2HttpMessageConverter.java b/src/main/java/org/springframework/data/web/ProjectingJackson2HttpMessageConverter.java index 9b55591f93..183b151637 100644 --- a/src/main/java/org/springframework/data/web/ProjectingJackson2HttpMessageConverter.java +++ b/src/main/java/org/springframework/data/web/ProjectingJackson2HttpMessageConverter.java @@ -20,6 +20,8 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.BeanFactory; @@ -32,7 +34,6 @@ import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/src/main/java/org/springframework/data/web/ReactiveOffsetScrollPositionHandlerMethodArgumentResolver.java b/src/main/java/org/springframework/data/web/ReactiveOffsetScrollPositionHandlerMethodArgumentResolver.java index 0db39b038c..f8fcc724f4 100644 --- a/src/main/java/org/springframework/data/web/ReactiveOffsetScrollPositionHandlerMethodArgumentResolver.java +++ b/src/main/java/org/springframework/data/web/ReactiveOffsetScrollPositionHandlerMethodArgumentResolver.java @@ -17,6 +17,8 @@ import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.data.domain.OffsetScrollPosition; import org.springframework.web.reactive.BindingContext; @@ -40,7 +42,7 @@ public boolean supportsParameter(MethodParameter parameter) { } @Override - public Object resolveArgumentValue(MethodParameter parameter, BindingContext bindingContext, + public @Nullable Object resolveArgumentValue(MethodParameter parameter, BindingContext bindingContext, ServerWebExchange exchange) { List offsetParameter = exchange.getRequest().getQueryParams().get(getOffsetParameter(parameter)); diff --git a/src/main/java/org/springframework/data/web/ReactivePageableHandlerMethodArgumentResolver.java b/src/main/java/org/springframework/data/web/ReactivePageableHandlerMethodArgumentResolver.java index 23246b29d8..2bc26f31b0 100644 --- a/src/main/java/org/springframework/data/web/ReactivePageableHandlerMethodArgumentResolver.java +++ b/src/main/java/org/springframework/data/web/ReactivePageableHandlerMethodArgumentResolver.java @@ -15,11 +15,12 @@ */ package org.springframework.data.web; +import org.jspecify.annotations.NonNull; + import org.springframework.core.MethodParameter; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; -import org.springframework.lang.NonNull; import org.springframework.util.Assert; import org.springframework.util.MultiValueMap; import org.springframework.web.reactive.BindingContext; diff --git a/src/main/java/org/springframework/data/web/ReactiveSortHandlerMethodArgumentResolver.java b/src/main/java/org/springframework/data/web/ReactiveSortHandlerMethodArgumentResolver.java index e001c94fa9..b89079057b 100644 --- a/src/main/java/org/springframework/data/web/ReactiveSortHandlerMethodArgumentResolver.java +++ b/src/main/java/org/springframework/data/web/ReactiveSortHandlerMethodArgumentResolver.java @@ -17,9 +17,10 @@ import java.util.List; +import org.jspecify.annotations.NonNull; + import org.springframework.core.MethodParameter; import org.springframework.data.domain.Sort; -import org.springframework.lang.NonNull; import org.springframework.util.StringUtils; import org.springframework.web.reactive.BindingContext; import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver; diff --git a/src/main/java/org/springframework/data/web/SlicedResourcesAssembler.java b/src/main/java/org/springframework/data/web/SlicedResourcesAssembler.java index 89c6d4ff71..968b7f291a 100644 --- a/src/main/java/org/springframework/data/web/SlicedResourcesAssembler.java +++ b/src/main/java/org/springframework/data/web/SlicedResourcesAssembler.java @@ -22,6 +22,8 @@ import java.util.List; import java.util.Optional; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -37,7 +39,6 @@ import org.springframework.hateoas.server.RepresentationModelAssembler; import org.springframework.hateoas.server.core.EmbeddedWrapper; import org.springframework.hateoas.server.core.EmbeddedWrappers; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; import org.springframework.web.util.UriComponents; @@ -54,7 +55,7 @@ public class SlicedResourcesAssembler implements RepresentationModelAssembler, SlicedModel>> { private final HateoasPageableHandlerMethodArgumentResolver pageableResolver; - private final Optional baseUri; + private final @Nullable UriComponents baseUri; private final EmbeddedWrappers wrappers = new EmbeddedWrappers(false); private boolean forceFirstRel = false; @@ -70,11 +71,11 @@ public class SlicedResourcesAssembler */ public SlicedResourcesAssembler(@Nullable HateoasPageableHandlerMethodArgumentResolver resolver, @Nullable UriComponents baseUri) { - this(resolver, Optional.ofNullable(baseUri), null); + this(resolver, baseUri, null); } private SlicedResourcesAssembler(@Nullable HateoasPageableHandlerMethodArgumentResolver resolver, - @Nullable Optional baseUri, @Nullable MethodParameter parameter) { + @Nullable UriComponents baseUri, @Nullable MethodParameter parameter) { this.pageableResolver = resolver == null ? new HateoasPageableHandlerMethodArgumentResolver() : resolver; this.baseUri = baseUri; @@ -131,7 +132,7 @@ public SlicedModel> toModel(Slice slice, Link selfLink) { */ public > SlicedModel toModel(Slice slice, RepresentationModelAssembler assembler) { - return createModel(slice, assembler, Optional.empty()); + return createModel(slice, assembler, null); } /** @@ -146,7 +147,7 @@ public > SlicedModel toModel(Slice slice, */ public > SlicedModel toModel(Slice slice, RepresentationModelAssembler assembler, Link link) { - return createModel(slice, assembler, Optional.of(link)); + return createModel(slice, assembler, link); } /** @@ -157,7 +158,7 @@ public > SlicedModel toModel(Slice slice, * @return */ public SlicedModel toEmptyModel(Slice slice, Class type) { - return toEmptyModel(slice, type, Optional.empty()); + return toEmptyModel(slice, type, (Link) null); } /** @@ -168,11 +169,7 @@ public SlicedModel toEmptyModel(Slice slice, Class type) { * @param link must not be {@literal null}. * @return */ - public SlicedModel toEmptyModel(Slice slice, Class type, Link link) { - return toEmptyModel(slice, type, Optional.of(link)); - } - - public SlicedModel toEmptyModel(Slice slice, Class type, Optional link) { + public SlicedModel toEmptyModel(Slice slice, Class type, @Nullable Link link) { Assert.notNull(slice, "Slice must not be null"); Assert.isTrue(!slice.hasContent(), "Slice must not have any content"); @@ -185,6 +182,12 @@ public SlicedModel toEmptyModel(Slice slice, Class type, Optional List embedded = Collections.singletonList(wrapper); return addPaginationLinks(SlicedModel.of(embedded, metadata), slice, link); + + } + + @Deprecated + public SlicedModel toEmptyModel(Slice slice, Class type, Optional link) { + return toEmptyModel(slice, type, link.orElse(null)); } /** @@ -205,7 +208,7 @@ protected , S> SlicedModel createSlicedModel } private > SlicedModel createModel(Slice slice, - RepresentationModelAssembler assembler, Optional link) { + RepresentationModelAssembler assembler, @Nullable Link link) { Assert.notNull(slice, "Slice must not be null"); Assert.notNull(assembler, "ResourceAssembler must not be null"); @@ -220,7 +223,8 @@ private > SlicedModel createModel(Slice SlicedModel addPaginationLinks(SlicedModel resources, Slice slice, Optional link) { + private SlicedModel addPaginationLinks(SlicedModel resources, Slice slice, @Nullable Link link) { + UriTemplate base = getUriTemplate(link); boolean isNavigable = slice.hasPrevious() || slice.hasNext(); @@ -230,8 +234,7 @@ private SlicedModel addPaginationLinks(SlicedModel resources, Slice createLink(base, PageRequest.of(0, slice.getSize(), slice.getSort()), IanaLinkRelations.FIRST)); } - Link selfLink = link.map(Link::withSelfRel) - .orElseGet(() -> createLink(base, slice.getPageable(), IanaLinkRelations.SELF)); + Link selfLink = link != null ? link.withSelfRel() : createLink(base, slice.getPageable(), IanaLinkRelations.SELF); resources.add(selfLink); @@ -252,8 +255,8 @@ private SlicedModel addPaginationLinks(SlicedModel resources, Slice * * @return */ - private UriTemplate getUriTemplate(Optional baseLink) { - return UriTemplate.of(baseLink.map(Link::getHref).orElseGet(this::baseUriOrCurrentRequest)); + private UriTemplate getUriTemplate(@Nullable Link baseLink) { + return UriTemplate.of(baseLink != null ? baseLink.getHref() : baseUriOrCurrentRequest()); } /** @@ -266,6 +269,7 @@ private UriTemplate getUriTemplate(Optional baseLink) { * @return */ private Link createLink(UriTemplate base, Pageable pageable, LinkRelation relation) { + UriComponentsBuilder builder = fromUri(base.expand()); pageableResolver.enhance(builder, parameter, pageable); @@ -279,6 +283,7 @@ private Link createLink(UriTemplate base, Pageable pageable, LinkRelation relati * @return */ private SliceMetadata asSliceMetadata(Slice slice) { + Assert.notNull(slice, "Slice must not be null"); int number = pageableResolver.isOneIndexedParameters() ? slice.getNumber() + 1 : slice.getNumber(); @@ -287,7 +292,7 @@ private SliceMetadata asSliceMetadata(Slice slice) { } private String baseUriOrCurrentRequest() { - return baseUri.map(Object::toString).orElseGet(SlicedResourcesAssembler::currentRequest); + return baseUri != null ? baseUri.toString() : SlicedResourcesAssembler.currentRequest(); } private static String currentRequest() { diff --git a/src/main/java/org/springframework/data/web/SlicedResourcesAssemblerArgumentResolver.java b/src/main/java/org/springframework/data/web/SlicedResourcesAssemblerArgumentResolver.java index c224bf0afd..66c2ddb649 100644 --- a/src/main/java/org/springframework/data/web/SlicedResourcesAssemblerArgumentResolver.java +++ b/src/main/java/org/springframework/data/web/SlicedResourcesAssemblerArgumentResolver.java @@ -15,9 +15,10 @@ */ package org.springframework.data.web; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; diff --git a/src/main/java/org/springframework/data/web/SortArgumentResolver.java b/src/main/java/org/springframework/data/web/SortArgumentResolver.java index 7db0861236..ec12421863 100644 --- a/src/main/java/org/springframework/data/web/SortArgumentResolver.java +++ b/src/main/java/org/springframework/data/web/SortArgumentResolver.java @@ -15,10 +15,11 @@ */ package org.springframework.data.web; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.data.domain.Sort; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; diff --git a/src/main/java/org/springframework/data/web/SortHandlerMethodArgumentResolver.java b/src/main/java/org/springframework/data/web/SortHandlerMethodArgumentResolver.java index 0c1b58bbb1..672694ca6d 100644 --- a/src/main/java/org/springframework/data/web/SortHandlerMethodArgumentResolver.java +++ b/src/main/java/org/springframework/data/web/SortHandlerMethodArgumentResolver.java @@ -18,10 +18,11 @@ import java.nio.charset.StandardCharsets; import java.util.Arrays; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.data.domain.Sort; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; diff --git a/src/main/java/org/springframework/data/web/SortHandlerMethodArgumentResolverSupport.java b/src/main/java/org/springframework/data/web/SortHandlerMethodArgumentResolverSupport.java index 6f6127dfd6..deb9845a33 100644 --- a/src/main/java/org/springframework/data/web/SortHandlerMethodArgumentResolverSupport.java +++ b/src/main/java/org/springframework/data/web/SortHandlerMethodArgumentResolverSupport.java @@ -22,6 +22,8 @@ import java.util.Optional; import java.util.function.Consumer; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.core.annotation.MergedAnnotation; import org.springframework.core.annotation.MergedAnnotations; @@ -30,7 +32,6 @@ import org.springframework.data.domain.Sort.Direction; import org.springframework.data.domain.Sort.Order; import org.springframework.data.web.SortDefault.SortDefaults; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; diff --git a/src/main/java/org/springframework/data/web/SpringDataAnnotationUtils.java b/src/main/java/org/springframework/data/web/SpringDataAnnotationUtils.java index 301c7f16b1..f8c95d873f 100644 --- a/src/main/java/org/springframework/data/web/SpringDataAnnotationUtils.java +++ b/src/main/java/org/springframework/data/web/SpringDataAnnotationUtils.java @@ -20,14 +20,13 @@ import java.util.HashSet; import java.util.Set; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.core.MethodParameter; -import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.MergedAnnotation; import org.springframework.core.annotation.MergedAnnotations; import org.springframework.data.domain.Pageable; -import org.springframework.lang.Nullable; -import org.springframework.util.ObjectUtils; /** * Helper class to ease sharing code between legacy {@link PageableHandlerMethodArgumentResolverSupport} and @@ -91,8 +90,7 @@ private static boolean containsMoreThanOnePageableParameter(Method method) { * @return the qualifier value if {@code @Qualifier} is present. * @since 2.5 */ - @Nullable - public static String getQualifier(@Nullable MethodParameter parameter) { + public static @Nullable String getQualifier(@Nullable MethodParameter parameter) { if (parameter == null) { return null; @@ -142,8 +140,7 @@ public static void assertQualifiersFor(Class[] parameterTypes, Annotation[][] * @param annotations must not be {@literal null}. * @return */ - @Nullable - private static Qualifier findAnnotation(Annotation[] annotations) { + private static @Nullable Qualifier findAnnotation(Annotation[] annotations) { for (Annotation annotation : annotations) { if (annotation instanceof Qualifier q) { diff --git a/src/main/java/org/springframework/data/web/XmlBeamHttpMessageConverter.java b/src/main/java/org/springframework/data/web/XmlBeamHttpMessageConverter.java index 852eb3d0a2..08c238c28c 100644 --- a/src/main/java/org/springframework/data/web/XmlBeamHttpMessageConverter.java +++ b/src/main/java/org/springframework/data/web/XmlBeamHttpMessageConverter.java @@ -22,6 +22,8 @@ import javax.xml.parsers.DocumentBuilderFactory; +import org.jspecify.annotations.Nullable; + import org.springframework.core.ResolvableType; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.http.HttpInputMessage; @@ -31,8 +33,8 @@ import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.http.converter.HttpMessageNotWritableException; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; + import org.xml.sax.SAXParseException; import org.xmlbeam.XBProjector; import org.xmlbeam.config.DefaultXMLFactoriesConfig; diff --git a/src/main/java/org/springframework/data/web/aot/WebRuntimeHints.java b/src/main/java/org/springframework/data/web/aot/WebRuntimeHints.java index eda2daf7e9..1956940ad5 100644 --- a/src/main/java/org/springframework/data/web/aot/WebRuntimeHints.java +++ b/src/main/java/org/springframework/data/web/aot/WebRuntimeHints.java @@ -15,6 +15,8 @@ */ package org.springframework.data.web.aot; +import org.jspecify.annotations.Nullable; + import org.springframework.aot.hint.MemberCategory; import org.springframework.aot.hint.RuntimeHints; import org.springframework.aot.hint.RuntimeHintsRegistrar; @@ -22,7 +24,6 @@ import org.springframework.data.web.PagedModel; import org.springframework.data.web.config.EnableSpringDataWebSupport; import org.springframework.data.web.config.SpringDataJacksonConfiguration.PageModule; -import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; /** diff --git a/src/main/java/org/springframework/data/web/config/SpringDataJacksonConfiguration.java b/src/main/java/org/springframework/data/web/config/SpringDataJacksonConfiguration.java index 4bf02df9ed..4e4014a5cd 100644 --- a/src/main/java/org/springframework/data/web/config/SpringDataJacksonConfiguration.java +++ b/src/main/java/org/springframework/data/web/config/SpringDataJacksonConfiguration.java @@ -18,8 +18,10 @@ import java.io.Serial; import java.util.List; +import org.jspecify.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.data.domain.Page; @@ -27,7 +29,6 @@ import org.springframework.data.geo.GeoModule; import org.springframework.data.web.PagedModel; import org.springframework.data.web.config.EnableSpringDataWebSupport.PageSerializationMode; -import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; import com.fasterxml.jackson.databind.BeanDescription; @@ -122,9 +123,8 @@ abstract class WrappingMixing {} static class PageModelConverter extends StdConverter, PagedModel> { - @Nullable @Override - public PagedModel convert(@Nullable Page value) { + public @Nullable PagedModel convert(@Nullable Page value) { return value == null ? null : new PagedModel<>(value); } } diff --git a/src/main/java/org/springframework/data/web/config/SpringDataWebConfiguration.java b/src/main/java/org/springframework/data/web/config/SpringDataWebConfiguration.java index 6d5fc8413d..505bb8c875 100644 --- a/src/main/java/org/springframework/data/web/config/SpringDataWebConfiguration.java +++ b/src/main/java/org/springframework/data/web/config/SpringDataWebConfiguration.java @@ -17,6 +17,8 @@ import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.annotation.Qualifier; @@ -37,7 +39,6 @@ import org.springframework.format.FormatterRegistry; import org.springframework.format.support.FormattingConversionService; import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.web.method.support.HandlerMethodArgumentResolver; diff --git a/src/main/java/org/springframework/data/web/config/package-info.java b/src/main/java/org/springframework/data/web/config/package-info.java index 5f3e4f3100..294048d325 100644 --- a/src/main/java/org/springframework/data/web/config/package-info.java +++ b/src/main/java/org/springframework/data/web/config/package-info.java @@ -1,5 +1,5 @@ /** * Spring Data web configuration. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.web.config; diff --git a/src/main/java/org/springframework/data/web/package-info.java b/src/main/java/org/springframework/data/web/package-info.java index 753aa3e87f..cd12f52cfd 100644 --- a/src/main/java/org/springframework/data/web/package-info.java +++ b/src/main/java/org/springframework/data/web/package-info.java @@ -1,5 +1,5 @@ /** * Integration with Spring MVC. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.web; diff --git a/src/main/java/org/springframework/data/web/querydsl/QuerydslPredicateArgumentResolver.java b/src/main/java/org/springframework/data/web/querydsl/QuerydslPredicateArgumentResolver.java index 74627dc10e..50f6d9b153 100644 --- a/src/main/java/org/springframework/data/web/querydsl/QuerydslPredicateArgumentResolver.java +++ b/src/main/java/org/springframework/data/web/querydsl/QuerydslPredicateArgumentResolver.java @@ -19,11 +19,12 @@ import java.util.Map; import java.util.Optional; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.data.querydsl.binding.QuerydslBindingsFactory; -import org.springframework.lang.Nullable; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.support.WebDataBinderFactory; @@ -69,9 +70,8 @@ public QuerydslPredicateArgumentResolver(QuerydslBindingsFactory factory, Conver super(factory, conversionService); } - @Nullable @Override - public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, + public @Nullable Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { MultiValueMap queryParameters = getQueryParameters(webRequest); diff --git a/src/main/java/org/springframework/data/web/querydsl/QuerydslPredicateArgumentResolverSupport.java b/src/main/java/org/springframework/data/web/querydsl/QuerydslPredicateArgumentResolverSupport.java index 186e400071..b969ed65d7 100644 --- a/src/main/java/org/springframework/data/web/querydsl/QuerydslPredicateArgumentResolverSupport.java +++ b/src/main/java/org/springframework/data/web/querydsl/QuerydslPredicateArgumentResolverSupport.java @@ -18,6 +18,8 @@ import java.lang.reflect.Method; import java.util.Optional; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.core.ResolvableType; import org.springframework.core.annotation.MergedAnnotation; @@ -29,7 +31,6 @@ import org.springframework.data.querydsl.binding.QuerydslPredicate; import org.springframework.data.querydsl.binding.QuerydslPredicateBuilder; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.MultiValueMap; import org.springframework.web.method.support.HandlerMethodArgumentResolver; @@ -107,8 +108,7 @@ Predicate getPredicate(MethodParameter parameter, MultiValueMap return predicateBuilder.getPredicate(domainType, queryParameters, bindings); } - @Nullable - static Object potentiallyConvertMethodParameterValue(MethodParameter parameter, Predicate predicate) { + static @Nullable Object potentiallyConvertMethodParameterValue(MethodParameter parameter, Predicate predicate) { if (!parameter.isOptional()) { return predicate; diff --git a/src/main/java/org/springframework/data/web/querydsl/ReactiveQuerydslPredicateArgumentResolver.java b/src/main/java/org/springframework/data/web/querydsl/ReactiveQuerydslPredicateArgumentResolver.java index fe95a9c658..597b1248fd 100644 --- a/src/main/java/org/springframework/data/web/querydsl/ReactiveQuerydslPredicateArgumentResolver.java +++ b/src/main/java/org/springframework/data/web/querydsl/ReactiveQuerydslPredicateArgumentResolver.java @@ -15,10 +15,11 @@ */ package org.springframework.data.web.querydsl; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.core.convert.ConversionService; import org.springframework.data.querydsl.binding.QuerydslBindingsFactory; -import org.springframework.lang.Nullable; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.reactive.BindingContext; @@ -45,8 +46,7 @@ public ReactiveQuerydslPredicateArgumentResolver(QuerydslBindingsFactory factory } @Override - @Nullable - public Object resolveArgumentValue(MethodParameter parameter, BindingContext bindingContext, + public @Nullable Object resolveArgumentValue(MethodParameter parameter, BindingContext bindingContext, ServerWebExchange exchange) { MultiValueMap queryParameters = getQueryParameters(exchange); diff --git a/src/main/java/org/springframework/data/web/querydsl/package-info.java b/src/main/java/org/springframework/data/web/querydsl/package-info.java index 2d7e9c9d9d..30f7862c0d 100644 --- a/src/main/java/org/springframework/data/web/querydsl/package-info.java +++ b/src/main/java/org/springframework/data/web/querydsl/package-info.java @@ -1,5 +1,5 @@ /** * Querydsl-specific web support. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.data.web.querydsl; diff --git a/src/test/java/org/springframework/data/aot/DeferredTypeBuilder.java b/src/test/java/org/springframework/data/aot/DeferredTypeBuilder.java index 53e767eeb9..09ec67315e 100644 --- a/src/test/java/org/springframework/data/aot/DeferredTypeBuilder.java +++ b/src/test/java/org/springframework/data/aot/DeferredTypeBuilder.java @@ -17,8 +17,9 @@ import java.util.function.Consumer; +import org.jspecify.annotations.Nullable; + import org.springframework.javapoet.TypeSpec.Builder; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** diff --git a/src/test/java/org/springframework/data/convert/PropertyValueConverterFactoryUnitTests.java b/src/test/java/org/springframework/data/convert/PropertyValueConverterFactoryUnitTests.java index 6cd16e7178..41aa06c1c0 100644 --- a/src/test/java/org/springframework/data/convert/PropertyValueConverterFactoryUnitTests.java +++ b/src/test/java/org/springframework/data/convert/PropertyValueConverterFactoryUnitTests.java @@ -20,6 +20,7 @@ import java.util.UUID; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; @@ -28,7 +29,6 @@ import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.context.SamplePersistentProperty; -import org.springframework.lang.Nullable; /** * Unit tests for {@link PropertyValueConverterFactory}. diff --git a/src/test/java/org/springframework/data/convert/PropertyValueConverterRegistrarUnitTests.java b/src/test/java/org/springframework/data/convert/PropertyValueConverterRegistrarUnitTests.java index ba02c5b3be..3f154f0117 100644 --- a/src/test/java/org/springframework/data/convert/PropertyValueConverterRegistrarUnitTests.java +++ b/src/test/java/org/springframework/data/convert/PropertyValueConverterRegistrarUnitTests.java @@ -17,10 +17,10 @@ import static org.assertj.core.api.Assertions.*; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.data.convert.PropertyValueConverterFactoryUnitTests.Person; import org.springframework.data.mapping.context.SamplePersistentProperty; -import org.springframework.lang.Nullable; /** * Unit tests for {@link ValueConverterRegistry}. diff --git a/src/test/java/org/springframework/data/expression/ValueEvaluationUnitTests.java b/src/test/java/org/springframework/data/expression/ValueEvaluationUnitTests.java index 99bbe390d8..db3891822b 100644 --- a/src/test/java/org/springframework/data/expression/ValueEvaluationUnitTests.java +++ b/src/test/java/org/springframework/data/expression/ValueEvaluationUnitTests.java @@ -49,7 +49,7 @@ void setUp() { StandardEnvironment environment = new StandardEnvironment(); environment.getPropertySources().addFirst(propertySource); - record MyRecord(String foo, @org.springframework.lang.Nullable String bar) { + record MyRecord(String foo, @org.jspecify.annotations.Nullable String bar) { } diff --git a/src/test/java/org/springframework/data/mapping/callback/CapturingEntityCallback.java b/src/test/java/org/springframework/data/mapping/callback/CapturingEntityCallback.java index 30904c942c..0a6e14af18 100644 --- a/src/test/java/org/springframework/data/mapping/callback/CapturingEntityCallback.java +++ b/src/test/java/org/springframework/data/mapping/callback/CapturingEntityCallback.java @@ -18,10 +18,11 @@ import java.util.ArrayList; import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.core.Ordered; import org.springframework.data.mapping.Person; import org.springframework.data.mapping.PersonDocument; -import org.springframework.lang.Nullable; import org.springframework.util.CollectionUtils; /** diff --git a/src/test/java/org/springframework/data/mapping/model/AnnotationBasedPersistentPropertyUnitTests.java b/src/test/java/org/springframework/data/mapping/model/AnnotationBasedPersistentPropertyUnitTests.java index 6f660ea308..dde6155ec0 100755 --- a/src/test/java/org/springframework/data/mapping/model/AnnotationBasedPersistentPropertyUnitTests.java +++ b/src/test/java/org/springframework/data/mapping/model/AnnotationBasedPersistentPropertyUnitTests.java @@ -32,6 +32,7 @@ import org.jmolecules.ddd.types.AggregateRoot; import org.jmolecules.ddd.types.Association; import org.jmolecules.ddd.types.Identifier; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.Test; @@ -49,7 +50,6 @@ import org.springframework.data.mapping.context.SampleMappingContext; import org.springframework.data.mapping.context.SamplePersistentProperty; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; import org.springframework.test.util.ReflectionTestUtils; /** diff --git a/src/test/java/org/springframework/data/mapping/model/BasicPersistentEntityUnitTests.java b/src/test/java/org/springframework/data/mapping/model/BasicPersistentEntityUnitTests.java index e87be7880a..8d5fdfc7ce 100755 --- a/src/test/java/org/springframework/data/mapping/model/BasicPersistentEntityUnitTests.java +++ b/src/test/java/org/springframework/data/mapping/model/BasicPersistentEntityUnitTests.java @@ -29,6 +29,7 @@ import java.util.function.Function; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -57,7 +58,6 @@ import org.springframework.data.mapping.context.SampleMappingContext; import org.springframework.data.mapping.context.SamplePersistentProperty; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; import org.springframework.test.util.ReflectionTestUtils; /** diff --git a/src/test/java/org/springframework/data/mapping/model/ClassGeneratingEntityInstantiatorUnitTests.java b/src/test/java/org/springframework/data/mapping/model/ClassGeneratingEntityInstantiatorUnitTests.java index 181aa1dc01..ee9e5ff6a4 100755 --- a/src/test/java/org/springframework/data/mapping/model/ClassGeneratingEntityInstantiatorUnitTests.java +++ b/src/test/java/org/springframework/data/mapping/model/ClassGeneratingEntityInstantiatorUnitTests.java @@ -19,7 +19,6 @@ import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; -import java.lang.reflect.Constructor; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -31,6 +30,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; + import org.springframework.data.annotation.PersistenceCreator; import org.springframework.data.classloadersupport.HidingClassLoader; import org.springframework.data.mapping.Parameter; @@ -142,7 +142,7 @@ void capturesContextOnInstantiationException() throws Exception { } catch (MappingInstantiationException o_O) { assertThat(o_O.getConstructorArguments()).isEqualTo(parameters); - assertThat(o_O.getEntityType()).hasValue(Sample.class); + assertThat(o_O.getEntityType()).isEqualTo(Sample.class); assertThat(o_O.getMessage()).contains(Sample.class.getName()); assertThat(o_O.getMessage()).contains(Long.class.getName()); diff --git a/src/test/java/org/springframework/data/mapping/model/ReflectionEntityInstantiatorUnitTests.java b/src/test/java/org/springframework/data/mapping/model/ReflectionEntityInstantiatorUnitTests.java index 5128b43e3e..3b67f31272 100755 --- a/src/test/java/org/springframework/data/mapping/model/ReflectionEntityInstantiatorUnitTests.java +++ b/src/test/java/org/springframework/data/mapping/model/ReflectionEntityInstantiatorUnitTests.java @@ -20,7 +20,6 @@ import static org.mockito.Mockito.*; import static org.springframework.data.mapping.model.ReflectionEntityInstantiator.*; -import java.lang.reflect.Constructor; import java.util.Arrays; import java.util.List; @@ -28,6 +27,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; + import org.springframework.data.mapping.Parameter; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; @@ -129,7 +129,7 @@ void capturesContextOnInstantiationException() { } catch (MappingInstantiationException o_O) { assertThat(o_O.getConstructorArguments()).isEqualTo(parameters); - assertThat(o_O.getEntityType()).hasValue(Sample.class); + assertThat(o_O.getEntityType()).isEqualTo(Sample.class); assertThat(o_O.getMessage()).contains(Sample.class.getName()); assertThat(o_O.getMessage()).contains(Long.class.getName()); diff --git a/src/test/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupportUnitTests.java b/src/test/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupportUnitTests.java index b6ceb75a48..d5e43c8153 100755 --- a/src/test/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupportUnitTests.java +++ b/src/test/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupportUnitTests.java @@ -20,11 +20,11 @@ import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.data.querydsl.QuerydslPredicateExecutor; import org.springframework.data.repository.Repository; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; import org.springframework.test.util.ReflectionTestUtils; /** diff --git a/src/test/java/org/springframework/data/repository/core/support/RepositoryFactorySupportUnitTests.java b/src/test/java/org/springframework/data/repository/core/support/RepositoryFactorySupportUnitTests.java index 21a0766ebe..0d3b8327c7 100755 --- a/src/test/java/org/springframework/data/repository/core/support/RepositoryFactorySupportUnitTests.java +++ b/src/test/java/org/springframework/data/repository/core/support/RepositoryFactorySupportUnitTests.java @@ -32,6 +32,7 @@ import org.aopalliance.intercept.MethodInvocation; import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -72,7 +73,6 @@ import org.springframework.data.repository.query.ValueExpressionDelegate; import org.springframework.data.repository.query.parser.PartTree; import org.springframework.data.repository.sample.User; -import org.springframework.lang.Nullable; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor; import org.springframework.test.util.ReflectionTestUtils; diff --git a/src/test/java/org/springframework/data/repository/core/support/RepositoryMethodInvokerUnitTests.java b/src/test/java/org/springframework/data/repository/core/support/RepositoryMethodInvokerUnitTests.java index 1e64e06ea9..265d50ffae 100644 --- a/src/test/java/org/springframework/data/repository/core/support/RepositoryMethodInvokerUnitTests.java +++ b/src/test/java/org/springframework/data/repository/core/support/RepositoryMethodInvokerUnitTests.java @@ -38,6 +38,7 @@ import org.assertj.core.api.Assertions; import org.assertj.core.data.Percentage; import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -53,7 +54,6 @@ import org.springframework.data.repository.core.support.RepositoryMethodInvocationListener.RepositoryMethodInvocationResult.State; import org.springframework.data.repository.query.RepositoryQuery; import org.springframework.data.repository.reactive.ReactiveCrudRepository; -import org.springframework.lang.Nullable; import org.springframework.util.CollectionUtils; import org.springframework.util.ReflectionUtils; diff --git a/src/test/java/org/springframework/data/util/AbstractAuditable.java b/src/test/java/org/springframework/data/util/AbstractAuditable.java index cec7ecdbd3..adb92170d7 100644 --- a/src/test/java/org/springframework/data/util/AbstractAuditable.java +++ b/src/test/java/org/springframework/data/util/AbstractAuditable.java @@ -20,7 +20,7 @@ import java.util.Date; import java.util.Optional; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; public abstract class AbstractAuditable { diff --git a/src/test/java/org/springframework/data/util/ClassTypeInformationUnitTests.java b/src/test/java/org/springframework/data/util/ClassTypeInformationUnitTests.java index 4b6c8ac949..f54d0be96b 100755 --- a/src/test/java/org/springframework/data/util/ClassTypeInformationUnitTests.java +++ b/src/test/java/org/springframework/data/util/ClassTypeInformationUnitTests.java @@ -27,6 +27,7 @@ import java.util.SortedMap; import org.aopalliance.aop.Advice; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.aop.Advisor; import org.springframework.aop.SpringProxy; @@ -35,7 +36,6 @@ import org.springframework.aop.framework.AopConfigException; import org.springframework.core.ResolvableType; import org.springframework.data.mapping.Person; -import org.springframework.lang.Nullable; /** * Unit tests for {@link ClassTypeInformation}. diff --git a/src/test/java/org/springframework/data/web/OffsetScrollPositionHandlerMethodArgumentResolverUnitTests.java b/src/test/java/org/springframework/data/web/OffsetScrollPositionHandlerMethodArgumentResolverUnitTests.java index 33691f72a5..18452c67b6 100755 --- a/src/test/java/org/springframework/data/web/OffsetScrollPositionHandlerMethodArgumentResolverUnitTests.java +++ b/src/test/java/org/springframework/data/web/OffsetScrollPositionHandlerMethodArgumentResolverUnitTests.java @@ -21,12 +21,13 @@ import java.util.Optional; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; + import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.core.MethodParameter; import org.springframework.data.domain.OffsetScrollPosition; import org.springframework.data.domain.ScrollPosition; -import org.springframework.lang.Nullable; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.util.StringUtils; import org.springframework.web.context.request.NativeWebRequest; diff --git a/src/test/java/org/springframework/data/web/ReactiveOffsetScrollPositionHandlerMethodArgumentResolverUnitTests.java b/src/test/java/org/springframework/data/web/ReactiveOffsetScrollPositionHandlerMethodArgumentResolverUnitTests.java index 29c0b35dcb..69502b9816 100755 --- a/src/test/java/org/springframework/data/web/ReactiveOffsetScrollPositionHandlerMethodArgumentResolverUnitTests.java +++ b/src/test/java/org/springframework/data/web/ReactiveOffsetScrollPositionHandlerMethodArgumentResolverUnitTests.java @@ -19,12 +19,12 @@ import java.util.Optional; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.core.MethodParameter; import org.springframework.data.domain.OffsetScrollPosition; import org.springframework.data.domain.ScrollPosition; -import org.springframework.lang.Nullable; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; import org.springframework.util.StringUtils; diff --git a/src/test/java/org/springframework/data/web/ReactiveSortHandlerMethodArgumentResolverUnitTests.java b/src/test/java/org/springframework/data/web/ReactiveSortHandlerMethodArgumentResolverUnitTests.java index 9a2c197f91..91d4f41f5e 100755 --- a/src/test/java/org/springframework/data/web/ReactiveSortHandlerMethodArgumentResolverUnitTests.java +++ b/src/test/java/org/springframework/data/web/ReactiveSortHandlerMethodArgumentResolverUnitTests.java @@ -19,6 +19,7 @@ import static org.springframework.data.domain.Sort.Direction.*; import static org.springframework.data.web.SortDefaultUnitTests.*; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Qualifier; @@ -26,7 +27,6 @@ import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.web.SortDefault.SortDefaults; -import org.springframework.lang.Nullable; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; import org.springframework.util.StringUtils; diff --git a/src/test/java/org/springframework/data/web/SortHandlerMethodArgumentResolverUnitTests.java b/src/test/java/org/springframework/data/web/SortHandlerMethodArgumentResolverUnitTests.java index ee7f1db066..5d8c97f5ba 100755 --- a/src/test/java/org/springframework/data/web/SortHandlerMethodArgumentResolverUnitTests.java +++ b/src/test/java/org/springframework/data/web/SortHandlerMethodArgumentResolverUnitTests.java @@ -23,15 +23,16 @@ import java.nio.charset.StandardCharsets; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; + import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.core.MethodParameter; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.domain.Sort.Order; import org.springframework.data.web.SortDefault.SortDefaults; -import org.springframework.lang.Nullable; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.util.StringUtils; import org.springframework.web.context.request.NativeWebRequest; diff --git a/src/test/java/org/springframework/data/web/querydsl/QuerydslPredicateArgumentResolverUnitTests.java b/src/test/java/org/springframework/data/web/querydsl/QuerydslPredicateArgumentResolverUnitTests.java index 7263f5b0d6..c2b4bdecce 100755 --- a/src/test/java/org/springframework/data/web/querydsl/QuerydslPredicateArgumentResolverUnitTests.java +++ b/src/test/java/org/springframework/data/web/querydsl/QuerydslPredicateArgumentResolverUnitTests.java @@ -24,8 +24,10 @@ import java.lang.annotation.Target; import java.util.Optional; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; + import org.springframework.core.MethodParameter; import org.springframework.core.annotation.AliasFor; import org.springframework.core.annotation.MergedAnnotation; @@ -42,7 +44,6 @@ import org.springframework.hateoas.EntityModel; import org.springframework.http.HttpEntity; import org.springframework.http.ResponseEntity; -import org.springframework.lang.Nullable; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.web.context.request.ServletWebRequest; diff --git a/src/test/java/org/springframework/data/web/querydsl/ReactiveQuerydslPredicateArgumentResolverUnitTests.java b/src/test/java/org/springframework/data/web/querydsl/ReactiveQuerydslPredicateArgumentResolverUnitTests.java index a11efb2393..5a6f600da8 100755 --- a/src/test/java/org/springframework/data/web/querydsl/ReactiveQuerydslPredicateArgumentResolverUnitTests.java +++ b/src/test/java/org/springframework/data/web/querydsl/ReactiveQuerydslPredicateArgumentResolverUnitTests.java @@ -19,8 +19,10 @@ import java.util.Optional; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; + import org.springframework.core.MethodParameter; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.data.querydsl.QUser; @@ -30,7 +32,6 @@ import org.springframework.data.querydsl.binding.QuerydslBindings; import org.springframework.data.querydsl.binding.QuerydslBindingsFactory; import org.springframework.data.querydsl.binding.QuerydslPredicate; -import org.springframework.lang.Nullable; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange;