java.lang.NoClassDefFoundError: org/sonar/java/checks/helpers/ReassignmentFinder

Must-share information (formatted with Markdown):

  • which versions are you using (SonarQube, Scanner, Plugin, and any relevant extension)
    SonarQube 9.5, Scanner 4.7, Java custom rule plugin
  • what are you trying to achieve
    Trying to create a custom rule
  • what have you tried so far to achieve this
    not much

Found the following error during scanner Execution

ERROR: Error during SonarScanner execution
java.lang.NoClassDefFoundError: org/sonar/java/checks/helpers/ReassignmentFinder
        at org.sonar.samples.java.checks.xyzSQLInjectionCheckCustomRule.visitNode(xyzSQLInjectionCheckCustomRule.java:55)
        at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.lambda$visit$6(VisitorsBridge.java:452)
        at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.lambda$forEach$9(VisitorsBridge.java:468)
        at org.sonar.java.model.VisitorsBridge.runScanner(VisitorsBridge.java:265)
        at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.forEach(VisitorsBridge.java:468)
        at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visit(VisitorsBridge.java:454)
        at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visitChildren(VisitorsBridge.java:438)
        at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visit(VisitorsBridge.java:458)
        at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visitChildren(VisitorsBridge.java:438)
        at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visit(VisitorsBridge.java:458)
        at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visitChildren(VisitorsBridge.java:438)
        at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visit(VisitorsBridge.java:458)
        at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visitChildren(VisitorsBridge.java:438)
        at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visit(VisitorsBridge.java:458)
        at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visitChildren(VisitorsBridge.java:438)
        at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visit(VisitorsBridge.java:458)
        at org.sonar.java.model.VisitorsBridge$IssuableSubscription

Let me know how to fix it

Thanks
vsk

Hi vsk,

The current version of SonarQube is 9.7. Could you upgrade and see if this is reproducible?

 
Thx,
Ann

Hi,
Yes, I tried with the latest version of SonarQube 9.7. But I am still getting the same issue.
Please guide me how to fix this issues.

Thanks

Hi,

I searched this (NoClassDeffFoundError during SonarScanner execution - #2 by ganncamp) old thread and couldn’t find an answer that is why i created a new thread here.

If there was a solution for the old thread please share it so that I can go through to fix my issue.

Thanks

Hi,

Thanks for confirming. It looks like you’re running into a problem with a custom rule. Can you share the code of the rule?

 
Ann

hi

package org.sonar.samples.java.checks;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import org.sonar.check.Rule;
import org.sonar.plugins.java.api.IssuableSubscriptionVisitor;
import org.sonar.plugins.java.api.JavaFileScannerContext;
import org.sonar.plugins.java.api.semantic.MethodMatchers;
import org.sonar.plugins.java.api.semantic.Symbol;
import org.sonar.plugins.java.api.tree.AssignmentExpressionTree;
import org.sonar.plugins.java.api.tree.ExpressionTree;
import org.sonar.plugins.java.api.tree.IdentifierTree;
import org.sonar.plugins.java.api.tree.MethodInvocationTree;
import org.sonar.plugins.java.api.tree.NewClassTree;
import org.sonar.plugins.java.api.tree.Tree;

import static org.sonar.java.checks.helpers.ReassignmentFinder.getInitializerOrExpression;
import static org.sonar.java.checks.helpers.ReassignmentFinder.getReassignments;
import static org.sonar.plugins.java.api.semantic.MethodMatchers.CONSTRUCTOR;

@Rule(key = "S2077-Custom")
public class SQLInjectionCustomCheck extends IssuableSubscriptionVisitor{
	
	 private static final String JAVA_SQL_STATEMENT = "java.sql.Statement";
	  private static final String JAVA_SQL_CONNECTION = "java.sql.Connection";
	  private static final String SPRING_JDBC_OPERATIONS = "org.springframework.jdbc.core.JdbcOperations";
	  private static final String JAVA_SQL_CALLABLESTATEMENT = "java.sql.CallableStatement";

	  private static final MethodMatchers SQL_INJECTION_SUSPECTS = MethodMatchers.or(
			    MethodMatchers.create()
			      .ofSubTypes("org.hibernate.Session")
			      .names("createQuery", "createSQLQuery")
			      .withAnyParameters()
			      .build(),
			    MethodMatchers.create()
			      .ofSubTypes(JAVA_SQL_STATEMENT)
			      .names("executeQuery", "execute", "executeUpdate", "executeLargeUpdate", "addBatch")
			      .withAnyParameters()
			      .build(),
				MethodMatchers.create()
			      .ofSubTypes(JAVA_SQL_CALLABLESTATEMENT)
			      .names("executeQuery", "createCallableStatement", "execute", "executeUpdate", "executeLargeUpdate", "addBatch")
			      .withAnyParameters()
			      .build(),
			    MethodMatchers.create()
			      .ofSubTypes(JAVA_SQL_CONNECTION)
			      .names("prepareStatement","createCallableStatement","prepareCall", "nativeSQL")
			      .withAnyParameters()
			      .build(),
			    MethodMatchers.create()
			      .ofTypes("javax.persistence.EntityManager")
			      .names("createNativeQuery", "createQuery")
			      .withAnyParameters()
			      .build(),
			    MethodMatchers.create().ofSubTypes(SPRING_JDBC_OPERATIONS)
			      .names("batchUpdate", "execute", "query", "queryForList", "queryForMap", "queryForObject",
			        "queryForRowSet", "queryForInt", "queryForLong", "update")
			      .withAnyParameters()
			      .build(),
			    MethodMatchers.create()
			      .ofTypes("org.springframework.jdbc.core.PreparedStatementCreatorFactory")
			      .names(CONSTRUCTOR, "newPreparedStatementCreator")
			      .withAnyParameters()
			      .build(),
			    MethodMatchers.create()
			      .ofSubTypes("javax.jdo.PersistenceManager")
			      .names("newQuery")
			      .withAnyParameters()
			      .build(),
			    MethodMatchers.create()
			      .ofSubTypes("javax.jdo.Query")
			      .names("setFilter", "setGrouping")
			      .withAnyParameters()
			      .build());
			  
			  private static final String MAIN_MESSAGE = "Make sure using a dynamically formatted SQL query is safe here.";

			  @Override
			  public List<Tree.Kind> nodesToVisit() {
			    return Arrays.asList(Tree.Kind.METHOD_INVOCATION, Tree.Kind.NEW_CLASS);
			  }

			  @Override
			  public void visitNode(Tree tree) {
			    if (anyMatch(tree)) {
			      Optional<ExpressionTree> sqlStringArg = arguments(tree)
			        .filter(arg -> arg.symbolType().is("java.lang.String"))
			        .findFirst();

			      if (sqlStringArg.isPresent()) {
			        ExpressionTree sqlArg = sqlStringArg.get();
			        if (isDynamicConcatenation(sqlArg)) {
			          reportIssue(sqlArg, MAIN_MESSAGE);
			        } else if (sqlArg.is(Tree.Kind.IDENTIFIER)) {
			          IdentifierTree identifierTree = (IdentifierTree) sqlArg;
			          Symbol symbol = identifierTree.symbol();
			          ExpressionTree initializerOrExpression = getInitializerOrExpression(symbol.declaration());
			          List<AssignmentExpressionTree> reassignments = getReassignments(symbol.owner().declaration(), symbol.usages());

			          if ((initializerOrExpression != null && isDynamicConcatenation(initializerOrExpression)) ||
			            reassignments.stream().anyMatch(SQLInjectionCustomCheck::isDynamicPlusAssignment)) {
			            reportIssue(sqlArg, MAIN_MESSAGE, secondaryLocations(initializerOrExpression, reassignments, identifierTree.name()), null);
			          }
			        }
			      }
			    }
			  }

			  private static List<JavaFileScannerContext.Location> secondaryLocations(@Nullable ExpressionTree initializerOrExpression,
			    List<AssignmentExpressionTree> reassignments,
			    String identifierName) {
			    List<JavaFileScannerContext.Location> secondaryLocations = reassignments.stream()
			      .map(assignment -> new JavaFileScannerContext.Location(String.format("SQL Query is assigned to '%s' -Custom", getVariableName(assignment)), assignment.expression()))
			      .collect(Collectors.toList());

			    if (initializerOrExpression != null) {
			      secondaryLocations.add(new JavaFileScannerContext.Location(String.format("SQL Query is dynamically formatted and assigned to '%s' -Custom",
			        identifierName),
			        initializerOrExpression));
			    }
			    return secondaryLocations;
			  }
			  
			  private static String getVariableName(AssignmentExpressionTree assignment) {
			    ExpressionTree variable = assignment.variable();
			    return ((IdentifierTree) variable).name();
			  }

			  private static Stream<ExpressionTree> arguments(Tree methodTree) {
			    if (methodTree.is(Tree.Kind.METHOD_INVOCATION)) {
			      return ((MethodInvocationTree) methodTree).arguments().stream();
			    }
			    if (methodTree.is(Tree.Kind.NEW_CLASS)) {
			      return ((NewClassTree) methodTree).arguments().stream();
			    }
			    return Stream.empty();
			  }

			  private static boolean anyMatch(Tree tree) {
			    if (!hasArguments(tree)) {
			      return false;
			    }
			    if (tree.is(Tree.Kind.NEW_CLASS)) {
			      return SQL_INJECTION_SUSPECTS.matches((NewClassTree) tree);
			    }
			    if (tree.is(Tree.Kind.METHOD_INVOCATION)) {
			      return SQL_INJECTION_SUSPECTS.matches((MethodInvocationTree) tree);
			    }
			    return false;
			  }

			  private static boolean hasArguments(Tree tree) {
			    return arguments(tree).findAny().isPresent();
			  }

			  private static boolean isDynamicPlusAssignment(ExpressionTree arg) {
			    return arg.is(Tree.Kind.PLUS_ASSIGNMENT) && !((AssignmentExpressionTree) arg).expression().asConstant().isPresent();
			  }

			  private static boolean isDynamicConcatenation(ExpressionTree arg) {
			    return arg.is(Tree.Kind.PLUS) && !arg.asConstant().isPresent();
			  }

}

please let me know

Hello @shiva_sq ,

Did you read the tutorial on how to write custom rules? (you can find it here). In particular, please have a look at the section “What you can use and what you can’t”.

What you are trying to achieve is not possible. You can not use sonar-java helper classes inside custom rules plugins. While your unit tests might be passing, this code is not available at runtime. This leads to the errors you face here. If you desperately need this code, you will have to duplicate it in your custom rules. It will also be your responsibility to make it evolves over time if it changes on the analyzer side.

Cheers,
Michael