From c01967a6b1c80c135c5c1b1c9fbf18bb510bf08d Mon Sep 17 00:00:00 2001 From: Romain Brenguier Date: Mon, 12 Oct 2026 13:41:43 +0200 Subject: [PATCH 1/4] SONARJAVA-7152 S1695: Update issue message to suggest Objects.requireNonNull() Co-Authored-By: Claude Opus 5.5 (1M context) --- .../default/src/main/java/checks/NPEThrowCheckSample.java | 6 +++--- .../src/main/java/org/sonar/java/checks/NPEThrowCheck.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/java-checks-test-sources/default/src/main/java/checks/NPEThrowCheckSample.java b/java-checks-test-sources/default/src/main/java/checks/NPEThrowCheckSample.java index 44e52d6da24..a11f58c3138 100644 --- a/java-checks-test-sources/default/src/main/java/checks/NPEThrowCheckSample.java +++ b/java-checks-test-sources/default/src/main/java/checks/NPEThrowCheckSample.java @@ -1,16 +1,16 @@ package checks; class NPEThrowCheckSample { - void foo() throws NullPointerException { // Noncompliant {{Throw some other exception here, such as "IllegalArgumentException".}} + void foo() throws NullPointerException { // Noncompliant {{Use Objects.requireNonNull() instead of explicitly throwing NullPointerException.}} // ^^^^^^^^^^^^^^^^^^^^ } void bar() { throw new - NullPointerException // Noncompliant {{Throw some other exception here, such as "IllegalArgumentException".}} + NullPointerException // Noncompliant {{Use Objects.requireNonNull() instead of explicitly throwing NullPointerException.}} (); } void baz() { - throw new java.lang.NullPointerException(); // Noncompliant {{Throw some other exception here, such as "IllegalArgumentException".}} + throw new java.lang.NullPointerException(); // Noncompliant {{Use Objects.requireNonNull() instead of explicitly throwing NullPointerException.}} // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ } void qix() throws IllegalArgumentException { diff --git a/java-checks/src/main/java/org/sonar/java/checks/NPEThrowCheck.java b/java-checks/src/main/java/org/sonar/java/checks/NPEThrowCheck.java index 07cc5da291e..dea76493a6d 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/NPEThrowCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/NPEThrowCheck.java @@ -50,7 +50,7 @@ public void visitNode(Tree tree) { private void raiseIssueOnNpe(Tree tree, Type type) { if (type.is("java.lang.NullPointerException")) { - reportIssue(treeAtFault(tree), "Throw some other exception here, such as \"IllegalArgumentException\"."); + reportIssue(treeAtFault(tree), "Use Objects.requireNonNull() instead of explicitly throwing NullPointerException."); } } From 09089d1c9b5fdd2072d1796b377adb6bcf787bcf Mon Sep 17 00:00:00 2001 From: Romain Brenguier Date: Tue, 13 Oct 2026 09:26:39 +0200 Subject: [PATCH 2/4] SONARJAVA-7152 S1695: Use dedicated message for throws clauses and align rule description Co-Authored-By: Claude Opus 5.5 (1M context) --- .../main/java/checks/NPEThrowCheckSample.java | 2 +- .../org/sonar/java/checks/NPEThrowCheck.java | 8 ++++---- .../org/sonar/l10n/java/rules/java/S1695.html | 17 ++++++++++------- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/java-checks-test-sources/default/src/main/java/checks/NPEThrowCheckSample.java b/java-checks-test-sources/default/src/main/java/checks/NPEThrowCheckSample.java index a11f58c3138..b935f98c637 100644 --- a/java-checks-test-sources/default/src/main/java/checks/NPEThrowCheckSample.java +++ b/java-checks-test-sources/default/src/main/java/checks/NPEThrowCheckSample.java @@ -1,7 +1,7 @@ package checks; class NPEThrowCheckSample { - void foo() throws NullPointerException { // Noncompliant {{Use Objects.requireNonNull() instead of explicitly throwing NullPointerException.}} + void foo() throws NullPointerException { // Noncompliant {{Remove NullPointerException from the throws clause.}} // ^^^^^^^^^^^^^^^^^^^^ } void bar() { diff --git a/java-checks/src/main/java/org/sonar/java/checks/NPEThrowCheck.java b/java-checks/src/main/java/org/sonar/java/checks/NPEThrowCheck.java index dea76493a6d..46892888181 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/NPEThrowCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/NPEThrowCheck.java @@ -40,17 +40,17 @@ public List nodesToVisit() { public void visitNode(Tree tree) { if (tree.is(Tree.Kind.THROW_STATEMENT)) { ExpressionTree expressionTree = ((ThrowStatementTree) tree).expression(); - raiseIssueOnNpe(expressionTree, expressionTree.symbolType()); + raiseIssueOnNpe(expressionTree, expressionTree.symbolType(), "Use Objects.requireNonNull() instead of explicitly throwing NullPointerException."); } else { for (TypeTree throwClause : ((MethodTree) tree).throwsClauses()) { - raiseIssueOnNpe(throwClause, throwClause.symbolType()); + raiseIssueOnNpe(throwClause, throwClause.symbolType(), "Remove NullPointerException from the throws clause."); } } } - private void raiseIssueOnNpe(Tree tree, Type type) { + private void raiseIssueOnNpe(Tree tree, Type type, String message) { if (type.is("java.lang.NullPointerException")) { - reportIssue(treeAtFault(tree), "Use Objects.requireNonNull() instead of explicitly throwing NullPointerException."); + reportIssue(treeAtFault(tree), message); } } diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S1695.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S1695.html index 2d6d90b6b8d..afd385fc30b 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S1695.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S1695.html @@ -1,20 +1,23 @@

Why is this an issue?

A NullPointerException should indicate that a null value was unexpectedly encountered. Good programming practice dictates that code is structured to avoid NPE’s.

-

Explicitly throwing NullPointerException forces a method’s callers to explicitly catch it, rather than coding to avoid it. Further, it -makes it difficult to distinguish between the unexpectedly-encountered null value and the condition which causes the method to purposely -throw an NPE.

-

If an NPE is being thrown to indicate that a parameter to the method should not have been null, use the @NotNull annotation -instead.

+

Explicitly throwing NullPointerException or declaring it in a throws clause suggests that callers should catch it, +rather than coding to avoid it. Since NullPointerException is an unchecked exception, declaring it in a throws clause is +unnecessary.

+

If an NPE is being thrown to indicate that a parameter to the method should not have been null, use Objects.requireNonNull() instead. +It makes the intent explicit and produces a consistent, descriptive error. Additionally, the parameter can be annotated with @NotNull to +document the contract and allow tools to detect violations.

Noncompliant code example

 public void doSomething (String aString) throws NullPointerException {
-     throw new NullPointerException();
+  if (aString == null) {
+    throw new NullPointerException();
+  }
 }
 

Compliant solution

 public void doSomething (@NotNull String aString) {
+  Objects.requireNonNull(aString, "aString must not be null");
 }
 
- From fd4ed7913a6747f8b0cc22a29d37cdd49fdaedb2 Mon Sep 17 00:00:00 2001 From: Romain Brenguier Date: Tue, 13 Oct 2026 09:29:53 +0200 Subject: [PATCH 3/4] SONARJAVA-7152 S1695: Revert rule description changes (handled in RSPEC PR #8333) Co-Authored-By: Claude Opus 5.5 (1M context) --- .../org/sonar/l10n/java/rules/java/S1695.html | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S1695.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S1695.html index afd385fc30b..2d6d90b6b8d 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S1695.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S1695.html @@ -1,23 +1,20 @@

Why is this an issue?

A NullPointerException should indicate that a null value was unexpectedly encountered. Good programming practice dictates that code is structured to avoid NPE’s.

-

Explicitly throwing NullPointerException or declaring it in a throws clause suggests that callers should catch it, -rather than coding to avoid it. Since NullPointerException is an unchecked exception, declaring it in a throws clause is -unnecessary.

-

If an NPE is being thrown to indicate that a parameter to the method should not have been null, use Objects.requireNonNull() instead. -It makes the intent explicit and produces a consistent, descriptive error. Additionally, the parameter can be annotated with @NotNull to -document the contract and allow tools to detect violations.

+

Explicitly throwing NullPointerException forces a method’s callers to explicitly catch it, rather than coding to avoid it. Further, it +makes it difficult to distinguish between the unexpectedly-encountered null value and the condition which causes the method to purposely +throw an NPE.

+

If an NPE is being thrown to indicate that a parameter to the method should not have been null, use the @NotNull annotation +instead.

Noncompliant code example

 public void doSomething (String aString) throws NullPointerException {
-  if (aString == null) {
-    throw new NullPointerException();
-  }
+     throw new NullPointerException();
 }
 

Compliant solution

 public void doSomething (@NotNull String aString) {
-  Objects.requireNonNull(aString, "aString must not be null");
 }
 
+ From 7eda71f0c0b98f14651d9e536568fbdd190ee605 Mon Sep 17 00:00:00 2001 From: Romain Brenguier Date: Tue, 13 Oct 2026 17:04:00 +0200 Subject: [PATCH 4/4] SONARJAVA-7152 S1695: Do not raise when thrown NullPointerException has a message argument Co-Authored-By: Claude Opus 5.5 (1M context) --- .../default/src/main/java/checks/NPEThrowCheckSample.java | 6 ++++++ .../src/main/java/org/sonar/java/checks/NPEThrowCheck.java | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/java-checks-test-sources/default/src/main/java/checks/NPEThrowCheckSample.java b/java-checks-test-sources/default/src/main/java/checks/NPEThrowCheckSample.java index b935f98c637..4aaf03c8d4a 100644 --- a/java-checks-test-sources/default/src/main/java/checks/NPEThrowCheckSample.java +++ b/java-checks-test-sources/default/src/main/java/checks/NPEThrowCheckSample.java @@ -13,6 +13,12 @@ void baz() { throw new java.lang.NullPointerException(); // Noncompliant {{Use Objects.requireNonNull() instead of explicitly throwing NullPointerException.}} // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ } + void withMessage(Object o) { + throw new NullPointerException("o must not be null"); // Compliant, a message is provided + } + void withComputedMessage(String name) { + throw new java.lang.NullPointerException(name + " must not be null"); // Compliant + } void qix() throws IllegalArgumentException { throw new IllegalArgumentException(); } diff --git a/java-checks/src/main/java/org/sonar/java/checks/NPEThrowCheck.java b/java-checks/src/main/java/org/sonar/java/checks/NPEThrowCheck.java index 46892888181..8896c28c5ac 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/NPEThrowCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/NPEThrowCheck.java @@ -40,6 +40,9 @@ public List nodesToVisit() { public void visitNode(Tree tree) { if (tree.is(Tree.Kind.THROW_STATEMENT)) { ExpressionTree expressionTree = ((ThrowStatementTree) tree).expression(); + if (hasArguments(expressionTree)) { + return; + } raiseIssueOnNpe(expressionTree, expressionTree.symbolType(), "Use Objects.requireNonNull() instead of explicitly throwing NullPointerException."); } else { for (TypeTree throwClause : ((MethodTree) tree).throwsClauses()) { @@ -54,6 +57,10 @@ private void raiseIssueOnNpe(Tree tree, Type type, String message) { } } + private static boolean hasArguments(ExpressionTree expressionTree) { + return expressionTree.is(Tree.Kind.NEW_CLASS) && !((NewClassTree) expressionTree).arguments().isEmpty(); + } + private static Tree treeAtFault(Tree tree) { return tree.is(Tree.Kind.NEW_CLASS) ? ((NewClassTree) tree).identifier() : tree; }