Skip to content

Commit 562afa8

Browse files
Add a setting 'java.jdt.ls.java.home' to manually set up a JDK to start JLS (#2284)
* Add a setting 'java.jdt.ls.java.home' to manually set up a JDK to start JLS Signed-off-by: Jinbo Wang <[email protected]>
1 parent 873d0ae commit 562afa8

File tree

4 files changed

+108
-64
lines changed

4 files changed

+108
-64
lines changed

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Quick Start
1212
============
1313
1. Install the Extension
1414
2. If you do not have a _Java_ Development Kit correctly [set](#setting-the-jdk)
15-
* Download and install a Java Development Kit for your project (Java 1.5 or above is supported)
15+
* Download and install a Java Development Kit for your project (Java 1.5 or above is supported)
1616
3. Extension is activated when you first access a Java file
1717
* Recognizes projects with *Maven* or *Gradle* build files in the directory hierarchy.
1818

@@ -60,7 +60,7 @@ The following part is only kept for the universal version without embedded JRE.
6060

6161
>The tooling JDK will be used to launch the Language Server for Java. And by default, will also be used to compile your projects.\
6262
\
63-
The path to the Java Development Kit can be specified by the `java.home` setting in VS Code settings (workspace/user settings). If not specified, it is searched in the following order until a JDK meets current minimum requirement.
63+
The path to the Java Development Kit can be specified by the `java.jdt.ls.java.home` setting in VS Code settings (workspace/user settings). If not specified, it is searched in the following order until a JDK meets current minimum requirement.
6464
>- the `JDK_HOME` environment variable
6565
>- the `JAVA_HOME` environment variable
6666
>- on the current system path
@@ -110,7 +110,7 @@ Supported VS Code settings
110110
==========================
111111
The following settings are supported:
112112

113-
* `java.home` : **Deprecated, only used for universal version without embedded JRE.** Absolute path to JDK home folder used to launch the Java Language Server. Requires VS Code restart.
113+
* `java.home` : **Deprecated, please use 'java.jdt.ls.java.home' instead.** Absolute path to JDK home folder used to launch the Java Language Server. Requires VS Code restart.
114114
* `java.jdt.ls.vmargs` : Extra VM arguments used to launch the Java Language Server. Requires VS Code restart.
115115
* `java.errors.incompleteClasspath.severity` : Specifies the severity of the message when the classpath is incomplete for a Java file. Supported values are `ignore`, `info`, `warning`, `error`.
116116
* `java.trace.server` : Traces the communication between VS Code and the Java language server.
@@ -196,12 +196,12 @@ The following settings are supported:
196196
- `lastMember`: Insert the generated code as the last member of the target type.
197197
* `java.settings.url` : Specifies the url or file path to the workspace Java settings. See [Setting Global Preferences](https://github.com/redhat-developer/vscode-java/wiki/Settings-Global-Preferences)
198198
* `java.symbols.includeSourceMethodDeclarations` : Include method declarations from source files in symbol search. Defaults to `false`.
199-
200-
New in 1.1.0:
201199
* `java.quickfix.showAt` : Show quickfixes at the problem or line level.
202200
* `java.configuration.workspaceCacheLimit` : The number of days (if enabled) to keep unused workspace cache data. Beyond this limit, cached workspace data may be removed.
203201
* `java.import.generatesMetadataFilesAtProjectRoot` : Specify whether the project metadata files(.project, .classpath, .factorypath, .settings/) will be generated at the project root. Defaults to `false`.
204202

203+
New in 1.3.0:
204+
* `java.jdt.ls.java.home`: Absolute path to JDK home folder used to launch the Java Language Server. This setting will replace the Java extension's embedded JRE to start the Java Language Server. Requires VS Code restart.
205205

206206
Semantic Highlighting
207207
===============

package.json

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"untrustedWorkspaces": {
1515
"supported": "limited",
1616
"restrictedConfigurations": [
17+
"java.jdt.ls.java.home",
1718
"java.home",
1819
"java.jdt.ls.vmargs"
1920
]
@@ -171,7 +172,16 @@
171172
"default": null,
172173
"description": "Specifies the folder path to the JDK (11 or more recent) used to launch the Java Language Server.\nOn Windows, backslashes must be escaped, i.e.\n\"java.home\":\"C:\\\\Program Files\\\\Java\\\\jdk11.0_8\"",
173174
"scope": "machine-overridable",
174-
"deprecationMessage": "This setting will be deprecated, please use the environment variable 'JAVA_HOME' instead."
175+
"deprecationMessage": "This setting is deprecated, please use 'java.jdt.ls.java.home' instead."
176+
},
177+
"java.jdt.ls.java.home": {
178+
"type": [
179+
"string",
180+
"null"
181+
],
182+
"default": null,
183+
"description": "Specifies the folder path to the JDK (11 or more recent) used to launch the Java Language Server. This setting will replace the Java extension's embedded JRE to start the Java Language Server. \n\nOn Windows, backslashes must be escaped, i.e.\n\"java.jdt.ls.java.home\":\"C:\\\\Program Files\\\\Java\\\\jdk11.0_8\"",
184+
"scope": "machine-overridable"
175185
},
176186
"java.jdt.ls.vmargs": {
177187
"type": [

src/requirements.ts

Lines changed: 44 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,12 @@ export async function resolveRequirements(context: ExtensionContext): Promise<Re
3434
let toolingJre: string = await findEmbeddedJRE(context);
3535
let toolingJreVersion: number = await getMajorVersion(toolingJre);
3636
return new Promise(async (resolve, reject) => {
37-
let source: string;
37+
const javaPreferences = await checkJavaPreferences(context);
38+
const preferenceName = javaPreferences.preference;
39+
let javaHome = javaPreferences.javaHome;
3840
let javaVersion: number = 0;
39-
let javaHome = await checkJavaPreferences(context);
40-
if (!toolingJre && javaHome) { // "java.home" setting is only used for the universal version.
41-
source = `java.home variable defined in ${env.appName} settings`;
41+
if (javaHome) {
42+
const source = `${preferenceName} variable defined in ${env.appName} settings`;
4243
javaHome = expandHomeDir(javaHome);
4344
if (!await fse.pathExists(javaHome)) {
4445
invalidJavaHome(reject, `The ${source} points to a missing or inaccessible folder (${javaHome})`);
@@ -52,51 +53,49 @@ export async function resolveRequirements(context: ExtensionContext): Promise<Re
5253
invalidJavaHome(reject, msg);
5354
}
5455
javaVersion = await getMajorVersion(javaHome);
55-
toolingJre = javaHome;
56-
toolingJreVersion = javaVersion;
57-
} else {
58-
// java.home not specified, search valid JDKs from env.JAVA_HOME, env.PATH, SDKMAN, jEnv, jabba, Common directories
59-
const javaRuntimes = await findRuntimes({checkJavac: true, withVersion: true, withTags: true});
60-
if (!toolingJre) { // universal version
61-
// as latest version as possible.
62-
sortJdksByVersion(javaRuntimes);
63-
const validJdks = javaRuntimes.filter(r => r.version.major >= REQUIRED_JDK_VERSION);
64-
if (validJdks.length > 0) {
65-
sortJdksBySource(validJdks);
66-
javaHome = validJdks[0].homedir;
67-
javaVersion = validJdks[0].version.major;
68-
toolingJre = javaHome;
69-
toolingJreVersion = javaVersion;
70-
}
71-
} else { // pick a default project JDK/JRE
72-
/**
73-
* For legacy users, we implicitly following the order below to
74-
* set a default project JDK during initialization:
75-
* java.home > env.JDK_HOME > env.JAVA_HOME > env.PATH
76-
*
77-
* We'll keep it for compatibility.
78-
*/
79-
if (javaHome && (await getRuntime(javaHome) !== undefined)) {
80-
const runtime = await getRuntime(javaHome, {withVersion: true});
81-
javaHome = runtime.homedir;
82-
javaVersion = runtime.version?.major;
83-
logger.info("Use the JDK from 'java.home' setting as the initial default project JDK.");
84-
} else if (javaRuntimes.length) {
85-
sortJdksBySource(javaRuntimes);
86-
javaHome = javaRuntimes[0].homedir;
87-
javaVersion = javaRuntimes[0].version?.major;
88-
logger.info(`Use the JDK from '${getSources(javaRuntimes[0])}' as the initial default project JDK.`);
89-
} else if (javaHome = await findDefaultRuntimeFromSettings()) {
90-
javaVersion = await getMajorVersion(javaHome);
91-
logger.info("Use the JDK from 'java.configuration.runtimes' as the initial default project JDK.");
92-
} else {
93-
openJDKDownload(reject, "Please download and install a JDK to compile your project. You can configure your projects with different JDKs by the setting ['java.configuration.runtimes'](https://github.com/redhat-developer/vscode-java/wiki/JDK-Requirements#java.configuration.runtimes)");
94-
}
56+
if (preferenceName === "java.jdt.ls.java.home" || !toolingJre) {
57+
toolingJre = javaHome;
58+
toolingJreVersion = javaVersion;
59+
}
60+
}
61+
62+
// search valid JDKs from env.JAVA_HOME, env.PATH, SDKMAN, jEnv, jabba, Common directories
63+
const javaRuntimes = await findRuntimes({ checkJavac: true, withVersion: true, withTags: true });
64+
if (!toolingJre) { // universal version
65+
// as latest version as possible.
66+
sortJdksByVersion(javaRuntimes);
67+
const validJdks = javaRuntimes.filter(r => r.version.major >= REQUIRED_JDK_VERSION);
68+
if (validJdks.length > 0) {
69+
sortJdksBySource(validJdks);
70+
javaHome = validJdks[0].homedir;
71+
javaVersion = validJdks[0].version.major;
72+
toolingJre = javaHome;
73+
toolingJreVersion = javaVersion;
74+
}
75+
} else { // pick a default project JDK/JRE
76+
/**
77+
* For legacy users, we implicitly following the order below to
78+
* set a default project JDK during initialization:
79+
* java.jdt.ls.java.home > java.home > env.JDK_HOME > env.JAVA_HOME > env.PATH
80+
*
81+
* We'll keep it for compatibility.
82+
*/
83+
if (javaHome) {
84+
logger.info("Use the JDK from 'java.home' setting as the initial default project JDK.");
85+
} else if (javaRuntimes.length) {
86+
sortJdksBySource(javaRuntimes);
87+
javaHome = javaRuntimes[0].homedir;
88+
javaVersion = javaRuntimes[0].version?.major;
89+
logger.info(`Use the JDK from '${getSources(javaRuntimes[0])}' as the initial default project JDK.`);
90+
} else if (javaHome = await findDefaultRuntimeFromSettings()) {
91+
javaVersion = await getMajorVersion(javaHome);
92+
logger.info("Use the JDK from 'java.configuration.runtimes' as the initial default project JDK.");
93+
} else {
94+
openJDKDownload(reject, "Please download and install a JDK to compile your project. You can configure your projects with different JDKs by the setting ['java.configuration.runtimes'](https://github.com/redhat-developer/vscode-java/wiki/JDK-Requirements#java.configuration.runtimes)");
9595
}
9696
}
9797

9898
if (!toolingJre || toolingJreVersion < REQUIRED_JDK_VERSION) {
99-
// For universal version, we still require users to install a qualified JDK to run Java extension.
10099
openJDKDownload(reject, `Java ${REQUIRED_JDK_VERSION} or more recent is required to run the Java extension. Please download and install a recent JDK. You can still compile your projects with older JDKs by configuring ['java.configuration.runtimes'](https://github.com/redhat-developer/vscode-java/wiki/JDK-Requirements#java.configuration.runtimes)`);
101100
}
102101

src/settings.ts

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import { cleanWorkspaceFileName } from './extension';
88
import { ensureExists, getJavaConfiguration } from './utils';
99

1010
const DEFAULT_HIDDEN_FILES: string[] = ['**/.classpath', '**/.project', '**/.settings', '**/.factorypath'];
11-
export const IS_WORKSPACE_JDK_ALLOWED = "java.ls.isJdkAllowed";
11+
const IS_WORKSPACE_JDK_ALLOWED = "java.ls.isJdkAllowed";
12+
const IS_WORKSPACE_JLS_JDK_ALLOWED = "java.jdt.ls.java.home.isAllowed";
1213
export const IS_WORKSPACE_VMARGS_ALLOWED = "java.ls.isVmargsAllowed";
1314
const extensionName = 'Language Support for Java';
1415
export const ACTIVE_BUILD_TOOL_STATE = "java.activeBuildTool";
@@ -102,7 +103,8 @@ function excludeProjectSettingsFilesForWorkspace(workspaceUri: Uri) {
102103
}
103104

104105
function hasJavaConfigChanged(oldConfig: WorkspaceConfiguration, newConfig: WorkspaceConfiguration) {
105-
return hasConfigKeyChanged('home', oldConfig, newConfig)
106+
return hasConfigKeyChanged('jdt.ls.java.home', oldConfig, newConfig)
107+
|| hasConfigKeyChanged('home', oldConfig, newConfig)
106108
|| hasConfigKeyChanged('jdt.ls.vmargs', oldConfig, newConfig)
107109
|| hasConfigKeyChanged('progressReports.enabled', oldConfig, newConfig)
108110
|| hasConfigKeyChanged('server.launchMode', oldConfig, newConfig);
@@ -125,30 +127,63 @@ export function getJavaEncoding(): string {
125127
return javaEncoding;
126128
}
127129

128-
export async function checkJavaPreferences(context: ExtensionContext) {
130+
export async function checkJavaPreferences(context: ExtensionContext): Promise<{javaHome?: string, preference: string}> {
129131
const allow = 'Allow';
130132
const disallow = 'Disallow';
131-
let javaHome = workspace.getConfiguration().inspect<string>('java.home').workspaceValue;
133+
let preference: string = 'java.jdt.ls.java.home';
134+
let javaHome = workspace.getConfiguration().inspect<string>('java.jdt.ls.java.home').workspaceValue;
132135
let isVerified = javaHome === undefined || javaHome === null;
133136
if (isVerified) {
134-
javaHome = getJavaConfiguration().get('home');
137+
javaHome = getJavaConfiguration().get('jdt.ls.java.home');
135138
}
136-
const key = getKey(IS_WORKSPACE_JDK_ALLOWED, context.storagePath, javaHome);
139+
const key = getKey(IS_WORKSPACE_JLS_JDK_ALLOWED, context.storagePath, javaHome);
137140
const globalState = context.globalState;
138141
if (!isVerified) {
139142
isVerified = globalState.get(key);
140143
if (isVerified === undefined) {
141-
await window.showErrorMessage(`Security Warning! Do you allow this workspace to set the java.home variable? \n java.home: ${javaHome}`, disallow, allow).then(async selection => {
144+
await window.showErrorMessage(`Security Warning! Do you allow this workspace to set the java.jdt.ls.java.home variable? \n java.jdt.ls.java.home: ${javaHome}`, disallow, allow).then(async selection => {
142145
if (selection === allow) {
143146
globalState.update(key, true);
144147
} else if (selection === disallow) {
145148
globalState.update(key, false);
146-
await workspace.getConfiguration().update('java.home', undefined, ConfigurationTarget.Workspace);
149+
await workspace.getConfiguration().update('java.jdt.ls.java.home', undefined, ConfigurationTarget.Workspace);
147150
}
148151
});
149152
isVerified = globalState.get(key);
150153
}
154+
if (!isVerified) { // java.jdt.ls.java.home from workspace settings is disallowed.
155+
javaHome = workspace.getConfiguration().inspect<string>('java.jdt.ls.java.home').globalValue;
156+
}
157+
}
158+
159+
if (!javaHome) { // Read java.home from the deprecated "java.home" setting.
160+
preference = 'java.home';
161+
javaHome = workspace.getConfiguration().inspect<string>('java.home').workspaceValue;
162+
isVerified = javaHome === undefined || javaHome === null;
163+
if (isVerified) {
164+
javaHome = getJavaConfiguration().get('home');
165+
}
166+
const key = getKey(IS_WORKSPACE_JDK_ALLOWED, context.storagePath, javaHome);
167+
const globalState = context.globalState;
168+
if (!isVerified) {
169+
isVerified = globalState.get(key);
170+
if (isVerified === undefined) {
171+
await window.showErrorMessage(`Security Warning! Do you allow this workspace to set the java.home variable? \n java.home: ${javaHome}`, disallow, allow).then(async selection => {
172+
if (selection === allow) {
173+
globalState.update(key, true);
174+
} else if (selection === disallow) {
175+
globalState.update(key, false);
176+
await workspace.getConfiguration().update('java.home', undefined, ConfigurationTarget.Workspace);
177+
}
178+
});
179+
isVerified = globalState.get(key);
180+
}
181+
if (!isVerified) { // java.home from workspace settings is disallowed.
182+
javaHome = workspace.getConfiguration().inspect<string>('java.home').globalValue;
183+
}
184+
}
151185
}
186+
152187
const vmargs = workspace.getConfiguration().inspect('java.jdt.ls.vmargs').workspaceValue;
153188
if (vmargs !== undefined) {
154189
const isWorkspaceTrusted = (workspace as any).isTrusted; // keep compatibility for old engines < 1.56.0
@@ -168,11 +203,11 @@ export async function checkJavaPreferences(context: ExtensionContext) {
168203
}
169204
}
170205
}
171-
if (isVerified) {
172-
return javaHome;
173-
} else {
174-
return workspace.getConfiguration().inspect<string>('java.home').globalValue;
175-
}
206+
207+
return {
208+
javaHome,
209+
preference
210+
};
176211
}
177212

178213
export function getKey(prefix, storagePath, value) {

0 commit comments

Comments
 (0)