Mr. Proper
Mr. Proper

Reputation: 43

How to build JavaFX app with Maven in 2021?

I need to support legacy JavaFX app which I cannot build and run properly. The app is fairly complex so instead on experimenting on it I made simple "Hello world" project. I could not compile it either. I'm hoping someone can point out my mistakes.

I started with this example, which is mentioned in JavaFX documentation: https://github.com/openjfx/samples

owner@owner-desktop:~$ mkdir example
owner@owner-desktop:~$ cd example/
owner@owner-desktop:~/example$ git clone https://github.com/openjfx/samples/
Cloning into 'samples'...
remote: Enumerating objects: 1870, done.
remote: Counting objects: 100% (215/215), done.
remote: Compressing objects: 100% (154/154), done.
remote: Total 1870 (delta 75), reused 183 (delta 56), pack-reused 1655
Receiving objects: 100% (1870/1870), 385.56 KiB | 3.38 MiB/s, done.
Resolving deltas: 100% (702/702), done.
owner@owner-desktop:~/example$ cd samples/HelloFX/Maven/hellofx/
owner@owner-desktop:~/example/samples/HelloFX/Maven/hellofx$ mvn package
[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------------< org.openjfx:hellofx >-------------------------
[INFO] Building demo 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hellofx ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/owner/example/samples/HelloFX/Maven/hellofx/src/main/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ hellofx ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /home/owner/example/samples/HelloFX/Maven/hellofx/target/classes
[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR : 
[INFO] -------------------------------------------------------------
[ERROR] Source option 5 is no longer supported. Use 6 or later.
[ERROR] Target option 1.5 is no longer supported. Use 1.6 or later.
[INFO] 2 errors 
[INFO] -------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.042 s
[INFO] Finished at: 2021-06-23T10:10:38+03:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project hellofx: Compilation failure: Compilation failure: 
[ERROR] Source option 5 is no longer supported. Use 6 or later.
[ERROR] Target option 1.5 is no longer supported. Use 1.6 or later.
[ERROR] -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException

OK, maybe the pom file is a bit outdated, it lacks maven.compiler.source and maven.compiler.target. Let's add them:

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>org.openjfx</groupId>
      <artifactId>hellofx</artifactId>
      <packaging>jar</packaging>
      <version>1.0-SNAPSHOT</version>
      <name>demo</name>
      <url>http://maven.apache.org</url>

      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <javafx.version>11</javafx.version>
        <javafx.maven.plugin.version>0.0.6</javafx.maven.plugin.version>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
      </properties>

      <dependencies>
        <dependency>
          <groupId>org.openjfx</groupId>
          <artifactId>javafx-controls</artifactId>
          <version>${javafx.version}</version>
        </dependency>
      </dependencies>
      <build>
        <plugins>
          <plugin>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-maven-plugin</artifactId>
            <version>${javafx.maven.plugin.version}</version>
            <configuration>
              <mainClass>HelloFX</mainClass>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </project>

Now it does compile...

owner@owner-desktop:~/example/samples/HelloFX/Maven/hellofx$ mvn package
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.google.inject.internal.cglib.core.$ReflectUtils$1 (file:/usr/share/maven/lib/guice.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain)
WARNING: Please consider reporting this to the maintainers of com.google.inject.internal.cglib.core.$ReflectUtils$1
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------------< org.openjfx:hellofx >-------------------------
[INFO] Building demo 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 

...CUT FOR BREVITY ...

[INFO] Building jar: /home/owner/example/samples/HelloFX/Maven/hellofx/target/hellofx-1.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.561 s
[INFO] Finished at: 2021-06-23T10:28:19+03:00
[INFO] ------------------------------------------------------------------------

... but it it seems that <mainClass> directive of javafx-maven-plugin does not help for creating and populating JAR's manifest.

owner@owner-desktop:~/example/samples/HelloFX/Maven/hellofx$ java --version
openjdk 11.0.11 2021-04-20
OpenJDK Runtime Environment (build 11.0.11+9-Ubuntu-0ubuntu2.20.10)
OpenJDK 64-Bit Server VM (build 11.0.11+9-Ubuntu-0ubuntu2.20.10, mixed mode, sharing)
owner@owner-desktop:~/example/samples/HelloFX/Maven/hellofx$ java -jar /home/owner/example/samples/HelloFX/Maven/hellofx/target/hellofx-1.0-SNAPSHOT.jar 
no main manifest attribute, in /home/owner/example/samples/HelloFX/Maven/hellofx/target/hellofx-1.0-SNAPSHOT.jar

Let's copy-paste some pom snippet I've found on stackoverflow previously. My understanding is that it will instruct maven-assembly-plugin to make custom jar that include all dependencies in it in addition to the normal JAR.

owner@owner-desktop:~/example/samples/HelloFX/Maven/hellofx$ cat pom.xml 
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>org.openjfx</groupId>
      <artifactId>hellofx</artifactId>
      <packaging>jar</packaging>
      <version>1.0-SNAPSHOT</version>
      <name>demo</name>
      <url>http://maven.apache.org</url>

      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <javafx.version>11</javafx.version>
        <javafx.maven.plugin.version>0.0.6</javafx.maven.plugin.version>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
      </properties>

      <dependencies>
        <dependency>
          <groupId>org.openjfx</groupId>
          <artifactId>javafx-controls</artifactId>
          <version>${javafx.version}</version>
        </dependency>
      </dependencies>
      <build>
        <plugins>
          <plugin>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-maven-plugin</artifactId>
            <version>${javafx.maven.plugin.version}</version>
            <configuration>
              <mainClass>HelloFX</mainClass>
            </configuration>
          </plugin>
          
        <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
          <executions>
            <execution>
              <phase>package</phase>
              <goals>
                <goal>single</goal>
              </goals>
            </execution>
          </executions>
          <configuration>
            <archive>
              <manifest>
                <mainClass>HelloFX</mainClass>
              </manifest>
            </archive>
            <descriptorRefs>
              <descriptorRef>jar-with-dependencies</descriptorRef>
            </descriptorRefs>
          </configuration>
      </plugin>
    </plugins>
  </build>
    </project>
owner@owner-desktop:~/example/samples/HelloFX/Maven/hellofx$ mvn package
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.google.inject.internal.cglib.core.$ReflectUtils$1 (file:/usr/share/maven/lib/guice.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain)
WARNING: Please consider reporting this to the maintainers of com.google.inject.internal.cglib.core.$ReflectUtils$1
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------------< org.openjfx:hellofx >-------------------------
[INFO] Building demo 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 

...CUT FOR BREVITY...

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  3.313 s
[INFO] Finished at: 2021-06-23T10:42:40+03:00
[INFO] ------------------------------------------------------------------------
owner@owner-desktop:~/example/samples/HelloFX/Maven/hellofx$ java -jar target/hellofx-1.0-SNAPSHOT-jar-with-dependencies.jar 
Error: JavaFX runtime components are missing, and are required to run this application
owner@owner-desktop:~/example/samples/HelloFX/Maven/hellofx$ 

Great, I think it's trying to tell me that it lacks the jmods. Let's download them:

owner@owner-desktop:~/example/samples/HelloFX/Maven/hellofx$ cd ~/example/
owner@owner-desktop:~/example$ ls -la openjfx-11.0.2_linux-x64_bin-jmods\(1\).zip 
-rw-rw-r-- 1 owner owner 38699001 юни 23 10:46 'openjfx-11.0.2_linux-x64_bin-jmods(1).zip'
owner@owner-desktop:~/example$ unzip openjfx-11.0.2_linux-x64_bin-jmods\(1\).zip 
Archive:  openjfx-11.0.2_linux-x64_bin-jmods(1).zip
   creating: javafx-jmods-11.0.2/
  inflating: javafx-jmods-11.0.2/javafx.graphics.jmod  
  inflating: javafx-jmods-11.0.2/javafx.media.jmod  
  inflating: javafx-jmods-11.0.2/javafx.controls.jmod  
  inflating: javafx-jmods-11.0.2/javafx.fxml.jmod  
  inflating: javafx-jmods-11.0.2/javafx.base.jmod  
  inflating: javafx-jmods-11.0.2/javafx.web.jmod  
  inflating: javafx-jmods-11.0.2/javafx.swing.jmod  

Now let's start it:

owner@owner-desktop:~/example$ java -jar samples/HelloFX/Maven/hellofx/target/hellofx-1.0-SNAPSHOT-jar-with-dependencies.jar --module-path ./javafx-jmods-11.0.2/ --add-modules=javafx.base,javafx.graphics,javafx.controls,javafx.fxml
Error: JavaFX runtime components are missing, and are required to run this application
owner@owner-desktop:~/example$ 

And I'm out of ideas by this point. What I am doing wrong?

Upvotes: 1

Views: 3708

Answers (1)

mipa
mipa

Reputation: 10640

You are trying to do several things at the same time, which is never a good idea, and you are not following the documentation closely. Have you tried running your sample with mvn clean javafx:run as indicated in the docs?

When porting a legacy app to a recent JDK/JavaFX the first thing you should do is getting it compiled and get it running using the JavaFX Maven plugin. If it is an old app written for JDK8 and its included JavaFX, then this may already be some challenge because there were some API changes and other things.

Once you have sorted out these issues and you got your app running you can start thinking about packaging. JavaFX applications nowadays should not just be thrown into some big jar file because this will just result in a lot of other problems. Instead you should consider using jpackage to create a proper application installer. You may want to have a look here: https://github.com/dlemmermann/JPackageScriptFX (Attention: I am biased on this.)

Upvotes: 2

Related Questions