From 5599787f091b6d78d8bebe5a9167b5490c2746df Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Mon, 17 Feb 2025 09:54:28 +0100 Subject: [PATCH 1/4] Prepare issue branch. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2f79fad4..809efac8 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-keyvalue - 4.0.0-SNAPSHOT + 4.0.x-GH-618-SNAPSHOT Spring Data KeyValue From 75bc46212ba25c05d1f088acf6cb24446d4c0023 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Fri, 14 Feb 2025 11:18:54 +0100 Subject: [PATCH 2/4] Move Nullable annotations to jspecify. --- .mvn/jvm.config | 10 ++++++ pom.xml | 5 +++ .../keyvalue/annotation/package-info.java | 3 +- .../keyvalue/aot/KeyValueRuntimeHints.java | 2 +- .../data/keyvalue/aot/package-info.java | 5 +++ .../core/AbstractKeyValueAdapter.java | 8 ++--- .../data/keyvalue/core/CriteriaAccessor.java | 2 +- .../core/ForwardingCloseableIterator.java | 2 +- .../keyvalue/core/GeneratingIdAccessor.java | 3 +- .../data/keyvalue/core/KeyValueAdapter.java | 14 ++++----- .../data/keyvalue/core/KeyValueCallback.java | 2 +- .../keyvalue/core/KeyValueOperations.java | 12 +++---- ...eyValuePersistenceExceptionTranslator.java | 6 ++-- .../data/keyvalue/core/KeyValueTemplate.java | 31 ++++++++++++------- .../data/keyvalue/core/PathSortAccessor.java | 5 ++- .../keyvalue/core/PredicateQueryEngine.java | 10 +++--- .../keyvalue/core/PropertyPathComparator.java | 14 ++++----- .../data/keyvalue/core/QueryEngine.java | 5 ++- .../core/SimplePropertyPathAccessor.java | 3 +- .../data/keyvalue/core/SortAccessor.java | 2 +- .../keyvalue/core/SpelCriteriaAccessor.java | 3 +- .../keyvalue/core/SpelPropertyComparator.java | 19 ++++++------ .../data/keyvalue/core/SpelQueryEngine.java | 3 +- .../data/keyvalue/core/SpelSortAccessor.java | 3 +- .../keyvalue/core/event/KeyValueEvent.java | 11 +++---- .../keyvalue/core/event/package-info.java | 3 +- .../AnnotationBasedKeySpaceResolver.java | 9 +++--- .../BasicKeyValuePersistentEntity.java | 8 ++--- .../core/mapping/KeySpaceResolver.java | 2 +- .../mapping/KeyValuePersistentEntity.java | 2 +- .../context/KeyValueMappingContext.java | 5 ++- .../core/mapping/context/package-info.java | 3 +- .../keyvalue/core/mapping/package-info.java | 3 +- .../data/keyvalue/core/package-info.java | 3 +- .../keyvalue/core/query/KeyValueQuery.java | 5 ++- .../keyvalue/core/query/package-info.java | 3 +- ...ValueRepositoryConfigurationExtension.java | 7 ++--- .../repository/config/package-info.java | 3 +- .../keyvalue/repository/package-info.java | 3 +- .../query/CachingKeyValuePartTreeQuery.java | 2 +- .../query/KeyValuePartTreeQuery.java | 8 ++--- .../query/PredicateQueryCreator.java | 2 +- .../repository/query/SpelQueryCreator.java | 3 +- .../repository/query/package-info.java | 3 +- .../support/KeyValueRepositoryFactory.java | 2 +- .../KeyValueRepositoryFactoryBean.java | 7 ++++- .../QuerydslKeyValuePredicateExecutor.java | 7 ++--- .../repository/support/package-info.java | 3 +- .../data/map/MapKeyValueAdapter.java | 11 ++++--- .../data/map/package-info.java | 3 +- .../MapRepositoryConfigurationExtension.java | 10 +++--- .../map/repository/config/package-info.java | 3 +- .../keyvalue/core/KeyValueTemplateTests.java | 2 +- .../core/KeyValueTemplateUnitTests.java | 4 +-- 54 files changed, 160 insertions(+), 152 deletions(-) create mode 100644 .mvn/jvm.config create mode 100644 src/main/java/org/springframework/data/keyvalue/aot/package-info.java diff --git a/.mvn/jvm.config b/.mvn/jvm.config new file mode 100644 index 00000000..32599cef --- /dev/null +++ b/.mvn/jvm.config @@ -0,0 +1,10 @@ +--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED +--add-opens jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED +--add-opens jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED diff --git a/pom.xml b/pom.xml index 809efac8..a7083bc4 100644 --- a/pom.xml +++ b/pom.xml @@ -45,6 +45,11 @@ ${querydsl} true + + org.jspecify + jspecify + 1.0.0 + diff --git a/src/main/java/org/springframework/data/keyvalue/annotation/package-info.java b/src/main/java/org/springframework/data/keyvalue/annotation/package-info.java index e4994ad6..acad4dc7 100644 --- a/src/main/java/org/springframework/data/keyvalue/annotation/package-info.java +++ b/src/main/java/org/springframework/data/keyvalue/annotation/package-info.java @@ -1,6 +1,5 @@ /** * Key-Value annotations for declarative keyspace configuration. */ -@org.springframework.lang.NonNullApi -@org.springframework.lang.NonNullFields +@org.jspecify.annotations.NullMarked package org.springframework.data.keyvalue.annotation; diff --git a/src/main/java/org/springframework/data/keyvalue/aot/KeyValueRuntimeHints.java b/src/main/java/org/springframework/data/keyvalue/aot/KeyValueRuntimeHints.java index b4417b3f..8959193a 100644 --- a/src/main/java/org/springframework/data/keyvalue/aot/KeyValueRuntimeHints.java +++ b/src/main/java/org/springframework/data/keyvalue/aot/KeyValueRuntimeHints.java @@ -18,13 +18,13 @@ import java.util.Arrays; import java.util.List; +import org.jspecify.annotations.Nullable; import org.springframework.aot.hint.ExecutableMode; import org.springframework.aot.hint.MemberCategory; import org.springframework.aot.hint.RuntimeHints; import org.springframework.aot.hint.RuntimeHintsRegistrar; import org.springframework.aot.hint.TypeReference; import org.springframework.data.keyvalue.repository.query.KeyValuePartTreeQuery; -import org.springframework.lang.Nullable; /** * {@link RuntimeHintsRegistrar} for KeyValue. diff --git a/src/main/java/org/springframework/data/keyvalue/aot/package-info.java b/src/main/java/org/springframework/data/keyvalue/aot/package-info.java new file mode 100644 index 00000000..199fb4ae --- /dev/null +++ b/src/main/java/org/springframework/data/keyvalue/aot/package-info.java @@ -0,0 +1,5 @@ +/** + * Support classes for key-value ahead of time computation + */ +@org.jspecify.annotations.NullMarked +package org.springframework.data.keyvalue.aot; diff --git a/src/main/java/org/springframework/data/keyvalue/core/AbstractKeyValueAdapter.java b/src/main/java/org/springframework/data/keyvalue/core/AbstractKeyValueAdapter.java index 80868a88..d64e226f 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/AbstractKeyValueAdapter.java +++ b/src/main/java/org/springframework/data/keyvalue/core/AbstractKeyValueAdapter.java @@ -18,8 +18,8 @@ import java.util.Collection; import java.util.Comparator; +import org.jspecify.annotations.Nullable; import org.springframework.data.keyvalue.core.query.KeyValueQuery; -import org.springframework.lang.Nullable; /** * Base implementation of {@link KeyValueAdapter} holds {@link QueryEngine} to delegate {@literal find} and @@ -69,15 +69,13 @@ protected AbstractKeyValueAdapter(@Nullable QueryEngine T get(Object id, String keyspace, Class type) { + public @Nullable T get(Object id, String keyspace, Class type) { return type.cast(get(id, keyspace)); } - @Nullable @Override - public T delete(Object id, String keyspace, Class type) { + public @Nullable T delete(Object id, String keyspace, Class type) { return type.cast(delete(id, keyspace)); } diff --git a/src/main/java/org/springframework/data/keyvalue/core/CriteriaAccessor.java b/src/main/java/org/springframework/data/keyvalue/core/CriteriaAccessor.java index d50c6268..2e226de6 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/CriteriaAccessor.java +++ b/src/main/java/org/springframework/data/keyvalue/core/CriteriaAccessor.java @@ -15,8 +15,8 @@ */ package org.springframework.data.keyvalue.core; +import org.jspecify.annotations.Nullable; import org.springframework.data.keyvalue.core.query.KeyValueQuery; -import org.springframework.lang.Nullable; /** * Resolves the criteria object from given {@link KeyValueQuery}. diff --git a/src/main/java/org/springframework/data/keyvalue/core/ForwardingCloseableIterator.java b/src/main/java/org/springframework/data/keyvalue/core/ForwardingCloseableIterator.java index 3867d74f..4a3a89f1 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/ForwardingCloseableIterator.java +++ b/src/main/java/org/springframework/data/keyvalue/core/ForwardingCloseableIterator.java @@ -17,8 +17,8 @@ import java.util.Iterator; +import org.jspecify.annotations.Nullable; import org.springframework.data.util.CloseableIterator; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** diff --git a/src/main/java/org/springframework/data/keyvalue/core/GeneratingIdAccessor.java b/src/main/java/org/springframework/data/keyvalue/core/GeneratingIdAccessor.java index 46a07ac2..d4ccc687 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/GeneratingIdAccessor.java +++ b/src/main/java/org/springframework/data/keyvalue/core/GeneratingIdAccessor.java @@ -15,6 +15,7 @@ */ package org.springframework.data.keyvalue.core; +import org.jspecify.annotations.Nullable; import org.springframework.data.mapping.IdentifierAccessor; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.PersistentPropertyAccessor; @@ -55,7 +56,7 @@ class GeneratingIdAccessor implements IdentifierAccessor { } @Override - public Object getIdentifier() { + public @Nullable Object getIdentifier() { return accessor.getProperty(identifierProperty); } diff --git a/src/main/java/org/springframework/data/keyvalue/core/KeyValueAdapter.java b/src/main/java/org/springframework/data/keyvalue/core/KeyValueAdapter.java index f3eaf1d1..e4848309 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/KeyValueAdapter.java +++ b/src/main/java/org/springframework/data/keyvalue/core/KeyValueAdapter.java @@ -18,10 +18,10 @@ import java.util.Collection; import java.util.Map; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.DisposableBean; import org.springframework.data.keyvalue.core.query.KeyValueQuery; import org.springframework.data.util.CloseableIterator; -import org.springframework.lang.Nullable; /** * {@link KeyValueAdapter} unifies access and shields the underlying key/value specific implementation. @@ -39,7 +39,7 @@ public interface KeyValueAdapter extends DisposableBean { * @param keyspace must not be {@literal null}. * @return the item previously associated with the id. */ - Object put(Object id, Object item, String keyspace); + @Nullable Object put(Object id, Object item, String keyspace); /** * Check if a object with given id exists in keyspace. @@ -69,8 +69,7 @@ public interface KeyValueAdapter extends DisposableBean { * @return {@literal null} in case no matching item exists. * @since 1.1 */ - @Nullable - T get(Object id, String keyspace, Class type); + @Nullable T get(Object id, String keyspace, Class type); /** * Delete and return the object with given type and id. @@ -91,8 +90,7 @@ public interface KeyValueAdapter extends DisposableBean { * @return {@literal null} if object could not be found * @since 1.1 */ - @Nullable - T delete(Object id, String keyspace, Class type); + @Nullable T delete(Object id, String keyspace, Class type); /** * Get all elements for given keyspace. @@ -100,7 +98,7 @@ public interface KeyValueAdapter extends DisposableBean { * @param keyspace must not be {@literal null}. * @return empty {@link Collection} if nothing found. */ - Iterable getAllOf(String keyspace); + Iterable getAllOf(String keyspace); /** * Get all elements for given keyspace. @@ -132,7 +130,7 @@ default Iterable getAllOf(String keyspace, Class type) { * @since 2.5 */ @SuppressWarnings("unchecked") - default CloseableIterator> entries(String keyspace, Class type) { + default CloseableIterator> entries(String keyspace, Class type) { return (CloseableIterator) entries(keyspace); } diff --git a/src/main/java/org/springframework/data/keyvalue/core/KeyValueCallback.java b/src/main/java/org/springframework/data/keyvalue/core/KeyValueCallback.java index 97328498..0014206f 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/KeyValueCallback.java +++ b/src/main/java/org/springframework/data/keyvalue/core/KeyValueCallback.java @@ -15,7 +15,7 @@ */ package org.springframework.data.keyvalue.core; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** * Generic callback interface for code that operates on a {@link KeyValueAdapter}. This is particularly useful for diff --git a/src/main/java/org/springframework/data/keyvalue/core/KeyValueOperations.java b/src/main/java/org/springframework/data/keyvalue/core/KeyValueOperations.java index 4caa2a09..e8f426f5 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/KeyValueOperations.java +++ b/src/main/java/org/springframework/data/keyvalue/core/KeyValueOperations.java @@ -17,12 +17,12 @@ import java.util.Optional; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.DisposableBean; import org.springframework.data.domain.Sort; import org.springframework.data.keyvalue.annotation.KeySpace; import org.springframework.data.keyvalue.core.query.KeyValueQuery; import org.springframework.data.mapping.context.MappingContext; -import org.springframework.lang.Nullable; /** * Interface that specifies a basic set of key/value operations. Implemented by {@link KeyValueTemplate}. @@ -84,8 +84,8 @@ public interface KeyValueOperations extends DisposableBean { * @param action must not be {@literal null}. * @return */ - @Nullable - T execute(KeyValueCallback action); + + @Nullable T execute(KeyValueCallback action); /** * Get all elements matching the given query.
@@ -145,8 +145,7 @@ public interface KeyValueOperations extends DisposableBean { * @param objectToDelete must not be {@literal null}. * @return */ - @Nullable - T delete(T objectToDelete); + @Nullable T delete(T objectToDelete); /** * Delete item of type with given id. @@ -155,8 +154,7 @@ public interface KeyValueOperations extends DisposableBean { * @param type must not be {@literal null}. * @return the deleted item or {@literal null} if no match found. */ - @Nullable - T delete(Object id, Class type); + @Nullable T delete(Object id, Class type); /** * Total number of elements with given type available. Respects {@link KeySpace} if present and therefore counts all diff --git a/src/main/java/org/springframework/data/keyvalue/core/KeyValuePersistenceExceptionTranslator.java b/src/main/java/org/springframework/data/keyvalue/core/KeyValuePersistenceExceptionTranslator.java index 3543c918..7a4f9ff4 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/KeyValuePersistenceExceptionTranslator.java +++ b/src/main/java/org/springframework/data/keyvalue/core/KeyValuePersistenceExceptionTranslator.java @@ -17,10 +17,10 @@ import java.util.NoSuchElementException; +import org.jspecify.annotations.Nullable; import org.springframework.dao.DataAccessException; import org.springframework.dao.DataRetrievalFailureException; import org.springframework.dao.support.PersistenceExceptionTranslator; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -32,9 +32,9 @@ */ public class KeyValuePersistenceExceptionTranslator implements PersistenceExceptionTranslator { - @Nullable @Override - public DataAccessException translateExceptionIfPossible(RuntimeException exception) { + @SuppressWarnings("NullAway") + public @Nullable DataAccessException translateExceptionIfPossible(RuntimeException exception) { Assert.notNull(exception, "Exception must not be null"); diff --git a/src/main/java/org/springframework/data/keyvalue/core/KeyValueTemplate.java b/src/main/java/org/springframework/data/keyvalue/core/KeyValueTemplate.java index f1cd793f..4cf793a6 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/KeyValueTemplate.java +++ b/src/main/java/org/springframework/data/keyvalue/core/KeyValueTemplate.java @@ -21,6 +21,7 @@ import java.util.Optional; import java.util.Set; +import org.jspecify.annotations.Nullable; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.dao.DataAccessException; @@ -34,7 +35,6 @@ import org.springframework.data.keyvalue.core.mapping.context.KeyValueMappingContext; import org.springframework.data.keyvalue.core.query.KeyValueQuery; import org.springframework.data.mapping.context.MappingContext; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; @@ -143,7 +143,7 @@ public T insert(T objectToInsert) { KeyValuePersistentEntity entity = getKeyValuePersistentEntity(objectToInsert); GeneratingIdAccessor generatingIdAccessor = new GeneratingIdAccessor(entity.getPropertyAccessor(objectToInsert), - entity.getIdProperty(), identifierGenerator); + entity.getRequiredIdProperty(), identifierGenerator); Object id = generatingIdAccessor.getOrGenerateIdentifier(); return insert(id, objectToInsert); @@ -195,6 +195,7 @@ public T update(Object id, T objectToUpdate) { Assert.notNull(objectToUpdate, "Object to be updated must not be null"); String keyspace = resolveKeySpace(objectToUpdate.getClass()); + Assert.notNull(keyspace, "Keyspace must not be null"); potentiallyPublishEvent(KeyValueEvent.beforeUpdate(id, keyspace, objectToUpdate.getClass(), objectToUpdate)); @@ -213,7 +214,8 @@ public Iterable findAll(Class type) { return executeRequired(adapter -> { - Iterable values = adapter.getAllOf(resolveKeySpace(type), type); + String keyspace = resolveKeySpace(type); + Iterable values = adapter.getAllOf(keyspace, type); ArrayList filtered = new ArrayList<>(); for (Object candidate : values) { @@ -233,6 +235,7 @@ public Optional findById(Object id, Class type) { Assert.notNull(type, "Type to fetch must not be null"); String keyspace = resolveKeySpace(type); + Assert.notNull(keyspace, "Keyspace must not be null"); potentiallyPublishEvent(KeyValueEvent.beforeGet(id, keyspace, type)); @@ -258,7 +261,6 @@ public void delete(Class type) { Assert.notNull(type, "Type to delete must not be null"); String keyspace = resolveKeySpace(type); - potentiallyPublishEvent(KeyValueEvent.beforeDropKeySpace(keyspace, type)); execute((KeyValueCallback) adapter -> { @@ -272,21 +274,22 @@ public void delete(Class type) { @SuppressWarnings("unchecked") @Override - public T delete(T objectToDelete) { + public @Nullable T delete(T objectToDelete) { Class type = (Class) ClassUtils.getUserClass(objectToDelete); KeyValuePersistentEntity entity = getKeyValuePersistentEntity(objectToDelete); - return delete(entity.getIdentifierAccessor(objectToDelete).getIdentifier(), type); + return delete(entity.getIdentifierAccessor(objectToDelete).getRequiredIdentifier(), type); } @Override - public T delete(Object id, Class type) { + public @Nullable T delete(Object id, Class type) { Assert.notNull(id, "Id for object to be deleted must not be null"); Assert.notNull(type, "Type to delete must not be null"); String keyspace = resolveKeySpace(type); + Assert.notNull(keyspace, "Keyspace must not be null"); potentiallyPublishEvent(KeyValueEvent.beforeDelete(id, keyspace, type)); @@ -301,12 +304,12 @@ public T delete(Object id, Class type) { public long count(Class type) { Assert.notNull(type, "Type for count must not be null"); - return adapter.count(resolveKeySpace(type)); + String keyspace = resolveKeySpace(type); + return adapter.count(keyspace); } - @Nullable @Override - public T execute(KeyValueCallback action) { + public @Nullable T execute(KeyValueCallback action) { Assert.notNull(action, "KeyValueCallback must not be null"); @@ -401,8 +404,12 @@ public void destroy() throws Exception { return this.mappingContext.getRequiredPersistentEntity(ClassUtils.getUserClass(objectToInsert)); } - private String resolveKeySpace(Class type) { - return this.mappingContext.getRequiredPersistentEntity(type).getKeySpace(); + + private String resolveKeySpace(Class type) { + + String keyspace = this.mappingContext.getRequiredPersistentEntity(type).getKeySpace(); + Assert.notNull(keyspace, "Keyspace must not be null"); + return keyspace; } private RuntimeException resolveExceptionIfPossible(RuntimeException e) { diff --git a/src/main/java/org/springframework/data/keyvalue/core/PathSortAccessor.java b/src/main/java/org/springframework/data/keyvalue/core/PathSortAccessor.java index 5e6bcab2..3441f0dc 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/PathSortAccessor.java +++ b/src/main/java/org/springframework/data/keyvalue/core/PathSortAccessor.java @@ -18,11 +18,11 @@ import java.util.Comparator; import java.util.Optional; +import org.jspecify.annotations.Nullable; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.domain.Sort.NullHandling; import org.springframework.data.domain.Sort.Order; import org.springframework.data.keyvalue.core.query.KeyValueQuery; -import org.springframework.lang.Nullable; /** * @author Christoph Strobl @@ -30,9 +30,8 @@ */ public class PathSortAccessor implements SortAccessor> { - @Nullable @Override - public Comparator resolve(KeyValueQuery query) { + public @Nullable Comparator resolve(KeyValueQuery query) { if (query.getSort().isUnsorted()) { return null; diff --git a/src/main/java/org/springframework/data/keyvalue/core/PredicateQueryEngine.java b/src/main/java/org/springframework/data/keyvalue/core/PredicateQueryEngine.java index 8c51fe6b..b8bb755a 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/PredicateQueryEngine.java +++ b/src/main/java/org/springframework/data/keyvalue/core/PredicateQueryEngine.java @@ -22,8 +22,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.springframework.data.keyvalue.core.query.KeyValueQuery; -import org.springframework.lang.Nullable; /** * {@link QueryEngine} implementation specific for executing {@link Predicate} based {@link KeyValueQuery} against @@ -46,9 +46,9 @@ public PredicateQueryEngine() { */ public PredicateQueryEngine(SortAccessor> sortAccessor) { super(new CriteriaAccessor<>() { - @Nullable + @Override - public Predicate resolve(KeyValueQuery query) { + public @Nullable Predicate resolve(KeyValueQuery query) { return (Predicate) query.getCriteria(); } }, sortAccessor); @@ -78,12 +78,12 @@ private List sortAndFilterMatchingRange(Iterable source, @Nullable Predica return filterMatchingRange(tmp, criteria, offset, rows); } - private static List filterMatchingRange(List source, @Nullable Predicate criteria, long offset, int rows) { + private static List filterMatchingRange(List source, @Nullable Predicate criteria, long offset, int rows) { Stream stream = source.stream(); if (criteria != null) { - stream = stream.filter(criteria); + stream = stream.filter((Predicate) criteria); } if (offset > 0) { stream = stream.skip(offset); diff --git a/src/main/java/org/springframework/data/keyvalue/core/PropertyPathComparator.java b/src/main/java/org/springframework/data/keyvalue/core/PropertyPathComparator.java index c6392aa6..ff28cb3e 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/PropertyPathComparator.java +++ b/src/main/java/org/springframework/data/keyvalue/core/PropertyPathComparator.java @@ -19,8 +19,8 @@ import java.util.HashMap; import java.util.Map; +import org.jspecify.annotations.Nullable; import org.springframework.data.mapping.PropertyPath; -import org.springframework.lang.Nullable; /** * {@link Comparator} implementation to compare objects based on a {@link PropertyPath}. This comparator obtains the @@ -67,12 +67,12 @@ public int compare(@Nullable T o1, @Nullable T o2) { return getComparator().compare(value1, value2) * (asc ? 1 : -1); } - protected Object getCompareValue(T object, PropertyPath propertyPath) { + protected @Nullable Object getCompareValue(S object, PropertyPath propertyPath) { return new SimplePropertyPathAccessor<>(object).getValue(propertyPath); } @SuppressWarnings("unchecked") - private Comparator getComparator() { + private Comparator<@Nullable Object> getComparator() { return (Comparator) (nullsFirst ? NULLS_FIRST : NULLS_LAST); } @@ -81,7 +81,7 @@ private Comparator getComparator() { * * @return */ - public PropertyPathComparator asc() { + public PropertyPathComparator<@Nullable T> asc() { this.asc = true; return this; } @@ -91,7 +91,7 @@ public PropertyPathComparator asc() { * * @return */ - public PropertyPathComparator desc() { + public PropertyPathComparator<@Nullable T> desc() { this.asc = false; return this; } @@ -101,7 +101,7 @@ public PropertyPathComparator desc() { * * @return */ - public PropertyPathComparator nullsFirst() { + public PropertyPathComparator<@Nullable T> nullsFirst() { this.nullsFirst = true; return this; } @@ -111,7 +111,7 @@ public PropertyPathComparator nullsFirst() { * * @return */ - public PropertyPathComparator nullsLast() { + public PropertyPathComparator<@Nullable T> nullsLast() { this.nullsFirst = false; return this; } diff --git a/src/main/java/org/springframework/data/keyvalue/core/QueryEngine.java b/src/main/java/org/springframework/data/keyvalue/core/QueryEngine.java index 33b581ce..9b9969f5 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/QueryEngine.java +++ b/src/main/java/org/springframework/data/keyvalue/core/QueryEngine.java @@ -18,8 +18,8 @@ import java.util.Collection; import java.util.Optional; +import org.jspecify.annotations.Nullable; import org.springframework.data.keyvalue.core.query.KeyValueQuery; -import org.springframework.lang.Nullable; /** * Base implementation for accessing and executing {@link KeyValueQuery} against a {@link KeyValueAdapter}. @@ -125,8 +125,7 @@ public Collection execute(@Nullable CRITERIA criteria, @Nullable SORT sor * * @return */ - @Nullable - protected ADAPTER getAdapter() { + protected @Nullable ADAPTER getAdapter() { return this.adapter; } diff --git a/src/main/java/org/springframework/data/keyvalue/core/SimplePropertyPathAccessor.java b/src/main/java/org/springframework/data/keyvalue/core/SimplePropertyPathAccessor.java index 84f21a35..4c3c6a27 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/SimplePropertyPathAccessor.java +++ b/src/main/java/org/springframework/data/keyvalue/core/SimplePropertyPathAccessor.java @@ -15,6 +15,7 @@ */ package org.springframework.data.keyvalue.core; +import org.jspecify.annotations.Nullable; import org.springframework.beans.BeanWrapper; import org.springframework.data.mapping.PropertyPath; import org.springframework.data.util.DirectFieldAccessFallbackBeanWrapper; @@ -31,7 +32,7 @@ public SimplePropertyPathAccessor(Object source) { this.root = source; } - public Object getValue(PropertyPath path) { + public @Nullable Object getValue(PropertyPath path) { Object currentValue = root; for (PropertyPath current : path) { diff --git a/src/main/java/org/springframework/data/keyvalue/core/SortAccessor.java b/src/main/java/org/springframework/data/keyvalue/core/SortAccessor.java index e7c43907..9ef228fd 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/SortAccessor.java +++ b/src/main/java/org/springframework/data/keyvalue/core/SortAccessor.java @@ -15,9 +15,9 @@ */ package org.springframework.data.keyvalue.core; +import org.jspecify.annotations.Nullable; import org.springframework.data.domain.Sort; import org.springframework.data.keyvalue.core.query.KeyValueQuery; -import org.springframework.lang.Nullable; /** * Resolves the {@link Sort} object from given {@link KeyValueQuery} and potentially converts it into a store specific diff --git a/src/main/java/org/springframework/data/keyvalue/core/SpelCriteriaAccessor.java b/src/main/java/org/springframework/data/keyvalue/core/SpelCriteriaAccessor.java index 4f91aa58..74c419b2 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/SpelCriteriaAccessor.java +++ b/src/main/java/org/springframework/data/keyvalue/core/SpelCriteriaAccessor.java @@ -15,6 +15,7 @@ */ package org.springframework.data.keyvalue.core; +import org.jspecify.annotations.Nullable; import org.springframework.data.keyvalue.core.query.KeyValueQuery; import org.springframework.expression.spel.standard.SpelExpression; import org.springframework.expression.spel.standard.SpelExpressionParser; @@ -43,7 +44,7 @@ public SpelCriteriaAccessor(SpelExpressionParser parser) { } @Override - public SpelCriteria resolve(KeyValueQuery query) { + public @Nullable SpelCriteria resolve(KeyValueQuery query) { if (query.getCriteria() == null) { return null; diff --git a/src/main/java/org/springframework/data/keyvalue/core/SpelPropertyComparator.java b/src/main/java/org/springframework/data/keyvalue/core/SpelPropertyComparator.java index b464c1a7..3aafcf00 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/SpelPropertyComparator.java +++ b/src/main/java/org/springframework/data/keyvalue/core/SpelPropertyComparator.java @@ -17,10 +17,10 @@ import java.util.Comparator; +import org.jspecify.annotations.Nullable; import org.springframework.expression.spel.standard.SpelExpression; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.SimpleEvaluationContext; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -63,7 +63,7 @@ public SpelPropertyComparator(String path, SpelExpressionParser parser) { * * @return */ - public SpelPropertyComparator asc() { + public SpelPropertyComparator<@Nullable T> asc() { this.asc = true; return this; } @@ -73,7 +73,7 @@ public SpelPropertyComparator asc() { * * @return */ - public SpelPropertyComparator desc() { + public SpelPropertyComparator<@Nullable T> desc() { this.asc = false; return this; } @@ -83,7 +83,7 @@ public SpelPropertyComparator desc() { * * @return */ - public SpelPropertyComparator nullsFirst() { + public SpelPropertyComparator<@Nullable T> nullsFirst() { this.nullsFirst = true; return this; } @@ -93,7 +93,7 @@ public SpelPropertyComparator nullsFirst() { * * @return */ - public SpelPropertyComparator nullsLast() { + public SpelPropertyComparator<@Nullable T> nullsLast() { this.nullsFirst = false; return this; } @@ -119,14 +119,12 @@ protected SpelExpression getExpression() { */ protected String buildExpressionForPath() { - String rawExpression = String.format("#comparator.compare(#arg1?.%s,#arg2?.%s)", path.replace(".", "?."), + return String.format("#comparator.compare(#arg1?.%s,#arg2?.%s)", path.replace(".", "?."), path.replace(".", "?.")); - - return rawExpression; } @Override - public int compare(T arg1, T arg2) { + public int compare(@Nullable T arg1, @Nullable T arg2) { SpelExpression expressionToUse = getExpression(); @@ -137,7 +135,8 @@ public int compare(T arg1, T arg2) { expressionToUse.setEvaluationContext(ctx); - return expressionToUse.getValue(Integer.class) * (asc ? 1 : -1); + Integer value = expressionToUse.getValue(Integer.class); + return (value != null ? value : 0) * (asc ? 1 : -1); } /** diff --git a/src/main/java/org/springframework/data/keyvalue/core/SpelQueryEngine.java b/src/main/java/org/springframework/data/keyvalue/core/SpelQueryEngine.java index cd8c27f5..4ce81fb4 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/SpelQueryEngine.java +++ b/src/main/java/org/springframework/data/keyvalue/core/SpelQueryEngine.java @@ -21,11 +21,11 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.springframework.data.keyvalue.core.query.KeyValueQuery; import org.springframework.expression.spel.SpelEvaluationException; import org.springframework.expression.spel.standard.SpelExpression; import org.springframework.expression.spel.standard.SpelExpressionParser; -import org.springframework.lang.Nullable; /** * {@link QueryEngine} implementation specific for executing {@link SpelExpression} based {@link KeyValueQuery} against @@ -97,6 +97,7 @@ private static List filterMatchingRange(List source, @Nullable SpelCri return stream.collect(Collectors.toList()); } + @SuppressWarnings("NullAway") private static boolean evaluateExpression(SpelCriteria criteria, Object candidate) { try { diff --git a/src/main/java/org/springframework/data/keyvalue/core/SpelSortAccessor.java b/src/main/java/org/springframework/data/keyvalue/core/SpelSortAccessor.java index c76da7c9..a8a00548 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/SpelSortAccessor.java +++ b/src/main/java/org/springframework/data/keyvalue/core/SpelSortAccessor.java @@ -18,6 +18,7 @@ import java.util.Comparator; import java.util.Optional; +import org.jspecify.annotations.Nullable; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.domain.Sort.NullHandling; import org.springframework.data.domain.Sort.Order; @@ -48,7 +49,7 @@ public SpelSortAccessor(SpelExpressionParser parser) { } @Override - public Comparator resolve(KeyValueQuery query) { + public @Nullable Comparator resolve(KeyValueQuery query) { if (query.getSort().isUnsorted()) { return null; diff --git a/src/main/java/org/springframework/data/keyvalue/core/event/KeyValueEvent.java b/src/main/java/org/springframework/data/keyvalue/core/event/KeyValueEvent.java index bae7114f..0daca132 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/event/KeyValueEvent.java +++ b/src/main/java/org/springframework/data/keyvalue/core/event/KeyValueEvent.java @@ -15,8 +15,8 @@ */ package org.springframework.data.keyvalue.core.event; +import org.jspecify.annotations.Nullable; import org.springframework.context.ApplicationEvent; -import org.springframework.lang.Nullable; /** * {@link KeyValueEvent} gets published for operations executed by eg. @@ -235,8 +235,7 @@ abstract static class KeyBasedEventWithPayload extends KeyBasedEvent { * * @return */ - @Nullable - public T getPayload() { + public @Nullable T getPayload() { return payload; } } @@ -336,8 +335,7 @@ public AfterUpdateEvent(Object key, String keyspace, Class type, T * * @return */ - @Nullable - public Object before() { + public @Nullable Object before() { return existing; } @@ -346,8 +344,7 @@ public Object before() { * * @return can be {@literal null}. */ - @Nullable - public T after() { + public @Nullable T after() { return getPayload(); } } diff --git a/src/main/java/org/springframework/data/keyvalue/core/event/package-info.java b/src/main/java/org/springframework/data/keyvalue/core/event/package-info.java index 7ec69d8b..c33d24c7 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/event/package-info.java +++ b/src/main/java/org/springframework/data/keyvalue/core/event/package-info.java @@ -1,6 +1,5 @@ /** * Support classes for key-value events, like standard persistence lifecycle events. */ -@org.springframework.lang.NonNullApi -@org.springframework.lang.NonNullFields +@org.jspecify.annotations.NullMarked package org.springframework.data.keyvalue.core.event; diff --git a/src/main/java/org/springframework/data/keyvalue/core/mapping/AnnotationBasedKeySpaceResolver.java b/src/main/java/org/springframework/data/keyvalue/core/mapping/AnnotationBasedKeySpaceResolver.java index 004a77ac..cbd33628 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/mapping/AnnotationBasedKeySpaceResolver.java +++ b/src/main/java/org/springframework/data/keyvalue/core/mapping/AnnotationBasedKeySpaceResolver.java @@ -15,11 +15,11 @@ */ package org.springframework.data.keyvalue.core.mapping; +import org.jspecify.annotations.Nullable; import org.springframework.core.annotation.MergedAnnotation; import org.springframework.core.annotation.MergedAnnotations; import org.springframework.data.annotation.Persistent; import org.springframework.data.keyvalue.annotation.KeySpace; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -36,8 +36,7 @@ public enum AnnotationBasedKeySpaceResolver implements KeySpaceResolver { INSTANCE; @Override - @Nullable - public String resolveKeySpace(Class type) { + public @Nullable String resolveKeySpace(Class type) { Assert.notNull(type, "Type for keyspace for null"); @@ -47,8 +46,8 @@ public String resolveKeySpace(Class type) { return keySpace != null ? keySpace.toString() : null; } - @Nullable - private static Object getKeySpace(Class type) { + + private static @Nullable Object getKeySpace(Class type) { MergedAnnotation annotation = MergedAnnotations .from(type, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY).get(KeySpace.class); diff --git a/src/main/java/org/springframework/data/keyvalue/core/mapping/BasicKeyValuePersistentEntity.java b/src/main/java/org/springframework/data/keyvalue/core/mapping/BasicKeyValuePersistentEntity.java index d1b4ade7..379b8e5f 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/mapping/BasicKeyValuePersistentEntity.java +++ b/src/main/java/org/springframework/data/keyvalue/core/mapping/BasicKeyValuePersistentEntity.java @@ -15,6 +15,7 @@ */ package org.springframework.data.keyvalue.core.mapping; +import org.jspecify.annotations.Nullable; import org.springframework.data.expression.ValueExpression; import org.springframework.data.expression.ValueExpressionParser; import org.springframework.data.mapping.model.BasicPersistentEntity; @@ -22,7 +23,6 @@ import org.springframework.expression.Expression; import org.springframework.expression.common.LiteralExpression; import org.springframework.expression.spel.standard.SpelExpressionParser; -import org.springframework.lang.Nullable; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; @@ -40,7 +40,7 @@ public class BasicKeyValuePersistentEntity information, @Nullable * @param potentialExpression must not be {@literal null} * @return the parsed {@link Expression} or {@literal null}. */ - @Nullable - private static ValueExpression detectExpression(String potentialExpression) { + + private static @Nullable ValueExpression detectExpression(String potentialExpression) { ValueExpression expression = PARSER.parse(potentialExpression); return expression.isLiteral() ? null : expression; diff --git a/src/main/java/org/springframework/data/keyvalue/core/mapping/KeySpaceResolver.java b/src/main/java/org/springframework/data/keyvalue/core/mapping/KeySpaceResolver.java index 0aa54013..fa63d9d1 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/mapping/KeySpaceResolver.java +++ b/src/main/java/org/springframework/data/keyvalue/core/mapping/KeySpaceResolver.java @@ -15,7 +15,7 @@ */ package org.springframework.data.keyvalue.core.mapping; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** * {@link KeySpaceResolver} determines the {@literal keyspace} a given type is assigned to. A keyspace in this context diff --git a/src/main/java/org/springframework/data/keyvalue/core/mapping/KeyValuePersistentEntity.java b/src/main/java/org/springframework/data/keyvalue/core/mapping/KeyValuePersistentEntity.java index 76ca8377..d0f1772f 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/mapping/KeyValuePersistentEntity.java +++ b/src/main/java/org/springframework/data/keyvalue/core/mapping/KeyValuePersistentEntity.java @@ -15,8 +15,8 @@ */ package org.springframework.data.keyvalue.core.mapping; +import org.jspecify.annotations.Nullable; import org.springframework.data.mapping.model.MutablePersistentEntity; -import org.springframework.lang.Nullable; /** * @author Christoph Strobl diff --git a/src/main/java/org/springframework/data/keyvalue/core/mapping/context/KeyValueMappingContext.java b/src/main/java/org/springframework/data/keyvalue/core/mapping/context/KeyValueMappingContext.java index 41bb882e..6f731750 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/mapping/context/KeyValueMappingContext.java +++ b/src/main/java/org/springframework/data/keyvalue/core/mapping/context/KeyValueMappingContext.java @@ -17,6 +17,7 @@ import java.util.Collections; +import org.jspecify.annotations.Nullable; import org.springframework.data.keyvalue.core.mapping.BasicKeyValuePersistentEntity; import org.springframework.data.keyvalue.core.mapping.KeySpaceResolver; import org.springframework.data.keyvalue.core.mapping.KeyValuePersistentEntity; @@ -26,7 +27,6 @@ import org.springframework.data.mapping.model.Property; import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.util.TypeInformation; -import org.springframework.lang.Nullable; /** * Default implementation of a {@link MappingContext} using {@link KeyValuePersistentEntity} and @@ -71,8 +71,7 @@ public void setKeySpaceResolver(KeySpaceResolver keySpaceResolver) { * @return the current {@link KeySpaceResolver}. Can be {@literal null}. * @since 3.1 */ - @Nullable - public KeySpaceResolver getKeySpaceResolver() { + public @Nullable KeySpaceResolver getKeySpaceResolver() { return keySpaceResolver; } diff --git a/src/main/java/org/springframework/data/keyvalue/core/mapping/context/package-info.java b/src/main/java/org/springframework/data/keyvalue/core/mapping/context/package-info.java index fa07bdc5..345ca1cb 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/mapping/context/package-info.java +++ b/src/main/java/org/springframework/data/keyvalue/core/mapping/context/package-info.java @@ -1,6 +1,5 @@ /** * Infrastructure for the Key-Value mapping context. */ -@org.springframework.lang.NonNullApi -@org.springframework.lang.NonNullFields +@org.jspecify.annotations.NullMarked package org.springframework.data.keyvalue.core.mapping.context; diff --git a/src/main/java/org/springframework/data/keyvalue/core/mapping/package-info.java b/src/main/java/org/springframework/data/keyvalue/core/mapping/package-info.java index aa504fca..a411590b 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/mapping/package-info.java +++ b/src/main/java/org/springframework/data/keyvalue/core/mapping/package-info.java @@ -1,6 +1,5 @@ /** * Infrastructure for the Key-Value mapping subsystem and keyspace resolution. */ -@org.springframework.lang.NonNullApi -@org.springframework.lang.NonNullFields +@org.jspecify.annotations.NullMarked package org.springframework.data.keyvalue.core.mapping; diff --git a/src/main/java/org/springframework/data/keyvalue/core/package-info.java b/src/main/java/org/springframework/data/keyvalue/core/package-info.java index e2461940..03eb9ea5 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/package-info.java +++ b/src/main/java/org/springframework/data/keyvalue/core/package-info.java @@ -1,6 +1,5 @@ /** * Core key/value implementation. */ -@org.springframework.lang.NonNullApi -@org.springframework.lang.NonNullFields +@org.jspecify.annotations.NullMarked package org.springframework.data.keyvalue.core; diff --git a/src/main/java/org/springframework/data/keyvalue/core/query/KeyValueQuery.java b/src/main/java/org/springframework/data/keyvalue/core/query/KeyValueQuery.java index d1dd1bc9..0cf1a3f7 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/query/KeyValueQuery.java +++ b/src/main/java/org/springframework/data/keyvalue/core/query/KeyValueQuery.java @@ -15,8 +15,8 @@ */ package org.springframework.data.keyvalue.core.query; +import org.jspecify.annotations.Nullable; import org.springframework.data.domain.Sort; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -76,8 +76,7 @@ public KeyValueQuery(Sort sort) { * @return * @since 2.0 */ - @Nullable - public T getCriteria() { + public @Nullable T getCriteria() { return criteria; } diff --git a/src/main/java/org/springframework/data/keyvalue/core/query/package-info.java b/src/main/java/org/springframework/data/keyvalue/core/query/package-info.java index b47343be..b8764304 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/query/package-info.java +++ b/src/main/java/org/springframework/data/keyvalue/core/query/package-info.java @@ -1,6 +1,5 @@ /** * Key/value specific query and abstractions. */ -@org.springframework.lang.NonNullApi -@org.springframework.lang.NonNullFields +@org.jspecify.annotations.NullMarked package org.springframework.data.keyvalue.core.query; diff --git a/src/main/java/org/springframework/data/keyvalue/repository/config/KeyValueRepositoryConfigurationExtension.java b/src/main/java/org/springframework/data/keyvalue/repository/config/KeyValueRepositoryConfigurationExtension.java index 9a99d099..f276451b 100644 --- a/src/main/java/org/springframework/data/keyvalue/repository/config/KeyValueRepositoryConfigurationExtension.java +++ b/src/main/java/org/springframework/data/keyvalue/repository/config/KeyValueRepositoryConfigurationExtension.java @@ -20,6 +20,7 @@ import java.util.Map; import java.util.Optional; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; @@ -36,7 +37,6 @@ import org.springframework.data.repository.config.RepositoryConfigurationExtension; import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport; import org.springframework.data.repository.config.RepositoryConfigurationSource; -import org.springframework.lang.Nullable; /** * {@link RepositoryConfigurationExtension} for {@link KeyValueRepository}. @@ -145,7 +145,7 @@ public void registerBeansForRoot(BeanDefinitionRegistry registry, RepositoryConf AbstractBeanDefinition beanDefinition = getDefaultKeyValueTemplateBeanDefinition(configurationSource); - if (beanDefinition != null) { + if (beanDefinition != null && configurationSource.getSource() != null) { registerIfNotAlreadyRegistered(() -> beanDefinition, registry, keyValueTemplateName.get(), configurationSource.getSource()); } @@ -158,8 +158,7 @@ public void registerBeansForRoot(BeanDefinitionRegistry registry, RepositoryConf * @return {@literal null} to explicitly not register a template. * @see #getDefaultKeyValueTemplateRef() */ - @Nullable - protected AbstractBeanDefinition getDefaultKeyValueTemplateBeanDefinition( + protected @Nullable AbstractBeanDefinition getDefaultKeyValueTemplateBeanDefinition( RepositoryConfigurationSource configurationSource) { return null; } diff --git a/src/main/java/org/springframework/data/keyvalue/repository/config/package-info.java b/src/main/java/org/springframework/data/keyvalue/repository/config/package-info.java index 8257cd59..87e9dcf7 100644 --- a/src/main/java/org/springframework/data/keyvalue/repository/config/package-info.java +++ b/src/main/java/org/springframework/data/keyvalue/repository/config/package-info.java @@ -1,6 +1,5 @@ /** * Support infrastructure for the configuration of key/value specific repositories. */ -@org.springframework.lang.NonNullApi -@org.springframework.lang.NonNullFields +@org.jspecify.annotations.NullMarked package org.springframework.data.keyvalue.repository.config; diff --git a/src/main/java/org/springframework/data/keyvalue/repository/package-info.java b/src/main/java/org/springframework/data/keyvalue/repository/package-info.java index 8212e371..cd152cc3 100644 --- a/src/main/java/org/springframework/data/keyvalue/repository/package-info.java +++ b/src/main/java/org/springframework/data/keyvalue/repository/package-info.java @@ -1,6 +1,5 @@ /** * Key/value specific repository implementation. */ -@org.springframework.lang.NonNullApi -@org.springframework.lang.NonNullFields +@org.jspecify.annotations.NullMarked package org.springframework.data.keyvalue.repository; diff --git a/src/main/java/org/springframework/data/keyvalue/repository/query/CachingKeyValuePartTreeQuery.java b/src/main/java/org/springframework/data/keyvalue/repository/query/CachingKeyValuePartTreeQuery.java index cbb23117..e11b6db2 100644 --- a/src/main/java/org/springframework/data/keyvalue/repository/query/CachingKeyValuePartTreeQuery.java +++ b/src/main/java/org/springframework/data/keyvalue/repository/query/CachingKeyValuePartTreeQuery.java @@ -15,13 +15,13 @@ */ package org.springframework.data.keyvalue.repository.query; +import org.jspecify.annotations.Nullable; import org.springframework.data.keyvalue.core.KeyValueOperations; import org.springframework.data.keyvalue.core.query.KeyValueQuery; import org.springframework.data.repository.query.QueryMethod; import org.springframework.data.repository.query.ValueExpressionDelegate; import org.springframework.data.repository.query.parser.AbstractQueryCreator; import org.springframework.data.repository.query.parser.PartTree; -import org.springframework.lang.Nullable; /** * {@link KeyValuePartTreeQuery} implementation deriving queries from {@link PartTree} using a predefined diff --git a/src/main/java/org/springframework/data/keyvalue/repository/query/KeyValuePartTreeQuery.java b/src/main/java/org/springframework/data/keyvalue/repository/query/KeyValuePartTreeQuery.java index 18a8db4e..76325790 100644 --- a/src/main/java/org/springframework/data/keyvalue/repository/query/KeyValuePartTreeQuery.java +++ b/src/main/java/org/springframework/data/keyvalue/repository/query/KeyValuePartTreeQuery.java @@ -17,6 +17,7 @@ import java.lang.reflect.Constructor; +import org.jspecify.annotations.Nullable; import org.springframework.beans.BeanUtils; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; @@ -38,7 +39,6 @@ import org.springframework.data.spel.EvaluationContextProvider; import org.springframework.data.util.Lazy; import org.springframework.expression.spel.standard.SpelExpression; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -105,7 +105,7 @@ public KeyValuePartTreeQuery(QueryMethod queryMethod, ValueExpressionDelegate va } @Override - public Object execute(Object[] parameters) { + public @Nullable Object execute(Object[] parameters) { ParameterAccessor accessor = new ParametersParameterAccessor(getQueryMethod().getParameters(), parameters); KeyValueQuery query = prepareQuery(parameters); @@ -118,9 +118,8 @@ public Object execute(Object[] parameters) { * @param parameters * @param query */ - @Nullable @SuppressWarnings({ "unchecked", "rawtypes" }) - protected Object doExecute(Object[] parameters, KeyValueQuery query) { + protected @Nullable Object doExecute(Object[] parameters, KeyValueQuery query) { if (queryMethod.isPageQuery() || queryMethod.isSliceQuery()) { @@ -203,6 +202,7 @@ private SpelExpression getSpelExpression(Object criteria) { * @param accessor must not be {@literal null}. * @return the {@link KeyValueQuery}. */ + @SuppressWarnings("NullAway") public KeyValueQuery createQuery(ParameterAccessor accessor) { PartTree tree = this.partTree.get(); diff --git a/src/main/java/org/springframework/data/keyvalue/repository/query/PredicateQueryCreator.java b/src/main/java/org/springframework/data/keyvalue/repository/query/PredicateQueryCreator.java index 12a24725..a1b63617 100644 --- a/src/main/java/org/springframework/data/keyvalue/repository/query/PredicateQueryCreator.java +++ b/src/main/java/org/springframework/data/keyvalue/repository/query/PredicateQueryCreator.java @@ -24,6 +24,7 @@ import java.util.function.Predicate; import java.util.regex.Pattern; +import org.jspecify.annotations.Nullable; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.domain.Sort; import org.springframework.data.keyvalue.core.SimplePropertyPathAccessor; @@ -34,7 +35,6 @@ import org.springframework.data.repository.query.parser.Part; import org.springframework.data.repository.query.parser.Part.IgnoreCaseType; import org.springframework.data.repository.query.parser.PartTree; -import org.springframework.lang.Nullable; import org.springframework.util.ObjectUtils; /** diff --git a/src/main/java/org/springframework/data/keyvalue/repository/query/SpelQueryCreator.java b/src/main/java/org/springframework/data/keyvalue/repository/query/SpelQueryCreator.java index 8660c3b3..25da4425 100644 --- a/src/main/java/org/springframework/data/keyvalue/repository/query/SpelQueryCreator.java +++ b/src/main/java/org/springframework/data/keyvalue/repository/query/SpelQueryCreator.java @@ -17,6 +17,7 @@ import java.util.Iterator; +import org.jspecify.annotations.Nullable; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.domain.Sort; import org.springframework.data.keyvalue.core.query.KeyValueQuery; @@ -74,7 +75,7 @@ protected String or(String base, String criteria) { } @Override - protected KeyValueQuery complete(String criteria, Sort sort) { + protected KeyValueQuery complete(@Nullable String criteria, Sort sort) { KeyValueQuery query = new KeyValueQuery<>(this.expression); diff --git a/src/main/java/org/springframework/data/keyvalue/repository/query/package-info.java b/src/main/java/org/springframework/data/keyvalue/repository/query/package-info.java index 64ad1798..11a2946c 100644 --- a/src/main/java/org/springframework/data/keyvalue/repository/query/package-info.java +++ b/src/main/java/org/springframework/data/keyvalue/repository/query/package-info.java @@ -1,6 +1,5 @@ /** * Query derivation mechanism for key/value specific repositories providing a generic SpEL based implementation. */ -@org.springframework.lang.NonNullApi -@org.springframework.lang.NonNullFields +@org.jspecify.annotations.NullMarked package org.springframework.data.keyvalue.repository.query; diff --git a/src/main/java/org/springframework/data/keyvalue/repository/support/KeyValueRepositoryFactory.java b/src/main/java/org/springframework/data/keyvalue/repository/support/KeyValueRepositoryFactory.java index 76b6db32..1b7d2455 100644 --- a/src/main/java/org/springframework/data/keyvalue/repository/support/KeyValueRepositoryFactory.java +++ b/src/main/java/org/springframework/data/keyvalue/repository/support/KeyValueRepositoryFactory.java @@ -22,6 +22,7 @@ import java.lang.reflect.Method; import java.util.Optional; +import org.jspecify.annotations.Nullable; import org.springframework.beans.BeanUtils; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.keyvalue.core.KeyValueOperations; @@ -44,7 +45,6 @@ import org.springframework.data.repository.query.RepositoryQuery; import org.springframework.data.repository.query.ValueExpressionDelegate; import org.springframework.data.repository.query.parser.AbstractQueryCreator; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; diff --git a/src/main/java/org/springframework/data/keyvalue/repository/support/KeyValueRepositoryFactoryBean.java b/src/main/java/org/springframework/data/keyvalue/repository/support/KeyValueRepositoryFactoryBean.java index 04942d83..7a47fbf6 100644 --- a/src/main/java/org/springframework/data/keyvalue/repository/support/KeyValueRepositoryFactoryBean.java +++ b/src/main/java/org/springframework/data/keyvalue/repository/support/KeyValueRepositoryFactoryBean.java @@ -15,6 +15,7 @@ */ package org.springframework.data.keyvalue.repository.support; +import org.jspecify.annotations.Nullable; import org.springframework.data.keyvalue.core.KeyValueOperations; import org.springframework.data.keyvalue.repository.KeyValueRepository; import org.springframework.data.keyvalue.repository.config.QueryCreatorType; @@ -24,7 +25,6 @@ import org.springframework.data.repository.core.support.RepositoryFactorySupport; import org.springframework.data.repository.query.RepositoryQuery; import org.springframework.data.repository.query.parser.AbstractQueryCreator; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -95,6 +95,11 @@ public void setQueryType(Class repositoryQueryType) { @Override protected final RepositoryFactorySupport createRepositoryFactory() { + + Assert.notNull(operations, "Operations must not be null"); + Assert.notNull(queryCreator, "QueryCreator must not be null"); + Assert.notNull(repositoryQueryType, "QueryType must not be null"); + return createRepositoryFactory(operations, queryCreator, repositoryQueryType); } diff --git a/src/main/java/org/springframework/data/keyvalue/repository/support/QuerydslKeyValuePredicateExecutor.java b/src/main/java/org/springframework/data/keyvalue/repository/support/QuerydslKeyValuePredicateExecutor.java index 46f60de4..9c5d5041 100644 --- a/src/main/java/org/springframework/data/keyvalue/repository/support/QuerydslKeyValuePredicateExecutor.java +++ b/src/main/java/org/springframework/data/keyvalue/repository/support/QuerydslKeyValuePredicateExecutor.java @@ -25,7 +25,7 @@ import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Stream; - +import org.jspecify.annotations.Nullable; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.data.convert.DtoInstantiatingConverter; import org.springframework.data.domain.Page; @@ -46,7 +46,6 @@ import org.springframework.data.querydsl.SimpleEntityPathResolver; import org.springframework.data.repository.core.EntityInformation; import org.springframework.data.repository.query.FluentQuery; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import com.querydsl.collections.AbstractCollQuery; @@ -281,7 +280,7 @@ public FluentQuery.FetchableFluentQuery project(Collection properties } @Override - public R oneValue() { + public @Nullable R oneValue() { List results = createQuery().limit(2).fetch(); @@ -299,7 +298,7 @@ public R oneValue() { } @Override - public R firstValue() { + public @Nullable R firstValue() { List results = createQuery().limit(1).fetch(); diff --git a/src/main/java/org/springframework/data/keyvalue/repository/support/package-info.java b/src/main/java/org/springframework/data/keyvalue/repository/support/package-info.java index fd58c5a2..0f67f8e2 100644 --- a/src/main/java/org/springframework/data/keyvalue/repository/support/package-info.java +++ b/src/main/java/org/springframework/data/keyvalue/repository/support/package-info.java @@ -1,6 +1,5 @@ /** * Support infrastructure for query derivation of key/value specific repositories. */ -@org.springframework.lang.NonNullApi -@org.springframework.lang.NonNullFields +@org.jspecify.annotations.NullMarked package org.springframework.data.keyvalue.repository.support; diff --git a/src/main/java/org/springframework/data/map/MapKeyValueAdapter.java b/src/main/java/org/springframework/data/map/MapKeyValueAdapter.java index ebe39ef9..3018c104 100644 --- a/src/main/java/org/springframework/data/map/MapKeyValueAdapter.java +++ b/src/main/java/org/springframework/data/map/MapKeyValueAdapter.java @@ -21,6 +21,7 @@ import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; +import org.jspecify.annotations.Nullable; import org.springframework.core.CollectionFactory; import org.springframework.data.keyvalue.core.AbstractKeyValueAdapter; import org.springframework.data.keyvalue.core.ForwardingCloseableIterator; @@ -131,7 +132,7 @@ public MapKeyValueAdapter(Map> store, QueryEngine> store, Class keySpaceMapType, QueryEngine engine) { + private MapKeyValueAdapter(Map> store, Class keySpaceMapType, @Nullable QueryEngine engine) { super(engine); @@ -143,7 +144,7 @@ private MapKeyValueAdapter(Map> store, Class getAllOf(String keyspace) { + public Collection getAllOf(String keyspace) { return getKeySpaceMap(keyspace).values(); } diff --git a/src/main/java/org/springframework/data/map/package-info.java b/src/main/java/org/springframework/data/map/package-info.java index d184db6f..09ccd20a 100644 --- a/src/main/java/org/springframework/data/map/package-info.java +++ b/src/main/java/org/springframework/data/map/package-info.java @@ -1,6 +1,5 @@ /** * Repository implementation backed by generic {@link java.util.Map} instances. */ -@org.springframework.lang.NonNullApi -@org.springframework.lang.NonNullFields +@org.jspecify.annotations.NullMarked package org.springframework.data.map; diff --git a/src/main/java/org/springframework/data/map/repository/config/MapRepositoryConfigurationExtension.java b/src/main/java/org/springframework/data/map/repository/config/MapRepositoryConfigurationExtension.java index e0632a4a..411f22e5 100644 --- a/src/main/java/org/springframework/data/map/repository/config/MapRepositoryConfigurationExtension.java +++ b/src/main/java/org/springframework/data/map/repository/config/MapRepositoryConfigurationExtension.java @@ -18,6 +18,7 @@ import java.lang.reflect.Constructor; import java.util.Map; +import org.jspecify.annotations.Nullable; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.AbstractBeanDefinition; @@ -32,7 +33,6 @@ import org.springframework.data.map.MapKeyValueAdapter; import org.springframework.data.repository.config.RepositoryConfigurationExtension; import org.springframework.data.repository.config.RepositoryConfigurationSource; -import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; /** @@ -83,14 +83,13 @@ protected AbstractBeanDefinition getDefaultKeyValueTemplateBeanDefinition( return ParsingUtils.getSourceBeanDefinition(builder, configurationSource.getSource()); } - @SuppressWarnings({ "unchecked", "rawtypes" }) + @SuppressWarnings({ "unchecked", "rawtypes", "NullAway" }) private static Class getMapTypeToUse(RepositoryConfigurationSource source) { return (Class) getAnnotationAttributes(source).get("mapType"); } - @Nullable - private static SortAccessor getSortAccessor(RepositoryConfigurationSource source) { + private static @Nullable SortAccessor getSortAccessor(RepositoryConfigurationSource source) { Class> sortAccessorType = (Class>) getAnnotationAttributes( source).get("sortAccessor"); @@ -102,8 +101,7 @@ private static SortAccessor getSortAccessor(RepositoryConfigurationSource sou return null; } - @Nullable - private static QueryEngine getQueryEngine(@Nullable SortAccessor sortAccessor, + private static @Nullable QueryEngine getQueryEngine(@Nullable SortAccessor sortAccessor, RepositoryConfigurationSource source) { Class queryEngineFactoryType = (Class) getAnnotationAttributes( diff --git a/src/main/java/org/springframework/data/map/repository/config/package-info.java b/src/main/java/org/springframework/data/map/repository/config/package-info.java index 346ace98..6b7b28ee 100644 --- a/src/main/java/org/springframework/data/map/repository/config/package-info.java +++ b/src/main/java/org/springframework/data/map/repository/config/package-info.java @@ -1,6 +1,5 @@ /** * Support infrastructure for the configuration of {@link java.util.Map} repositories. */ -@org.springframework.lang.NonNullApi -@org.springframework.lang.NonNullFields +@org.jspecify.annotations.NullMarked package org.springframework.data.map.repository.config; diff --git a/src/test/java/org/springframework/data/keyvalue/core/KeyValueTemplateTests.java b/src/test/java/org/springframework/data/keyvalue/core/KeyValueTemplateTests.java index 4967357f..b794840d 100644 --- a/src/test/java/org/springframework/data/keyvalue/core/KeyValueTemplateTests.java +++ b/src/test/java/org/springframework/data/keyvalue/core/KeyValueTemplateTests.java @@ -197,7 +197,7 @@ void deleteReturnsRemovedObject() { @Test // DATACMNS-525 void deleteThrowsExceptionWhenIdCannotBeExctracted() { - assertThatIllegalArgumentException().isThrownBy(() -> operations.delete(FOO_ONE)); + assertThatIllegalStateException().isThrownBy(() -> operations.delete(FOO_ONE)); } @Test // DATACMNS-525 diff --git a/src/test/java/org/springframework/data/keyvalue/core/KeyValueTemplateUnitTests.java b/src/test/java/org/springframework/data/keyvalue/core/KeyValueTemplateUnitTests.java index 6953e959..22774b0b 100644 --- a/src/test/java/org/springframework/data/keyvalue/core/KeyValueTemplateUnitTests.java +++ b/src/test/java/org/springframework/data/keyvalue/core/KeyValueTemplateUnitTests.java @@ -140,7 +140,7 @@ void insertShouldGenerateId() { @Test // DATACMNS-525 void insertShouldThrowErrorWhenIdCannotBeResolved() { - assertThatIllegalArgumentException().isThrownBy(() -> template.insert(FOO_ONE)); + assertThatIllegalStateException().isThrownBy(() -> template.insert(FOO_ONE)); } @Test // DATACMNS-525 @@ -281,7 +281,7 @@ void deleteRemovesObjectUsingExtractedId() { @Test // DATACMNS-525 void deleteThrowsExceptionWhenIdCannotBeExctracted() { - assertThatIllegalArgumentException().isThrownBy(() -> template.delete(FOO_ONE)); + assertThatIllegalStateException().isThrownBy(() -> template.delete(FOO_ONE)); } @Test // DATACMNS-525 From 1e7597d36102989e81f67e57a60fa19a56368d93 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Mon, 17 Feb 2025 09:52:59 +0100 Subject: [PATCH 3/4] Add contract annotations. --- .../data/keyvalue/core/IterableConverter.java | 10 +++++- .../keyvalue/core/PredicateQueryEngine.java | 2 ++ .../keyvalue/core/PropertyPathComparator.java | 5 +++ .../keyvalue/core/SpelPropertyComparator.java | 5 +++ .../keyvalue/core/query/KeyValueQuery.java | 4 +++ .../query/PredicateQueryCreator.java | 34 +++++++++++++------ .../support/KeyValueQuerydslUtils.java | 2 ++ 7 files changed, 50 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/springframework/data/keyvalue/core/IterableConverter.java b/src/main/java/org/springframework/data/keyvalue/core/IterableConverter.java index 23527ebd..5a32b3d4 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/IterableConverter.java +++ b/src/main/java/org/springframework/data/keyvalue/core/IterableConverter.java @@ -20,6 +20,9 @@ import java.util.Collections; import java.util.List; +import org.jspecify.annotations.Nullable; +import org.springframework.lang.Contract; + /** * Converter capable of transforming a given {@link Iterable} into a collection type. * @@ -36,7 +39,12 @@ private IterableConverter() {} * @param source * @return {@link Collections#emptyList()} when source is {@literal null}. */ - public static List toList(Iterable source) { + @Contract("_ -> !null") + public static List toList(@Nullable Iterable source) { + + if(source == null) { + return Collections.emptyList(); + } if (source instanceof List) { return (List) source; diff --git a/src/main/java/org/springframework/data/keyvalue/core/PredicateQueryEngine.java b/src/main/java/org/springframework/data/keyvalue/core/PredicateQueryEngine.java index b8bb755a..1577a7a2 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/PredicateQueryEngine.java +++ b/src/main/java/org/springframework/data/keyvalue/core/PredicateQueryEngine.java @@ -24,6 +24,7 @@ import org.jspecify.annotations.Nullable; import org.springframework.data.keyvalue.core.query.KeyValueQuery; +import org.springframework.lang.Contract; /** * {@link QueryEngine} implementation specific for executing {@link Predicate} based {@link KeyValueQuery} against @@ -78,6 +79,7 @@ private List sortAndFilterMatchingRange(Iterable source, @Nullable Predica return filterMatchingRange(tmp, criteria, offset, rows); } + @Contract("!null, _, _, _ -> !null") private static List filterMatchingRange(List source, @Nullable Predicate criteria, long offset, int rows) { Stream stream = source.stream(); diff --git a/src/main/java/org/springframework/data/keyvalue/core/PropertyPathComparator.java b/src/main/java/org/springframework/data/keyvalue/core/PropertyPathComparator.java index ff28cb3e..ce2c121d 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/PropertyPathComparator.java +++ b/src/main/java/org/springframework/data/keyvalue/core/PropertyPathComparator.java @@ -21,6 +21,7 @@ import org.jspecify.annotations.Nullable; import org.springframework.data.mapping.PropertyPath; +import org.springframework.lang.Contract; /** * {@link Comparator} implementation to compare objects based on a {@link PropertyPath}. This comparator obtains the @@ -81,6 +82,7 @@ public int compare(@Nullable T o1, @Nullable T o2) { * * @return */ + @Contract("-> this") public PropertyPathComparator<@Nullable T> asc() { this.asc = true; return this; @@ -91,6 +93,7 @@ public int compare(@Nullable T o1, @Nullable T o2) { * * @return */ + @Contract("-> this") public PropertyPathComparator<@Nullable T> desc() { this.asc = false; return this; @@ -101,6 +104,7 @@ public int compare(@Nullable T o1, @Nullable T o2) { * * @return */ + @Contract("-> this") public PropertyPathComparator<@Nullable T> nullsFirst() { this.nullsFirst = true; return this; @@ -111,6 +115,7 @@ public int compare(@Nullable T o1, @Nullable T o2) { * * @return */ + @Contract("-> this") public PropertyPathComparator<@Nullable T> nullsLast() { this.nullsFirst = false; return this; diff --git a/src/main/java/org/springframework/data/keyvalue/core/SpelPropertyComparator.java b/src/main/java/org/springframework/data/keyvalue/core/SpelPropertyComparator.java index 3aafcf00..5e3d4d1b 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/SpelPropertyComparator.java +++ b/src/main/java/org/springframework/data/keyvalue/core/SpelPropertyComparator.java @@ -21,6 +21,7 @@ import org.springframework.expression.spel.standard.SpelExpression; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.SimpleEvaluationContext; +import org.springframework.lang.Contract; import org.springframework.util.Assert; /** @@ -63,6 +64,7 @@ public SpelPropertyComparator(String path, SpelExpressionParser parser) { * * @return */ + @Contract("-> this") public SpelPropertyComparator<@Nullable T> asc() { this.asc = true; return this; @@ -73,6 +75,7 @@ public SpelPropertyComparator(String path, SpelExpressionParser parser) { * * @return */ + @Contract("-> this") public SpelPropertyComparator<@Nullable T> desc() { this.asc = false; return this; @@ -83,6 +86,7 @@ public SpelPropertyComparator(String path, SpelExpressionParser parser) { * * @return */ + @Contract("-> this") public SpelPropertyComparator<@Nullable T> nullsFirst() { this.nullsFirst = true; return this; @@ -93,6 +97,7 @@ public SpelPropertyComparator(String path, SpelExpressionParser parser) { * * @return */ + @Contract("-> this") public SpelPropertyComparator<@Nullable T> nullsLast() { this.nullsFirst = false; return this; diff --git a/src/main/java/org/springframework/data/keyvalue/core/query/KeyValueQuery.java b/src/main/java/org/springframework/data/keyvalue/core/query/KeyValueQuery.java index 0cf1a3f7..9931d45c 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/query/KeyValueQuery.java +++ b/src/main/java/org/springframework/data/keyvalue/core/query/KeyValueQuery.java @@ -17,6 +17,7 @@ import org.jspecify.annotations.Nullable; import org.springframework.data.domain.Sort; +import org.springframework.lang.Contract; import org.springframework.util.Assert; /** @@ -143,6 +144,7 @@ public void setSort(Sort sort) { * @param sort must not be {@literal null}. * @return */ + @Contract("_ -> this") public KeyValueQuery orderBy(Sort sort) { Assert.notNull(sort, "Sort must not be null"); @@ -161,6 +163,7 @@ public KeyValueQuery orderBy(Sort sort) { * @param offset * @return */ + @Contract("_ -> this") public KeyValueQuery skip(long offset) { setOffset(offset); @@ -173,6 +176,7 @@ public KeyValueQuery skip(long offset) { * @param rows * @return */ + @Contract("_ -> this") public KeyValueQuery limit(int rows) { setRows(rows); return this; diff --git a/src/main/java/org/springframework/data/keyvalue/repository/query/PredicateQueryCreator.java b/src/main/java/org/springframework/data/keyvalue/repository/query/PredicateQueryCreator.java index a1b63617..efb4ff95 100644 --- a/src/main/java/org/springframework/data/keyvalue/repository/query/PredicateQueryCreator.java +++ b/src/main/java/org/springframework/data/keyvalue/repository/query/PredicateQueryCreator.java @@ -35,6 +35,7 @@ import org.springframework.data.repository.query.parser.Part; import org.springframework.data.repository.query.parser.Part.IgnoreCaseType; import org.springframework.data.repository.query.parser.PartTree; +import org.springframework.lang.Contract; import org.springframework.util.ObjectUtils; /** @@ -124,7 +125,8 @@ public Predicate isFalse() { return new ValueComparingPredicate(part.getProperty(), false); } - public Predicate isEqualTo(Object value) { + @Contract("_ -> new") + public Predicate isEqualTo(@Nullable Object value) { return new ValueComparingPredicate(part.getProperty(), o -> { if (!ObjectUtils.nullSafeEquals(IgnoreCaseType.NEVER, part.shouldIgnoreCase())) { @@ -145,22 +147,27 @@ public Predicate isNotNull() { return isNull().negate(); } - public Predicate isLessThan(Object value) { + @Contract("_ -> new") + public Predicate isLessThan(@Nullable Object value) { return new ValueComparingPredicate(part.getProperty(), o -> comparator().compare(o, value) < 0); } - public Predicate isLessThanEqual(Object value) { + @Contract("_ -> new") + public Predicate isLessThanEqual(@Nullable Object value) { return new ValueComparingPredicate(part.getProperty(), o -> comparator().compare(o, value) <= 0); } - public Predicate isGreaterThan(Object value) { + @Contract("_ -> new") + public Predicate isGreaterThan(@Nullable Object value) { return new ValueComparingPredicate(part.getProperty(), o -> comparator().compare(o, value) > 0); } - public Predicate isGreaterThanEqual(Object value) { + @Contract("_ -> new") + public Predicate isGreaterThanEqual(@Nullable Object value) { return new ValueComparingPredicate(part.getProperty(), o -> comparator().compare(o, value) >= 0); } + @Contract("!null -> new") public Predicate matches(Pattern pattern) { return new ValueComparingPredicate(part.getProperty(), o -> { @@ -172,7 +179,8 @@ public Predicate matches(Pattern pattern) { }); } - public Predicate matches(Object value) { + @Contract("_ -> new") + public Predicate matches(@Nullable Object value) { return new ValueComparingPredicate(part.getProperty(), o -> { if (o == null || value == null) { @@ -188,10 +196,12 @@ public Predicate matches(Object value) { }); } + @Contract("!null -> new") public Predicate matches(String regex) { return matches(Pattern.compile(regex)); } + @Contract("!null -> new") public Predicate in(Object value) { return new ValueComparingPredicate(part.getProperty(), o -> { @@ -207,11 +217,11 @@ public Predicate in(Object value) { return ObjectUtils.containsElement(ObjectUtils.toObjectArray(value), value); } return false; - }); } - public Predicate contains(Object value) { + @Contract("_ -> new") + public Predicate contains(@Nullable Object value) { return new ValueComparingPredicate(part.getProperty(), o -> { @@ -245,6 +255,7 @@ public Predicate contains(Object value) { }); } + @Contract("!null -> new") public Predicate startsWith(Object value) { return new ValueComparingPredicate(part.getProperty(), o -> { @@ -261,6 +272,7 @@ public Predicate startsWith(Object value) { } + @Contract("!null -> new") public Predicate endsWith(Object value) { return new ValueComparingPredicate(part.getProperty(), o -> { @@ -281,13 +293,13 @@ public Predicate endsWith(Object value) { static class ValueComparingPredicate implements Predicate { private final PropertyPath path; - private final Function check; + private final Function<@Nullable Object, Boolean> check; - public ValueComparingPredicate(PropertyPath path, Object expected) { + public ValueComparingPredicate(PropertyPath path, @Nullable Object expected) { this(path, (value) -> ObjectUtils.nullSafeEquals(value, expected)); } - public ValueComparingPredicate(PropertyPath path, Function check) { + public ValueComparingPredicate(PropertyPath path, Function<@Nullable Object, Boolean> check) { this.path = path; this.check = check; } diff --git a/src/main/java/org/springframework/data/keyvalue/repository/support/KeyValueQuerydslUtils.java b/src/main/java/org/springframework/data/keyvalue/repository/support/KeyValueQuerydslUtils.java index e2d256bd..7e41e3db 100644 --- a/src/main/java/org/springframework/data/keyvalue/repository/support/KeyValueQuerydslUtils.java +++ b/src/main/java/org/springframework/data/keyvalue/repository/support/KeyValueQuerydslUtils.java @@ -22,6 +22,7 @@ import org.springframework.data.domain.Sort.Order; import org.springframework.data.mapping.PropertyPath; import org.springframework.data.querydsl.QSort; +import org.springframework.lang.Contract; import org.springframework.util.Assert; import com.querydsl.core.types.Expression; @@ -52,6 +53,7 @@ private KeyValueQuerydslUtils() { * @param builder must not be {@literal null}. * @return empty {@code OrderSpecifier[]} when sort is {@literal null}. */ + @Contract("!null, !null -> new") static OrderSpecifier[] toOrderSpecifier(Sort sort, PathBuilder builder) { Assert.notNull(sort, "Sort must not be null"); From 2bc8e41f01f69c147590cdbe8e0e6c515db00b84 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Wed, 19 Feb 2025 09:10:34 +0100 Subject: [PATCH 4/4] Update after review. --- pom.xml | 6 ------ .../data/keyvalue/core/KeyValueTemplate.java | 3 --- .../data/keyvalue/core/PredicateQueryEngine.java | 2 -- 3 files changed, 11 deletions(-) diff --git a/pom.xml b/pom.xml index a7083bc4..95ed70b8 100644 --- a/pom.xml +++ b/pom.xml @@ -45,12 +45,6 @@ ${querydsl} true - - org.jspecify - jspecify - 1.0.0 - - diff --git a/src/main/java/org/springframework/data/keyvalue/core/KeyValueTemplate.java b/src/main/java/org/springframework/data/keyvalue/core/KeyValueTemplate.java index 4cf793a6..3b33b821 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/KeyValueTemplate.java +++ b/src/main/java/org/springframework/data/keyvalue/core/KeyValueTemplate.java @@ -195,7 +195,6 @@ public T update(Object id, T objectToUpdate) { Assert.notNull(objectToUpdate, "Object to be updated must not be null"); String keyspace = resolveKeySpace(objectToUpdate.getClass()); - Assert.notNull(keyspace, "Keyspace must not be null"); potentiallyPublishEvent(KeyValueEvent.beforeUpdate(id, keyspace, objectToUpdate.getClass(), objectToUpdate)); @@ -235,7 +234,6 @@ public Optional findById(Object id, Class type) { Assert.notNull(type, "Type to fetch must not be null"); String keyspace = resolveKeySpace(type); - Assert.notNull(keyspace, "Keyspace must not be null"); potentiallyPublishEvent(KeyValueEvent.beforeGet(id, keyspace, type)); @@ -289,7 +287,6 @@ public void delete(Class type) { Assert.notNull(type, "Type to delete must not be null"); String keyspace = resolveKeySpace(type); - Assert.notNull(keyspace, "Keyspace must not be null"); potentiallyPublishEvent(KeyValueEvent.beforeDelete(id, keyspace, type)); diff --git a/src/main/java/org/springframework/data/keyvalue/core/PredicateQueryEngine.java b/src/main/java/org/springframework/data/keyvalue/core/PredicateQueryEngine.java index 1577a7a2..b8bb755a 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/PredicateQueryEngine.java +++ b/src/main/java/org/springframework/data/keyvalue/core/PredicateQueryEngine.java @@ -24,7 +24,6 @@ import org.jspecify.annotations.Nullable; import org.springframework.data.keyvalue.core.query.KeyValueQuery; -import org.springframework.lang.Contract; /** * {@link QueryEngine} implementation specific for executing {@link Predicate} based {@link KeyValueQuery} against @@ -79,7 +78,6 @@ private List sortAndFilterMatchingRange(Iterable source, @Nullable Predica return filterMatchingRange(tmp, criteria, offset, rows); } - @Contract("!null, _, _, _ -> !null") private static List filterMatchingRange(List source, @Nullable Predicate criteria, long offset, int rows) { Stream stream = source.stream();