JavaFX access internal webkit document - javafx

I am trying to access javafx.web/com.sun.webkit.dom from my unnamed module javafx project. For this, I have created a class com.sun.webkit.dom.DomMapper.
I do not see any error in the IDE, but when I run it using mvn clean javafx:run it complains -
Exception in thread "JavaFX Application Thread" java.lang.NoClassDefFoundError: com/sun/webkit/dom/DomMapper
....
Caused by: java.lang.ClassNotFoundException: com.sun.webkit.dom.DomMapper
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
...
This is how my pom.xml looks
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId> ... </groupId>
<artifactId> ... </artifactId>
<version> ... </version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<exec.mainClass> .... </exec.mainClass>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>11</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>11</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics</artifactId>
<version>11</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-web</artifactId>
<version>11</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.14.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.4</version>
<configuration>
<options>
<option>--add-exports</option><option>javafx.web/com.sun.webkit.dom=ALL-UNAMED</option>
<option>--add-opens</option><option>javafx.web/com.sun.webkit.dom=ALL-UNAMED</option>
</options>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<compilerArgs>
<arg>--add-exports</arg><arg>javafx.web/com.sun.webkit.dom=ALL-UNAMED</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
If I use the Maven shade plugin, I am able to bypass this issue.
I think it has got to do with how JPMS security works, but I cannot figure out how to bypass this. I tried add-exports, and add-opens in various combinations, but it did not help me.
What am I doing wrong?
BTW, I want to map the WebKit DOM to the JSoup dom element, as they give a nice API for CSS selectors.
Update
I am adding an additional stack trace of the error
java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051)
Caused by: java.lang.RuntimeException: Exception in Application start method
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.NoClassDefFoundError: com/sun/webkit/dom/DomMapper
at xyz.jphil.internal_browser.TestApp.start(TestApp.java:86)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
... 1 more
Caused by: java.lang.ClassNotFoundException: com.sun.webkit.dom.DomMapper
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 10 more

The solution for this problem lies in using using --patch-module. As I have added a class - com.sun.webkit.dom.DomMapper which is completely sealed by JPMS. The reason why I added DomMapper in the com.sun.webkit.dom.DomMapper was to access some package-private functions.
However, I see that can be easily avoided so I am choosing to avoid using those package-private functions. With this --patch-module is not required, which is also not a recommended thing to do as per JPMS documentation. Now the solution is simpler. Adding --add exports is enough (which is already there in the POM) and I am able to get it working.
Finally exporting the entire program as a farjar using maven shade plugin for example, also works. This I am adding just for information.
This answer is based on comments and valuable inputs by Jewelsea and Slaw.
Further notes:
This example shows the public (although internal) functions of the com.sun.webkit.dom are quite good as it is, gist.github.com/jewelsea/6722397
The problem I created by making a class inside com.sun.webkit.dom is called split-package - read here How split packages are avoided in Java 9

Related

I created a JavaFX App and I get an the following error: "JavaFX runtime components are missing, and are required to run this application" [duplicate]

I'm trying to create a JFX11 self-containing jar using maven dependencies. From the research I've done, it seems the best way to do this is through the maven shade plugin. However, When I run it, I get the this error:
Error: JavaFX runtime components are missing, and are required to run this application
I don't understand why this is happening. What am I messing up? Is there a better way to do this? I've also tried the maven assembly plugin with the same message.
pom file for reference
<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>Application</groupId>
<artifactId>Main</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>SpaceRunner</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>11</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>10</release>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>Application.Main</mainClass>
</configuration>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>
Application.Main
</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>Application.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
UPDATE 10/2021
Since JavaFX 16 a warning is displayed when JavaFX doesn't run on the module path, which is the case of an uber/fat jar:
$ java -jar myFatJar-1.0-SNAPSHOT.jar
Oct 02, 2021 1:45:21 PM com.sun.javafx.application.PlatformImpl startup
WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module #14c24f4c'
Also, you get a warning from the shade plugin itself:
[WARNING] Discovered module-info.class. Shading will break its strong encapsulation.
While these warnings can be initially ignored, there is a reason for them.
As explained in this CSR:
JavaFX is built and distributed as a set of named modules, each in its own modular jar file, and the JavaFX runtime expects its classes to be loaded from a set of named javafx.* modules, and does not support loading those modules from the classpath.
And:
when the JavaFX classes are loaded from the classpath, it breaks encapsulation, since we no longer get the benefit of the java module system.
Therefore, even this widely accepted answer explains how can an uber/fat jar can be created on Maven projects, its use is discouraged, and other modern alternatives to distribute your application, like jlink, jpackage or native-image, should be used.
ORIGINAL ANSWER
This answer explains why a fat/uber jar fails on JavaFX 11. In short:
This error comes from sun.launcher.LauncherHelper in the java.base module. The reason for this is that the Main app extends Application and has a main method. If that is the case, the LauncherHelper will check for the javafx.graphics module to be present as a named module. If that module is not present, the launch is aborted.
And already proposes a fix for Gradle.
For Maven the solution is exactly the same: provide a new main class that doesn't extend from Application.
You will have new class in your application package (bad name):
// NewMain.java
public class NewMain {
public static void main(String[] args) {
Main.main(args);
}
}
And your existing Main class, as is:
//Main.java
public class Main extends Application {
#Override
public void start(Stage stage) {
...
}
public static void main(String[] args) {
launch(args);
}
}
Now you need to modify your pom and set your main class for the different plugins:
<mainClass>application.NewMain</mainClass>
Platform-specific Fat jar
Finally, with the shade plugin you are going to produce a fat jar, on your machine.
This means that, so far, your JavaFX dependencies are using a unique classifier. If for instance you are on Windows, Maven will be using internally the win classifier. This has the effect of including only the native libraries for Windows.
So you are using:
org.openjfx:javafx-controls:11
org.openjfx:javafx-controls:11:win
org.openjfx:javafx-graphics:11
org.openjfx:javafx-graphics:11:win <-- this contains the native dlls for Windows
org.openjfx:javafx-base:11
org.openjfx:javafx-base:11:win
Now, if you produce the fat jar, you will bundle all those dependencies (and those other regular third party dependencies from your project), and you will be able to run your project as:
java -jar myFatJar-1.0-SNAPSHOT.jar
While this is very nice, if you want to distribute you jar, be aware that this jar is not cross-platform, and it will work only on your platform, in this case Windows.
Cross-Platform Fat Jar
There is a solution to generate a cross-platform jar that you can distribute: include the rest of the native libraries of the other platforms.
This can be easily done, as you just need to include the graphics module dependencies for the three platforms:
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>11</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics </artifactId>
<version>11</version>
<classifier>win</classifier>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics </artifactId>
<version>11</version>
<classifier>linux</classifier>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics </artifactId>
<version>11</version>
<classifier>mac</classifier>
</dependency>
</dependencies>
Size
There is a main issue with this approach: the size. As you can see in this other answer, if you use the WebView control, you will be bundling around 220 MB due to the WebKit native libraries.

Embedded Kafka test cases are error after adding jsonschema2pojo-core

I have an application that created with Spring boot and Spring kafka libraries. Now I added jsonschema2pojo-core library to my pom file. After adding this jar file my test cases are failing with below error
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'embeddedKafka': Invocation of init method failed; nested exception is java.lang.NoClassDefFoundError: scala/runtime/java8/JFunction0$mcZ$sp
Caused by: java.lang.NoClassDefFoundError: scala/runtime/java8/JFunction0$mcZ$sp
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath />
</parent>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
<!-- Test Dependencies -->
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jsonschema2pojo</groupId>
<artifactId>jsonschema2pojo-core</artifactId>
<version>1.0.2</version>
</dependency>
It's probably similar to this https://docs.spring.io/spring-kafka/docs/2.5.11.RELEASE/reference/html/#jacksonscala-incompatibility
with the library pulling in an incompatible scala library.
Yes, adding
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.12.11</version>
</dependency>
fixed it for me; but I can't guarantee that jsonschema2pojo will work with that version.
The scala folks are notorious for breaking API changes in patch releases.

NullPointerException in ControlsFX Notification

I want to show notifications to the user in my JavaFX application and chose the ControlsFX library for that purpose. However whenever I create a warning via: Notifications.create().showWarning();, I get the following Exception:
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at org.controlsfx.controls/org.controlsfx.control.Notifications$NotificationPopupHandler.getScreenBounds(Notifications.java:364)
at org.controlsfx.controls/org.controlsfx.control.Notifications$NotificationPopupHandler.show(Notifications.java:343)
at org.controlsfx.controls/org.controlsfx.control.Notifications.show(Notifications.java:305)
at org.controlsfx.controls/org.controlsfx.control.Notifications.showWarning(Notifications.java:271)
This is called when my whole application is set up and visible.
Could this be a version mismatch? I use JavaFX 12 but ControlsFX only has a version 11.
This is an abbreviated version of my pom.xml:
<project xmlns="[...]">
[...]
<properties>
<maven.compiler.release>12</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>${maven.compiler.release}</release>
</configuration>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.3</version>
<configuration>
<mainClass>eu.snik.tag.gui.Main</mainClass>
</configuration>
[...]
</plugin>
</plugins>
[...]
<dependencies>
[...]
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>12.0.1</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>12.0.1</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-web</artifactId>
<version>12.0.1</version>
</dependency>
<dependency>
<groupId>org.controlsfx</groupId>
<artifactId>controlsfx</artifactId>
<version>11.0.0</version>
</dependency>
</dependencies>
</project>
This is a bug that is now fixed, see https://github.com/controlsfx/controlsfx/issues/1140
Unfortunately the bugfix is not included in the current release (or any release candidate: According to the version history it was fixed April 30th, 2019 but the last release was on the 19th of the same month).
Note that the code before the check for null preventing the NPE was added iterated through the window list returned by Window.getWindows() looking for a window that is focused. null is used, if no such window is found. With the current code the primary screen is used, to determine the position of the notification, if no focused window is found.

Caused by: java.lang.NoSuchFieldError: TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256

When using web3j java library in a spring boot application, I am getting the below exception in the Web3j.build line. Any idea to fix this issue?
private static final Web3j web3j = Web3j.build(new HttpService("https://rinkeby.infura.io/v3/sdas"));
Caused by: java.lang.NoSuchFieldError: TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
at org.web3j.protocol.http.HttpService.<clinit>(HttpService.java:37)
at sg.com.paloit.hashit.service.ContractService.<clinit>(ContractService.java:36)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:142)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:89)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1147)
... 48 common frames omitted
<dependency>
<groupId>org.web3j</groupId>
<artifactId>core</artifactId>
<version>4.1.0</version>
</dependency>
org.web3j (4.1.0) core comes with lower version of okhttp which doesn't have the cipher: TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256.
Its a relatively new cipher, changing okhttp to okhttp3 helped to resolve the issue.
<dependency>
<groupId>org.web3j</groupId>
<artifactId>core</artifactId>
<version>4.1.0</version>
<exclusions>
<exclusion>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.9.0</version>
</dependency>

Compiling multiple .as files using Maven

I am having issues getting maven to do a simple clean install I am getting the following error:
Failed to execute goal org.sonatype.flexmojos:flexmojos-maven-plugin:3.8:compile-swf (default-compile-swf) on project flex: Source file not expecified and no default found! -> [Help 1]
I was following the tutorial on this site: Adobe Developer Connection - Flex and Maven
I have all of my .as files located in: src/main/flex/ but the problem is that I don't have a Main class, these are all basically interfaces so I can't just choose one of them to be the source file.
I have Eclipse installed as well, and it is yelling at me for the plugin part of the POM, saying:
Multiple annotations found at this line:
- Plugin execution not covered by lifecycle configuration: org.sonatype.flexmojos:flexmojos-maven-plugin:
3.8:compile-swf (execution: default-compile-swf, phase: compile)
- Plugin execution not covered by lifecycle configuration: org.sonatype.flexmojos:flexmojos-maven-plugin:
3.8:test-compile (execution: default-test-compile, phase: test-compile)
So I am not sure if this is related or not, but I have tried to copy/paste the code from the link above verbatim but I still get that error and the guy never mentions anything about it, so perhaps it's just a bug in the maven plugin in Eclipse.
Here is my POM.xml file:
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.company</groupId>
<artifactId>parent</artifactId>
<version>1.0</version>
</parent>
<artifactId>flex</artifactId>
<name>flex</name>
<packaging>swf</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.company</groupId>
<artifactId>common</artifactId>
</dependency>
<dependency>
<groupId>com.adobe.flex.framework</groupId>
<artifactId>flex-framework</artifactId>
<version>3.6.0.16995</version>
<type>pom</type>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main/flex</sourceDirectory>
<plugins>
<plugin>
<groupId>org.sonatype.flexmojos</groupId>
<artifactId>flexmojos-maven-plugin</artifactId>
<extensions>true</extensions>
<dependencies>
<dependency>
<groupId>com.adobe.flex</groupId>
<artifactId>compiler</artifactId>
<version>3.6.0.16995</version>
<type>pom</type>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
I am open to ANY ideas on how to get this to compile these .as files. Thank you!
Edit: Okay I figured it out. I changed the packaging from swf to swc and it works. So very sad.
I converted the package from swf to swc and it worked like a champ. Hopefully this helps someone in the future.
you need the configuration tag so flexmojos knows where to start the build. (default application, or main class)
<plugin>
<groupId>org.sonatype.flexmojos</groupId>
<artifactId>flexmojos-maven-plugin</artifactId>
<extensions>true</extensions>
<dependencies>
<dependency>
<groupId>com.adobe.flex</groupId>
<artifactId>compiler</artifactId>
<configuration>
<sourceFile>Module.mxml</sourceFile>
</configuration>
<version>3.6.0.16995</version>
<type>pom</type>
</dependency>
</dependencies>
</plugin>

Resources