0

This sample program exhibits the behavior I do not understand:

public class Main {

    public static String foo(String value) {
        return "length: " + value.length();
    }

    public static void main(String[] args) {
        System.out.println(foo(null));
    }

}

The runtime behavior of this problem is clear: It throws a NullPointerException. What is not clear, however, is the warning I get from IntelliJ:

Passing 'null' argument to parameter annotated as @NotNull 
Main
@Contract(pure = true)  
@NotNull  
public static String foo(
  @NotNull  String value
)

The Contract and NotNull annotations are obviously not in my code. I cannot tell which package they are from since IntelliJ does not support "go to declaration" in the warning tooltip, and I cannot use the normal "go to declaration" because, well, the annotations do not exist in the code.

This is a plain new project without any Maven/Gradle build script nor any included libraries, just to rule out any "magic" compile-time plugins that could try to add annotations.

This leaves the possibility that @NotNull adds itself. But how? Does it have some meta-annotations that trigger its own annotation processor which adds them to my code? Sadly I cannot even try to find out because I don't which package they are from.

What exactly is happening here?

mernst
  • 7,437
  • 30
  • 45
Martin Geisse
  • 1,189
  • 1
  • 9
  • 22
  • IntelliJ is adding them to assist with internal checks. It's only for the IDE, the annotations won't end up in the compiled code. – Jorn Jun 09 '23 at 11:04
  • If IntelliJ is adding annotations just for itself, then why does it complain to *me* about them? More importantly, how can I stop IntelliJ from doing this? I did not find anything in the settings. – Martin Geisse Jun 09 '23 at 11:16
  • What do you mean by complaining? It's giving you a warning, so you can prevent the `NullPointerException` you've already identified. IDEs are supposed to help you, that's what it's doing. – Jorn Jun 09 '23 at 11:21
  • But IntelliJ is not helping, it is producing false positives based on the annotations it should not have added in the first place. The above code is a simplified example to reproduce the problem, based on the netiquette convention to "provide a minimal example that demonstrates the problem". In my actual code, IntelliJ is placing these annotations in such a way that the unit tests, which should check that the method under test correctly throws a NPE when passing null, are littered with warnings about passing null. I mean, how else are you supposed to write such a test? – Martin Geisse Jun 09 '23 at 11:28
  • 1
    @MartinGeisse Umm, if you embrace these annotations and use them correctly everywhere, you wouldn't need to write those tests. You'd just need to write tests for where these annotations *can't* help. Isn't that awesome? – Sweeper Jun 09 '23 at 11:30
  • That isn't awesome because it is false. NotNull annotations produce compile-time hints, nothing more. They are not rigorously verified at compile-time, nor at class-loading time, nor at run-time. It is trivial to violate them at run-time. Hence unit tests are absolutely called for if I want to write high-quality code. – Martin Geisse Jun 09 '23 at 11:34
  • @MartinGeisse You misunderstand me. "It is trivial to violate them at run-time" Then test those "trivial" ways to violate them, instead of testing something that can be caught at compile time like `foo(null)`. – Sweeper Jun 09 '23 at 11:37
  • Are you suggesting in writing a unit test in a more-complex-than necessary way just to silence a static code analysis? The class under test is defined to throw an NPE when passed null, even in cases when the argument is otherwise ignored, so a unit test would have to test that because it *can* be violated at run-time. If your argument is that "this only happens if there is a bug in the calling class" then yes, that's the point: Bugs happen, so the class-under-test is defined in such a way to limit the effect, and that behavior should be tested. – Martin Geisse Jun 09 '23 at 11:42
  • In that case, you could just turn off the IntelliJ feature... That's putting the cart before the horse, but you can do if if you really want to. – Jorn Jun 09 '23 at 11:43
  • Now, your argument would be valid if such a bug in the calling class is rigorously prevented by the language, such as not being able to pass an int for a String, then the need for a unit test would vanish. But this is not the case because, as I said, NotNull is just a hint. – Martin Geisse Jun 09 '23 at 11:44
  • I would really like to turn of this "feature", but as written below, I don't know how. There seems to be only a switch to turn off analysis of NotNull annotations in general, i.e. ignoring NotNull annotations I have actually placed in my code. But there doesn't seem to be a switch to prevent IntelliJ from conjuring up its own annotations. – Martin Geisse Jun 09 '23 at 11:46
  • 1
    In the end, IntelliJ is right in that your code will break when you pass `null` and produces a warning when you pass `null`. It could be worse, e.g. a developer could be obsessed with turning off this justified warning, for incomprehensible reasons. – Holger Jun 09 '23 at 14:45

1 Answers1

2

These are annotations inferred by IntelliJ IDEA. The IDE sees that you are doing value.length(), so it infers that value cannot be null. See also the blog post that introduced this feature.

You should be able to see a gutter icon looking like a "@". If you hover over it, it will show you want annotations are inferred:

enter image description here

Notice that there is also @Contract in addition to @NotNull. See this post for more about @Contract.

If you don't see this, go to Settings -> Editor -> General -> Gutter Icons and turn them on. There are "Inferred nullability annotations" and "Inferred contract annotations".

You can inspect what the actual annotation types of these inferred annotations are, by going into Settings -> Editor -> Inspections -> Java -> Probable bugs -> Nullability and data flow problems,

enter image description here

Go to the "Options" section on the right, and you'll see a "Configure Annotations" button. Note that you may need to scroll down.

enter image description here

Upon clicking the button, you can see and choose the fully-qualified name for the nullable annotations.

enter image description here

IntelliJ supports such annotations from many different libraries. If you don't have any installed, you'll still have the built-in org.jetbrains.annotations.NotNull.

Also in the Inspections section of the settings, you can disable/enable the reporting of warnings such as the one that you're getting.

enter image description here

See also the IntelliJ docs on this.

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • Thanks for the information. Wouldn't that checkbox also disable warnings for NotNull which are actually in the code? To clarify: Getting a warning about a violation of NotNull is perfectly fine for me, especially for annotations that I have placed in the code. What I do not understand at all is why these annotations are supposed to be there in the first place, and how to prevent them from appearing. – Martin Geisse Jun 09 '23 at 11:31
  • @MartinGeisse Yes it will disable warnings on explicit `@NotNull`s too. Why do you have them explicit in the first place? "why these annotations are supposed to be there" Because that is how the IDE is designed. See [this](https://meta.stackoverflow.com/a/323382/5133585) first and clarify your question. – Sweeper Jun 09 '23 at 11:46
  • @MartinGeisse Bottom line is: you either write everything without these annotations, in which case turning the related inspections off will silence the warnings. Or, you write everything with nullable annotations and have the warnings warn you. Yes, the annotations are only compile time checks and isn't guaranteed to be safe, but as I said in another comment, *those bypasses* are what you should be testing. – Sweeper Jun 09 '23 at 11:49
  • As said above, turning on NotNull warnings is fine for me. This still didn't doesn't answer the core question: How can I make IntelliJ process the code I have written, and not the code it wants to believe I have written? – Martin Geisse Jun 09 '23 at 11:53
  • @MartinGeisse I don't think that is an option right now. You can suppress the inspection for specific lines by adding `//noinspection DataFlowIssue` before the line, or suppress it for the whole class/method by annotating `@SuppressWarnings("DataFlowIssue")`. That said, I don't recommend doing this. – Sweeper Jun 09 '23 at 12:16
  • @MartinGeisse Also, note that "How can I make IntelliJ process the code I have written, and not the code it wants to believe I have written?" is basically a duplicate of [this](https://stackoverflow.com/q/65191557/5133585), and totally different from what you have asked in your post body, which is mainly about what the annotation is, and how this annotation is added. If you have a different problem, please post a new question and explain why it isn't a duplicate. – Sweeper Jun 09 '23 at 12:20
  • I agree that "how to fix" was not part of the original question, so I'll mark your answer as the correct one. I'll watch the question you linked in case this is changed in IntelliJ. Any reader who has the same problem may also be interested in the fact that you can silence this warning "in tests only", which may or may not be more targeted than silencing individual lines. – Martin Geisse Jun 09 '23 at 12:34