Search code examples
javajavafxvisual-studio-codeant

How to resolve 'import javafx cannot be resolved' in VSCode?


I am working on a simple program of JavaFX, HelloFX. I execute tasks like building or launching with ant. I have zero problems with that, it works perfectly so the code and the libraries are well linked in build.xml as you can see in the code.

But, VSCode does not find JavaFX and says 'import javafx cannot be resolved'. So I am wondering how does VSCode find Java dependencies? And how could he find the JavaFX one, As ant does? I thought that VSCode uses build.xml to find dependencies so, maybe I am wrong, or maybe my build.xml is bad.

Thank you in advance for your help!

<project name="HelloFX" basedir="." default="rebuild-run">



<property name="src.dir"     value="src"/>
<property name="lib.dir"     value="/home/rafael/javafx-sdk-12.0.1/lib"/>
<path id="classpath">
    <fileset dir="${lib.dir}" includes="**/*.jar"/>
</path>

<property name="build.dir"   value="bin"/>
<property name="classes.dir" value="${build.dir}/classes"/>
<property name="jar.dir"     value="${build.dir}/jar"/>

<property name="main-class"  value="${ant.project.name}"/>


<target name="clean">
    <delete dir="${build.dir}"/>
</target>

<target name="compile">
    <mkdir dir="${classes.dir}"/>
    <javac includeantruntime="false" srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath" modulepath="/home/rafael/javafx-sdk-12.0.1/lib">
        <compilerarg line="--add-modules javafx.controls"/> 
    </javac>
</target>

<target name="jar" depends="compile">
    <mkdir dir="${jar.dir}"/>
    <jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}">
        <manifest>
            <attribute name="Main-Class" value="${main-class}"/>
        </manifest>
    </jar>
</target>

<target name="run" depends="jar">
    <java fork="true" classname="${main-class}"  modulepath="/home/rafael/javafx-sdk-12.0.1/lib" >
        <jvmarg line="--add-modules javafx.controls"/>
        <sysproperty key="java.library.path" path="$(lib.dir)"/>
        <classpath>
            <path refid="classpath"/>
            <path location="${jar.dir}/${ant.project.name}.jar"/>
        </classpath>
    </java>
</target>

<target name="rebuild" depends="clean,jar"/>

<target name="rebuild-run" depends="clean,run"/>


Solution

  • There is an Ant extension for VSCode, named Ant Target Runner.

    Once you install it, you can open your JavaFX project that contains a build.xml file at the root directory.

    I was able to modify a little bit your build above, in order to add a run target, and run HelloFX from here.

    <?xml version="1.0" encoding="UTF-8"?>
    <project name="HelloFX" default="default" basedir="." xmlns:fx="javafx:com.sun.javafx.tools.ant">
    
    <property name="src.dir"     value="src"/>
    <property name="lib.dir"     value="/Users/user/Downloads/javafx-sdk-12.0.1/lib"/>
    <path id="classpath">
        <fileset dir="${lib.dir}" includes="**/*.jar"/>
    </path>
    
    <property name="build.dir"   value="bin"/>
    <property name="classes.dir" value="${build.dir}/classes"/>
    <property name="jar.dir"     value="${build.dir}/jar"/>
    
    <property name="main-class"  value="hellofx.Main"/>
    
    <property environment="env"/>
    <target name="clean">
        <!-- Verify that JDK is 11+ -->
        <echo message="JAVA_HOME is set to = ${env.JAVA_HOME}" />
        <delete dir="${build.dir}"/>
    </target>
    
    <target name="compile">
        <mkdir dir="${classes.dir}"/>
        <javac includeantruntime="false" srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath" modulepath="/Users/user/Downloads/javafx-sdk-12.0.1/lib">
            <compilerarg line="--add-modules javafx.controls,javafx.fxml"/> 
        </javac>
        <copy todir="${classes.dir}">
        <fileset dir="src"
                 includes="**/*.fxml,**/*.properties,**/*.css" />
    </copy>
    </target>
    
    <target name="run" depends="jar">
        <java fork="true" modulepath="/Users/user/Downloads/javafx-sdk-12.0.1/lib" jar="${jar.dir}/${ant.project.name}.jar">
            <jvmarg line="--add-modules javafx.controls,javafx.fxml"/> 
        </java>
    </target>
    
    <target name="jar" depends="compile">
        <mkdir dir="${jar.dir}"/>
        <jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}">
            <manifest>
                <attribute name="Main-Class" value="${main-class}"/>
            </manifest>
        </jar>
    </target>
    </project>
    

    Every time you modify the file and save it, the ant target panel is reloaded and the targets show up:

    VSCode with Ant

    If you run any of the targets, the output is shown in the terminal.

    Make sure you have JDK 11+ selected (I've added an echo to the clean target). If that is not the case, you can set it directly from the same terminal (export JAVA_HOME=...).

    Then you can run the run target and get the app working:

    Running Ant from VSCode

    Note that while this works fine, it will be more convenient to use build tools like Maven or Gradle.

    Getting the IDE to use the JavaFX library

    By default, you will get a warning message Classpath is incomplete, and there is no autocompletion for JavaFX classes.

    Since VSCode is expecting a Maven pom.xml or an Eclipse .classpath file, I'm going to add the latter:

    <?xml version="1.0" encoding="UTF-8"?>
    <classpath>
        <classpathentry kind="src" output="bin/classes" path="src/">
            <attributes>
                <attribute name="optional" value="true"/>
                <attribute name="maven.pomderived" value="false"/>
            </attributes>
        </classpathentry>
        <classpathentry kind="lib" path="/Users/user/Downloads/javafx-sdk-12.0.1/lib/javafx.base.jar"/>
        <classpathentry kind="lib" path="/Users/user/Downloads/javafx-sdk-12.0.1/lib/javafx.graphics.jar"/>
        <classpathentry kind="lib" path="/Users/user/Downloads/javafx-sdk-12.0.1/lib/javafx.controls.jar"/>
        <classpathentry kind="lib" path="/Users/user/Downloads/javafx-sdk-12.0.1/lib/javafx.fxml.jar"/>
    
        <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-12">
            <attributes>
                <attribute name="maven.pomderived" value="true"/>
            </attributes>
        </classpathentry>
        <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
            <attributes>
                <attribute name="maven.pomderived" value="true"/>
            </attributes>
        </classpathentry>
    </classpath>
    

    And that seems to solve the issues with JavaFX syntax and autocompletion. Note that this might require installing Eclipse.

    JavaFX syntax

    Finally you can add the same launcher.json as in here, so you can run the app directly, without the ant tasks (though I take this isn't your goal).