Skip to content

Move to jspecify for nullness checks. #3159

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>4.0.0-SNAPSHOT</version>
<version>4.0.0-GH-3290-SNAPSHOT</version>

<name>Spring Data Redis</name>
<description>Spring Data module for Redis</description>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import java.io.Serial;

import org.jspecify.annotations.Nullable;
import org.springframework.dao.DataRetrievalFailureException;

/**
Expand Down Expand Up @@ -44,7 +45,7 @@ public class ClusterRedirectException extends DataRetrievalFailureException {
* @param targetPort the port on the host.
* @param e the root cause from the data access API in use.
*/
public ClusterRedirectException(int slot, String targetHost, int targetPort, Throwable e) {
public ClusterRedirectException(int slot, String targetHost, int targetPort, @Nullable Throwable e) {

super("Redirect: slot %s to %s:%s.".formatted(slot, targetHost, targetPort), e);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import java.io.Serial;

import org.jspecify.annotations.Nullable;
import org.springframework.dao.DataAccessResourceFailureException;

/**
Expand All @@ -38,7 +39,7 @@ public class ClusterStateFailureException extends DataAccessResourceFailureExcep
*
* @param msg the detail message.
*/
public ClusterStateFailureException(String msg) {
public ClusterStateFailureException(@Nullable String msg) {
super(msg);
}

Expand All @@ -48,7 +49,7 @@ public ClusterStateFailureException(String msg) {
* @param msg the detail message.
* @param cause the nested exception.
*/
public ClusterStateFailureException(String msg, Throwable cause) {
public ClusterStateFailureException(@Nullable String msg, @Nullable Throwable cause) {
super(msg, cause);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
*/
package org.springframework.data.redis;

import org.jspecify.annotations.Nullable;
import org.springframework.dao.DataAccessException;
import org.springframework.lang.Nullable;

/**
* Potentially translates an {@link Exception} into appropriate {@link DataAccessException}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
*/
package org.springframework.data.redis;

import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.converter.Converter;
import org.springframework.dao.DataAccessException;
import org.springframework.lang.Nullable;

/**
* {@link PassThroughExceptionTranslationStrategy} returns {@literal null} for unknown {@link Exception}s.
Expand All @@ -34,9 +34,8 @@ public PassThroughExceptionTranslationStrategy(Converter<Exception, DataAccessEx
this.converter = converter;
}

@Nullable
@Override
public DataAccessException translate(Exception e) {
public @Nullable DataAccessException translate(Exception e) {
return this.converter.convert(e);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package org.springframework.data.redis;

import org.jspecify.annotations.Nullable;
import org.springframework.dao.DataAccessResourceFailureException;

/**
Expand All @@ -27,15 +28,15 @@ public class RedisConnectionFailureException extends DataAccessResourceFailureEx
/**
* @param msg the detail message.
*/
public RedisConnectionFailureException(String msg) {
public RedisConnectionFailureException(@Nullable String msg) {
super(msg);
}

/**
* @param msg the detail message.
* @param cause the nested exception.
*/
public RedisConnectionFailureException(String msg, Throwable cause) {
public RedisConnectionFailureException(@Nullable String msg, @Nullable Throwable cause) {
super(msg, cause);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
*/
package org.springframework.data.redis;

import org.jspecify.annotations.Nullable;
import org.springframework.dao.UncategorizedDataAccessException;
import org.springframework.lang.Nullable;

/**
* Exception thrown when we can't classify a Redis exception into one of Spring generic data access exceptions.
Expand All @@ -29,7 +29,7 @@ public class RedisSystemException extends UncategorizedDataAccessException {
* @param msg the detail message.
* @param cause the root cause from the data access API in use.
*/
public RedisSystemException(String msg, @Nullable Throwable cause) {
public RedisSystemException(@Nullable String msg, @Nullable Throwable cause) {
super(msg, cause);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import java.io.Serial;

import org.jspecify.annotations.Nullable;
import org.springframework.dao.DataRetrievalFailureException;

/**
Expand All @@ -35,7 +36,7 @@ public class TooManyClusterRedirectionsException extends DataRetrievalFailureExc
*
* @param msg the detail message.
*/
public TooManyClusterRedirectionsException(String msg) {
public TooManyClusterRedirectionsException(@Nullable String msg) {
super(msg);
}

Expand All @@ -45,7 +46,7 @@ public TooManyClusterRedirectionsException(String msg) {
* @param msg the detail message.
* @param cause the root cause from the data access API in use.
*/
public TooManyClusterRedirectionsException(String msg, Throwable cause) {
public TooManyClusterRedirectionsException(@Nullable String msg, @Nullable Throwable cause) {
super(msg, cause);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.Arrays;
import java.util.function.Consumer;

import org.jspecify.annotations.Nullable;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
Expand Down Expand Up @@ -50,7 +51,6 @@
import org.springframework.data.redis.repository.query.RedisPartTreeQuery;
import org.springframework.data.redis.repository.query.RedisQueryCreator;
import org.springframework.data.redis.repository.support.RedisRepositoryFactoryBean;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.util.function.Function;
import java.util.function.Supplier;

import org.jspecify.annotations.Nullable;
import org.springframework.dao.PessimisticLockingFailureException;
import org.springframework.data.redis.connection.ReactiveRedisConnection;
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
Expand All @@ -38,7 +39,6 @@
import org.springframework.data.redis.connection.RedisStringCommands.SetOption;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.data.redis.util.ByteUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
Expand Down Expand Up @@ -142,8 +142,9 @@ public byte[] get(String name, byte[] key, @Nullable Duration ttl) {
return execute(name, connection -> doGet(connection, name, key, ttl));
}

@Nullable
private byte[] doGet(RedisConnection connection, String name, byte[] key, @Nullable Duration ttl) {

@SuppressWarnings("NullAway")
private byte @Nullable[] doGet(RedisConnection connection, String name, byte[] key, @Nullable Duration ttl) {

byte[] result = shouldExpireWithin(ttl) ? connection.stringCommands().getEx(key, Expiration.from(ttl))
: connection.stringCommands().get(key);
Expand Down Expand Up @@ -241,6 +242,7 @@ public void put(String name, byte[] key, byte[] value, @Nullable Duration ttl) {

}

@SuppressWarnings("NullAway")
private void doPut(RedisConnection connection, String name, byte[] key, byte[] value, @Nullable Duration ttl) {

if (shouldExpireWithin(ttl)) {
Expand All @@ -265,6 +267,7 @@ public CompletableFuture<Void> store(String name, byte[] key, byte[] value, @Nul
}

@Override
@SuppressWarnings("NullAway")
public byte[] putIfAbsent(String name, byte[] key, byte[] value, @Nullable Duration ttl) {

Assert.notNull(name, "Name must not be null");
Expand Down Expand Up @@ -538,6 +541,7 @@ public boolean isSupported() {
}

@Override
@SuppressWarnings("NullAway")
public CompletableFuture<byte[]> retrieve(String name, byte[] key, @Nullable Duration ttl) {

return doWithConnection(connection -> {
Expand Down Expand Up @@ -572,6 +576,7 @@ private Mono<Boolean> doStoreWithLocking(String name, byte[] key, byte[] value,
unused -> doUnlock(name, connection));
}

@SuppressWarnings("NullAway")
private Mono<Boolean> doStore(byte[] cacheKey, byte[] value, @Nullable Duration ttl,
ReactiveRedisConnection connection) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@

import java.time.Duration;

import org.jspecify.annotations.Nullable;
import org.springframework.data.redis.cache.RedisCacheWriter.TtlFunction;
import org.springframework.lang.Nullable;

/**
* {@link TtlFunction} implementation returning the given, predetermined {@link Duration} used for per cache entry
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import java.time.Instant;
import java.util.concurrent.TimeUnit;

import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.ObjectUtils;

/**
Expand Down
25 changes: 13 additions & 12 deletions src/main/java/org/springframework/data/redis/cache/RedisCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;

import org.jspecify.annotations.Nullable;
import org.springframework.cache.Cache;
import org.springframework.cache.support.AbstractValueAdaptingCache;
import org.springframework.cache.support.NullValue;
Expand All @@ -37,7 +38,6 @@
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.util.ByteUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
Expand All @@ -57,6 +57,7 @@
@SuppressWarnings("unused")
public class RedisCache extends AbstractValueAdaptingCache {

@SuppressWarnings("NullAway")
static final byte[] BINARY_NULL_VALUE = RedisSerializer.java().serialize(NullValue.INSTANCE);

static final String CACHE_RETRIEVAL_UNSUPPORTED_OPERATION_EXCEPTION_MESSAGE = "The Redis driver configured with RedisCache through RedisCacheWriter does not support CompletableFuture-based retrieval";
Expand Down Expand Up @@ -146,7 +147,7 @@ public CacheStatistics getStatistics() {

@Override
@SuppressWarnings("unchecked")
public <T> T get(Object key, Callable<T> valueLoader) {
public <T> @Nullable T get(Object key, Callable<T> valueLoader) {

byte[] binaryKey = createAndConvertCacheKey(key);
byte[] binaryValue = getCacheWriter().get(getName(), binaryKey,
Expand Down Expand Up @@ -176,7 +177,7 @@ protected <T> T loadCacheValue(Object key, Callable<T> valueLoader) {
}

@Override
protected Object lookup(Object key) {
protected @Nullable Object lookup(Object key) {

byte[] binaryKey = createAndConvertCacheKey(key);

Expand All @@ -196,6 +197,7 @@ private Duration getTimeToLive(Object key, @Nullable Object value) {
}

@Override
@SuppressWarnings("NullAway")
public void put(Object key, @Nullable Object value) {

Object cacheValue = processAndCheckValue(value);
Expand All @@ -209,7 +211,8 @@ public void put(Object key, @Nullable Object value) {
}

@Override
public ValueWrapper putIfAbsent(Object key, @Nullable Object value) {
@SuppressWarnings("NullAway")
public @Nullable ValueWrapper putIfAbsent(Object key, @Nullable Object value) {

Object cacheValue = preProcessCacheValue(value);

Expand Down Expand Up @@ -268,7 +271,7 @@ public CompletableFuture<ValueWrapper> retrieve(Object key) {
}

@Override
@SuppressWarnings("unchecked")
@SuppressWarnings({"unchecked", "NullAway"})
public <T> CompletableFuture<T> retrieve(Object key, Supplier<CompletableFuture<T>> valueLoader) {

return retrieve(key).thenCompose(wrapper -> {
Expand All @@ -291,7 +294,7 @@ public <T> CompletableFuture<T> retrieve(Object key, Supplier<CompletableFuture<
});
}

private Object processAndCheckValue(@Nullable Object value) {
private @Nullable Object processAndCheckValue(@Nullable Object value) {

Object cacheValue = preProcessCacheValue(value);

Expand All @@ -311,8 +314,7 @@ private Object processAndCheckValue(@Nullable Object value) {
* @param value can be {@literal null}.
* @return preprocessed value. Can be {@literal null}.
*/
@Nullable
protected Object preProcessCacheValue(@Nullable Object value) {
protected @Nullable Object preProcessCacheValue(@Nullable Object value) {
return value != null ? value : isAllowNullValues() ? NullValue.INSTANCE : null;
}

Expand Down Expand Up @@ -351,8 +353,7 @@ protected byte[] serializeCacheValue(Object value) {
* {@link RedisSerializationContext.SerializationPair}; can be {@literal null}.
* @see RedisCacheConfiguration#getValueSerializationPair()
*/
@Nullable
protected Object deserializeCacheValue(byte[] value) {
protected @Nullable Object deserializeCacheValue(byte[] value) {

if (isAllowNullValues() && ObjectUtils.nullSafeEquals(value, BINARY_NULL_VALUE)) {
return NullValue.INSTANCE;
Expand Down Expand Up @@ -381,6 +382,7 @@ protected String createCacheKey(Object key) {
* @return never {@literal null}.
* @throws IllegalStateException if {@code key} cannot be converted to {@link String}.
*/
@SuppressWarnings("NullAway")
protected String convertKey(Object key) {

if (key instanceof String stringKey) {
Expand Down Expand Up @@ -425,8 +427,7 @@ private CompletableFuture<ValueWrapper> retrieveValue(Object key) {
.thenApply(this::toValueWrapper);
}

@Nullable
private Object nullSafeDeserializedStoreValue(@Nullable byte[] value) {
private @Nullable Object nullSafeDeserializedStoreValue(byte @Nullable[] value) {
return value != null ? fromStoreValue(deserializeCacheValue(value)) : null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.time.Duration;
import java.util.function.Consumer;

import org.jspecify.annotations.Nullable;
import org.springframework.cache.Cache;
import org.springframework.cache.interceptor.SimpleKey;
import org.springframework.core.convert.ConversionService;
Expand All @@ -28,7 +29,6 @@
import org.springframework.data.redis.serializer.RedisSerializationContext.SerializationPair;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

/**
Expand Down
Loading