Summary
String @NotNull [] means the "non-null array of (any) strings".
@NotNull String [] means "an array (or null) of non-null strings".
See JLS 9.7.4
@C int @A [] @B [] f;@Aapplies to the array typeint[][],@Bapplies to its component typeint[], and@Capplies to the element typeint. For more examples, see ยง10.2.
Symptoms
User is working with a block of code in IntelliJ IDEA. The code has been written using org.jspecify.annotations.Nullable. However, org.jspecify.annotations seems to not be recognized within the particular call.
Here is the mentioned block of code:
private Object makeReadable(@org.jspecify.annotations.Nullable Object[] arguments, int index, @Nullable Format format) {
return format != null ? arguments == null ? "" : arguments[index] :
truncateIfExceedsMaxLength(StringUtils.nullSafeToString(arguments[index]));
}
private Object makeReadable2(@org.jetbrains.annotations.Nullable Object[] arguments, int index, @Nullable Format format) {
return format != null ? arguments == null ? "" : arguments[index] :
truncateIfExceedsMaxLength(StringUtils.nullSafeToString(arguments[index]));
}
The user is receiving this feedback/error message indicating "Condition 'arguments == null' is always 'false' ".
Cause
The issue is based on the interpretation of the @Nullable attribute in code. This is being used for the Object array 'arguments'. However, IntelliJ IDEA interprets this annotation as referring to the component of the array, not the array itself. This interpretation leads to the condition 'arguments == null' being always 'false'.
Resolution
To annotate the array itself as nullable (that is, allowing it to be null), rather than its components, the syntax needs to be written differently. The array itself should be annotated through this syntax: Object @Nullable [] arguments. With this change, the array will now be identified as possibly being null, and the condition 'arguments == null' will not always return 'false'.
A sample:
@NonNull Object[] specifies that the array elements are non-null. If theObject is changed to byte , which is always the case since they are primitives.
Object[] - Array can be null, elements can also be null
Object @NonNull [] - Modifies the array itself can't be null.
@NonNull Object [] - Modifies the array elements, indicating that each element in the array must not be null; the array itself can be null.
@NonNull Object @NonNull [] - Neither array nor elements can be null.
// Valid declaration and usage
@NonNull Object @NonNull [] array = new @NonNull Object @NonNull [3];
array[0] = new Object();
array[1] = new String();
array[2] = new Integer(42);
// The compiler will prevent the following operations:
// 1. array = null; // Violates the first @NonNull
// 2. array[0] = null; // Violates the second @NonNull
More complete sample files below:
build.gradle
plugins {
id 'java'
id 'net.ltgt.errorprone' version '4.2.0' // https://github.com/tbroyer/gradle-errorprone-plugin
}
group = 'org.example'
version = '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
sourceSets {
main {
java {
srcDirs 'src/main/java', 'build/generated/sources/annotationProcessor/java/main'
}
}
}
dependencies {
implementation 'org.jspecify:jspecify:1.0.0' // https://jspecify.dev
errorprone 'com.uber.nullaway:nullaway:0.13.1' // https://github.com/uber/NullAway
errorprone 'com.google.errorprone:error_prone_core:2.38.0' // https://github.com/google/error-prone
}
tasks.withType(JavaCompile).configureEach {
options.errorprone {
option("NullAway:CheckOptionalEmptiness", true)
// Enables experimental support for fuller JSpecify checking
option("NullAway:JSpecifyMode", true)
disableAllChecks = true // Other error prone checks are disabled
option("NullAway:OnlyNullMarked", "true") // Enable nullness checks only in null-marked code
error("NullAway") // bump checks from warnings (default) to errors
}
}
NullableDemo.java
import org.jspecify.annotations.*;
public class NullableDemo {
static @NonNull Object @NonNull [] array = new @NonNull Object @NonNull[3];
static String @NonNull [] arrayNonNull = new String @NonNull[3];
static @NonNull String [] arrayElementsNonNull = new String[3];
public static void main(String[] args) {
array[0] = new Object();
array[1] = new String();
array[2] = Integer.valueOf(42);
// The compiler will prevent the following operations:
array = null; // Violates the first @NonNull
array[0] = null; // Violates the second @NonNull
arrayNonNull[0] = null;
arrayNonNull = null;
arrayElementsNonNull[0] = null;
arrayElementsNonNull = null;
}
}
Comments
0 comments
Please sign in to leave a comment.