Show a warning message about the Unsupported JDK error (#790)

* Show a warning message about the Unsupported JDK error

Signed-off-by: Jinbo Wang <jinbwan@microsoft.com>

* adjust the description

Signed-off-by: Jinbo Wang <jinbwan@microsoft.com>

* Improve troubleshooting description

Signed-off-by: Jinbo Wang <jinbwan@microsoft.com>
This commit is contained in:
Jinbo Wang 2020-04-10 15:42:37 +08:00 committed by GitHub
parent 6b52079ce4
commit 656beaab8f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 80 additions and 29 deletions

View File

@ -51,6 +51,26 @@ This error indicates your application attempts to reference some classes which a
3. Run VS Code command *"Java: Force Java compilation"* to force the language server to rebuild the current project.
4. If the problem persists, it's probably because the language server doesn't load your project correctly. Please reference the [language server troubleshooting](#try) paragraph for more troubleshooting info.
## Program throws UnsupportedClassVersionError
Below is a typical error message.
![image](https://user-images.githubusercontent.com/14052197/78854443-ed47c780-7a53-11ea-8317-d8b097dfba99.png)
### Reason:
The compiled classes are not compatible with the runtime JDK.
The class file version `57.65535` stands for Java 13 preview, where the major version `57` stands for Java 13, the minor version `65535` stands for preview feature. Similarly `58.65535` stands for Java 14 preview.
The error says the compiled class is `57.65535`, but the runtime JDK only recognizes class file versoin `58.65535`. That's because the preview feature is not backward compatible, i.e. JVM 14 doesn't support 13 preview feature. The [openjdk](https://openjdk.java.net/jeps/12) website has claimed the reason that it would be costly for JDK 14 to support preview features from JDK 13 which were changed or dropped in response to feedback.
One possible root cause for this error is your runtime JDK is the latest JDK but the upstream [Language Support for Java](https://marketplace.visualstudio.com/items?itemName=redhat.java) extension doesn't catch up the support yet.
### Try:
1. Try to update [Language Support for Java](https://marketplace.visualstudio.com/items?itemName=redhat.java) to the latest, and then try step 3 to rebuild the workspace.
2. If it doesn't work, then try to install an older JDK version, set its installation folder to "java.home" user setting in _.vscode/settings.json_ and reopen your VS Code workspace.
3. Click **F1** -> **Java: Force Java compilation** -> **Full** to rebuild the workspace.
4. If it still doesn't work, then try **F1** -> **Java: Clean the Java language server workspace** to clean the cache.
## Failed to complete hot code replace:
### Reason:
This error indicates you are doing `Hot Code Replace`. The `Hot Code Replace` feature depends on the underlying JVM implementation. If you get this error, that indicates the new changes cannot be hot replaced by JVM.

View File

@ -7,3 +7,4 @@ export const ATTACH_CONFIG_ERROR = "please-specify-the-host-name-and-the-port-of
export const EVALUATE_ON_RUNNING_THREAD = "failed-to-evaluate-reason-cannot-evaluate-because-the-thread-is-resumed";
export const CANNOT_FIND_MAIN_CLASS = "cannot-find-a-class-with-the-main-method";
export const BUILD_FAILED = "build-failed-do-you-want-to-continue";
export const UNSUPPORTED_CLASS_VERSION_ERROR = "program-throws-unsupportedclassversionerror";

View File

@ -38,6 +38,8 @@ export const JAVA_IS_ON_CLASSPATH = "vscode.java.isOnClasspath";
export const JAVA_RESOLVE_JAVAEXECUTABLE = "vscode.java.resolveJavaExecutable";
export const JAVA_FETCH_PLATFORM_SETTINGS = "vscode.java.fetchPlatformSettings";
export function executeJavaLanguageServerCommand(...rest) {
return executeJavaExtensionCommand(JAVA_EXECUTE_WORKSPACE_COMMAND, ...rest);
}

View File

@ -11,7 +11,7 @@ import * as anchor from "./anchor";
import { buildWorkspace } from "./build";
import * as commands from "./commands";
import * as lsPlugin from "./languageServerPlugin";
import { detectLaunchCommandStyle } from "./launchCommand";
import { detectLaunchCommandStyle, validateRuntime } from "./launchCommand";
import { logger, Type } from "./logger";
import * as utility from "./utility";
import { VariableResolver } from "./variableResolver";
@ -207,6 +207,27 @@ export class JavaDebugConfigurationProvider implements vscode.DebugConfiguration
config.javaExec = await lsPlugin.resolveJavaExecutable(config.mainClass, config.projectName);
// Add the default launch options to the config.
config.cwd = config.cwd || _.get(folder, "uri.fsPath");
if (Array.isArray(config.args)) {
config.args = this.concatArgs(config.args);
}
if (Array.isArray(config.vmArgs)) {
config.vmArgs = this.concatArgs(config.vmArgs);
}
// Auto add '--enable-preview' vmArgs if the java project enables COMPILER_PB_ENABLE_PREVIEW_FEATURES flag.
if (await lsPlugin.detectPreviewFlag(config.mainClass, config.projectName)) {
config.vmArgs = (config.vmArgs || "") + " --enable-preview";
validateRuntime(config);
}
if (!config.shortenCommandLine || config.shortenCommandLine === "auto") {
config.shortenCommandLine = await detectLaunchCommandStyle(config);
}
if (process.platform === "win32" && config.console !== "internalConsole") {
config.launcherScript = utility.getLauncherScriptPath();
}
} else if (config.request === "attach") {
if (!config.hostName || !config.port) {
throw new utility.UserError({
@ -223,27 +244,6 @@ export class JavaDebugConfigurationProvider implements vscode.DebugConfiguration
});
}
if (Array.isArray(config.args)) {
config.args = this.concatArgs(config.args);
}
if (Array.isArray(config.vmArgs)) {
config.vmArgs = this.concatArgs(config.vmArgs);
}
// Auto add '--enable-preview' vmArgs if the java project enables COMPILER_PB_ENABLE_PREVIEW_FEATURES flag.
if (await lsPlugin.detectPreviewFlag(config.mainClass, config.projectName)) {
config.vmArgs = (config.vmArgs || "") + " --enable-preview";
}
if (config.request === "launch" && (!config.shortenCommandLine || config.shortenCommandLine === "auto")) {
config.shortenCommandLine = await detectLaunchCommandStyle(config);
}
if (process.platform === "win32" && config.request === "launch" && config.console !== "internalConsole") {
config.launcherScript = utility.getLauncherScriptPath();
}
const debugServerPort = await lsPlugin.startDebugSession();
if (debugServerPort) {
config.debugServer = debugServerPort;

View File

@ -100,3 +100,7 @@ export async function isOnClasspath(uri: string): Promise<boolean> {
export function resolveJavaExecutable(mainClass, projectName) {
return commands.executeJavaLanguageServerCommand(commands.JAVA_RESOLVE_JAVAEXECUTABLE, mainClass, projectName);
}
export function fetchPlatformSettings(): any {
return commands.executeJavaLanguageServerCommand(commands.JAVA_FETCH_PLATFORM_SETTINGS);
}

View File

@ -5,8 +5,9 @@ import * as _ from "lodash";
import * as path from "path";
import * as vscode from "vscode";
import { inferLaunchCommandLength } from "./languageServerPlugin";
import { getJavaHome } from "./utility";
import { UNSUPPORTED_CLASS_VERSION_ERROR } from "./anchor";
import { fetchPlatformSettings, inferLaunchCommandLength } from "./languageServerPlugin";
import { getJavaHome, showWarningMessageWithTroubleshooting } from "./utility";
enum shortenApproach {
none = "none",
@ -21,6 +22,24 @@ export async function detectLaunchCommandStyle(config: vscode.DebugConfiguration
return (await shouldShortenIfNecessary(config)) ? recommendedShortenApproach : shortenApproach.none;
}
export async function validateRuntime(config: vscode.DebugConfiguration) {
try {
const platformSettings = await fetchPlatformSettings();
if (platformSettings && platformSettings.latestSupportedJavaVersion) {
const latestSupportedVersion = flattenMajorVersion(platformSettings.latestSupportedJavaVersion);
const runtimeVersion = await checkJavaVersion(config.javaExec || path.join(await getJavaHome(), "bin", "java"));
if (latestSupportedVersion < runtimeVersion) {
showWarningMessageWithTroubleshooting({
message: "The compiled classes are not compatible with the runtime JDK. To mitigate the issue, please refer to \"Learn More\".",
anchor: UNSUPPORTED_CLASS_VERSION_ERROR,
});
}
}
} catch (err) {
// do nothing
}
}
function checkJavaVersion(javaExec: string): Promise<number> {
return new Promise((resolve, reject) => {
cp.execFile(javaExec, ["-version"], {}, (error, stdout, stderr) => {
@ -31,24 +50,29 @@ function checkJavaVersion(javaExec: string): Promise<number> {
}
function parseMajorVersion(content: string): number {
let regexp = /version "(.*)"/g;
let match = regexp.exec(content);
const regexp = /version "(.*)"/g;
const match = regexp.exec(content);
if (!match) {
return 0;
}
let version = match[1];
return flattenMajorVersion(match[1]);
}
function flattenMajorVersion(version: string): number {
// Ignore '1.' prefix for legacy Java versions
if (version.startsWith("1.")) {
version = version.substring(2);
}
// look into the interesting bits now
regexp = /\d+/g;
match = regexp.exec(version);
const regexp = /\d+/g;
const match = regexp.exec(version);
let javaVersion = 0;
if (match) {
javaVersion = parseInt(match[0], 10);
}
return javaVersion;
}