Migrate to JSpecify annotations for nullability constraints.

Closes #618
Original pull request: #625
This commit is contained in:
Christoph Strobl
2025-02-14 11:18:54 +01:00
committed by Mark Paluch
parent 958c00e76e
commit cf6e82df9d
53 changed files with 142 additions and 153 deletions

View File

@@ -45,7 +45,6 @@
<version>${querydsl}</version>
<optional>true</optional>
</dependency>
</dependencies>
<build>

View File

@@ -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;

View File

@@ -18,13 +18,13 @@ package org.springframework.data.keyvalue.aot;
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.

View File

@@ -0,0 +1,5 @@
/**
* Support classes for key-value ahead of time computation
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.keyvalue.aot;

View File

@@ -18,8 +18,8 @@ package org.springframework.data.keyvalue.core;
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 @@ public abstract class AbstractKeyValueAdapter implements KeyValueAdapter {
return engine;
}
@Nullable
@Override
public <T> T get(Object id, String keyspace, Class<T> type) {
public <T> @Nullable T get(Object id, String keyspace, Class<T> type) {
return type.cast(get(id, keyspace));
}
@Nullable
@Override
public <T> T delete(Object id, String keyspace, Class<T> type) {
public <T> @Nullable T delete(Object id, String keyspace, Class<T> type) {
return type.cast(delete(id, keyspace));
}

View File

@@ -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}.

View File

@@ -17,8 +17,8 @@ package org.springframework.data.keyvalue.core;
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;
/**

View File

@@ -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);
}

View File

@@ -18,10 +18,10 @@ package org.springframework.data.keyvalue.core;
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> T get(Object id, String keyspace, Class<T> type);
<T> @Nullable T get(Object id, String keyspace, Class<T> 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> T delete(Object id, String keyspace, Class<T> type);
<T> @Nullable T delete(Object id, String keyspace, Class<T> 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<Object> getAllOf(String keyspace);
/**
* Get all elements for given keyspace.
@@ -132,7 +130,7 @@ public interface KeyValueAdapter extends DisposableBean {
* @since 2.5
*/
@SuppressWarnings("unchecked")
default <T> CloseableIterator<Map.Entry<Object, T>> entries(String keyspace, Class<T> type) {
default <T> CloseableIterator<Map.Entry<Object,T>> entries(String keyspace, Class<T> type) {
return (CloseableIterator) entries(keyspace);
}

View File

@@ -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

View File

@@ -17,12 +17,12 @@ package org.springframework.data.keyvalue.core;
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> T execute(KeyValueCallback<T> action);
<T> @Nullable T execute(KeyValueCallback<T> action);
/**
* Get all elements matching the given query. <br />
@@ -145,8 +145,7 @@ public interface KeyValueOperations extends DisposableBean {
* @param objectToDelete must not be {@literal null}.
* @return
*/
@Nullable
<T> T delete(T objectToDelete);
<T> @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> T delete(Object id, Class<T> type);
<T> @Nullable T delete(Object id, Class<T> type);
/**
* Total number of elements with given type available. Respects {@link KeySpace} if present and therefore counts all

View File

@@ -17,10 +17,10 @@ package org.springframework.data.keyvalue.core;
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 @@ import org.springframework.util.Assert;
*/
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");

View File

@@ -21,6 +21,7 @@ import java.util.List;
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.KeyValuePersistentProperty
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 class KeyValueTemplate implements KeyValueOperations, ApplicationEventPub
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);
@@ -213,7 +213,8 @@ public class KeyValueTemplate implements KeyValueOperations, ApplicationEventPub
return executeRequired(adapter -> {
Iterable<?> values = adapter.getAllOf(resolveKeySpace(type), type);
String keyspace = resolveKeySpace(type);
Iterable<?> values = adapter.getAllOf(keyspace, type);
ArrayList<T> filtered = new ArrayList<>();
for (Object candidate : values) {
@@ -258,7 +259,6 @@ public class KeyValueTemplate implements KeyValueOperations, ApplicationEventPub
Assert.notNull(type, "Type to delete must not be null");
String keyspace = resolveKeySpace(type);
potentiallyPublishEvent(KeyValueEvent.beforeDropKeySpace(keyspace, type));
execute((KeyValueCallback<Void>) adapter -> {
@@ -272,16 +272,16 @@ public class KeyValueTemplate implements KeyValueOperations, ApplicationEventPub
@SuppressWarnings("unchecked")
@Override
public <T> T delete(T objectToDelete) {
public <T> @Nullable T delete(T objectToDelete) {
Class<T> type = (Class<T>) ClassUtils.getUserClass(objectToDelete);
KeyValuePersistentEntity<?, ?> entity = getKeyValuePersistentEntity(objectToDelete);
return delete(entity.getIdentifierAccessor(objectToDelete).getIdentifier(), type);
return delete(entity.getIdentifierAccessor(objectToDelete).getRequiredIdentifier(), type);
}
@Override
public <T> T delete(Object id, Class<T> type) {
public <T> @Nullable T delete(Object id, Class<T> type) {
Assert.notNull(id, "Id for object to be deleted must not be null");
Assert.notNull(type, "Type to delete must not be null");
@@ -301,12 +301,12 @@ public class KeyValueTemplate implements KeyValueOperations, ApplicationEventPub
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> T execute(KeyValueCallback<T> action) {
public <T> @Nullable T execute(KeyValueCallback<T> action) {
Assert.notNull(action, "KeyValueCallback must not be null");
@@ -401,8 +401,12 @@ public class KeyValueTemplate implements KeyValueOperations, ApplicationEventPub
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) {

View File

@@ -18,11 +18,11 @@ package org.springframework.data.keyvalue.core;
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 @@ import org.springframework.lang.Nullable;
*/
public class PathSortAccessor implements SortAccessor<Comparator<?>> {
@Nullable
@Override
public Comparator<?> resolve(KeyValueQuery<?> query) {
public @Nullable Comparator<?> resolve(KeyValueQuery<?> query) {
if (query.getSort().isUnsorted()) {
return null;

View File

@@ -22,8 +22,8 @@ import java.util.function.Predicate;
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 class PredicateQueryEngine extends QueryEngine<KeyValueAdapter, Predicate
*/
public PredicateQueryEngine(SortAccessor<Comparator<?>> 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 @@ public class PredicateQueryEngine extends QueryEngine<KeyValueAdapter, Predicate
return filterMatchingRange(tmp, criteria, offset, rows);
}
private static <S> List<S> filterMatchingRange(List<S> source, @Nullable Predicate criteria, long offset, int rows) {
private static <S> List<S> filterMatchingRange(List<S> source, @Nullable Predicate<?> criteria, long offset, int rows) {
Stream<S> stream = source.stream();
if (criteria != null) {
stream = stream.filter(criteria);
stream = stream.filter((Predicate<? super S>) criteria);
}
if (offset > 0) {
stream = stream.skip(offset);

View File

@@ -19,8 +19,8 @@ import java.util.Comparator;
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 class PropertyPathComparator<T> implements Comparator<T> {
return getComparator().compare(value1, value2) * (asc ? 1 : -1);
}
protected <T> Object getCompareValue(T object, PropertyPath propertyPath) {
protected <S> @Nullable Object getCompareValue(S object, PropertyPath propertyPath) {
return new SimplePropertyPathAccessor<>(object).getValue(propertyPath);
}
@SuppressWarnings("unchecked")
private Comparator<Object> getComparator() {
private Comparator<@Nullable Object> getComparator() {
return (Comparator<Object>) (nullsFirst ? NULLS_FIRST : NULLS_LAST);
}
@@ -81,7 +81,7 @@ public class PropertyPathComparator<T> implements Comparator<T> {
*
* @return
*/
public PropertyPathComparator<T> asc() {
public PropertyPathComparator<@Nullable T> asc() {
this.asc = true;
return this;
}
@@ -91,7 +91,7 @@ public class PropertyPathComparator<T> implements Comparator<T> {
*
* @return
*/
public PropertyPathComparator<T> desc() {
public PropertyPathComparator<@Nullable T> desc() {
this.asc = false;
return this;
}
@@ -101,7 +101,7 @@ public class PropertyPathComparator<T> implements Comparator<T> {
*
* @return
*/
public PropertyPathComparator<T> nullsFirst() {
public PropertyPathComparator<@Nullable T> nullsFirst() {
this.nullsFirst = true;
return this;
}
@@ -111,7 +111,7 @@ public class PropertyPathComparator<T> implements Comparator<T> {
*
* @return
*/
public PropertyPathComparator<T> nullsLast() {
public PropertyPathComparator<@Nullable T> nullsLast() {
this.nullsFirst = false;
return this;
}

View File

@@ -18,8 +18,8 @@ package org.springframework.data.keyvalue.core;
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 abstract class QueryEngine<ADAPTER extends KeyValueAdapter, CRITERIA, SOR
*
* @return
*/
@Nullable
protected ADAPTER getAdapter() {
protected @Nullable ADAPTER getAdapter() {
return this.adapter;
}

View File

@@ -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 class SimplePropertyPathAccessor<T> {
this.root = source;
}
public Object getValue(PropertyPath path) {
public @Nullable Object getValue(PropertyPath path) {
Object currentValue = root;
for (PropertyPath current : path) {

View File

@@ -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

View File

@@ -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 @@ class SpelCriteriaAccessor implements CriteriaAccessor<SpelCriteria> {
}
@Override
public SpelCriteria resolve(KeyValueQuery<?> query) {
public @Nullable SpelCriteria resolve(KeyValueQuery<?> query) {
if (query.getCriteria() == null) {
return null;

View File

@@ -17,10 +17,10 @@ package org.springframework.data.keyvalue.core;
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 class SpelPropertyComparator<T> implements Comparator<T> {
*
* @return
*/
public SpelPropertyComparator<T> asc() {
public SpelPropertyComparator<@Nullable T> asc() {
this.asc = true;
return this;
}
@@ -73,7 +73,7 @@ public class SpelPropertyComparator<T> implements Comparator<T> {
*
* @return
*/
public SpelPropertyComparator<T> desc() {
public SpelPropertyComparator<@Nullable T> desc() {
this.asc = false;
return this;
}
@@ -83,7 +83,7 @@ public class SpelPropertyComparator<T> implements Comparator<T> {
*
* @return
*/
public SpelPropertyComparator<T> nullsFirst() {
public SpelPropertyComparator<@Nullable T> nullsFirst() {
this.nullsFirst = true;
return this;
}
@@ -93,7 +93,7 @@ public class SpelPropertyComparator<T> implements Comparator<T> {
*
* @return
*/
public SpelPropertyComparator<T> nullsLast() {
public SpelPropertyComparator<@Nullable T> nullsLast() {
this.nullsFirst = false;
return this;
}
@@ -119,14 +119,12 @@ public class SpelPropertyComparator<T> implements Comparator<T> {
*/
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 class SpelPropertyComparator<T> implements Comparator<T> {
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);
}
/**

View File

@@ -21,11 +21,11 @@ import java.util.List;
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 @@ public class SpelQueryEngine extends QueryEngine<KeyValueAdapter, SpelCriteria,
return stream.collect(Collectors.toList());
}
@SuppressWarnings("NullAway")
private static boolean evaluateExpression(SpelCriteria criteria, Object candidate) {
try {

View File

@@ -18,6 +18,7 @@ package org.springframework.data.keyvalue.core;
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 class SpelSortAccessor implements SortAccessor<Comparator<?>> {
}
@Override
public Comparator<?> resolve(KeyValueQuery<?> query) {
public @Nullable Comparator<?> resolve(KeyValueQuery<?> query) {
if (query.getSort().isUnsorted()) {
return null;

View File

@@ -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 @@ public class KeyValueEvent<T> extends ApplicationEvent {
*
* @return
*/
@Nullable
public T getPayload() {
public @Nullable T getPayload() {
return payload;
}
}
@@ -336,8 +335,7 @@ public class KeyValueEvent<T> extends ApplicationEvent {
*
* @return
*/
@Nullable
public Object before() {
public @Nullable Object before() {
return existing;
}
@@ -346,8 +344,7 @@ public class KeyValueEvent<T> extends ApplicationEvent {
*
* @return can be {@literal null}.
*/
@Nullable
public T after() {
public @Nullable T after() {
return getPayload();
}
}

View File

@@ -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;

View File

@@ -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 enum AnnotationBasedKeySpaceResolver implements KeySpaceResolver {
return keySpace != null ? keySpace.toString() : null;
}
@Nullable
private static Object getKeySpace(Class<?> type) {
private static @Nullable Object getKeySpace(Class<?> type) {
MergedAnnotation<KeySpace> annotation = MergedAnnotations
.from(type, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY).get(KeySpace.class);

View File

@@ -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.data.util.TypeInformation;
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<T, P extends KeyValuePersistentProper
private static final ValueExpressionParser PARSER = ValueExpressionParser.create(SpelExpressionParser::new);
private final @Nullable ValueExpression keyspaceExpression;
private final @Nullable String keyspace;
private final String keyspace;
/**
* @param information must not be {@literal null}.
@@ -90,8 +90,8 @@ public class BasicKeyValuePersistentEntity<T, P extends KeyValuePersistentProper
* @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;

View File

@@ -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

View File

@@ -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

View File

@@ -17,6 +17,7 @@ package org.springframework.data.keyvalue.core.mapping.context;
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.context.MappingContext;
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 class KeyValueMappingContext<E extends KeyValuePersistentEntity<?, P>, P
* @return the current {@link KeySpaceResolver}. Can be {@literal null}.
* @since 3.1
*/
@Nullable
public KeySpaceResolver getKeySpaceResolver() {
public @Nullable KeySpaceResolver getKeySpaceResolver() {
return keySpaceResolver;
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 class KeyValueQuery<T> {
* @return
* @since 2.0
*/
@Nullable
public T getCriteria() {
public @Nullable T getCriteria() {
return criteria;
}

View File

@@ -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;

View File

@@ -20,6 +20,7 @@ import java.util.Collections;
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.AnnotationRepositoryConfigurat
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 abstract class KeyValueRepositoryConfigurationExtension extends Repositor
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 abstract class KeyValueRepositoryConfigurationExtension extends Repositor
* @return {@literal null} to explicitly not register a template.
* @see #getDefaultKeyValueTemplateRef()
*/
@Nullable
protected AbstractBeanDefinition getDefaultKeyValueTemplateBeanDefinition(
protected @Nullable AbstractBeanDefinition getDefaultKeyValueTemplateBeanDefinition(
RepositoryConfigurationSource configurationSource) {
return null;
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -17,6 +17,7 @@ package org.springframework.data.keyvalue.repository.query;
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.repository.query.parser.PartTree;
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 class KeyValuePartTreeQuery implements RepositoryQuery {
}
@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 class KeyValuePartTreeQuery implements RepositoryQuery {
* @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 @@ public class KeyValuePartTreeQuery implements RepositoryQuery {
* @param accessor must not be {@literal null}.
* @return the {@link KeyValueQuery}.
*/
@SuppressWarnings("NullAway")
public KeyValueQuery<?> createQuery(ParameterAccessor accessor) {
PartTree tree = this.partTree.get();

View File

@@ -24,6 +24,7 @@ import java.util.function.Function;
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.AbstractQueryCreator;
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;
/**

View File

@@ -17,6 +17,7 @@ package org.springframework.data.keyvalue.repository.query;
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 @@ public class SpelQueryCreator extends AbstractQueryCreator<KeyValueQuery<SpelExp
}
@Override
protected KeyValueQuery<SpelExpression> complete(String criteria, Sort sort) {
protected KeyValueQuery<SpelExpression> complete(@Nullable String criteria, Sort sort) {
KeyValueQuery<SpelExpression> query = new KeyValueQuery<>(this.expression);

View File

@@ -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;

View File

@@ -22,6 +22,7 @@ import java.lang.reflect.Constructor;
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.QueryMethod;
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;

View File

@@ -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.RepositoryFactoryBeanSup
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 class KeyValueRepositoryFactoryBean<T extends Repository<S, ID>, S, ID>
@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);
}

View File

@@ -25,7 +25,7 @@ import java.util.Optional;
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.QuerydslPredicateExecutor;
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 class QuerydslKeyValuePredicateExecutor<T> implements ListQuerydslPredica
}
@Override
public R oneValue() {
public @Nullable R oneValue() {
List<T> results = createQuery().limit(2).fetch();
@@ -299,7 +298,7 @@ public class QuerydslKeyValuePredicateExecutor<T> implements ListQuerydslPredica
}
@Override
public R firstValue() {
public @Nullable R firstValue() {
List<T> results = createQuery().limit(1).fetch();

View File

@@ -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;

View File

@@ -21,6 +21,7 @@ import java.util.Map;
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 class MapKeyValueAdapter extends AbstractKeyValueAdapter {
* @param engine the query engine.
*/
@SuppressWarnings("rawtypes")
private MapKeyValueAdapter(Map<String, Map<Object, Object>> store, Class<? extends Map> keySpaceMapType, QueryEngine<? extends KeyValueAdapter, ?, ?> engine) {
private MapKeyValueAdapter(Map<String, Map<Object, Object>> store, Class<? extends Map> keySpaceMapType, @Nullable QueryEngine<? extends KeyValueAdapter, ?, ?> engine) {
super(engine);
@@ -143,7 +144,7 @@ public class MapKeyValueAdapter extends AbstractKeyValueAdapter {
}
@Override
public Object put(Object id, Object item, String keyspace) {
public @Nullable Object put(Object id, Object item, String keyspace) {
Assert.notNull(id, "Cannot add item with null id");
Assert.notNull(keyspace, "Cannot add item for null collection");
@@ -162,21 +163,21 @@ public class MapKeyValueAdapter extends AbstractKeyValueAdapter {
}
@Override
public Object get(Object id, String keyspace) {
public @Nullable Object get(Object id, String keyspace) {
Assert.notNull(id, "Cannot get item with null id");
return getKeySpaceMap(keyspace).get(id);
}
@Override
public Object delete(Object id, String keyspace) {
public @Nullable Object delete(Object id, String keyspace) {
Assert.notNull(id, "Cannot delete item with null id");
return getKeySpaceMap(keyspace).remove(id);
}
@Override
public Collection<?> getAllOf(String keyspace) {
public Collection<Object> getAllOf(String keyspace) {
return getKeySpaceMap(keyspace).values();
}

View File

@@ -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;

View File

@@ -18,6 +18,7 @@ package org.springframework.data.map.repository.config;
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.keyvalue.repository.config.KeyValueRepositoryCon
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 @@ public class MapRepositoryConfigurationExtension extends KeyValueRepositoryConfi
return ParsingUtils.getSourceBeanDefinition(builder, configurationSource.getSource());
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@SuppressWarnings({ "unchecked", "rawtypes", "NullAway" })
private static Class<? extends Map> getMapTypeToUse(RepositoryConfigurationSource source) {
return (Class<? extends Map>) getAnnotationAttributes(source).get("mapType");
}
@Nullable
private static SortAccessor<?> getSortAccessor(RepositoryConfigurationSource source) {
private static @Nullable SortAccessor<?> getSortAccessor(RepositoryConfigurationSource source) {
Class<? extends SortAccessor<?>> sortAccessorType = (Class<? extends SortAccessor<?>>) getAnnotationAttributes(
source).get("sortAccessor");
@@ -102,8 +101,7 @@ public class MapRepositoryConfigurationExtension extends KeyValueRepositoryConfi
return null;
}
@Nullable
private static QueryEngine<?, ?, ?> getQueryEngine(@Nullable SortAccessor<?> sortAccessor,
private static @Nullable QueryEngine<?, ?, ?> getQueryEngine(@Nullable SortAccessor<?> sortAccessor,
RepositoryConfigurationSource source) {
Class<? extends QueryEngineFactory> queryEngineFactoryType = (Class<? extends QueryEngineFactory>) getAnnotationAttributes(

View File

@@ -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;

View File

@@ -197,7 +197,7 @@ class KeyValueTemplateTests {
@Test // DATACMNS-525
void deleteThrowsExceptionWhenIdCannotBeExctracted() {
assertThatIllegalArgumentException().isThrownBy(() -> operations.delete(FOO_ONE));
assertThatIllegalStateException().isThrownBy(() -> operations.delete(FOO_ONE));
}
@Test // DATACMNS-525

View File

@@ -140,7 +140,7 @@ class KeyValueTemplateUnitTests {
@Test // DATACMNS-525
void insertShouldThrowErrorWhenIdCannotBeResolved() {
assertThatIllegalArgumentException().isThrownBy(() -> template.insert(FOO_ONE));
assertThatIllegalStateException().isThrownBy(() -> template.insert(FOO_ONE));
}
@Test // DATACMNS-525
@@ -281,7 +281,7 @@ class KeyValueTemplateUnitTests {
@Test // DATACMNS-525
void deleteThrowsExceptionWhenIdCannotBeExctracted() {
assertThatIllegalArgumentException().isThrownBy(() -> template.delete(FOO_ONE));
assertThatIllegalStateException().isThrownBy(() -> template.delete(FOO_ONE));
}
@Test // DATACMNS-525