javavisual-studio-code

How does Visual Studio Code compile Java code?


For example, there is a base class HelloWorld.java

package main;

public class HelloWorld {
    public static void main(String[] args) {
        
    }
    
}

When I first run the program with "Run Java", the following command appears in the terminal:

& 'C:\Program Files\Java\jdk-23\bin\java.exe' '@C:\Users\User\AppData\Local\Temp\cp_9ml7m3ovzvunqyna5xgx27y4b.argfile' 'main.HelloWorld' 

when secondly:

  c:; cd 'c:\Users\User\VStudioPorjects\Hello'; & 'C:\Program Files\Java\jdk-23\bin\java.exe' '@C:\Users\User\AppData\Local\Temp\cp_9ml7m3ovzvunqyna5xgx27y4b.argfile' 'main.HelloWorld' 

Where:

cd 'c:\Users\User\VStudioPorjects\Hello'; - change directory to my project.

C:\Program Files\Java\jdk-23\bin\java.exe - path to the file that runs the already compiled class.

@C:\\Users\\User\\AppData\\Local\\Temp\\cp_9ml7m3ovzvunqyna5xgx27y4b.argfile - argfile that keep different libraries.

main.HelloWorld - class with package.

How does compilation happen? Where is javac? Why is Hello.class file created when the class is first run, but when it is deleted and run again, the file is not re-created, and the error java.lang.ClassNotFoundException: main.Hello occurs?

ps: I disabled java.autobuild

I tried to find an answer for my problem in the VS Code web site but didn't find anything.

I read the readme from Language Support for Java(TM) by Red Hat but there was no explanation in it.


Solution

  • VSC doesn't use javac, it uses the Eclipse Java Compiler.

    Specifically, it uses the Language Server Protocol to communicate with external processes called language servers which handle language specific tooling (code completion, compilation, etc). The RedHat extension uses the JDT-LS language server which in turn uses the Eclipse Compiler for Java (ECJ). This is an alternative compiler to javac that offers a different DOM API, better incremental compilation, additional warnings as well as additional capabilities and is optimized for use within IDEs. It doesn't run ECJ in a new process whenever you want to compile the application. Instead, there is one process and any compilations are done in that process.

    In addition to running ECJ by compiling via VSC (or the Eclipse IDE), you can also run it from the command-line. After downloading it, you can the compiler (which is just a Java application) with java -jar and add additional arguments at the end. As ECJ doesn't use the JDK it is running on as a baseline, you can add the jDK to the classpath/moduleoath.

    JDT-LS is also capable of using javac which can be used from VSC. To switch to javac, you can set java.jdt.ls.javac.enabled to on. It would still use the JDT APIs but internally, EJC would be switched out by javac.
    Please note that even with this option, you probably won't see a command-line invocation for javac as it would still keep it in one process.