Open megri opened 5 days ago
I'm sitting here writing a small VSCode plugin that tests different ways of accessing env. With jenv
, you control the JAVA_HOME property by setting a value in a file .java-version, which is activated when you cd into the directory. Not sure how exactly it works—I was never very good at OS-specific stuff—but the net result is that process.env from within an extension seems to be bound to an env where JAVA_HOME has not been initialised by jenv. Which makes sense, coming to think of it, as if you start VSCode from Spotlight how could it. This value is never updated.
What I did find was that it's possible to grab the workspace's env by forking a new process that calls env with workdir set to the project root. This is quite slow though, and opens up new questions, like how to pick the correct shell to run.
A better way might be to forgo JAVA_HOME
entirely and use the specific tool's way of calling/locating the active java version, but that would require some way of finding the java version manager tool itself and using it in the correct way..
metals.javaVersion dictates what version metals should start with, though if you choose 17 and we find 21 then we will use that. Bloop should use the same version unless it was started separately, but we will try to restart it if the version changed (we might need to double check that one.)
JAVA_HOME is a pretty standard way tools use to specify the java home to be used and I don't think we should forgo that. And there should not be an issue if the version of that java is correct, metals will work correctly.
There was a lot of issues detecting Java and I'd rather keep what we have right now with possible fixes.
The algorithm is:
The actual specific Java versions used by metals doesn't really matter unless it's lower than what you might need, We always add proper -release flags based on the version set in metals.javaHome, which is the java version to be used for the project.
What problems do you actually encounter if the java is not the one you expect?
There's a multitude of problems with using JAVA_HOME:
To be fair having Metals use JAVA_HOME to get at least something running is nice, but it is still quite hard to understand what you're actually using, especially as your terminal might well report a different JAVA_HOME than what's detected by Metals.
However, working on different projects in as few as two separate vscode-windows using two different JDKs, I've found myself chasing environment variables around trying to understand why one of the project suddenly starts reporting that String#indent
(which was added in Java 12) doesn't exist.
It is impossible to configure a project so that other users can open them and have the correct JDK used.
I think a much safer approach is just to use "-release" flags which means you will not ever publish a wrong bytecode version by default and it doesn't matter what JDK user has as long as it's higher than the release flag version. You don't have to make sure that the build tools picks up a correct java version either.
When working in multi-root workspaces where projects run on different java versions this becomes a nightmare since I can no longer know/trust which JDK is used to compile which project;
I would really want to know what problems you are encountering here. It should not be an issue especially since Bloop will report the correct errors according to metals.javaHome
version or anything set up by the build tool.
So ideally, Java version should be set up by the build tools (some special variable or just release flag) and Bloop/Metals will take care of it having all the errors that it should.
And also coming back to you description:
What is important is that both compile server and language server are kept in sync, so to not create a situation where code that looks like it should compile doesn't or compiled code refers to symbols not available in the language server.
This is handled currently, there might be some issues to improve, but the errors and completions should be correct.
I would really want to know what problems you are encountering here. It should not be an issue especially since Bloop will report the correct errors according to
metals.javaHome
version or anything set up by the build tool.So ideally, Java version should be set up by the build tools (some special variable or just release flag) and Bloop/Metals will take care of it having all the errors that it should.
Issues I've seen is that Bloop is running with the wrong JDK/flag so that a project for which say JDK 17 is used, is reported as using methods that do not exist, such as String#indent
which came in JDK 12. Other issues is Metals picking up the wrong JDK even though the correct JAVA_HOME is set for the current session.
My more "shell-savvy" colleague tried helping me look into this yesterday, and it seemed like either VSCode or metals uses the path /
when launching, which means JAVA_HOME comes from whatever is configured in the user's home directory, depending on which tool the user is using to provision JDKs. Everyone in the team is using the same tool for this at least, but not everyone has the same JDK set in their user config.
If metals picked up the JDK from the workspace root it'd probably work better, not sure how it would handle multi-projects though 🤔
Issues I've seen is that Bloop is running with the wrong JDK/flag so that a project for which say JDK 17 is used, is reported as using methods that do not exist, such as String#indent which came in JDK 12.
That's not really possible if we use JDK 17+ by default, unless metals.javaHome
is set to JDK 11 or 8. Or the export from the build tool used a lower JDK. You can confirm that in the metals doctor.
Other issues is Metals picking up the wrong JDK even though the correct JAVA_HOME is set for the current session.
As I said this should not be an issue at all since Metals just uses any correct version that it finds, it has nothing to do with the version that you might want to use for compilation.
The build tool need to export the proper JDK or you need to modify metals.javaHome
manually.
If metals picked up the JDK from the workspace root it'd probably work better, not sure how it would handle multi-projects though 🤔
How it's defined? I am not aware of cases where JAVA_HOME or other env variables were different depending on directory.
metals-vscode does a bunch of work to find a version of java which to run:
java
onPATH
, it runs a small java-snippet in a shell process which captures the the java.home property of the java-process.metals.javaVersion
in the plugin. I'm not sure when this is used. It lets me select either 17 or 21.metals.javaHome
setting which in my installation is a blank free text field but says it defaults whatevermetals.javaVersion
is set to.Note that I set the
metals.javaVersion
to 21 but it still usedJAVA_HOME
and managed to locate java 17, which I did not want. At the same time my integrated shell reported no JAVA_HOME being set, whilejava -version
reported the desired version 21.Since the metals language server has a different lifecycle than bloop, the java version used for metals might differ from the java-version used by bloop, which exacerbates the problem.
Expected behavior If using either JAVA_HOME or PATH:java is desired, the values used for these should be the ones available from the project root: different tools in this space sets (usually) both of these depending on some arbitrary logic, usually from a
.java-version
or.tool-versions
file which lists the version of java to use for the workspace, but the actual mechanism is not really important.What is important is that both compile server and language server are kept in sync, so to not create a situation where code that looks like it should compile doesn't or compiled code refers to symbols not available in the language server.
If the
metals.javaVersion
setting is meant to dictate which version of java to use for the whole of the project then JAVA_HOME should not be searched. If it is only meant to be used for a component which does not provide code introspection but only shuffles data between vscode and bloop, then I think it shouldn't be a controllable setting, as the plugin could manage this version by itself.As an aside other tools, for instance IntelliJ, keeps a list of JVMs that the user can choose from for his projects. There are no surprises, other than a JVM missing, which is easy to signal to the user with an error message. Perhaps this would be a better solution to the problem?
Search terms JAVA_HOME