Custom Java plugin: Unsatisfied Dependency Error on Sensor initialization

Hi All,

I am developing a custom java plugin to add some i18n check, but got a Unsatisfied Dependency error on the Custom sensor. Could you help me out? Thanks a lot, I’m new to sonarqube…

Details pls find below:

  • SonarSever: 7.5
  • Sonar-java: sonar-java-plugin-5.9.2.16552.jar
  • custom language: i18njava
  • custom profile: I18NProfile

I’m writing my Sensor referring to the JavaSquidSensor impl.

Senor class:

@Phase(name = Phase.Name.PRE)
@DependsUpon("BEFORE_SQUID")
@DependedUpon("squid")
public class I18NJavaPreCheckSensor implements Sensor {

    private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(I18NJavaPreCheckSensor.class);
    private static final JavaHardCodedCheck hcc = new JavaHardCodedCheck();

    private final SonarComponents sonarComponents;
    private final DefaultJavaResourceLocator javaResourceLocator;
    private final Configuration settings;
    private final NoSonarFilter noSonarFilter;
    private final PostAnalysisIssueFilter postAnalysisIssueFilter;
    private final FileSystem fs;

    public I18NJavaPreCheckSensor(SonarComponents sonarComponents, @Nullable FileSystem fs,
                                  @Nullable DefaultJavaResourceLocator javaResourceLocator, @Nullable Configuration settings, @Nullable NoSonarFilter noSonarFilter, @Nullable PostAnalysisIssueFilter postAnalysisIssueFilter) {
        System.out.println("nos: " +noSonarFilter.toString());
        this.noSonarFilter = noSonarFilter;
        this.sonarComponents = sonarComponents;
        this.javaResourceLocator = javaResourceLocator;
        this.settings = settings;
        this.postAnalysisIssueFilter = postAnalysisIssueFilter;
        System.out.println("postAnalysisIssueFilter: " +postAnalysisIssueFilter.toString());
        this.fs = fs;
        System.out.println("fs: " +fs.toString());

    }

    @Override
    public void describe(SensorDescriptor descriptor) {
        descriptor.onlyOnLanguage(Constants.LANGUAGE_KEY).name("I18NJavaPreCheckSensor");
    }

    @Override
    public void execute(SensorContext context) {
            javaResourceLocator.setSensorContext(context);
            sonarComponents.setSensorContext(context);

            List<Class<? extends JavaCheck>> checks = ImmutableList.<Class<? extends JavaCheck>>builder()
                    .addAll(I18NCheckClasses.getJavaChecks())
                    .build();
            sonarComponents.registerCheckClasses(I18NJavaRulesDefinition.REPOSITORY_KEY, checks);
            sonarComponents.registerTestCheckClasses(I18NJavaRulesDefinition.REPOSITORY_KEY,I18NCheckClasses.getJavaTestChecks());
            Measurer measurer = new Measurer(fs, context, noSonarFilter);
            I18NJavaSquid squid = new I18NJavaSquid(getJavaVersion(), isXFileEnabled(), sonarComponents, measurer, javaResourceLocator, postAnalysisIssueFilter, sonarComponents.checkClasses());
            squid.scan(getSourceFiles(), getTestFiles());
            sonarComponents.saveAnalysisErrors();
        
    }
    }

I run from the sonar scanner, and got the error below:

16:06:04.781 ERROR: Error during SonarQube Scanner execution
org.picocontainer.injectors.AbstractInjector$UnsatisfiableDependenciesException: i18n.sensor.I18NJavaPreCheckSensor has unsatisfied dependency 'class org.sonar.java.filters.PostAnalysisIssueFilter' for constructor 'public i18n.sensor.I18NJavaPreCheckSensor(org.sonar.java.SonarComponents,org.sonar.api.batch.fs.FileSystem,org.sonar.java.DefaultJavaResourceLocator,org.sonar.api.config.Configuration,org.sonar.api.issue.NoSonarFilter,org.sonar.java.filters.PostAnalysisIssueFilter)' from org.sonar.core.platform.ComponentContainer$ExtendedDefaultPicoContainer@22c01ab0:151<[Immutable]:org.sonar.core.platform.ComponentContainer$ExtendedDefaultPicoContainer@63a270c9:218<[Immutable]:org.sonar.core.platform.ComponentContainer$ExtendedDefaultPicoContainer@4f4c4b1a:9<[Immutable]:org.sonar.core.platform.ComponentContainer$ExtendedDefaultPicoContainer@53dfacba:37<|
        at org.picocontainer.injectors.ConstructorInjector.getGreediestSatisfiableConstructor(ConstructorInjector.java:191)
        at org.picocontainer.injectors.ConstructorInjector.getGreediestSatisfiableConstructor(ConstructorInjector.java:110)
        at org.picocontainer.injectors.ConstructorInjector.access$100(ConstructorInjector.java:51)
        at org.picocontainer.injectors.ConstructorInjector$1.run(ConstructorInjector.java:331)
        at org.picocontainer.injectors.AbstractInjector$ThreadLocalCyclicDependencyGuard.observe(AbstractInjector.java:270)
        at org.picocontainer.injectors.ConstructorInjector.getComponentInstance(ConstructorInjector.java:364)
        at org.picocontainer.injectors.AbstractInjectionFactory$LifecycleAdapter.getComponentInstance(AbstractInjectionFactory.java:56)
        at org.picocontainer.behaviors.AbstractBehavior.getComponentInstance(AbstractBehavior.java:64)
        at org.picocontainer.behaviors.Stored.getComponentInstance(Stored.java:91)
        at org.picocontainer.DefaultPicoContainer.getLocalInstance(DefaultPicoContainer.java:606)
        at org.picocontainer.DefaultPicoContainer.getComponents(DefaultPicoContainer.java:587)
        at org.sonar.core.platform.ComponentContainer.getComponentsByType(ComponentContainer.java:290)
        at org.sonar.scanner.bootstrap.ScannerExtensionDictionnary.completeScannerExtensions(ScannerExtensionDictionnary.java:118)
        at org.sonar.scanner.bootstrap.ScannerExtensionDictionnary.getExtensions(ScannerExtensionDictionnary.java:113)
        at org.sonar.scanner.bootstrap.ScannerExtensionDictionnary.getFilteredExtensions(ScannerExtensionDictionnary.java:103)
        at org.sonar.scanner.bootstrap.ScannerExtensionDictionnary.selectSensors(ScannerExtensionDictionnary.java:77)
        at org.sonar.scanner.phases.SensorsExecutor.execute(SensorsExecutor.java:55)
        at org.sonar.scanner.phases.AbstractPhaseExecutor.execute(AbstractPhaseExecutor.java:74)
        at org.sonar.scanner.scan.ModuleScanContainer.doAfterStart(ModuleScanContainer.java:164)
        at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:136)
        at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:122)
        at org.sonar.scanner.scan.ProjectScanContainer.scan(ProjectScanContainer.java:319)
        at org.sonar.scanner.scan.ProjectScanContainer.scanRecursively(ProjectScanContainer.java:314)
        at org.sonar.scanner.scan.ProjectScanContainer.doAfterStart(ProjectScanContainer.java:288)
        at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:136)
        at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:122)
        at org.sonar.scanner.task.ScanTask.execute(ScanTask.java:48)
        at org.sonar.scanner.task.TaskContainer.doAfterStart(TaskContainer.java:82)
        at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:136)
        at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:122)
        at org.sonar.scanner.bootstrap.GlobalContainer.executeTask(GlobalContainer.java:131)
        at org.sonar.batch.bootstrapper.Batch.doExecuteTask(Batch.java:116)
        at org.sonar.batch.bootstrapper.Batch.execute(Batch.java:71)
        at org.sonarsource.scanner.api.internal.batch.BatchIsolatedLauncher.execute(BatchIsolatedLauncher.java:46)
        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:498)
        at org.sonarsource.scanner.api.internal.IsolatedLauncherProxy.invoke(IsolatedLauncherProxy.java:60)
        at com.sun.proxy.$Proxy0.execute(Unknown Source)
        at org.sonarsource.scanner.api.EmbeddedScanner.doExecute(EmbeddedScanner.java:185)
        at org.sonarsource.scanner.api.EmbeddedScanner.execute(EmbeddedScanner.java:137)
        at org.sonarsource.scanner.cli.Main.execute(Main.java:111)
        at org.sonarsource.scanner.cli.Main.execute(Main.java:75)
        at org.sonarsource.scanner.cli.Main.main(Main.java:61)

Hi. Only the classes in the org.sonar.plugins.java.api package (and its subpackages) are accessible by custom plugins. This is why you can’t use org.sonar.java.filters.PostAnalysisIssueFilter.

Thank you @Scott, in this case, how shall I construct the custom Sensor class, could you help suggest?

I need to call the JavaSquid scan method, where the arguments like SonarComponents sonarComponents, @Nullable FileSystem fs,
JavaResourceLocator javaResourceLocator, @Nullable Configuration settings, @Nullable NoSonarFilter noSonarFilter), @Nullable PostAnalysisIssueFilter postAnalysisIssueFilter) are needed, pls correct me if I unserstood wrong

I didn’t really understand what you’re trying to implement… What is “i18njava”? What kind of rules you want to add? Because it looks like you’re kinda trying to reimplement the SonarJava plugin…

Correct me if I’m wrong, but you’re not trying to “extend” the SonarJava (in the sense of adding some custom rules to the Java repository), but you’re “reusing” its code it to create a new plugin, completely independent of SonarJava.

Sorry for the confusion, I missed some background,

We are using sonarqube to do some internalization check like hardcoded string issues on java project, since there is no existing i18n rule, so we decide to write a custom one.

At first we do extend the sonarjava plugin, added our rule and it works well. we also wrote our sensors(simply read and set configurations).

later we do the same to add new custom rules extending SonarHtml for Html projects, but found a problem, that is, if project has both java and html files, scanner will run all the Sensors (if no specific language filter set in the sensor descriptor). So to solve it, we created new plugin for html, which works well.

and then we would like to do the same on java, that is to write a new plugin but not completely independent of sonarJava, we just want to add our own language “i18njava” and own profile, but as you’ve seen, I failed to construct the custom sensor class.

would this be possible to do, write a new plugin but not completely independent from sonarjava, we do need its tree visitors etc.

As far as I understand your usecase it seems you are looking to implement custom rules. You should then refer to the documentation for this : https://docs.sonarqube.org/display/PLUG/Writing+Custom+Java+Rules+101