Marvin Newton
Marvin Newton

Reputation: 11

jar image from jlink does not show org.kordamp.materialdesign2 icons but they load when program is run in intellij

javafx applications not showing org.kordamp.materialdesign2 icons

I recently completed a school management program with JavaFX 18 which runs properly using the normal IntelliJ run configurations but fails to load ALL icons from org.kordamp.materialdesign2. I have scanned the entire web and come across a few answers regarding service files. I have all three required packages in my module-info file org.kormap.ikoli.core,org.kordamp.javafx and org.kordamp.materialdesign2

When the jar is run, it shows messages like this:

Exception in thread "JavaFX Application Thread" java.lang.UnsupportedOperationException: Cannot resolve 'mdi2o-office-building'
    at org.kordamp.ikonli.AbstractIkonResolver.resolve(AbstractIkonResolver.java:61)
    at org.kordamp.ikonli.javafx.IkonResolver.resolve(IkonResolver.java:73)
    at org.kordamp.ikonli.javafx.FontIcon.lambda$new$2(FontIcon.java:76)
    at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:360)
    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:80)
    at javafx.beans.property.ObjectPropertyBase.fireValueChangedEvent(ObjectPropertyBase.java:106)
    at javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:113)
    at javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:147)
    at javafx.css.StyleableObjectProperty.set(StyleableObjectProperty.java:82)
    at org.kordamp.ikonli.javafx.FontIcon.setIconCode(FontIcon.java:231)
    at org.kordamp.ikonli.javafx.FontIcon.<init>(FontIcon.java:97)
    at manager.school_manager.EntryController.initialize(EntryController.java:115)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2573)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2466)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2435)
    at manager.school_manager.Entry.start(Entry.java:56)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
    at java.base/java.lang.Thread.run(Thread.java:1589)

error messages on running jar | Program without icons on running jar | Program showing icons when run in intellij

module-info.java with all three co-dependencies

Tried using the shadow jar plugin as stated in it's documentation

build.gradle file showing use of shadow jar plugin

Also opened the jar file with winrar and checked the Manifest/Manifest.MF/services and here is what I found:

it shows two files related to ikonli. Am not quite versed to services in general so I can't tell if these would suffice.*** I would gladly accept any help that would help me resolve this problem***

Upvotes: 0

Views: 270

Answers (3)

kenTom
kenTom

Reputation: 1

I have faced the same issue here and I just think of creating my own Icon library at this point

Upvotes: 0

Marvin Newton
Marvin Newton

Reputation: 11

module-info.java

module manager.school_manager {
    //javafx and related deps
    requires javafx.controls;
    requires javafx.fxml;
    requires org.controlsfx.controls;
    requires com.dlsc.formsfx;
    requires org.jfxtras.styles.jmetro;

    requires org.kordamp.ikonli.javafx;
    requires org.kordamp.ikonli.materialdesign2;
    requires org.kordamp.ikonli.core;

    requires javafx.base;
    requires java.desktop;
    requires javafx.graphics;
    requires javafx.web;
    requires javafx.media;

    // json io
    requires com.google.code.gson;




    //itext 7 ===> pdf deps
    requires itextpdf.layout;
    requires itextpdf.kernel;
    requires itextpdf.io;
    requires itextpdf.commons;
    requires itextpdf.pdfa;
    requires itextpdf.barcodes;

    // postgres deps
    requires java.sql;
    requires org.postgresql;

    //excel deps
    requires org.apache.poi.ooxml;

    //logging deps and transitive deps
    requires org.slf4j;
    requires commons.math3;


    opens manager.school_manager to javafx.fxml;
    opens manager.school_manager.controllers to javafx.fxml;

    exports manager.school_manager;
}`



build.gradle

plugins {
    id 'java'
    id 'application'
    id 'org.openjfx.javafxplugin' version '0.0.10'
    id 'org.beryx.jlink' version '2.24.1'
    id 'org.gradlex.extra-java-module-info' version '1.3'
    id 'java-library'
//    id 'com.github.johnrengelman.shadow' version '6.1.0'
}


//shadowJar {
//    mergeServiceFiles()
//}
//


group 'manager'
version '1.0-SNAPSHOT'

ext.moduleName= 'manager.school_manager'


extraJavaModuleInfo{
    failOnMissingModuleInfo.set(false)

    module("org.tinylog:tinylog-api","org.tinylog.api"){
        exportAllPackages()
        requireAllDefinedDependencies
    }
    module("org.tinylog:tinylog-impl","org.tinylog.impl"){
        exportAllPackages()
        requireAllDefinedDependencies
    }

    module("com.google.code.gson:gson","com.google.code.gson"){
        exportAllPackages()
        requireAllDefinedDependencies
    }
    module("io.github.typhon0:AnimateFX","io.github.typhon0"){
        exportAllPackages()
        requireAllDefinedDependencies
    }
    module("com.github.Dansoftowner:PDFViewerFX","com.github.Dansoftowner"){
        exportAllPackages()
        requireAllDefinedDependencies
    }
    module("org.apache.commons:commons-math3","commons.math3"){
        exportAllPackages()
        requireAllDefinedDependencies
    }
    module("com.zaxxer:SparseBitSet","SparseBitSet"){
        exportAllPackages()
        requireAllDefinedDependencies
    }



    automaticModule("fxribbon.jar","com.pixelduke.fxribbon")
    automaticModule("postgresql.jar","org.postgresql")

    automaticModule("log4j.jar","org.log4j")
    automaticModule("log4j-api.jar","org.log4j-api")
    automaticModule("slf4j-api.jar","org.slf4j")

    automaticModule("layout.jar","itextpdf.layout")
    automaticModule("kernel.jar","itextpdf.kernel")
    automaticModule("pdfa.jar","itextpdf.pdfa")
    automaticModule("io.jar","itextpdf.io")
    automaticModule("commons.jar","itextpdf.commons")
    automaticModule("barcodes.jar","itextpdf.barcodes")
    automaticModule("sign.jar","itextpdf.sign")
    automaticModule("svg.jar","itextpdf.svg")


    automaticModule("javafxweb.jar","javafx.web")
    automaticModule("javafxmedia.jar","javafx.media")


}

repositories {
    mavenCentral()
    maven{
        url "https://plugins.gradle.org/m2/"
    }
    maven {
        url "https://jitpack.io"
    }

}

ext {
    junitVersion = '5.9.2'
}


tasks.withType(JavaCompile) {
    options.encoding = 'UTF-8'
}

application {
    mainModule = 'manager.school_manager'
    mainClass = 'manager.school_manager.Main'
}

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


dependencies {
//    converts non modular jars to jpms compatible
    implementation('org.gradlex:extra-java-module-info:1.3')
//
//    implementation('com.google.firebase:firebase-admin:9.1.1')

    implementation('org.controlsfx:controlsfx:11.1.2')
    implementation('com.dlsc.formsfx:formsfx-core:11.6.0') {
        exclude(group: 'org.openjfx')
    }
    implementation('net.synedra:validatorfx:0.4.0') {
        exclude(group: 'org.openjfx')
    }


    implementation('org.jfxtras:jmetro:11.6.16')
    implementation(fileTree(dir:'/libs',includes:['*.jar']))
//    implementation('org.openpnp:opencv:3.4.2-0')
//    implementation('eu.hansolo.fx:charts:17.1.27')

    implementation('org.tinylog:tinylog-api:2.6.1')
    implementation('org.tinylog:tinylog-impl:2.6.1')
    implementation('com.google.code.gson:gson:2.3.1')
    implementation('io.github.typhon0:AnimateFX:1.2.4')

    implementation('org.kordamp.ikonli:ikonli-materialdesign2-pack:12.3.1')
    implementation 'org.kordamp.ikonli:ikonli-core:12.3.1'
    implementation('org.kordamp.ikonli:ikonli-javafx:12.3.1')


    implementation('org.apache.poi:poi-ooxml:5.2.3'){
        exclude(group: "javax.xml")
    }
    implementation('com.zaxxer:SparseBitSet:1.2')

    implementation 'org.kordamp.jipsy:jipsy-annotations:1.2.0'
//    implementation 'org.apache.xmlgraphics:batik-transcoder:1.13'


    testImplementation("org.junit.jupiter:junit-jupiter-api:${junitVersion}")
    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${junitVersion}")
}

test {
    useJUnitPlatform()
}

jlink {
    imageZip = project.file("${buildDir}/distributions/app-${javafx.platform.classifier}.zip") as RegularFile
    options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
    launcher {
        name = 'app'
    }
}

jlinkZip {
    group = 'distribution'
}


Main.java *** a simple entry that show the icon implementation throughout the code in a simple Label ***


import org.kordamp.ikonli.javafx.FontIcon;
import org.kordamp.ikonli.materialdesign2.*;
... other imports  






public class Main extends Application {

    @Override
    public void start(Stage stage) throws IOException, ClassNotFoundException, SQLException {
        System.out.println("LAUCHING SMPRO....");

//      loading main.fxml
        FXMLLoader loader = new FXMLLoader();
        URL fxmlLocation = ResourceAnchor.getAppResource("views/main.fxml");
        loader.setLocation(fxmlLocation);
        loader.setResources(ResourceBundle.getBundle(StaticNames.RESOURCE_BUNDLE_BASENAME.getName()));
        Parent root = loader.<VBox>load();
        root.getStyleClass().add(JMetroStyleClass.BACKGROUND);

//        get controller instance
        EntryController entryController  = loader.getController();
        entryController.EntryStage.set(stage);


        Scene scene = new Scene(new Button("Click me",new FontIcon(MaterialDesignA.ACCOUNT_CIRCLE)));



        stage.setTitle("Sample title");
        stage.setScene(scene);
        stage.setResizable(false);
        stage.getIcons().add(new Image(ResourceAnchor.getResourceStream("images/logo.png")));

        stage.show();
    }

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




}

Upvotes: 0

jewelsea
jewelsea

Reputation: 159576

Example app

  • Uses jlink to link the app into an image that is zipped for deployment, rather than packaging the app as an executable jar (because this is what the asker stated they wanted to do in comments).
  • Uses maven for build and packaging, as that is what I am familiar with.
  • Will create an app usable only on the same platform type and architecture as the machine used to build the app.

Build requires Maven installation and JDK 20 installation. Deployment is standalone and has no dependencies other than the OS it runs on.

src/main/java/module-info.java

module com.example.materialicons {
    requires javafx.controls;
    requires org.kordamp.ikonli.javafx;
    requires org.kordamp.ikonli.materialdesign2;

    exports com.example.materialicons;
}

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.example</groupId>
    <artifactId>materialicons</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>materialicons</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>20.0.2</version>
        </dependency>
        <dependency>
            <groupId>org.kordamp.ikonli</groupId>
            <artifactId>ikonli-javafx</artifactId>
            <version>12.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.kordamp.ikonli</groupId>
            <artifactId>ikonli-materialdesign2-pack</artifactId>
            <version>12.3.1</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <source>20</source>
                    <target>20</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-maven-plugin</artifactId>
                <version>0.0.8</version>
                <executions>
                    <execution>
                        <id>default-cli</id>
                        <configuration>
                            <mainClass>com.example.materialicons/com.example.materialicons.IconApplication</mainClass>
                            <launcher>iconapp</launcher>
                            <jlinkZipName>iconapp</jlinkZipName>
                            <jlinkImageName>iconapp</jlinkImageName>
                            <noManPages>true</noManPages>
                            <stripDebug>true</stripDebug>
                            <noHeaderFiles>true</noHeaderFiles>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

src/main/java/com/example/materialicons/IconApplication.java

Material Design has icon packs, named A -> Z. We just use the A icon pack here, usage of icons from other packs is similar.

package com.example.materialicons;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;
import org.kordamp.ikonli.javafx.FontIcon;
import org.kordamp.ikonli.materialdesign2.MaterialDesignA;

public class IconApplication extends Application {
    @Override
    public void start(Stage stage) {
        FlowPane layout = new FlowPane();
        layout.setPadding(new Insets(10));
        layout.setPrefWrapLength(500);
        for (MaterialDesignA iconEnumVal : MaterialDesignA.values()) {
            FontIcon icon = new FontIcon(
                    iconEnumVal.getDescription()
            );
            icon.setIconSize(40);
            layout.getChildren().add(
                    icon
            );
        }

        Scene scene = new Scene(new ScrollPane(layout), 530, 400);
        stage.setScene(scene);
        stage.show();
    }

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

Build

Build command (execute from the project root directory):

mvn clean javafx:jlink

Build output:

[INFO] Scanning for projects...
[INFO] 
[INFO] ---------------------< com.example:materialicons >----------------------
[INFO] Building materialicons 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ materialicons ---
[INFO] Deleting /Users/username/dev/materialicons/target
[INFO] 
[INFO] >>> javafx-maven-plugin:0.0.8:jlink (default-cli) > process-classes @ materialicons >>>
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ materialicons ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /Users/username/dev/materialicons/src/main/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.11.0:compile (default-compile) @ materialicons ---
[INFO] Changes detected - recompiling the module! :source
[INFO] Compiling 2 source files with javac [debug target 20 module-path] to target/classes
[INFO] 
[INFO] <<< javafx-maven-plugin:0.0.8:jlink (default-cli) < process-classes @ materialicons <<<
[INFO] 
[INFO] 
[INFO] --- javafx-maven-plugin:0.0.8:jlink (default-cli) @ materialicons ---
[INFO] Building zip: /Users/username/dev/materialicons/target/iconapp.zip
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS

Example usage

Execute from your project root directory. Adjust the command syntax for your OS type.

mkdir tmp
cd tmp
unzip ../target/iconapp.zip 
bin/iconapp

Example output

icons

Upvotes: 1

Related Questions