Search code examples
javaxmlgradlejavafxjlink

JLink XML dependency issue


So I recently took a Java job and needed a project to brush up on my Java skills (been a few years). I started writing a JavaFX app - some game mod tooling, essentially - and used JLink / plugin to make sure I could build a standalone executable. This all went smoothly and I started developing my app. I've now tried to build an executable for a friend to help test out, and I've hit a dependency issue when I run the app as an executable or from the packaged jar file:

Exception in thread "JavaFX Application Thread" javax.xml.stream.FactoryConfigurationError: Provider for javax.xml.stream.XMLInputFactory cannot be found
        at java.xml/javax.xml.stream.FactoryFinder.find(Unknown Source)
        at java.xml/javax.xml.stream.XMLInputFactory.newFactory(Unknown Source)
        at [email protected]/com.fasterxml.jackson.dataformat.xml.XmlFactory.<init>(Unknown Source)
        at [email protected]/com.fasterxml.jackson.dataformat.xml.XmlFactory.<init>(Unknown Source)
        at [email protected]/com.fasterxml.jackson.dataformat.xml.XmlFactory.<init>(Unknown Source)
        at [email protected]/com.fasterxml.jackson.dataformat.xml.XmlMapper.<init>(Unknown Source)
        at expmanager/expmanager.data.FileManager.<init>(Unknown Source)
        at expmanager/expmanager.project.Project.<init>(Unknown Source)
        at expmanager/expmanager.controller.SelectorController.handleLoadClick(Unknown Source)

My module-info.java:

module expmanager {
    requires javafx.controls;
    requires javafx.fxml;
    requires com.fasterxml.jackson.core;
    requires com.fasterxml.jackson.dataformat.xml;
    requires com.fasterxml.jackson.databind;
    requires transitive javafx.graphics;

    opens expmanager.controller to javafx.fxml;
    opens expmanager.controller.listItem to javafx.fxml;
    opens expmanager.controller.tab to javafx.fxml;
    opens expmanager.controller.component to javafx.fxml;
    opens expmanager.data.itemtypes to com.fasterxml.jackson.databind;
    opens expmanager.data.core to com.fasterxml.jackson.databind;
    opens expmanager.data.expansion to com.fasterxml.jackson.databind;
    opens expmanager.project.expansion to javafx.base;
    opens expmanager.project.mission to javafx.base;

    exports expmanager;
    exports expmanager.data.core;
    exports expmanager.data.itemtypes;
    exports expmanager.data.expansion;
    exports expmanager.project;
    exports expmanager.project.expansion;
    exports expmanager.project.mission;
}

And build.gradle:

plugins {
  id 'application'
  id 'org.openjfx.javafxplugin' version '0.0.10'
  id 'org.beryx.jlink' version '2.25.0'
  id "com.diffplug.spotless" version "6.11.0"
}

spotless {
    ratchetFrom 'main'
    java {
        eclipse().configFile('formatter.xml')
    }
}

repositories {
    mavenCentral()
}

javafx {
    version = "19"
    modules = [ 'javafx.controls', 'javafx.fxml' ]
}

application {
    mainClass = "expmanager.SelectorApp"
    mainModule = "expmanager"
}

jlink {
    options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
    mergedModule {
        requires 'java.xml'
    }
    launcher {
        name = 'expmanager'
    }
    jpackage {
        imageOptions = ['--win-console']
        skipInstaller = 'true'
    }
}

dependencies {
    implementation 'com.fasterxml.jackson.core:jackson-core:2.13.4'
    implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.4'
    implementation 'com.fasterxml.jackson.core:jackson-annotations:2.13.4'
    implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.13.4'
}

The app works perfectly when I run. Based on some googling, I have tried including java.xml as a mergedModule but this has no effect. Attempting to do the same with the missing library throws errors, as does attempting to add it as a dependency to gradle.

This is my first time using j-link, j-modules etc. any help diagnosing this would be appreciated!


Solution

  • So I managed to fix my issue after a little more time... Typical!

    If anyone else happens across this, it was indeed due to a missing transitive dependency. Looking at my project's dependencies (using VS Code):

    dependency view

    Looking at the module-info for woodstox-core I found:

    module-info module com.ctc.wstx  {
      ...
      provides javax.xml.stream.XMLEventFactory with com.ctc.wstx.stax.WstxEventFactory;
      provides javax.xml.stream.XMLInputFactory with com.ctc.wstx.stax.WstxInputFactory;
      provides javax.xml.stream.XMLOutputFactory with com.ctc.wstx.stax.WstxOutputFactory;
      ...
    }
    

    And so, I have fixed the issue by adding this to my module's module-info:

    module expmanager {
        ...
        requires transitive com.ctc.wstx;
        ...
    }