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());
  }