-
Notifications
You must be signed in to change notification settings - Fork 2
Description
Background: What Are Named Modules?
Since Java 9, JARs can declare themselves as named modules by including a module-info.java file. This file explicitly declares:
- The module's name
- What other modules it depends on
- What packages it exposes to other modules
Without module-info.java, a JAR is an unnamed module - it just goes on the classpath like traditional Java.
// Example module-info.java
module fiftyone.pipeline.engines.fiftyone {
requires fiftyone.pipeline.core;
exports fiftyone.pipeline.engines.fiftyone.flowelements;
}The Problem
Our LibLoader class calls System.load() to load native libraries. Starting with Java 16+, this is a "restricted method" and produces warnings:
WARNING: java.lang.System::load has been called by ...LibLoader in an unnamed module
WARNING: Use --enable-native-access=ALL-UNNAMED to avoid a warning
WARNING: Restricted methods will be blocked in a future release unless native access is enabled
The warning is not critical for now, but can only be suppressed with: --enable-native-access=ALL-UNNAMED
Problem: This grants native access to ALL JARs - overly permissive and will eventually be deprecated.
Better solution: Name our module, so users can grant access to just our code:
--enable-native-access=fiftyone.pipeline.engines.fiftyone
Dependency Constraint
Named modules can only depend on other named modules. This is contagious to dependencies.
pipeline.engines.fiftyone ← we want to name this (contains LibLoader)
├── pipeline.engines ← must also be named (dependency)
└── pipeline.core ← must also be named (dependency)
Downstream consumers (device-detection, customer code) can stay unnamed - they'll still work.
Think of it as: "Named modules can only see other named modules, but unnamed modules can see everything."
Implementation
Modules to Convert
Add module-info.java to these modules in pipeline-java:
| Module | Artifact ID | Why |
|------------------------------------|---------------------------|--------------------------------|
| fiftyone.common | pipeline.common | Dependency of core |
| fiftyone.caching | pipeline.caching | Dependency of engines |
| fiftyone.pipeline.core | pipeline.core | Dependency of engines |
| fiftyone.pipeline.engines | pipeline.engines | Dependency of engines.fiftyone |
| fiftyone.pipeline.engines.fiftyone | pipeline.engines.fiftyone | Contains LibLoader |
module fiftyone.pipeline.engines.fiftyone {
requires fiftyone.pipeline.engines;
exports fiftyone.pipeline.engines.fiftyone;
exports fiftyone.pipeline.engines.fiftyone.data;
exports fiftyone.pipeline.engines.fiftyone.flowelements;
exports fiftyone.pipeline.engines.fiftyone.flowelements.interop;
}
The exports and requires statements are standard module plumbing for compilation. There is no special directive for native access - the module just needs a name so users can reference it with: --enable-native-access=fiftyone.pipeline.engines.fiftyone
Steps
- Analyze full dependency tree to identify all modules requiring conversion (see the table above)
- Create
module-info.javafor each module with correct requires and exports - Update Maven build configuration for module compilation
- Test on Java 17, 21 with
--enable-native-access=fiftyone.pipeline.engines.fiftyone - Verify downstream unnamed consumers still work
Documentation Updates
Add to READMEs in pipeline-java, device-detection-java, and device-detection-java-examples:
Native Library Access (Java 16+)
Enable native access for the 51Degrees module:
Command line:
java --enable-native-access=fiftyone.pipeline.engines.fiftyone -jar your-app.jarMaven exec plugin:
<configuration>
<arguments>
<argument>--enable-native-access=fiftyone.pipeline.engines.fiftyone</argument>
...
</arguments>
</configuration>Acceptance Criteria
- No warnings when running with
--enable-native-access=fiftyone.pipeline.engines.fiftyone - Existing functionality preserved
- Unnamed downstream consumers work without changes
- Documentation updated with clear instructions
References
- JEP 472: Prepare to Restrict the Use of JNI - The JEP that introduces the warning and future restrictions on
System.load() - The Unnamed Module - Dev.java - Official Java documentation explaining named vs unnamed modules
- A Guide to Java 9 Modularity - Baeldung - Practical guide to creating
module-info.java