Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JetBrains @Contract using field

I've got the following class*:

public class MyClass {

  @Nullable
  private String mString;

  /* ... */

  public boolean contains(@NotNull final String text) {
    if(!isNullOrEmpty()) {
      return mString.contains(text);
    } else {
      return false;
    }
  }

  public boolean isNullOrEmpty() {
      return mString == null || mString.isEmpty();
  }
}

Now at mString.contains(text), IntelliJ warns me that mString might be null, even though it is guaranteed that it isn't. I've noticed JetBrains has the @Contract annotation. Is there a way I can annotate isNullOrEmpty() in such a way that I don't get this warning when the method returns true?

I am hoping the @Contract annotation will come close to the Java Modeling Language functionality, like so:

//@ ensure \result == true ==> mString != null;
public boolean isNullOrEmpty() {
  return mString == null || mString.isEmpty();
}

Furthermore, I'd like isNullOrEmpty() to remain parameterless, since it is part of the public API.

*Just a fictional class for demonstration purposes :) The actual code uses a more complex class.

like image 369
nhaarman Avatar asked Dec 25 '22 22:12

nhaarman


2 Answers

Your mString is mutable so between the check 'isNullOrEmpty' and the access 'mString.contains' mString value can be changed. So it is the reason why @Contract annotation works only for method parameters. You can use @Contract if your method isNullOrEmpty looks like:

public boolean isNullOrEmpty(String pString) {}
like image 91
anstarovoyt Avatar answered Dec 28 '22 07:12

anstarovoyt


Well, because you've annotated mString with @Nullable, mString could very well be null. This is static analysis at work; you've already declared that this field may or may not be null, so IntelliJ is going to inform you about that.

Consider why the field is annotated with @Nullable. Maybe it should be @NotNull?

Keep in mind, I'm only getting the warning in the contains method, since IntelliJ is doing the smart thing; it knows that if mString == null, the other condition won't be evaluated.

As a reminder: @Contract only applies to the arguments. It won't check anything to do with the fields, which is why one would annotate the fields differently (with @Nullable, @NonNull, @MagicConstant, etc.).

like image 32
Makoto Avatar answered Dec 28 '22 08:12

Makoto