javachecker-framework

Resolve Nullness Error from checkerframework


I have some java code which looks like below

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

abstract class Foo {

  abstract @Nullable String getFoo();
  
  void foo() {
    if (getFoo() != null) {
      bar(getFoo());  
    }
  }
  
  void bar(String str) {
      str.charAt(1);
  }
}

Which gives me the error

Error: [argument.type.incompatible] incompatible types in argument.
   found   : @Initialized @Nullable String
   required: @Initialized @NonNull String

which is undestandable as getFoo as been decorated with Nullable.

can I prevent this without modifying the bar method ? both methods getFoo and bar are out of my control for modifications. What are the solutions to resolve this ?


Solution

  • In general, the Nullness Checker is correct that the given code might throw a NullPointerException, because getFoo() might return different values on different invocations. You can express that getFoo() returns the same value on every invocation (on the same receiver) by using the @Deterministic method annotation:

    import org.checkerframework.dataflow.qual.Deterministic;
    import org.checkerframework.checker.nullness.qual.Nullable;
    
    abstract class Foo {
    
      @Deterministic
      abstract @Nullable String getFoo();
      
      void foo() {
        if (getFoo() != null) {
          bar(getFoo());  
        }
      }
      
      void bar(String str) {
          str.charAt(1);
      }
    }
    

    This is discussed in the Checker Framework manual.

    If you cannot directly add @Deterministic to a library, you can write a stub file with that annotation and use it while type-checking your code.