SkillAgentSearch skills...

Moditect

Tooling for the Java Module System

Install / Use

/learn @moditect/Moditect
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

ModiTect - Tooling for the Java Module System

Version 1.0.0.Final - 2023-05-03

The ModiTect project aims at providing productivity tools for working with the Java module system ("Jigsaw").

Currently the following tasks are supported:

  • Generating module-info.java descriptors for given artifacts (Maven dependencies or local JAR files)
  • Adding module descriptors to your project's JAR as well as existing JAR files (dependencies)
  • Creating module runtime images

Compared to authoring module descriptors by hand, using ModiTect saves you work by defining dependence clauses based on your project's dependencies, describing exported and opened packages with patterns (instead of listing all packages separately), auto-detecting service usages and more. You also can use ModiTect to add a module descriptor to your project JAR while staying on Java 8 with your own build.

In future versions functionality may be added to work with other tools like jmod etc. under Maven and other dependency management tools in a comfortable manner.

Usage

ModiTect's functionality is currently exclusively exposed through a Maven plug-in. The core implementation is a separate module, though, so that plug-ins for other build systems such as Gradle could be written, too.

Generating module-info.java descriptors

To create a module-info.java descriptor for a given artifact, configure the generate-module-info goal as follows:

...
<plugin>
    <groupId>org.moditect</groupId>
    <artifactId>moditect-maven-plugin</artifactId>
    <version>1.0.0.Final</version>
    <executions>
        <execution>
            <id>generate-module-info</id>
            <phase>generate-sources</phase>
            <goals>
                <goal>generate-module-info</goal>
            </goals>
            <configuration>
                <modules>
                    <module>
                        <artifact>
                            <groupId>com.example</groupId>
                            <artifactId>example-core</artifactId>
                            <version>1.0.0.Final</version>
                        </artifact>
                        <additionalDependencies>
                            <dependency>
                                <groupId>com.example</groupId>
                                <artifactId>example-extended</artifactId>
                                <version>1.0.0.Final</version>
                            </dependency>
                        </additionalDependencies>
                        <moduleInfo>
                            <name>com.example.core</name>
                            <exports>
                                !com.example.core.internal*;
                                *;
                            </exports>
                            <requires>
                                static com.some.optional.dependency;
                                !com.excluded.dependency;
                                *;
                            </requires>
                            <opens>
                                com.example.core.internal.controller to javafx.fxml;
                            </opens>
                            <opensResources>
                                com.example.resource;
                                com.example.resource.icon;
                                com.example.resource.sound;
                            </opensResources>
                            <uses>
                                 com.example.SomeService;
                            </uses>
                            <provides>
                                com.example.SomeService with com.example.SomeServiceImpl1,com.example.SomeServiceImpl2;
                            </provides>
                            <addServiceUses>true</addServiceUses>
                        </moduleInfo>
                    </module>
                    <module>
                        ...
                    </module>
                </modules>
                <jdepsExtraArgs>
                  <arg>--upgrade-module-path=...</arg>
                </jdepsExtraArgs>
            </configuration>
        </execution>
    </executions>
</plugin>
...

This will generate a module descriptor at target/generated-sources/com.example.core/module-info.java.

For each module to be processed, the following configuration options exist:

  • artifact: The GAV coordinates of the artifact for which a descriptor should be generated (required)
  • additionalDependencies: Additional artifacts to be processed; useful if the main artifact depends on code from another artifact but doesn't declare a dependency to that one (optional)
  • moduleInfo: Allows fine-grained configuration of the generated module descriptor (optional); has the following sub-elements:
    • name: Name to be used within the descriptor; if not given the name will be derived from the JAR name as per the naming rules for automatic modules (optional)
    • open: Whether the descriptor should be an open module or not (optional, defaults to false)
    • exports: List of name patterns for describing the exported packages of the module, separated by ";". Patterns can be inclusive or exclusive (starting with "!") and may contain the "*" as a wildcard. Inclusive patterns may be qualified exports ("to xyz"). For each package from the module, the given patterns are processed in the order they are given. As soon a package is matched by an inclusive pattern, the package will be added to the list of exported packages and no further patterns will be applied. As soon as a package is matched by an exclusive pattern, this package will not be added to the list of exported packages and no further patterns will be applied. (optional; the default value is "*;", i.e. all packages will be exported)
    • opens: List of name patterns for describing the open packages of the module, separated by ";". Patterns can be inclusive or exclusive (starting with "!") and may contain the "*" as a wildcard. Inclusive patterns may be qualified exports ("to xyz"). For each package from the module, the given patterns are processed in the order they are given. As soon a package is matched by an inclusive pattern, the package will be added to the list of open packages and no further patterns will be applied. As soon as a package is matched by an exclusive pattern, this package will not be added to the list of open packages and no further patterns will be applied. (optional; the default value is "!*;", i.e. no packages will be opened)
    • opensResources: List of package names only containing resources as png, css or mp3 files i.e. everything not being java files, separated by ";". For JavaFX 9+, it is required to force open resource-only packages. Please, refer to https://github.com/javafxports/openjdk-jfx/issues/441 for more details. opensResources allows to do this. Contrary to opens, opensResources cannot accept patterns because Moditect manages patterns using a technical solution that can only works with compiled java classes. Hence, each resource-only packages must be declared one by one.
    • requires: List of name patterns for describing the dependences of the module, based on the automatically determined dependences. Patterns are inclusive or exclusive (starting with "!") and may contain the "*" character as a wildcard. Inclusive patterns may contain the static and transitive modifiers, in which case those modifiers will override the modifiers of the automatically determined dependence. For each of the automatically determined dependences of the module, the given patterns are processed in the order they are given. As soon as a dependence is matched by a pattern, the dependence will be added to the list of dependences (if the pattern is inclusive) or the dependence will be filtered out (for exclusive patterns) and no further patterns will be applied. Usually, only a few dependences will be given explicitly in order to override their modifiers, followed by a *; pattern to add all remaining automatically determined dependences.
    • addServiceUses: If true, the given artifact will be scanned for usages of ServiceLoader#load() and if usages passing a class literal are found (load( MyService.class )), an equivalent uses() clause will be added to the generated descriptor; usages of load() where a non-literal class object is passed, are ignored (optional, defaults to false)
    • uses: List of names of used services, separated by ";" only required if addServiceUses cannot be used due to dynamic invocations of ServiceLoader#load(), i.e. no class literal is passed (optional)
    • provides: List of services with their provided service implementations, separated by ";". A service and its implementation must be separated by the keyword "with" e.g. serviceX with implementationX; serviceY with implementationY;. If the module implements a particular service through several service implementations, those implementation classes must be separated by "," e.g. myService with implementation1, implementation2, implementation3;.
    • jdepsExtraArgs: A list of arguments passed to the jdeps invocation for creating a "candidate descriptor"

It is also possible to run this goal directly, specifying the different options as JVM parameters like this:

mvn moditect:generate-module-info \
    -Dm
View on GitHub
GitHub Stars577
CategoryDevelopment
Updated18d ago
Forks69

Languages

Java

Security Score

100/100

Audited on Mar 8, 2026

No findings