Is the maven scanner forking a new JVM?

Hello,
I am writing a plugin to report errorprone findings in SonarQube.
Since errorprone uses some internal JDK API (and since JEP-396) it needs the JVM to start with some options such as: --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED.

I have integration tests running the plugin an analysing a sample maven project, it is working as expected on SonarQube 10.4 however on 10.6 (or 10.7 or 24.12) I’m getting an error indicating that the JVM options were not enabled:

 [INFO] Sensor Errorprone sensor [errorawaysonar]
 [ERROR] [stderr] Exception in thread "main" java.util.ServiceConfigurationError: com.google.errorprone.bugpatterns.BugChecker: com.uber.nullaway.NullAway Unable to get public no-arg constructor
 [ERROR] [stderr] 	at java.base/java.util.ServiceLoader.fail(Unknown Source)
 [ERROR] [stderr] 	at java.base/java.util.ServiceLoader.getConstructor(Unknown Source)
 [ERROR] [stderr] 	at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNextService(Unknown Source)
 [ERROR] [stderr] 	at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNext(Unknown Source)
 [ERROR] [stderr] 	at java.base/java.util.ServiceLoader$2.hasNext(Unknown Source)
 [ERROR] [stderr] 	at java.base/java.util.ServiceLoader$3.hasNext(Unknown Source)
 [ERROR] [stderr] 	at com.github.erroraway.sonarqube.ErrorAwaySensor.execute(ErrorAwaySensor.java:86)
 [ERROR] [stderr] 	at org.sonar.scanner.sensor.AbstractSensorWrapper.analyse(AbstractSensorWrapper.java:64)
 [ERROR] [stderr] 	at org.sonar.scanner.sensor.ModuleSensorsExecutor.execute(ModuleSensorsExecutor.java:88)
 [ERROR] [stderr] 	at org.sonar.scanner.sensor.ModuleSensorsExecutor.lambda$execute$1(ModuleSensorsExecutor.java:61)
 [ERROR] [stderr] 	at org.sonar.scanner.sensor.ModuleSensorsExecutor.withModuleStrategy(ModuleSensorsExecutor.java:79)
 [ERROR] [stderr] 	at org.sonar.scanner.sensor.ModuleSensorsExecutor.execute(ModuleSensorsExecutor.java:61)
 [ERROR] [stderr] 	at org.sonar.scanner.scan.SpringModuleScanContainer.doAfterStart(SpringModuleScanContainer.java:82)
 [ERROR] [stderr] 	at org.sonar.core.platform.SpringComponentContainer.startComponents(SpringComponentContainer.java:226)
 [ERROR] [stderr] 	at org.sonar.core.platform.SpringComponentContainer.execute(SpringComponentContainer.java:205)
 [ERROR] [stderr] 	at org.sonar.scanner.scan.SpringProjectScanContainer.scan(SpringProjectScanContainer.java:204)
 [ERROR] [stderr] 	at org.sonar.scanner.scan.SpringProjectScanContainer.scanRecursively(SpringProjectScanContainer.java:200)
 [ERROR] [stderr] 	at org.sonar.scanner.scan.SpringProjectScanContainer.doAfterStart(SpringProjectScanContainer.java:173)
 [ERROR] [stderr] 	at org.sonar.core.platform.SpringComponentContainer.startComponents(SpringComponentContainer.java:226)
 [ERROR] [stderr] 	at org.sonar.core.platform.SpringComponentContainer.execute(SpringComponentContainer.java:205)
 [ERROR] [stderr] 	at org.sonar.scanner.bootstrap.SpringScannerContainer.doAfterStart(SpringScannerContainer.java:351)
 [ERROR] [stderr] 	at org.sonar.core.platform.SpringComponentContainer.startComponents(SpringComponentContainer.java:226)
 [ERROR] [stderr] 	at org.sonar.core.platform.SpringComponentContainer.execute(SpringComponentContainer.java:205)
 [ERROR] [stderr] 	at org.sonar.scanner.bootstrap.SpringGlobalContainer.doAfterStart(SpringGlobalContainer.java:144)
 [ERROR] [stderr] 	at org.sonar.core.platform.SpringComponentContainer.startComponents(SpringComponentContainer.java:226)
 [ERROR] [stderr] 	at org.sonar.core.platform.SpringComponentContainer.execute(SpringComponentContainer.java:205)
 [ERROR] [stderr] 	at org.sonar.scanner.bootstrap.ScannerMain.runScannerEngine(ScannerMain.java:149)
 [ERROR] [stderr] 	at org.sonar.scanner.bootstrap.ScannerMain.run(ScannerMain.java:66)
 [ERROR] [stderr] 	at org.sonar.scanner.bootstrap.ScannerMain.main(ScannerMain.java:52)
 [ERROR] [stderr] Caused by: java.lang.NoClassDefFoundError: com/sun/source/tree/Tree
 [ERROR] [stderr] 	at java.base/java.lang.Class.getDeclaredConstructors0(Native Method)
 [ERROR] [stderr] 	at java.base/java.lang.Class.privateGetDeclaredConstructors(Unknown Source)
 [ERROR] [stderr] 	at java.base/java.lang.Class.getConstructor0(Unknown Source)
 [ERROR] [stderr] 	at java.base/java.lang.Class.getConstructor(Unknown Source)
 [ERROR] [stderr] 	at java.base/java.util.ServiceLoader$1.run(Unknown Source)
 [ERROR] [stderr] 	at java.base/java.util.ServiceLoader$1.run(Unknown Source)
 [ERROR] [stderr] 	at java.base/java.security.AccessController.doPrivileged(Unknown Source)
 [ERROR] [stderr] 	... 28 more
 [ERROR] [stderr] Caused by: java.lang.ClassNotFoundException: com.sun.source.tree.Tree
 [ERROR] [stderr] 	at org.sonar.classloader.ParentFirstStrategy.loadClass(ParentFirstStrategy.java:39)
 [ERROR] [stderr] 	at org.sonar.classloader.ClassRealm.loadClass(ClassRealm.java:97)
 [ERROR] [stderr] 	at org.sonar.classloader.ClassRealm.loadClass(ClassRealm.java:86)
 [ERROR] [stderr] 	... 35 more

Indeed when comparing the logs I see that when running on SonarQube 10.7 the scanner seems to provision a JVM:

 [INFO] Java 17.0.13 Eclipse Adoptium (64-bit)
 [INFO] Linux 6.5.0-1025-azure (amd64)
 [INFO] MAVEN_OPTS=--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED --add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED  -Djava.awt.headless=true
 [INFO] User cache: /home/runner/.sonar/cache
 [INFO] JRE provisioning: os[linux], arch[x86_64]
 [INFO] Communicating with SonarQube Server 10.7.0.96327
 [INFO] Starting SonarScanner Engine...
 [INFO] Java 17.0.11 Eclipse Adoptium (64-bit)
 [INFO] Load global settings
 [INFO] Load global settings (done) | time=237ms
 [INFO] Server id: 59CB0369-AZOrU2kGu2wk1AyH6d7L
 [WARNING] sonar.plugins.downloadOnlyRequired is false, so ALL available plugins will be downloaded
 [INFO] Loading all plugins
 [INFO] Load plugins index

When running on 10.4 there’s no mention of provisioning a JRE:

 [INFO] Java 17.0.13 Eclipse Adoptium (64-bit)
 [INFO] Linux 6.5.0-1025-azure (amd64)
 [INFO] MAVEN_OPTS=--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED --add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED  -Djava.awt.headless=true
 [INFO] User cache: /home/runner/.sonar/cache
 > 2024.12.09 12:11:55 WARN  web[ab36584e-2c6a-48a1-86bb-cf9166839f70][o.s.w.s.PageNotFound] No mapping for GET /api/v2/analysis/version
 [INFO] Communicating with SonarQube Server 10.4.0.87286
 [INFO] Load global settings
 [INFO] Load global settings (done) | time=162ms
 [INFO] Server id: 8D08E935-AZOrU2bhNOMCuPjScYlG
 [INFO] User cache: /home/runner/.sonar/cache
 [WARNING] sonar.plugins.downloadOnlyRequired is false, so ALL available plugins will be downloaded
 [INFO] Loading all plugins
 [INFO] Load plugins index

Can you please advise if the scanner is indeed forking a new JVM on newer versions of SonarQube?
I suspect the issue might be that the JVM is a JRE (not a JDK), so it is missing the javac module.
Even it is a JDK, I think it would need the extra --add-exports options. Is there a way to start that JVM with plugin-supplied arguments?

Hey there.

  • Yes, starting in SonarQube v10.6 (and SonarScanner for Maven v5.0), by default a JVM is downloaded from the SonarQube server.
  • You should be able to pass additional options to this JVM by using sonar.scanner.javaOpts

That was fast, thanks Colin!
Let me try that, thanks for the answer

In the end it seems that I needed to disable the JRE provisionning: I need the javac module therefore I need a JDK, not a JRE.
I used the sonar.scanner.skipJreProvisioning option to do that.

Thank you very much for giving me the hint @Colin !