Search code examples
javagradlejavafxjavadoc

Gradle module not found in custom uml task


I am using this "plugin" on javadoc to generate a UML Class Diagram with Gradle: https://github.com/talsma-ict/umldoclet This "plugin" uses javadoc to create UML Class Diagrams.

I am working with the JavaFX library to build my application. When I run my custom task that should generate the image I get an error in my module-info.java that javafx.controls cannot be found.

build.gradle:

plugins {
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.8'
id 'org.beryx.jlink' version '2.12.0'
}

apply plugin: 'java'

repositories {
    mavenCentral()
}

configurations {
    umlDoclet
}

dependencies {
    // https://mvnrepository.com/artifact/org.apache.commons/commons-collections4
    compile group: 'org.apache.commons', name: 'commons-collections4', version: '4.4'
    // https://mvnrepository.com/artifact/mysql/mysql-connector-java
    compile group: 'mysql', name: 'mysql-connector-java', version: '8.0.18'
    // Used for generating UML class diagram
    umlDoclet "nl.talsmasoftware:umldoclet:2.0.6"
}

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

javadoc {
    source = sourceSets.main.allJava
    options.docletpath = configurations.umlDoclet.files.asType(List)
    options.doclet = "nl.talsmasoftware.umldoclet.UMLDoclet"
}

task generateUmlClass(type: Javadoc) {
    dependsOn("javadoc")
    source = sourceSets.main.allJava
    destinationDir = reporting.file("uml")
    options.docletpath = configurations.umlDoclet.files.asType(List)
    options.doclet = "nl.talsmasoftware.umldoclet.UMLDoclet"
}

mainClassName = "$moduleName/nl.avans.sagrada.MainApp"

jlink {
    options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
    launcher {
        name = 'Sagrada'
    }
}

I tried adding dependsOn("javadoc") so I would build first but this doesn't seem to work.

My module-info.java

module Sagrada {
requires javafx.controls;
requires java.sql;

opens nl.avans.sagrada to javafx.base;
opens nl.avans.sagrada.controllers to javafx.controls;
opens nl.avans.sagrada.view.scenes to javafx.controls;
opens nl.avans.sagrada.view.panes to javafx.controls;

opens nl.avans.sagrada.database to java.sql;

exports nl.avans.sagrada;
exports nl.avans.sagrada.controllers;
exports nl.avans.sagrada.view.scenes;
exports nl.avans.sagrada.view.panes;
exports nl.avans.sagrada.interfaces;
exports nl.avans.sagrada.helpers;
exports nl.avans.sagrada.models;
exports nl.avans.sagrada.database;
exports nl.avans.sagrada.database.annotations;
exports nl.avans.sagrada.database.models;
}

Whenever I try to run gradle generateUmlClass it gives following error:

2:55:13 PM: Executing task 'generateUmlClass'...

> Configure project :
Found module name 'Sagrada'

> Task :compileJava UP-TO-DATE
> Task :processResources UP-TO-DATE
> Task :classes UP-TO-DATE
> Task :jar
> Task :startScripts
> Task :distTar
> Task :distZip
> Task :assemble
> Task :compileTestJava NO-SOURCE
> Task :processTestResources NO-SOURCE
> Task :testClasses UP-TO-DATE
> Task :test NO-SOURCE
> Task :check UP-TO-DATE
> Task :build

> Task :generateUmlClass FAILED
D:\Avans\Blok 2\Sagrada-Core\src\main\java\module-info.java:2: error: module not found: javafx.controls
    requires javafx.controls;
                   ^
D:\Avans\Blok 2\Sagrada-Core\src\main\java\module-info.java:3: error: module not found: javafx.fxml
    requires javafx.fxml;
                   ^
2 errors

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':generateUmlClass'.
> Javadoc generation failed. Generated Javadoc options file (useful for troubleshooting): 'D:\Avans\Blok 2\Sagrada-Core\build\tmp\generateUmlClass\javadoc.options'

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 1s
7 actionable tasks: 5 executed, 2 up-to-date
2:55:15 PM: Task execution finished 'generateUmlClass'.

Solution

  • For starters, you are adding two javadoc tasks:

    javadoc {
        source = sourceSets.main.allJava
        options.docletpath = configurations.umlDoclet.files.asType(List)
        options.doclet = "nl.talsmasoftware.umldoclet.UMLDoclet"
    }
    
    task generateUmlClass(type: Javadoc) {
        dependsOn("javadoc")
        source = sourceSets.main.allJava
        destinationDir = reporting.file("uml")
        options.docletpath = configurations.umlDoclet.files.asType(List)
        options.doclet = "nl.talsmasoftware.umldoclet.UMLDoclet"
    }
    

    With same options in both and when you run ./gradlew generateUmlClass you are calling both tasks.

    If you add some required options to one of them, the other will miss it. So you should only use one. Let's keep the default task javadoc.

    Now:

    javadoc {
        source = sourceSets.main.allJava
        options.docletpath = configurations.umlDoclet.files.asType(List)
        options.doclet = "nl.talsmasoftware.umldoclet.UMLDoclet"
        destinationDir = reporting.file("uml")
    }
    

    If you run ./gradlew javadoc, you get the errors you have reported:

    ...src/main/java/module-info.java:2: error: module not found: javafx.controls
        requires javafx.controls;
                       ^
    

    This happens because JavaFX is modular, and you should put it in the module-path.

    The JavaFX gradle org.openjfx.javafxplugin plugin does precisely that for the run task, but not for the Javadoc one, so to fix the issue we need to add an option to the task with the module-path.

    Using gradle's addStringOption, the way to do it is:

    javadoc {
        options.addStringOption('-module-path', ...)
        ...
    }
    

    The module path now can be taken from the classpath (classpath.asPath), however the JavaFX plugin uses implementation instead of the deprecated compile, so the now we need to use runtimeClasspath:

    javadoc {
        options.addStringOption('-module-path', configurations.runtimeClasspath.asPath)
        ...
    }
    

    Finally, this is all you should need:

    javadoc {
        options.addStringOption('-module-path', configurations.runtimeClasspath.asPath)
        source = sourceSets.main.allJava
        options.docletpath = configurations.umlDoclet.files.asType(List)
        options.doclet = "nl.talsmasoftware.umldoclet.UMLDoclet"
        destinationDir = reporting.file("uml")
    }
    

    Now running ./gradlew javadoc should work successfully.

    At least I can get some nice SVG images under `build/reports/uml: