Making FindBugs work with `downloadOnlyRequired`

Hello, as reported here the FindBugs plugin seems to be missing classes from the sonar-java built-in plugin when running on a non-java JVM project (such as Kotlin).

The plugin is packaged with: <requiredForLanguages>java,scala,jsp,clojure,kotlin</requiredForLanguages> but there does not seem to be a way to declare a dependency on another plugin.

Is there something I’m missing or the workaround is to disable the sonar.plugins.downloadOnlyRequired option?

I also see this error at the end of the scanner logs:

 Error: Exception in thread "Thread-1" java.lang.NoClassDefFoundError: ch/qos/logback/classic/spi/ThrowableProxy
	at ch.qos.logback.classic.spi.LoggingEvent.<init>(LoggingEvent.java:145)
	at ch.qos.logback.classic.Logger.buildLoggingEventAndAppend(Logger.java:424)
	at ch.qos.logback.classic.Logger.filterAndLog_0_Or3Plus(Logger.java:386)
	at ch.qos.logback.classic.Logger.error(Logger.java:543)
	at org.eclipse.jgit.internal.util.ShutdownHook.cleanup(ShutdownHook.java:87)
	at java.base/java.lang.Thread.run(Thread.java:840)
Caused by: java.lang.ClassNotFoundException: ch.qos.logback.classic.spi.ThrowableProxy
	at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:445)
	at org.sonarsource.scanner.api.internal.IsolatedClassloader.loadClass(IsolatedClassloader.java:82)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525)
	... 6 more

Hello Guillaume,

Thanks for reporting this use case.

We will discuss it some more internally to see what solutions there could be for addressing this particular use case. In the meantime, here are two ideas:

  • If you analyze non-java code, you may not need to depend on the sonar-java plugin for projects that don’t contain Java code. So perhaps you can check if the sonar-java plugin is available / catch if it isn’t and only analyze non-Java code in that case. If I’m not mistaken, you don’t have a huge amount of dependencies on sonar-java anyway, so perhaps it is worth thinking about removing that dependency entirely and implementing the missing logic on the FindBugs side.
  • As already stated in the issue you linked to, as a workaround, users can disable the on-demand plugin downloading by setting sonar.plugins.downloadOnlyRequired to false.

I’ll provide an update if we come up with a better solution, in the meantime I hope these two options help!

Thanks Johann,
The plugin uses the JavaResourceLocator.classpath() which is useful for non Java projects too.
There’s also JavaResourceLocator.classFilesToAnalyze(), I think these are also populated for non Java projects.

Also the JavaResourceLocator is used via constructor injection, so the class currently needs to be available for the plugin to even start.
Is there a better way to test its availability and to retrieve it?

I seem to be running into the same problem with the error prone plugin: it also uses JavaResourceLocator.classpath() and is packaged with <requiredForLanguages>java</requiredForLanguages>.
Even for projects with some java files the JavaResourceLocator is missing:

Hello @jbeleites,
I understand why the issue happens for the Findbugs plugin and for non-java projects: there are no java files so the built-in Java plugin is not downloaded, and the JavaResourceLocator class is missing.
However for the errorprone plugin I have the issue for Java projects, so I would expect that the built-in Java plugin is downloaded, but it does not seem to happen.
Could it be because the plugins are executed in alphabetical order? Does it matter if the quality profile has rules from the built-in Java plugin?

I’ve tried adding <basePlugin>java</basePlugin> to the packaging and seemed to get a different error:

Caused by: java.io.IOException: Resource not found in the classpath: /org/sonar/l10n/java/rules/java/Sonar_way_profile.json
>       at org.sonarsource.analyzer.commons.Resources.toString(Resources.java:47)
>       at org.sonarsource.analyzer.commons.BuiltInQualityProfileJsonLoader.loadActiveKeysFromJsonProfile(BuiltInQualityProfileJsonLoader.java:73)

Hum… I might be confused here but it seems that the sonar.plugins.downloadOnlyRequired options needs to be disabled on the analyzer AND on the server for the workaround to work.
I’ve just realized this and now I can get my errorprone plugin to work again.
Does it make sense @jbeleites ?

You just need to disable it on the server side to continue to work with plugins that are not compatible.

1 Like

Thank you for the answer Alexandre.
I was under the impression that these options are configurable either on the server or on the analyzer but I was mistaken.

Hello,

We looked at your case with some others here and came to the conclusion that the best approach is to no longer rely on the sonar-java-plugin dependency. I mean you should find a way to completely remove that:

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

This will mean that you will have to duplicate a couple of classes from sonar-java-plugin into your plugins (or create a lib if you want to use the same code in FindBugs and ErrorProne plugins).

There are only 2 classes used from SonarJava which are just utility classes:

  • org.sonar.plugins.java.api.JavaResourceLocator
  • org.sonar.plugins.java.Java

The latter is a no-brainer. JavaResourceLocator will be a little tricky, but it looks like it’s doable.
You will have to duplicate the content of DefaultJavaResourceLocator.java, org.sonar.java.classpath.ClasspathForMain, and org.sonar.java.classpath.ClasspathForTest and certainly instantiate them yourself instead of relying on injection through the constructor.

Alex

Hello,

Sorry I did not see that you had answered.

I think the biggest problems will be replicating DefaultJavaResourceLocator.classFilesToAnalyze(), from memory (I checked a long while ago) the files are populated as a side effect of the analysis by the built-in java plugin.

Reimplementing the logic to locate the files under analysis is not trivial unfortunately.
I guess it will also make it harder to remain compatible with multiple versions of SonarQube