False positive on java:S2259 with @Nonnull

Given the following code:

	record Thing(String val) {}

	public void falsePositive(@Nonnull Thing thing, boolean someCondition) {
		Thing foo = someCondition ? thing : otherThing(someCondition);
		String bar = foo == null ? thing.val() : foo.val();

		System.out.println(bar);
	}

	public Thing otherThing(boolean someCondition) {
		return someCondition ? null : new Thing("hello");
	}

SonarQube for IDE (IntelliJ) reports a false positive warning that thing.val() might throw a NPE, but thing is explicitly annotated @Nonnull in the method signature.

Hi Bastien! Thank you for an example! I have some problems reproducing the issue. Could you tell us the full qualified name of the @Nonnnull annotation that you are using?

Hi, it’s jakarta.annotation.Nonnull.

Well, the problem disappears if I paste my example in a dedicated file. If I leave it in my “real world” class, both my “real” and “example” code are flagged by SonarLint.
I’ll try to understand what’s causing this difference.

I am also having what seems to be a false positive on this rule linked to annotations. I have isolated the case in a class outside my codebase.

import java.util.ArrayList;
import java.util.List;

import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;

public class NullTest {


    public class TestObject {
        @Nullable String field;

        public @Nullable String getField() {
            return this.field;
        }

        public void setField(@Nullable final String field) {
            this.field = field;
        }
    }

    public static void main(String[] args) {

        List<@NonNull TestObject> testObjects = new ArrayList<>();

        String result = testObjects.stream()
                .findAny()
                .map(t -> t.getField())
                .orElse(null);

        System.out.println(result);


    }

}

The Nullable annotation on the getField() method seems to confuse the rule. map() will never return null, it will always return an Optional that may be empty.
I get the same error on the findAny() method if I switch the position of the findAny() and map() lines.

Kind regards

Hi Bastien! I think the problem might be caused by some missing dependencies or something else that breaks the classpath in the IDE (so it should not affect CI). I created SONARJAVA-5326 for tracking.

Daniel, I see you have another thread for @Nullable in generics, so I will let other folks handle it.

Yes this is fine.