Herberts Markūns
Herberts Markūns

Reputation: 139

How to avoid null warning when using @NotNull and checking for null in another method before method call?

I have a bit of a complex validation system, that simplified looks something like the following:

private static void mainMethod(@Nullable String startParam, @Nullable String nextParam) {

    String nextStep = methodSelect(startParam, nextParam);

    switch (nextStep) {
        case "none":
            break;
        case "goFinal":
            finalMethod(startParam);
            break;
        case "goNext":
            nextMethod(nextParam);
            break;
    }
}

private static void nextMethod(@NotNull String nextParam) {
    System.out.println(nextParam);
}

private static void finalMethod(@NotNull String startParam) {
    System.out.println(startParam);
}

@NotNull
private static String methodSelect(@Nullable String startParam,@Nullable String nextParam) {
    if (startParam == null && nextParam == null) {
        return "none";
    } if (startParam == null) {
        return "goNext";
    } else {
        return "goFinal";
    }
}

But I get warnings when in the switch statement calling both finalMethod() and nextMethod() about "Argument x might be null", even though methodSelect() and the switch statement afterwards makes sure that these arguments will not be null. How do I correctly get rid of these warnings, hopefully without having another check for null in or before these methods? Thanks!

I'm using IntelliJ IDEA 2016.3.4, Java 8, and annotations:

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

Upvotes: 1

Views: 914

Answers (1)

mernst
mernst

Reputation: 8117

This is very tricky code -- you are mimicking reflection to make a call to different methods depending on run-time tests.

In IntelliJ IDEA, you will want to suppress the warning in the IDE or via a code annotation.

Some other tools have more sophisticated code analysis. Here is a slight variant of your code that uses a boolean instead of a string to indicate which method to call. The Nullness Checker of the Checker Framework is able to verify the nullness-safety of this code, thanks to the postcondition annotation @EnsuresNonNullIf.

import org.checkerframework.checker.nullness.qual.*;

class Example {

  private static void mainMethod(@Nullable String startParam, @Nullable String nextParam) {

    if (! useFinal(startParam)) {
      // do nothing
    } else {
      finalMethod(startParam);
    }
  }

  private static void nextMethod(@NonNull String nextParam) {
    System.out.println(nextParam);
  }

  private static void finalMethod(@NonNull String startParam) {
    System.out.println(startParam);
  }

  @EnsuresNonNullIf(expression="#1", result=true)
  private static boolean useFinal(@Nullable String startParam) {
    if (startParam == null) {
      return false;
    } else {
      return true;
    }
  }

}

The @EnsuresNonNullIf annotation doesn't currently handle Strings as used in your original code; you could request such an extension from the maintainers or implement it yourself and submit a pull request.

Upvotes: 1

Related Questions