Operating System: macOS Sequoia 15.7.2
SonarQube for IntelliJ plugin version: 11.6.0.83783
IntelliJ version: 2025.2.5
Programming Language: Java
SonarQube for IDE is giving a false positive for a nullability rule. I have projects where it appears as if the @NonNullApiNonNullApi annotation on the package level interferes with the @Nullable annotation on an interface in that package. For now, the only way to replicate the issue is with Spring Data’s library. I have updated to the latest versions, and the false positive report still remains.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.github.example</groupId>
<artifactId>sonarqube-nullable-20251127</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>SonarQube Nullable</name>
<description>SonarQube False Positive for @Nullable in Interface for @NonNullApi package.</description>
<properties>
<!-- Settings: maven-compiler-plugin -->
<maven.compiler.release>25</maven.compiler.release>
<!-- Settings: maven-resource-plugin -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.source.sourceEncoding>UTF-8</project.source.sourceEncoding>
<project.report.sourceEncoding>UTF-8</project.report.sourceEncoding>
<!-- Settings: maven-build -->
<maven.build.timestamp.format>yyyy-MM-dd'T'HH:mm:ss'Z'</maven.build.timestamp.format>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>5.0.0</version>
</dependency>
</dependencies>
</project>
package com.github.example.component;
import com.github.example.model.AttributeSource;
import com.github.example.model.OptimizedAttributes;
import com.github.example.mongo.Attribute;
import java.util.List;
import java.util.Objects;
import org.bson.Document;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.springframework.data.convert.PropertyValueConverter;
import org.springframework.data.convert.ValueConversionContext;
/** Converter for AttributeSource field in MongoDB documents. */
public class AttributeSourceConverter
implements PropertyValueConverter<
@NonNull AttributeSource, @NonNull List<Document>, @NonNull ValueConversionContext<?>> {
/** {@inheritDoc} */
@Override
@Nullable
public AttributeSource read(
@Nullable List<Document> documents, @NonNull ValueConversionContext<?> context) {
// Return null for null documents.
if (documents == null) {
return null;
}
// Convert to a list of attributes.
final var attributes =
documents.stream()
.map(document -> context.read(document, Attribute.class))
.filter(Objects::nonNull)
.toList();
// Return the attribute source.
return new OptimizedAttributes(attributes);
}
/** {@inheritDoc} */
@Override
@Nullable
public List<Document> write(
@Nullable AttributeSource attributeSource, @NonNull ValueConversionContext<?> context) {
// Return null for null attribute source.
if (attributeSource == null) {
return null;
}
// Define the attributes.
final var attributes = attributeSource.attributes();
// Return the list of documents.
return attributes.stream()
.map(attribute -> context.write(attribute, Document.class))
.filter(Objects::nonNull)
.toList();
}
}
package com.github.example.model;
import com.github.example.mongo.Attribute;
import java.util.List;
public interface AttributeSource {
List<Attribute> attributes();
}
package com.github.example.model;
import com.github.example.mongo.Attribute;
import java.util.List;
public record OptimizedAttributes(List<Attribute> attributes) implements AttributeSource {}
package com.github.example.mongo;
import static java.util.Objects.requireNonNull;
import com.github.example.component.AttributeSourceConverter;
import com.github.example.model.AttributeSource;
import com.github.example.model.OptimizedAttributes;
import java.util.List;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.springframework.data.convert.ValueConverter;
import org.springframework.data.mongodb.core.mapping.Field;
/**
* Model for documents in the classification collection.
*
* @param id classification Id
* @param attributes classification attribute source
*/
public record Classification(
@Field("_id") @NonNull String id,
@ValueConverter(AttributeSourceConverter.class) @NonNull AttributeSource attributes) {
/**
* The public constructor for nullable sources.
*
* @param id classification Id
* @param attributes classification attribute source
*/
public Classification(@Nullable String id, @Nullable AttributeSource attributes) {
this.id = requireNonNull(id, "Classification Id not present.");
this.attributes = attributes != null ? attributes : new OptimizedAttributes(List.of());
}
}
package com.github.example.mongo;
public record Attribute(String name, String value) {}
The report is generated for the following method:
public List<Document> write( @Nullable AttributeSource attributeSource, @NonNull ValueConversionContext<?> context)
The report message:
Fix the incompatibility @NullablefNullablefNullablefNullablef the a@Nullable@Nullableotation @Nullable to honor @NullMarked at package level of the overridden method.