javajavafxwebsocketwebview

Why did a WebView fail to connect to a WebSocket in JavaFX?


I'm trying to connect to a WebSocket from a WebView in JavaFX (because I want to use a third-party component available only in Javascript). In the WebView's HTML file, I used Javascript to create a WebSocket instance, and in the JavaFX part, I used Java-WebSocket to create a WebSocketServer. But now, after the WebSocketServer started and the Javascript WebSocket client was initialized, the WebSocketServer didn't seem to open a connection to the WebView. What's more, if I open the HTML file in a browser (using IntelliJ IDEA's "open in browser" feature) while running the application, the WebSocket seems to open a connection.

I have searched for some answers on Stack Overflow, but they all seem to be outdated.


Here is the code.

HelloApplication.java

package com.remmymilkyway.websocketdemo;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Objects;

public class HelloApplication extends Application {
    private WebSocketServer server;

    @Override
    public void start(Stage stage) {
        WebView webView = new WebView();
        webView.getEngine().load(Objects.requireNonNull(this.getClass().getResource("web-view.html")).toExternalForm());

        server = new WebSocketServer(new InetSocketAddress("localhost", 8080)) {
            @Override
            public void onOpen(WebSocket conn, ClientHandshake handshake) {
                System.out.println("New connection: " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
            }

            @Override
            public void onClose(WebSocket conn, int code, String reason, boolean remote) {
                System.out.println("Connection closed: " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
            }

            @Override
            public void onMessage(WebSocket conn, String message) {
                System.out.println("Received message: " + message);
            }

            @Override
            public void onError(WebSocket conn, Exception ex) {
                System.out.println("An error occurred: " + ex);
            }

            @Override
            public void onStart() {
                System.out.println("Server started");
            }
        };
        server.start();
        server.broadcast("Server started.");

        Scene scene = new Scene(webView);
        stage.setTitle("Hello!");
        stage.setScene(scene);
        stage.show();
    }

    @Override
    public void stop() throws Exception {
        super.stop();
        server.stop();
        System.out.println("Server stopped");
    }

    public static void main(String[] args) {
        launch();
    }
}

web-view.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>
<p id="text"></p>
<script>
    var webSocket = new WebSocket("ws://localhost:8080");
    document.getElementById("text").innerHTML = "WebSocket instance created: " + webSocket.url; // show the URL of the WebSocket instance
</script>
</body>
</html>

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.remmymilkyway</groupId>
    <artifactId>WebSocketDemo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>WebSocketDemo</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <junit.version>5.10.2</junit.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>22.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-fxml</artifactId>
            <version>22.0.1</version>
        </dependency>

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-web</artifactId>
            <version>22.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.java-websocket</groupId>
            <artifactId>Java-WebSocket</artifactId>
            <version>1.5.7</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.13.0</version>
                <configuration>
                    <source>22</source>
                    <target>22</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-maven-plugin</artifactId>
                <version>0.0.8</version>
                <executions>
                    <execution>
                        <!-- Default configuration for running with: mvn clean javafx:run -->
                        <id>default-cli</id>
                        <configuration>
                            <mainClass>
                                com.remmymilkyway.websocketdemo/com.remmymilkyway.websocketdemo.HelloApplication
                            </mainClass>
                            <launcher>app</launcher>
                            <jlinkZipName>app</jlinkZipName>
                            <jlinkImageName>app</jlinkImageName>
                            <noManPages>true</noManPages>
                            <stripDebug>true</stripDebug>
                            <noHeaderFiles>true</noHeaderFiles>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

module-info.java

module com.remmymilkyway.websocketdemo {
    requires javafx.controls;
    requires javafx.fxml;
    requires javafx.web;
    requires org.java_websocket;


    opens com.remmymilkyway.websocketdemo to javafx.fxml;
    exports com.remmymilkyway.websocketdemo;
}

Here is the output and exceptions I get when I run my application.

SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See https://www.slf4j.org/codes.html#noProviders for further details.
Server started
xxxx-xx-xx xx:xx:xx.xxx java[76456:7816534] +[IMKClient subclass]: chose IMKClient_Modern
xxxx-xx-xx xx:xx:xx.xxx java[76456:7816534] +[IMKInputSession subclass]: chose IMKInputSession_Modern
Server stopped

If I open web-view.html in a browser tab, here's the additional output I get.

New connection: 127.0.0.1
Connection closed: 127.0.0.1

Solution

  • Summarizing our colloquy, this Q&A examines a related issue. Although outdated, the version is still supported modulo back-port latency. In this case, JDK-8331765, affecting multiple versions, is relevant. As you are using v22.0.1, which was affected, you might try a later build. I found v21.0.5 [LTS] sufficient, and @jewelsea found that v23.0.1 worked.

    The way forward depends to some extent on your configuration management plan, Java support requirements, and target platforms. Among the OpenJDK releases offered by Gluon, note that release 22 does not "receive updates anymore." In particular,

    We strongly encourage all our users to use either the latest version (currently 23) or the latest version of one of the LTS releases (currently 17 and 21).

    Released October 2024; projected support until March 2025.