Access Configuration From Custom JavaCheck

Hello!

I would like to create a JavaCheck which needs to have some awareness of the context it is running in. Specifically:

  • The value of a custom command-line flag argument, passed in from a call to mvn sonar:sonar -DmyFlag=true in my continuous integration script
  • Nice to have but not crucial – The ProjectKey, or some equivalent way of uniquely identifying the project that the check is running on

Is there a way to access the SensorContext and Configuration from inside a JavaCheck? What I want is something like the following:

import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.config.Configuration;

public class MyCheck extends IssuableSubscriptionVisitor {

    SensorContext context;
    Configuration configuration;

    @Override
    public void visitNode(Tree tree) {
        DefaultInputModule module = (DefaultInputModule) context.module();
        String projectKey = module.key();
        boolean myFlag = configuration.getBoolean("myFlag").orElse(false);
        saveTree(tree, projectKey, myFlag);
    }

    private void saveTree(Tree tree, String projectKey, boolean myFlag) { ... }
}

I have been able to get something working by writing a custom extension which instantiates its own VisitorsBridge and JavaAstScanner, so that I’m able to construct my JavaChecks how I wish. However, I would much rather hook into the existing JavaSquidSensor so that I am not writing as much duplicate code. I have also not seen my extension run in SonarLint, which is a requirement for me.

If anyone has suggestions, I would appreciate it.

Thanks,
Adam

Hi,

I’m not 100% sure how SonarJava custom check API is designed, but if your check class is a pico container component, then you can use constructor injection to access Configuration.

For the projectKey, there are many tricky issues, so could you please share your use case?

Hi Julien,

Thanks for the reply. JavaChecks are not pico components, from what I can tell. If you don’t define a no-args constructor, you get an error during analysis:

[ERROR] Failed to execute goal org.sonarsource.scanner.maven:sonar-maven-plugin:3.4.0.905:sonar
(default-cli) on project parent: Unable to load component class org.sonar.java.SonarComponents:
Fail to instantiate class class foo.bar.MyCustomCheck for rule my-repository:my-rule-id:
foo.bar.MyCustomCheck.<init>()

Getting into the specifics of my use case…

I’m writing a custom rule for my team which checks that changes made to a serializable Java class are forwards and backwards compatible with the previous release of our project. So unlike most rules, this rule needs to be able to compare the code to a previous version of the code.

I have a DynamoDB table which I’m using to store information about the serializable Java classes on each version of the project we have released.

ItemKey ReleaseVersion Data
sonarProjectId#fullyQualifiedClassName XX.XX binary blob

The specific serializable classes are not known ahead of time – they implement a common interface, which the rule is able to recognize.

My custom rule scans the ClassTree for these serializable classes, then queries the DynamoDB table for data about the class from the previously released version, then compares the two.

The projectId is useful in case there are two classes with the same fullyQualifiedName but in different modules, which could happen.

Then another option is to get the Configuration injected in your CheckRegistrar, and expose it as a static field that all your checks will be able to access. I don’t like exposing static fields, but here it is acceptable.

Regarding using the projectKey, you have to be careful of those points:

  • is your check supposed to work in SonarLint? I would suggest to disable it in SonarLint, since it is relying on an external DB, and that would slow down SonarLint
  • is your check supposed to work with branches and pull requests? You would have to get the data not only for the correct project/version, but also for the correct branch.