Why do I still receive warning for possible NPE in IntelliJ when I do my null checking?

I have a function that could return a null value. So I used JetBrains annotation and put a @Nullable annotation on top of the function.

@Nullable
public static ConnectionManager getConnectionManager() {
    return connectionManager;
}

Then, I runned a Lint inspection. I found 4 places when I use this function and I wasn't doing any null check.

Before:

Service.getConnectionManager().onAssetInfoChanged();

After:

if(Service.getConnectionManager() != null) {
    Service.getConnectionManager().onAssetInfoChanged();
}

Then I run the Lint inspection again. To my big surprise, I'm still getting:

Method invocation 'Service.getConnectionManager().onAssetInfoChanged()' at line 308 may produce 'java.lang.NullPointerException'.

What am I doing wrong? Is this a bug in the Lint inspector?

Upvotes: 3

Views: 1304

Answers (3)

Aleksandar Stojadinovic
Aleksandar Stojadinovic

Reputation: 5049

First of all, the @Nullable is related to method parameters that can be null. The opposite is NotNull which means that the parameter must be set. And secondly, each call of getConnectionManager is treated by the analyzer separately. Do it like this

ConnectionManager connManager = Service.getConnectionManager();
if(connManager != null
{
//do your stuff
}

Upvotes: 1

tddmonkey
tddmonkey

Reputation: 21184

The problem is that you're calling Service.getConnectionManager() twice. On the second invocation when you actually use it Lint has to make the assumption it could now be null. One way to solve this is to use a local variable like this:

ConnectionManager connectionManager = Service.getConnectionManager();
if(connectionManager != null) {
    connectionManager.onAssetInfoChanged();
}

An alternative, and in my opinion preferred approach would be to avoid the null in the first place. If you're using Java 8 you can use an Optional to represent the fact your ConnectionManager can be null.

The best approach would be to ensure your ConnectionManager is actually never null

Upvotes: 3

Tunaki
Tunaki

Reputation: 137064

The inspector is not completely wrong. It is possible that you could have a NullPointerException in this case: since you are calling Service.getConnectionManager() each time, there's no way we can be absolutely sure that it won't return null the second time even though it did not the first time: the getter could have a more complicated logic than return ... or the variable may have been set to null concurrently between the two method calls.

As such, you could refactor your code to:

ConnectionManager manager = Service.getConnectionManager();
if (manager != null) {
    manager.onAssetInfoChanged();
}

assuming that the return type of getConnectionManager() is an object of type ConnectionManager. With this, it is impossible to have a NullPointerException on that line.

Upvotes: 5

Related Questions