I’ve used the JetBrains nullability and contract annotations extensively in my plugin project over the years. Ever since the relatively recent change to support – and even prefer – the JSpecify annotations, I feel like I’m constantly wrestling with those types of annotations. Often when a base class or method uses JetBrains’ @NotNull/@Nullable, the JSpecify annotations are used when implementing/overriding that base declaration. Similar with extract refactorings against signatures that specify nullability on the return type. Sometimes I’m even seeing the IDE use Android @Nullable annotations with a fully-qualified name to avoid the conflict with the JetBrains version!
Is there any way to tell the IDE to use the JetBrains annotations by default and only use the JSpecify annotations if/when those are exactly what was used on the original declaration? It just feels like this is suddenly a mess that I’m constantly having to fight…
Thanks for raising this. There is a setting that controls which nullability annotations IntelliJ IDEA uses for code generation.
You can open it via Settings | Editor | Inspections | Probable bugs | Nullability and data flow problems | Configure Annotations. In that dialog, IDEA lets you choose which @Nullable / @NotNull annotations are used for code generation, and the selected ones are marked explicitly in the list (Annotations, Nullable/NotNull configuration dialog).
So if you want IDEA to generate JetBrains annotations by default, try selecting:
as the annotations used for code generation.
That said, IDEA now recognizes JSpecify as a first-class nullability framework, alongside JetBrains annotations (What’s New in IntelliJ IDEA 2025.2, Annotations). So if you still see JSpecify (or even Android annotations) being inserted in override/implement or refactoring scenarios after changing the generation setting, that sounds like a separate behavior — and possibly a bug or at least something we should investigate.
If you can share a small reproducible example (for example, a base declaration with JetBrains annotations and the exact action that inserts JSpecify/Android annotations), that would help confirm whether this is expected or not.
Thanks. That’s what I was hoping to find. I’ve moved the JetBrains annotations to the top of the respective tabs.
IMO those should not be listed alphabetically by default since “The topmost annotation that is available will be used for code generation.” Because I have the Android plugin installed – for a totally different reason – that automatically causes the Android annotations to be used when I’m not actually doing Android dev.
I guess they’re not quite alphabetical either because the JSpecify annotations are ordered before the JetBrains annotations by default.
I’m assuming having those two ordered before the JetBrains annotations – and having the Android plugin installed/enabled – would be why I’ve been seeing the behavior I’ve been seeing.