diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/AvoidThrowingNullPointerExceptionRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/AvoidThrowingNullPointerExceptionRule.java
new file mode 100644
index 0000000000..b1e4f541bd
--- /dev/null
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/AvoidThrowingNullPointerExceptionRule.java
@@ -0,0 +1,77 @@
+/**
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.rule.design;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression;
+import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody;
+import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
+import net.sourceforge.pmd.lang.java.ast.ASTThrowStatement;
+import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;
+import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
+
+/**
+ * Finds throw
statements containing NullPointerException
+ * instances as thrown values
+ *
+ * @author Mykhailo Palahuta
+ */
+public class AvoidThrowingNullPointerExceptionRule extends AbstractJavaRule {
+
+ @Override
+ public Object visit(ASTClassOrInterfaceBody node, Object data) {
+ if (bodyHasThrowNullPointerExceptionStatement(node)) {
+ addViolation(data, node);
+ }
+ return super.visit(node, data);
+ }
+
+ private boolean bodyHasThrowNullPointerExceptionStatement(ASTClassOrInterfaceBody body) {
+ List throwStatements = body.findDescendantsOfType(ASTThrowStatement.class);
+ List npeInstances = getNullPointerExceptionInstances(body);
+ for (ASTThrowStatement throwStatement : throwStatements) {
+ if (throwsNullPointerException(throwStatement, npeInstances)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private List getNullPointerExceptionInstances(ASTClassOrInterfaceBody body) {
+ List allocations = body.findDescendantsOfType(ASTAllocationExpression.class);
+ List npeInstances = new ArrayList<>();
+ for (ASTAllocationExpression allocation : allocations) {
+ if (allocatesNullPointerException(allocation)) {
+ String assignedVarName = getNameOfAssignedVariable(allocation);
+ npeInstances.add(assignedVarName);
+ }
+ }
+ return npeInstances;
+ }
+
+ private boolean allocatesNullPointerException(ASTAllocationExpression allocation) {
+ Class> allocatedType = getAllocatedInstanceType(allocation);
+ return allocatedType != null && NullPointerException.class.isAssignableFrom(allocatedType);
+ }
+
+ private Class> getAllocatedInstanceType(ASTAllocationExpression allocation) {
+ List allocatedTypes = allocation
+ .findDescendantsOfType(ASTClassOrInterfaceType.class);
+ return allocatedTypes.isEmpty() ? null : allocatedTypes.get(0).getType();
+ }
+
+ private String getNameOfAssignedVariable(ASTAllocationExpression allocation) {
+ List variableDeclarators = allocation.getParent()
+ .findDescendantsOfType(ASTVariableDeclarator.class);
+ return variableDeclarators.isEmpty() ? null : variableDeclarators.get(0).getName();
+ }
+
+ private boolean throwsNullPointerException(ASTThrowStatement throwStatement, List npeInstances) {
+ String thrownImage = throwStatement.getFirstClassOrInterfaceTypeImage();
+ return "NullPointerException".equals(thrownImage) || npeInstances.contains(thrownImage);
+ }
+}
diff --git a/pmd-java/src/main/resources/category/java/design.xml b/pmd-java/src/main/resources/category/java/design.xml
index 069b50e18a..eb5378dd33 100644
--- a/pmd-java/src/main/resources/category/java/design.xml
+++ b/pmd-java/src/main/resources/category/java/design.xml
@@ -200,7 +200,7 @@ public void bar() {
language="java"
since="1.8"
message="Avoid throwing null pointer exceptions."
- class="net.sourceforge.pmd.lang.rule.XPathRule"
+ class="net.sourceforge.pmd.lang.java.rule.design.AvoidThrowingNullPointerExceptionRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_design.html#avoidthrowingnullpointerexception">
1
-
-
-
-
-
-
-
-
-->
-
+
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/AvoidThrowingNullPointerException.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/AvoidThrowingNullPointerException.xml
index 843e2e09f9..80243f7c16 100644
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/AvoidThrowingNullPointerException.xml
+++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/AvoidThrowingNullPointerException.xml
@@ -12,6 +12,32 @@ public class Foo {
void bar() {
throw new NullPointerException();
}
+}
+ ]]>
+
+
+
+ no problems if NullPointerException is only instantiated but not thrown
+ 0
+
+
+
+
+ problem should be detected even if NullPointerException is stored in some intermediate variable
+ 1
+