Skip to content

Convert to named modules for native library access permission #476

@justadreamer

Description

@justadreamer

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.java for 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.jar

Maven 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions