Skip to content

Commit 656beaa

Browse files
Show a warning message about the Unsupported JDK error (#790)
* Show a warning message about the Unsupported JDK error Signed-off-by: Jinbo Wang <[email protected]> * adjust the description Signed-off-by: Jinbo Wang <[email protected]> * Improve troubleshooting description Signed-off-by: Jinbo Wang <[email protected]>
1 parent 6b52079 commit 656beaa

File tree

6 files changed

+80
-29
lines changed

6 files changed

+80
-29
lines changed

Troubleshooting.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,26 @@ This error indicates your application attempts to reference some classes which a
5151
3. Run VS Code command *"Java: Force Java compilation"* to force the language server to rebuild the current project.
5252
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.
5353

54+
## Program throws UnsupportedClassVersionError
55+
Below is a typical error message.
56+
57+
![image](https://user-images.githubusercontent.com/14052197/78854443-ed47c780-7a53-11ea-8317-d8b097dfba99.png)
58+
59+
### Reason:
60+
The compiled classes are not compatible with the runtime JDK.
61+
62+
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.
63+
64+
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.
65+
66+
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.
67+
68+
### Try:
69+
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.
70+
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.
71+
3. Click **F1** -> **Java: Force Java compilation** -> **Full** to rebuild the workspace.
72+
4. If it still doesn't work, then try **F1** -> **Java: Clean the Java language server workspace** to clean the cache.
73+
5474
## Failed to complete hot code replace:
5575
### Reason:
5676
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.

src/anchor.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ export const ATTACH_CONFIG_ERROR = "please-specify-the-host-name-and-the-port-of
77
export const EVALUATE_ON_RUNNING_THREAD = "failed-to-evaluate-reason-cannot-evaluate-because-the-thread-is-resumed";
88
export const CANNOT_FIND_MAIN_CLASS = "cannot-find-a-class-with-the-main-method";
99
export const BUILD_FAILED = "build-failed-do-you-want-to-continue";
10+
export const UNSUPPORTED_CLASS_VERSION_ERROR = "program-throws-unsupportedclassversionerror";

src/commands.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ export const JAVA_IS_ON_CLASSPATH = "vscode.java.isOnClasspath";
3838

3939
export const JAVA_RESOLVE_JAVAEXECUTABLE = "vscode.java.resolveJavaExecutable";
4040

41+
export const JAVA_FETCH_PLATFORM_SETTINGS = "vscode.java.fetchPlatformSettings";
42+
4143
export function executeJavaLanguageServerCommand(...rest) {
4244
return executeJavaExtensionCommand(JAVA_EXECUTE_WORKSPACE_COMMAND, ...rest);
4345
}

src/configurationProvider.ts

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import * as anchor from "./anchor";
1111
import { buildWorkspace } from "./build";
1212
import * as commands from "./commands";
1313
import * as lsPlugin from "./languageServerPlugin";
14-
import { detectLaunchCommandStyle } from "./launchCommand";
14+
import { detectLaunchCommandStyle, validateRuntime } from "./launchCommand";
1515
import { logger, Type } from "./logger";
1616
import * as utility from "./utility";
1717
import { VariableResolver } from "./variableResolver";
@@ -207,6 +207,27 @@ export class JavaDebugConfigurationProvider implements vscode.DebugConfiguration
207207
config.javaExec = await lsPlugin.resolveJavaExecutable(config.mainClass, config.projectName);
208208
// Add the default launch options to the config.
209209
config.cwd = config.cwd || _.get(folder, "uri.fsPath");
210+
if (Array.isArray(config.args)) {
211+
config.args = this.concatArgs(config.args);
212+
}
213+
214+
if (Array.isArray(config.vmArgs)) {
215+
config.vmArgs = this.concatArgs(config.vmArgs);
216+
}
217+
218+
// Auto add '--enable-preview' vmArgs if the java project enables COMPILER_PB_ENABLE_PREVIEW_FEATURES flag.
219+
if (await lsPlugin.detectPreviewFlag(config.mainClass, config.projectName)) {
220+
config.vmArgs = (config.vmArgs || "") + " --enable-preview";
221+
validateRuntime(config);
222+
}
223+
224+
if (!config.shortenCommandLine || config.shortenCommandLine === "auto") {
225+
config.shortenCommandLine = await detectLaunchCommandStyle(config);
226+
}
227+
228+
if (process.platform === "win32" && config.console !== "internalConsole") {
229+
config.launcherScript = utility.getLauncherScriptPath();
230+
}
210231
} else if (config.request === "attach") {
211232
if (!config.hostName || !config.port) {
212233
throw new utility.UserError({
@@ -223,27 +244,6 @@ export class JavaDebugConfigurationProvider implements vscode.DebugConfiguration
223244
});
224245
}
225246

226-
if (Array.isArray(config.args)) {
227-
config.args = this.concatArgs(config.args);
228-
}
229-
230-
if (Array.isArray(config.vmArgs)) {
231-
config.vmArgs = this.concatArgs(config.vmArgs);
232-
}
233-
234-
// Auto add '--enable-preview' vmArgs if the java project enables COMPILER_PB_ENABLE_PREVIEW_FEATURES flag.
235-
if (await lsPlugin.detectPreviewFlag(config.mainClass, config.projectName)) {
236-
config.vmArgs = (config.vmArgs || "") + " --enable-preview";
237-
}
238-
239-
if (config.request === "launch" && (!config.shortenCommandLine || config.shortenCommandLine === "auto")) {
240-
config.shortenCommandLine = await detectLaunchCommandStyle(config);
241-
}
242-
243-
if (process.platform === "win32" && config.request === "launch" && config.console !== "internalConsole") {
244-
config.launcherScript = utility.getLauncherScriptPath();
245-
}
246-
247247
const debugServerPort = await lsPlugin.startDebugSession();
248248
if (debugServerPort) {
249249
config.debugServer = debugServerPort;

src/languageServerPlugin.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,7 @@ export async function isOnClasspath(uri: string): Promise<boolean> {
100100
export function resolveJavaExecutable(mainClass, projectName) {
101101
return commands.executeJavaLanguageServerCommand(commands.JAVA_RESOLVE_JAVAEXECUTABLE, mainClass, projectName);
102102
}
103+
104+
export function fetchPlatformSettings(): any {
105+
return commands.executeJavaLanguageServerCommand(commands.JAVA_FETCH_PLATFORM_SETTINGS);
106+
}

src/launchCommand.ts

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ import * as _ from "lodash";
55
import * as path from "path";
66
import * as vscode from "vscode";
77

8-
import { inferLaunchCommandLength } from "./languageServerPlugin";
9-
import { getJavaHome } from "./utility";
8+
import { UNSUPPORTED_CLASS_VERSION_ERROR } from "./anchor";
9+
import { fetchPlatformSettings, inferLaunchCommandLength } from "./languageServerPlugin";
10+
import { getJavaHome, showWarningMessageWithTroubleshooting } from "./utility";
1011

1112
enum shortenApproach {
1213
none = "none",
@@ -21,6 +22,24 @@ export async function detectLaunchCommandStyle(config: vscode.DebugConfiguration
2122
return (await shouldShortenIfNecessary(config)) ? recommendedShortenApproach : shortenApproach.none;
2223
}
2324

25+
export async function validateRuntime(config: vscode.DebugConfiguration) {
26+
try {
27+
const platformSettings = await fetchPlatformSettings();
28+
if (platformSettings && platformSettings.latestSupportedJavaVersion) {
29+
const latestSupportedVersion = flattenMajorVersion(platformSettings.latestSupportedJavaVersion);
30+
const runtimeVersion = await checkJavaVersion(config.javaExec || path.join(await getJavaHome(), "bin", "java"));
31+
if (latestSupportedVersion < runtimeVersion) {
32+
showWarningMessageWithTroubleshooting({
33+
message: "The compiled classes are not compatible with the runtime JDK. To mitigate the issue, please refer to \"Learn More\".",
34+
anchor: UNSUPPORTED_CLASS_VERSION_ERROR,
35+
});
36+
}
37+
}
38+
} catch (err) {
39+
// do nothing
40+
}
41+
}
42+
2443
function checkJavaVersion(javaExec: string): Promise<number> {
2544
return new Promise((resolve, reject) => {
2645
cp.execFile(javaExec, ["-version"], {}, (error, stdout, stderr) => {
@@ -31,24 +50,29 @@ function checkJavaVersion(javaExec: string): Promise<number> {
3150
}
3251

3352
function parseMajorVersion(content: string): number {
34-
let regexp = /version "(.*)"/g;
35-
let match = regexp.exec(content);
53+
const regexp = /version "(.*)"/g;
54+
const match = regexp.exec(content);
3655
if (!match) {
3756
return 0;
3857
}
39-
let version = match[1];
58+
59+
return flattenMajorVersion(match[1]);
60+
}
61+
62+
function flattenMajorVersion(version: string): number {
4063
// Ignore '1.' prefix for legacy Java versions
4164
if (version.startsWith("1.")) {
4265
version = version.substring(2);
4366
}
4467

4568
// look into the interesting bits now
46-
regexp = /\d+/g;
47-
match = regexp.exec(version);
69+
const regexp = /\d+/g;
70+
const match = regexp.exec(version);
4871
let javaVersion = 0;
4972
if (match) {
5073
javaVersion = parseInt(match[0], 10);
5174
}
75+
5276
return javaVersion;
5377
}
5478

0 commit comments

Comments
 (0)