文章目錄
- 1、問題現象
- 2、問題根因
- 3、解決思路
- 3.1 解決思路1
- 3.2 解決思路2
- 3.3 解決思路3
1、問題現象
問題現象:在每次Jenkins觸發sonar掃描時,Sonar-scanner掃描器執行都會出現UnsupportedClassVersionError
異常,如下:
ERROR: Error during SonarQube Scanner execution
java.lang.UnsupportedClassVersionError: org/sonar/batch/bootstrapper/EnvironmentInformation has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 55.0at java.base/java.lang.ClassLoader.defineClass1(Native Method)at java.base/java.lang.ClassLoader.defineClass(Unknown Source)at java.base/java.security.SecureClassLoader.defineClass(Unknown Source)at java.base/java.net.URLClassLoader.defineClass(Unknown Source)at java.base/java.net.URLClassLoader$1.run(Unknown Source)at java.base/java.net.URLClassLoader$1.run(Unknown Source)at java.base/java.security.AccessController.doPrivileged(Native Method)at java.base/java.net.URLClassLoader.findClass(Unknown Source)at org.sonarsource.scanner.api.internal.IsolatedClassloader.loadClass(IsolatedClassloader.java:82)at java.base/java.lang.ClassLoader.loadClass(Unknown Source)at org.sonarsource.scanner.api.internal.batch.DefaultBatchFactory.createBatch(DefaultBatchFactory.java:32)at org.sonarsource.scanner.api.internal.batch.BatchIsolatedLauncher.execute(BatchIsolatedLauncher.java:46)at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)at java.base/java.lang.reflect.Method.invoke(Unknown Source)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:189)at org.sonarsource.scanner.api.EmbeddedScanner.execute(EmbeddedScanner.java:138)at org.sonarsource.scanner.cli.Main.execute(Main.java:112)at org.sonarsource.scanner.cli.Main.execute(Main.java:75)at org.sonarsource.scanner.cli.Main.main(Main.java:61)
ERROR:
ERROR: Re-run SonarQube Scanner using the -X switch to enable full debug logging.
2、問題根因
這個問題表現在于掃描環境中java版本的錯誤,要求執行sonar-scanner
時Java版本 >= Java17(class version 61),但當前環境實際Java版本為Java11(class version 55),存在不支持的類,所以報錯。這個問題本身很好解決,重新配置java環境變量即可,但這里面有個坑,配置的環境變量可能會不生效,需要專門的來說一下。
根因具體有幾方面:
- 1、系統默認的Java版本為Java11,導致sonar-scanner執行失敗
- 2、sonar-scanner.properties配置文件指定了Java11的版本
- 3、sonar-scanner執行時使用了內嵌Java,并且版本為Java11(重點)
3、解決思路
3.1 解決思路1
針對第1點: 直接重新配置執行時的環境變量即可,刷新Java生效的環境。
通過在Execute shell中指定重新配置Java環境變量,添加的時候必須將PATH一起配置,否則,當PATH路徑中Java11版本的配置排列在Java17之前,會被優先索引到并采用:
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
export PATH=${JAVA_HOME}/bin:$PATH
3.2 解決思路2
針對第2點: 需要對sonar-scanner.properties
中設置進行修正,將其指定為Java17的版本。
配置文件路徑通常為/opt/sonarqube/sonar-scanner/conf/sonar-scanner.properties
配置內容如下:
sonar.scanner.javaHome=/usr/lib/jvm/java-17-openjdk-amd64
注意: sonar.scanner.javaHome
的參數支持,需要要求sonar-scanner版本>=4.12,將sonar-scanner.properties
配置完成之后,最好再根據第1點,在執行前指定Java17,sonar-scanner.properties的作用通常在執行掃描時生效。
3.3 解決思路3
針對第3點:這里面埋了個大坑,sonar-scanner腳本本身會指定Java版本,當內嵌的版本為Java11時,外部所有其他方式指定的Java配置均不生效。
檢查sonar-scanner執行腳本,文件路徑在這/opt/sonarqube/sonar-scanner/bin/sonar-scanner
,在下面幾句會指明是否使用內嵌的Java:
use_embedded_jre=true
if [ "$use_embedded_jre" = true ]; thenexport JAVA_HOME=$sonar_scanner_home/jre
fi
當
use_embedded_jre
變量值為true時,會直接采用內嵌的java版本,將內嵌的jre路徑導入export JAVA_HOME=$sonar_scanner_home/jre
,這一項的優先級高于其他所有的配置。當此配置為true時,我們在第1點、第2點中所修改的內容都將不生效。
解決方法: 直接修改sonar-scanner執行腳本
,將use_embedded_jre
設置為false,其他無需更改,即修改為如下內容:
use_embedded_jre=false
if [ "$use_embedded_jre" = true ]; thenexport JAVA_HOME=$sonar_scanner_home/jre
fi

這樣就默認不會采用內嵌的Java,之后再結合第1點的配置調整環境變量。重新觸發構建,可正常進行掃描:
如果沒有Jenkins服務器權限,可以在Jenkins配置中新建Execute shell,填入以下指令,直接在命令行對sonar-scanner
進行修改:除了改動use_embedded_jre
值外,其他原封不動粘貼
cat << 'EOF' > /opt/sonarqube/sonar-scanner/bin/sonar-scanner
#!/bin/sh
#
# SonarQube Scanner Startup Script for Unix
#
# Optional ENV vars:
# SONAR_SCANNER_OPTS - Parameters passed to the Java VM when running the SonarQube Scanner
# SONAR_SCANNER_DEBUG_OPTS - Extra parameters passed to the Java VM for debugging
# JAVA_HOME - Location of Java's installationreal_path () {target=$1(while true; docd "$(dirname "$target")"target=$(basename "$target")test -L "$target" || breaktarget=$(readlink "$target")doneecho "$(pwd -P)/$target")
}script_path=$(real_path "$0")
sonar_scanner_home=$(dirname "$script_path")/..# make it fully qualified
sonar_scanner_home=$(cd "$sonar_scanner_home" && pwd -P)jar_file=$sonar_scanner_home/lib/sonar-scanner-cli-4.2.0.1873.jar# check that sonar_scanner_home has been correctly set
if [ ! -f "$jar_file" ] ; thenecho "File does not exist: $jar_file"echo "'$sonar_scanner_home' does not point to a valid installation directory: $sonar_scanner_home"exit 1
fiuse_embedded_jre=false
if [ "$use_embedded_jre" = true ]; thenexport JAVA_HOME=$sonar_scanner_home/jre
fiif [ -n "$JAVA_HOME" ]
thenjava_cmd="$JAVA_HOME/bin/java"
elsejava_cmd="$(which java)"
fiif [ -z "$java_cmd" -o ! -x "$java_cmd" ] ; thenecho "Could not find 'java' executable in JAVA_HOME or PATH."exit 1
fiproject_home=$(pwd)#echo "Info: Using sonar-scanner at $sonar_scanner_home"
#echo "Info: Using java at $java_cmd"
#echo "Info: Using classpath $jar_file"
#echo "Info: Using project $project_home"exec "$java_cmd" \-Djava.awt.headless=true \$SONAR_SCANNER_OPTS \$SONAR_SCANNER_DEBUG_OPTS \-classpath "$jar_file" \-Dscanner.home="$sonar_scanner_home" \-Dproject.home="$project_home" \org.sonarsource.scanner.cli.Main "$@"
EOF