diff --git a/java/java-impl/resources/META-INF/JavaPlugin.xml b/java/java-impl/resources/META-INF/JavaPlugin.xml
index 89bf3ff454e6..c9f41d6cd287 100644
--- a/java/java-impl/resources/META-INF/JavaPlugin.xml
+++ b/java/java-impl/resources/META-INF/JavaPlugin.xml
@@ -1291,7 +1291,8 @@
group="ANNOTATIONS_GROUP"
providerId="java.annotation.hints"
bundle="messages.JavaBundle"
- nameKey="settings.inlay.java.annotations">
+ nameKey="settings.inlay.java.annotations"
+ descriptionKey="settings.inlay.java.annotations.description">
-
+
-
diff --git a/java/java-impl/resources/inlayProviders/java.annotation.hints/preview.java b/java/java-impl/resources/inlayProviders/java.annotation.hints/preview.java
index ca8452da4e14..122e40aec176 100644
--- a/java/java-impl/resources/inlayProviders/java.annotation.hints/preview.java
+++ b/java/java-impl/resources/inlayProviders/java.annotation.hints/preview.java
@@ -1,6 +1,7 @@
/*<# block fmt:fontSize=ABitSmallerThanInEditor,marginPadding=OnlyPadding #>*/
+/*<# @Deprecated #>*/
class Test {
- public int getSize(/*<# @NotNull #>*/String s) {
+ public int getSize(String/*<# ! #>*/ s) {
return s.length();
}
}
\ No newline at end of file
diff --git a/java/java-impl/resources/inlayProviders/java.annotation.hints/showExternal.java b/java/java-impl/resources/inlayProviders/java.annotation.hints/showExternal.java
index 81342bbb7005..122e40aec176 100644
--- a/java/java-impl/resources/inlayProviders/java.annotation.hints/showExternal.java
+++ b/java/java-impl/resources/inlayProviders/java.annotation.hints/showExternal.java
@@ -1,5 +1,7 @@
/*<# block fmt:fontSize=ABitSmallerThanInEditor,marginPadding=OnlyPadding #>*/
+/*<# @Deprecated #>*/
class Test {
- /*<# block [@Deprecated] [@NotNull] #>*/
- public void perform() {}
+ public int getSize(String/*<# ! #>*/ s) {
+ return s.length();
+ }
}
\ No newline at end of file
diff --git a/java/java-impl/resources/inlayProviders/java.annotation.hints/showInferred.java b/java/java-impl/resources/inlayProviders/java.annotation.hints/showInferred.java
index ca8452da4e14..df47515305c2 100644
--- a/java/java-impl/resources/inlayProviders/java.annotation.hints/showInferred.java
+++ b/java/java-impl/resources/inlayProviders/java.annotation.hints/showInferred.java
@@ -1,6 +1,8 @@
/*<# block fmt:fontSize=ABitSmallerThanInEditor,marginPadding=OnlyPadding #>*/
class Test {
- public int getSize(/*<# @NotNull #>*/String s) {
- return s.length();
+ /*<# @Contract(value = "!null -> param1", pure = true) #>*/
+ public final String/*<# ! #>*/ bar(String x) {
+ if (x != null) return x;
+ return "|----------------------------|";
}
}
\ No newline at end of file
diff --git a/java/java-impl/src/com/intellij/codeInsight/hints/AnnotationInlayProvider.kt b/java/java-impl/src/com/intellij/codeInsight/hints/AnnotationInlayProvider.kt
index 7667ad459fde..04cc229b5af5 100644
--- a/java/java-impl/src/com/intellij/codeInsight/hints/AnnotationInlayProvider.kt
+++ b/java/java-impl/src/com/intellij/codeInsight/hints/AnnotationInlayProvider.kt
@@ -1,11 +1,7 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInsight.hints
-import com.intellij.codeInsight.AnnotationUtil
-import com.intellij.codeInsight.ExternalAnnotationsManager
-import com.intellij.codeInsight.InferredAnnotationsManager
-import com.intellij.codeInsight.MakeInferredAnnotationExplicit
-import com.intellij.codeInsight.NullableNotNullManager
+import com.intellij.codeInsight.*
import com.intellij.codeInsight.hints.declarative.*
import com.intellij.codeInsight.hints.declarative.InlayHintsCollector
import com.intellij.codeInsight.hints.declarative.InlayHintsProvider
@@ -21,7 +17,6 @@ import com.intellij.openapi.application.WriteAction
import com.intellij.openapi.editor.BlockInlayPriority
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
-import com.intellij.openapi.util.registry.Registry
import com.intellij.pom.java.JavaFeature
import com.intellij.psi.*
import com.intellij.psi.impl.source.PsiClassReferenceType
@@ -121,7 +116,7 @@ public class AnnotationInlayProvider : InlayHintsProvider {
(shownAnnotations.add(nameReferenceElement.qualifiedName) || JavaDocInfoGenerator.isRepeatableAnnotationType(annotation))) {
val hintPos = (if (isTypeAnno(annotation)) typeHintPos else modifierListHintPos) ?: return
val suffixText = getTypeSuffixText(annotation)
- if (suffixText != null && Registry.`is`("java.exclamation.mark.inlay.for.inferred.and.external.notnull.annotations")) {
+ if (suffixText != null && AnnotationInlaySettings.getInstance().shortenNotNull) {
if (!shownAnnotations.add(suffixText)) return // to prevent duplicates when external and inferred annotations use different @NotNull classes
val suffixOffset = calculateSuffixOffset(element)
sink.addPresentation(InlineInlayPosition(suffixOffset, false), inlayPayloads,
@@ -212,7 +207,7 @@ public class AnnotationInlayProvider : InlayHintsProvider {
anchor: PsiElement,
) {
val suffixText = getTypeSuffixText(annotation)
- if (suffixText != null && Registry.`is`("java.exclamation.mark.inlay.for.inferred.and.external.notnull.annotations")) {
+ if (suffixText != null && AnnotationInlaySettings.getInstance().shortenNotNull) {
val offset = calculateSuffixOffset(anchor)
sink.addPresentation(InlineInlayPosition(offset, false), TYPE_ANNOTATION_PAYLOADS,
hintFormat = HintFormat.default, tooltip = "@${annotation.nameReferenceElement?.referenceName}") {
diff --git a/java/java-impl/src/com/intellij/codeInsight/hints/AnnotationInlaySettings.java b/java/java-impl/src/com/intellij/codeInsight/hints/AnnotationInlaySettings.java
new file mode 100644
index 000000000000..66c54f612a77
--- /dev/null
+++ b/java/java-impl/src/com/intellij/codeInsight/hints/AnnotationInlaySettings.java
@@ -0,0 +1,33 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.hints;
+
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.components.*;
+import com.intellij.util.xmlb.XmlSerializerUtil;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Bas Leijdekkers
+ */
+@ApiStatus.Internal
+@Service(Service.Level.APP)
+@State(name = "AnnotationInlaySettings", storages = @Storage("editor.xml"), category = SettingsCategory.CODE)
+public final class AnnotationInlaySettings implements PersistentStateComponent {
+
+ public boolean shortenNotNull = true;
+
+ public static @NotNull AnnotationInlaySettings getInstance() {
+ return ApplicationManager.getApplication().getService(AnnotationInlaySettings.class);
+ }
+
+ @Override
+ public @NotNull AnnotationInlaySettings getState() {
+ return this;
+ }
+
+ @Override
+ public void loadState(@NotNull AnnotationInlaySettings state) {
+ XmlSerializerUtil.copyBean(state, this);
+ }
+}
diff --git a/java/java-impl/src/com/intellij/codeInsight/hints/AnnotationInlaySettingsProvider.java b/java/java-impl/src/com/intellij/codeInsight/hints/AnnotationInlaySettingsProvider.java
new file mode 100644
index 000000000000..2a1b63021e48
--- /dev/null
+++ b/java/java-impl/src/com/intellij/codeInsight/hints/AnnotationInlaySettingsProvider.java
@@ -0,0 +1,48 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.hints;
+
+import com.intellij.codeInsight.hints.declarative.InlayHintsCustomSettingsProvider;
+import com.intellij.java.JavaBundle;
+import com.intellij.lang.Language;
+import com.intellij.openapi.project.Project;
+import com.intellij.ui.components.JBCheckBox;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+
+/**
+ * @author Bas Leijdekkers
+ */
+final class AnnotationInlaySettingsProvider implements InlayHintsCustomSettingsProvider {
+
+ private boolean myShortenNotNull;
+
+ AnnotationInlaySettingsProvider() {
+ myShortenNotNull = AnnotationInlaySettings.getInstance().shortenNotNull;
+ }
+
+ @Override
+ public @NotNull JComponent createComponent(@NotNull Project project, @NotNull Language language) {
+ final JBCheckBox myCheckBox = new JBCheckBox(JavaBundle.message("settings.inlay.java.shortened.notnull.annotation"), myShortenNotNull);
+ myCheckBox.addItemListener(e -> myShortenNotNull = myCheckBox.isSelected());
+ return myCheckBox;
+ }
+
+ @Override
+ public boolean isDifferentFrom(@NotNull Project project, Boolean shortenNotNull) {
+ return myShortenNotNull != shortenNotNull.booleanValue();
+ }
+
+ @Override
+ public Boolean getSettingsCopy() {
+ return myShortenNotNull;
+ }
+
+ @Override
+ public void persistSettings(@NotNull Project project, Boolean shortenNotNull, @NotNull Language language) {
+ AnnotationInlaySettings.getInstance().shortenNotNull = shortenNotNull.booleanValue();
+ }
+
+ @Override
+ public void putSettings(@NotNull Project project, Boolean settings, @NotNull Language language) {}
+}
diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/inlays/AnnotationHintsTest.kt b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/inlays/AnnotationHintsTest.kt
index 95572af3ea05..c474a2c816f0 100644
--- a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/inlays/AnnotationHintsTest.kt
+++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/inlays/AnnotationHintsTest.kt
@@ -3,7 +3,7 @@ package com.intellij.java.codeInsight.daemon.inlays
import com.intellij.JavaTestUtil
import com.intellij.codeInsight.hints.AnnotationInlayProvider
-import com.intellij.openapi.util.registry.Registry
+import com.intellij.codeInsight.hints.AnnotationInlaySettings
import com.intellij.pom.java.LanguageLevel
import com.intellij.psi.CommonClassNames
import com.intellij.psi.JavaPsiFacade
@@ -279,16 +279,19 @@ public final class Optional*<# @NotNull #>*/T> {
}
}
"""
- val registry = Registry.get("java.exclamation.mark.inlay.for.inferred.and.external.notnull.annotations")
- val old = registry.asBoolean()
- registry.setValue(true)
- doTestProviderWithConfigured(myFixture.editor.document.text,
- convert(expected),
- AnnotationInlayProvider(),
- enabledOptions = mapOf(AnnotationInlayProvider.SHOW_INFERRED to false,
- AnnotationInlayProvider.SHOW_EXTERNAL to true),
- testMode = ProviderTestMode.SIMPLE)
- registry.setValue(old)
+ val settings = AnnotationInlaySettings.getInstance()
+ val old = settings.shortenNotNull
+ settings.shortenNotNull = true
+ try {
+ doTestProviderWithConfigured(myFixture.editor.document.text,
+ convert(expected),
+ AnnotationInlayProvider(),
+ enabledOptions = mapOf(AnnotationInlayProvider.SHOW_INFERRED to false,
+ AnnotationInlayProvider.SHOW_EXTERNAL to true),
+ testMode = ProviderTestMode.SIMPLE)
+ } finally {
+ settings.shortenNotNull = old
+ }
}
private fun convert(text: String): String{
@@ -315,24 +318,27 @@ public final class Optional*<# @NotNull #>*/T> {
@Language("JAVA") nullnessMarkerText: String,
enabledOptions: Map = mapOf("showInferred" to true, "showExternal" to true),
) {
- val registry = Registry.get("java.exclamation.mark.inlay.for.inferred.and.external.notnull.annotations")
- val old = registry.asBoolean()
- registry.setValue(false)
- doTestProvider(
- "test.java",
- annotatedText,
- AnnotationInlayProvider(),
- enabledOptions,
- testMode = ProviderTestMode.SIMPLE,
- )
- registry.setValue(true)
- doTestProvider(
- "test.java",
- nullnessMarkerText,
- AnnotationInlayProvider(),
- enabledOptions,
- testMode = ProviderTestMode.SIMPLE,
- )
- registry.setValue(old)
+ val settings = AnnotationInlaySettings.getInstance()
+ val old = settings.shortenNotNull
+ settings.shortenNotNull = false
+ try {
+ doTestProvider(
+ "test.java",
+ annotatedText,
+ AnnotationInlayProvider(),
+ enabledOptions,
+ testMode = ProviderTestMode.SIMPLE,
+ )
+ settings.shortenNotNull = true
+ doTestProvider(
+ "test.java",
+ nullnessMarkerText,
+ AnnotationInlayProvider(),
+ enabledOptions,
+ testMode = ProviderTestMode.SIMPLE,
+ )
+ } finally {
+ settings.shortenNotNull = old
+ }
}
}
\ No newline at end of file
diff --git a/java/openapi/resources/messages/JavaBundle.properties b/java/openapi/resources/messages/JavaBundle.properties
index e7ba9429b351..3f91202f7787 100644
--- a/java/openapi/resources/messages/JavaBundle.properties
+++ b/java/openapi/resources/messages/JavaBundle.properties
@@ -1215,12 +1215,14 @@ section.title.inspection.suspicious.names.ignore.methods=Ignore methods:
set.language.level=Set language level
set.language.level.to.0=Set language level to {0}
settings.completion.ml.java.display.name=Java
-settings.inlay.java.annotations=Annotations
+settings.inlay.java.annotations=Java
+settings.inlay.java.annotations.description=Show automatically generated annotations and annotations stored externally from your Java code.
settings.inlay.java.builder.like.methods=Builder-like methods
settings.inlay.java.complex.expressions.binary.functional.array.access.and.other=Complex expressions as arguments
settings.inlay.java.enum.constants=Enum constants
settings.inlay.java.external.annotations=External annotations
settings.inlay.java.inferred.annotations=Inferred annotations
+settings.inlay.java.shortened.notnull.annotation=Shorten @NotNull annotations to !-suffix
settings.inlay.java.inheritors=Inheritors
settings.inlay.java.implicit.types.local=Implicit types
settings.inlay.java.implicit.types.local.description=Local variables declared with the var keyword when the inferred type may not be clear from the right part of the assignment, for example, when using a factory method.