Skip to content

Please do NOT incorrectly add @Nullable annotations #3222

@CodePlayer

Description

@CodePlayer

I’m sorry if this comes across as offensive, but I’m somewhat skeptical whether the official Spring Data Redis development team has ever actually used their own library in real-world projects.

If you had, you would have easily noticed that the usage of @Nullable annotations across many Spring Data Redis APIs is deeply problematic.

Take, for example, the API org.springframework.data.redis.core.ValueOperations#increment(K). Its return value is annotated with @Nullable.

However, in reality, this Redis command never returns null.

I understand that the official team might argue: “In Redis pipelining or transactions, this command returns null.”

But please think carefully:

First, any Redis command is used in one of two scenarios:

  1. Direct usage in Java code:
// code snippet 1
Long value = redisTemplate().opsForValue().increment("redisKey");
// value must be NOT null
  1. Usage within Redis pipelining or transactions:
// code snippet 2
redisTemplate.executePipelined(new SessionCallback<>() {
    @Override
    public List<Object> execute(RedisOperations operations) throws DataAccessException {
        Long value = operations.opsForValue().increment("redisKey");
        // value is always null
        return null;
    }
});

In 2nd scenario, every Redis command returns null.
So, who in the real world would actually capture the return value inside a pipeline or transaction and write code like this?

// code snippet 3
redisTemplate.executePipelined(new SessionCallback<>() {
    @Override
    public List<Object> execute(RedisOperations operations) throws DataAccessException {
        Long value = operations.opsForValue().increment("redisKey"); // value always null
        if (value == null) {
            // do something when value is null
        } else if (value > 100) {
            // do something when value > 100
        } else {
            // do something when value <= 100
        }
        return null;
    }
});

Since value is always null, the if-else logic code above is meaningless in practice.
In real-world applications, no one captures and uses Redis command return values inside pipelines or transactions.
This is simply not a realistic business scenario.

In the real world, the vast majority of Redis commands are executed in first scenario.

Yet, because of the poorly applied @Nullable annotations, every usage of Redis commands now forces developers to suppress or handle IDE null warnings — adding unnecessary overhead — even though null will never be returned.

It’s highly questionable to annotate all non-null APIs with @Nullable just to accommodate an unrealistic edge case that shouldn’t exist in production.

Secondly, the official team might argue that adding @Nullable helps remind developers to use Redis command return values correctly within pipelines or transactions.

Let’s analyze both possibilities:

  1. If a developer understands pipelining/transactions correctly, they won’t capture the return value at all — so whether @Nullable is present or not makes no difference.
  2. If a developer is a beginner unfamiliar with pipelining/transactions, and mistakenly captures the return value inside a pipeline,
    seeing the IDE null warning might lead them to instinctively write code like code snippet 3 — adding if (value == null) else ... branches to silence the warning.
    While this avoids runtime errors, it introduces serious logical bugs, because the else if/else branches will never execute.
    In this case, If the API is not annotated with @Nullable, developers won’t add null-checking code, and any incorrect usage will trigger an NullPointerException directly at runtime — which, ironically, is the most effective way to expose the issue sooner.

Moreover, even according to your own reasoning — ValueOperations#increment(K) requires the @Nullable annotation, because it may return null in pipelines or transaction, then why does NOT HashOperations#increment(H, HK, long) receive the same annotation? Shouldn’t nearly all Redis commands be consistently annotated with @Nullable ?

Your usage of the @Nullable annotation is confusing, logically inconsistent, and lacks rigor and scientific grounding — it fails to meet the objective demands of real-world scenarios.
To cope with this poor design, we developers are forced to pay an unnecessary additional cost.

Genuine suggestion: Please do not add @Nullable annotations solely based on extreme edge cases — such as capturing return values inside pipelines or transactions — which hold no practical meaning in the real world.

If an API does not return null under normal (non-pipeline, non-transaction) usage, it should not be annotated with @Nullable.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions