Create java custom rule

I created a custom java rules based on https://docs.sonarqube.org/display/PLUG/Writing+Custom+Java+Rules+101
but when i put my java-custom-rules-1.0-SNAPSHOT.jar in SONARQUBE_HOME/Extension/plugins and i restart sonarQube i can’t see my new rules.
I create a JavaCustomRulesList.java like this:

package org.sonar.samples.java;

import java.util.List;

import org.sonar.api.internal.google.common.collect.ImmutableList;
import org.sonar.plugins.java.api.JavaCheck;
import org.sonar.samples.java.checks.MyFirstCustomCheck;
import org.sonar.samples.java.checks.MySecondCustomCheck;

public class JavaCustomRulesList {

	public static List<Class<? extends JavaCheck>> getJavaChecks() {
		  return ImmutableList.<Class<? extends JavaCheck>>builder()
		    // other rules...
				    .add(MySecondCustomCheck.class)
				    .add(MyFirstCustomCheck.class)
		    .build();
		}
}

MyFirstCustomCheck look like this:

@Rule(
  key = "MyFirstCustomCheck",
  name = "Return type and parameter of a method should not be the same",
  description = "For a method having a single parameter, the types of its return value and its parameter should never be the same.",
  priority = Priority.CRITICAL,
  tags = {"bug"})
public class MyFirstCustomCheck extends IssuableSubscriptionVisitor {
 
  @Override
  public List<Kind> nodesToVisit() {
	  return ImmutableList.of(Kind.METHOD);
  }
  @Override
  public void visitNode(Tree tree) {	
	  MethodTree method = (MethodTree) tree;
	  if (method.parameters().size() == 1) {
		    MethodSymbol symbol = method.symbol();
		    Type firstParameterType = symbol.parameterTypes().get(0);
		    Type returnType = symbol.returnType().type();
		    if (returnType.is(firstParameterType.fullyQualifiedName())) {
		        reportIssue(method.simpleName(), "Never do that!");
		    }
	  }
	 
	}
  } 

Can someone help me?
thank you

hello @bruna,

the rules look ok, can you share pom.xml you use to package the plugin? In the resulting jar, does it containt META-INF/MANIFEST.MF file? Can you share its content?

Also, you didn’t share which versions of SonarQube and SonarJava do you use. Make sure that the versions you use to build the rules are matching those were you deploy (it’s ok if there is few versions difference, but it could be a problem if there is a big mismatch).

Hi, thank you for your reply.
I’m using SonarQube 7.7
My pom.xml is this

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>org.sonarsource.samples</groupId>
	<artifactId>java-custom-rules</artifactId>
	<version>1.0-SNAPSHOT</version>
	<packaging>sonar-plugin</packaging>

	<name>SonarQube Java Custom Rules Example</name>
	<description>Java Custom Rules Example for SonarQube</description>
	<inceptionYear>2016</inceptionYear>

	<properties>
		<sslr.version>1.21</sslr.version>
		<gson.version>2.6.2</gson.version>

		<sonar.version>7.6</sonar.version>
		<sonarjava.version>5.12.1.17771</sonarjava.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.sonarsource.sonarqube</groupId>
			<artifactId>sonar-plugin-api</artifactId>
			<version>${sonar.version}</version>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>org.sonarsource.java</groupId>
			<artifactId>sonar-java-plugin</artifactId>
			<type>sonar-plugin</type>
			<version>${sonarjava.version}</version>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>org.sonarsource.sslr-squid-bridge</groupId>
			<artifactId>sslr-squid-bridge</artifactId>
			<version>2.6.1</version>
			<exclusions>
				<exclusion>
					<groupId>org.codehaus.sonar.sslr</groupId>
					<artifactId>sslr-core</artifactId>
				</exclusion>
				<exclusion>
					<groupId>org.codehaus.sonar</groupId>
					<artifactId>sonar-plugin-api</artifactId>
				</exclusion>
				<exclusion>
					<groupId>org.codehaus.sonar.sslr</groupId>
					<artifactId>sslr-xpath</artifactId>
				</exclusion>
				<exclusion>
					<groupId>org.slf4j</groupId>
					<artifactId>jcl-over-slf4j</artifactId>
				</exclusion>
				<exclusion>
					<groupId>org.slf4j</groupId>
					<artifactId>slf4j-api</artifactId>
				</exclusion>
			</exclusions>
		</dependency>

		<dependency>
			<groupId>org.sonarsource.java</groupId>
			<artifactId>java-checks-testkit</artifactId>
			<version>${sonarjava.version}</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>com.google.code.gson</groupId>
			<artifactId>gson</artifactId>
			<version>${gson.version}</version>
		</dependency>

		<dependency>
			<groupId>org.sonarsource.sslr</groupId>
			<artifactId>sslr-testing-harness</artifactId>
			<version>${sslr.version}</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>commons-lang</groupId>
			<artifactId>commons-lang</artifactId>
			<version>2.6</version>
		</dependency>

		<dependency>
			<groupId>com.google.guava</groupId>
			<artifactId>guava</artifactId>
			<version>19.0</version>
		</dependency>

		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>1.6.2</version>
		</dependency>

		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.11</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.assertj</groupId>
			<artifactId>assertj-core</artifactId>
			<version>3.6.1</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>0.9.30</version>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.sonarsource.sonar-packaging-maven-plugin</groupId>
				<artifactId>sonar-packaging-maven-plugin</artifactId>
				<version>1.17</version>
				<extensions>true</extensions>
				<configuration>
					<pluginKey>java-custom</pluginKey>
					<pluginName>Java Custom Rules</pluginName>
					<pluginClass>org.sonar.samples.java.MyJavaRulesPlugin</pluginClass>
					<sonarLintSupported>true</sonarLintSupported>
					<sonarQubeMinVersion>6.7</sonarQubeMinVersion>
				</configuration>
			</plugin>

			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.6.0</version>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
				</configuration>
			</plugin>

			<!-- only required to run UT - these are UT dependencies -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-dependency-plugin</artifactId>
				<version>2.10</version>
				<executions>
					<execution>
						<id>copy</id>
						<phase>test-compile</phase>
						<goals>
							<goal>copy</goal>
						</goals>
						<configuration>
							<artifactItems>
								<artifactItem>
									<groupId>org.apache.commons</groupId>
									<artifactId>commons-collections4</artifactId>
									<version>4.0</version>
									<type>jar</type>
								</artifactItem>
								<artifactItem>
									<groupId>javax</groupId>
									<artifactId>javaee-api</artifactId>
									<version>6.0</version>
								</artifactItem>
								<artifactItem>
									<groupId>org.springframework</groupId>
									<artifactId>spring-webmvc</artifactId>
									<version>4.3.3.RELEASE</version>
								</artifactItem>
								<artifactItem>
									<groupId>org.springframework</groupId>
									<artifactId>spring-webmvc</artifactId>
									<version>4.3.3.RELEASE</version>
								</artifactItem>
								<artifactItem>
									<groupId>org.springframework</groupId>
									<artifactId>spring-web</artifactId>
									<version>4.3.3.RELEASE</version>
								</artifactItem>
								<artifactItem>
									<groupId>org.springframework</groupId>
									<artifactId>spring-context</artifactId>
									<version>4.3.3.RELEASE</version>
								</artifactItem>
							</artifactItems>
							<outputDirectory>${project.build.directory}/test-jars</outputDirectory>
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>

</project>

And this my manifest file
Manifest-Version: 1.0
Plugin-Dependencies: META-INF/lib/commons-lang-2.6.jar META-INF/lib/ss
lr-squid-bridge-2.6.1.jar META-INF/lib/guava-19.0.jar META-INF/lib/sl
f4j-api-1.6.2.jar META-INF/lib/picocontainer-2.14.1.jar META-INF/lib/
gson-2.6.2.jar
Plugin-Description: Java Custom Rules Example for SonarQube
Plugin-BuildDate: 2019-06-03T11:58:05+0200
Archiver-Version: Plexus Archiver
SonarLint-Supported: true
Built-By: bruna.gabutti
Plugin-License:
Plugin-Version: 1.0-SNAPSHOT
Sonar-Version: 6.7
Plugin-Developers:
Plugin-ChildFirstClassLoader: false
Plugin-Key: javacustom
Plugin-Class: org.sonar.samples.java.MyJavaRulesPlugin
Created-By: Apache Maven 3.6.0
Build-Jdk: 1.8.0_201
Plugin-Name: Java Custom Rules

Other question, the class JavaCustomRulesList where are called?
I have create the new class but i am not sure that is the correct method

You should call this list from the class that implements org.sonar.plugins.java.api.CheckRegistrar

And have an implementation of that class along the lines of :

 @Override
 public void register(RegistrarContext registrarContext) {
    registrarContext.registerClassesForRepository(
      "My_REPO_KEY",
      RulesList.getJavaChecks(),
      Collections.emptyList());
  }

I am getting this error while running test case of new custom rule.
i feel its problem with my pom.xml
Can any one help me i am new with this, i tried all the example but still error is there.
Using java 1.8 and Apache Maven 3.5.4.
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException

at com.google.common.base.Throwables.propagate(Throwables.java:160)
at com.sonar.sslr.impl.typed.ReflectionUtils.invokeMethod(ReflectionUtils.java:38)
at com.sonar.sslr.api.typed.ActionParser.<init>(ActionParser.java:79)
at org.sonar.java.ast.parser.JavaParser.<init>(JavaParser.java:37)
at org.sonar.java.ast.parser.JavaParser.createParser(JavaParser.java:41)
at org.sonar.java.ast.JavaAstScanner.scanSingleFileForTests(JavaAstScanner.java:136)
at org.sonar.java.checks.verifier.JavaCheckVerifier.scanFile(JavaCheckVerifier.java:280)
at org.sonar.java.checks.verifier.JavaCheckVerifier.scanFile(JavaCheckVerifier.java:267)
at org.sonar.java.checks.verifier.JavaCheckVerifier.scanFile(JavaCheckVerifier.java:221)
at org.sonar.java.checks.verifier.JavaCheckVerifier.verify(JavaCheckVerifier.java:105)
at org.sonar.samples.java.checks.AvoidTooManyParametersForMethodTest.test(AvoidTooManyParametersForMethodTest.java:11)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.sonar.sslr.impl.typed.ReflectionUtils.invokeMethod(ReflectionUtils.java:36)
… 31 more
Caused by: org.sonar.sslr.grammar.GrammarException: The rule ‘f.newTuple20(Object, Object)’ has already been defined somewhere in the grammar.
at org.sonar.sslr.grammar.GrammarBuilder$RuleBuilder.is(GrammarBuilder.java:285)
at com.sonar.sslr.impl.typed.GrammarBuilderInterceptor.replaceByRule(GrammarBuilderInterceptor.java:159)
at com.sonar.sslr.api.typed.ActionParser$ActionMethodInterceptor.intercept(ActionParser.java:138)
at org.sonar.java.ast.parser.TreeFactory$$EnhancerByCGLIB$$803021b3.newTuple20()
at org.sonar.java.ast.parser.JavaGrammar.SWITCH_CASE_EXPRESSION_LIST(JavaGrammar.java:954)
at org.sonar.java.ast.parser.JavaGrammar$$EnhancerByCGLIB$$a0c5716.CGLIB$SWITCH_CASE_EXPRESSION_LIST$88()
at org.sonar.java.ast.parser.JavaGrammar$$EnhancerByCGLIB$$a0c5716$$FastClassByCGLIB$$7513a60e.invoke()
at net.sf.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at com.sonar.sslr.impl.typed.GrammarBuilderInterceptor.intercept(GrammarBuilderInterceptor.java:76)
at org.sonar.java.ast.parser.JavaGrammar$$EnhancerByCGLIB$$a0c5716.SWITCH_CASE_EXPRESSION_LIST()
… 36 moreAvoidTooManyParametersForMethodCheck.txt (389 Bytes) AvoidTooManyParametersForMethodTest.txt (423 Bytes) MyJavaRulesDefinition.txt (6.1 KB) RulesList.txt (2.0 KB) pom.txt (4.9 KB)

Did you fix this? I’m getting the same thing in intelij when i try to run tests.

Closing this topic for lack of activity, and to avoid having more questions going in all directions.

If you face trouble with custom rules, please have a look at:

We update it on a regular basis.
In addition, if you have trouble testing a rule in an IDE, this post could also help.

If you still face any issue related to custom rule for Java, please create a new thread, with a clear title and description.

Thanks!