Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
262 changes: 262 additions & 0 deletions .github/workflows/java-module-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
name: Java 9+ Module Support

on:
push:
branches: [ 'master', 'main', 'release/**' ]
pull_request:
branches: [ '*' ]

jobs:
# Test Java 9+ module support (JPMS)
# Verifies that module-info.java is properly compiled and the resulting
# JAR can be used with jlink to create custom Java runtimes.
# See GitHub issue #85 for background.
module-test:
strategy:
matrix:
os: [ 'ubuntu-latest' ]
jdk_version: [ '11', '17', '21' ]
runs-on: ${{ matrix.os }}
name: Module Test (JDK ${{ matrix.jdk_version }})

steps:
- uses: actions/checkout@v4

- name: Cache JUnit dependencies
uses: actions/cache@v4
id: cache-junit
with:
path: junit
key: junit-jars-v1

- name: Download junit-4.13.2.jar
if: steps.cache-junit.outputs.cache-hit != 'true'
run: wget --directory-prefix=$GITHUB_WORKSPACE/junit https://repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar

- name: Download hamcrest-all-1.3.jar
if: steps.cache-junit.outputs.cache-hit != 'true'
run: wget --directory-prefix=$GITHUB_WORKSPACE/junit https://repo1.maven.org/maven2/org/hamcrest/hamcrest-all/1.3/hamcrest-all-1.3.jar

- name: Build native wolfSSL
uses: wolfSSL/actions-build-autotools-project@v1
with:
repository: wolfSSL/wolfssl
ref: master
path: wolfssl
configure: --enable-jni
check: false
install: true

- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: 'zulu'
java-version: ${{ matrix.jdk_version }}

- name: Set JUNIT_HOME
run: |
echo "JUNIT_HOME=$GITHUB_WORKSPACE/junit" >> "$GITHUB_ENV"

- name: Set LD_LIBRARY_PATH
run: |
echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$GITHUB_WORKSPACE/build-dir/lib" >> "$GITHUB_ENV"

- name: Build JNI library
run: ./java.sh $GITHUB_WORKSPACE/build-dir

- name: Build JAR with module support (ant)
run: ant

- name: Verify module-info.class exists in JAR
run: |
echo "Checking for module-info.class in wolfssl-jsse.jar..."
if jar tf lib/wolfssl-jsse.jar | grep -q "module-info.class"; then
echo "SUCCESS: module-info.class found in JAR"
else
echo "FAILURE: module-info.class not found in JAR"
echo "JAR contents:"
jar tf lib/wolfssl-jsse.jar | head -20
exit 1
fi

- name: Verify module descriptor with jar --describe-module
run: |
echo "Describing module in wolfssl-jsse.jar..."
jar --describe-module --file=lib/wolfssl-jsse.jar
echo ""
echo "Verifying module name is 'com.wolfssl'..."
MODULE_NAME=$(jar --describe-module --file=lib/wolfssl-jsse.jar 2>&1 | head -1 | cut -d' ' -f1)
if [ "$MODULE_NAME" = "com.wolfssl" ]; then
echo "SUCCESS: Module name is correct: $MODULE_NAME"
else
echo "FAILURE: Expected module name 'com.wolfssl', got '$MODULE_NAME'"
exit 1
fi

- name: Verify module exports correct packages
run: |
echo "Verifying module exports..."
EXPORTS=$(jar --describe-module --file=lib/wolfssl-jsse.jar 2>&1)
echo "$EXPORTS"
echo ""
if echo "$EXPORTS" | grep -q "exports com.wolfssl"; then
echo "SUCCESS: exports com.wolfssl"
else
echo "FAILURE: missing 'exports com.wolfssl'"
exit 1
fi
if echo "$EXPORTS" | grep -q "exports com.wolfssl.provider.jsse"; then
echo "SUCCESS: exports com.wolfssl.provider.jsse"
else
echo "FAILURE: missing 'exports com.wolfssl.provider.jsse'"
exit 1
fi

- name: Test jlink can create runtime with module
run: |
echo "Testing jlink integration..."
jlink \
--module-path lib/wolfssl-jsse.jar \
--add-modules com.wolfssl \
--output test-jlink-runtime \
--no-header-files \
--no-man-pages
echo ""
echo "SUCCESS: jlink created custom runtime"
echo "Runtime modules:"
./test-jlink-runtime/bin/java --list-modules
echo ""
echo "Verifying com.wolfssl module is present..."
if ./test-jlink-runtime/bin/java --list-modules | grep -q "com.wolfssl"; then
echo "SUCCESS: com.wolfssl module found in custom runtime"
else
echo "FAILURE: com.wolfssl module not found in custom runtime"
exit 1
fi

- name: Clean up jlink test runtime
run: rm -rf test-jlink-runtime

- name: Run standard tests to verify module doesn't break functionality
run: ant test

- name: Clean ant build for Maven test
run: ant clean

- name: Maven build and verify module-info in JAR
run: |
echo "Building with Maven..."
mvn package -DskipTests -q
echo ""
MAVEN_JAR=$(ls target/wolfssl-jsse-*.jar)
echo "Maven JAR: $MAVEN_JAR"
echo ""
echo "Checking for module-info.class in Maven-built JAR..."
if jar tf "$MAVEN_JAR" | grep -q "module-info.class"; then
echo "SUCCESS: module-info.class found in Maven JAR"
else
echo "FAILURE: module-info.class not found in Maven JAR"
jar tf "$MAVEN_JAR" | head -20
exit 1
fi
echo ""
echo "Verifying Maven JAR module descriptor..."
jar --describe-module --file="$MAVEN_JAR"

- name: Clean Maven build
run: mvn clean -q

- name: Show logs on failure
if: failure() || cancelled()
run: |
cat build/reports/*.txt 2>/dev/null || echo "No test reports found"

# Verify Java 8 builds do NOT include module-info.class
# This ensures the conditional compilation works correctly for Java 8 users
java8-no-module-test:
runs-on: ubuntu-latest
name: Java 8 No Module Test

steps:
- uses: actions/checkout@v4

- name: Cache JUnit dependencies
uses: actions/cache@v4
id: cache-junit
with:
path: junit
key: junit-jars-v1

- name: Download junit-4.13.2.jar
if: steps.cache-junit.outputs.cache-hit != 'true'
run: wget --directory-prefix=$GITHUB_WORKSPACE/junit https://repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar

- name: Download hamcrest-all-1.3.jar
if: steps.cache-junit.outputs.cache-hit != 'true'
run: wget --directory-prefix=$GITHUB_WORKSPACE/junit https://repo1.maven.org/maven2/org/hamcrest/hamcrest-all/1.3/hamcrest-all-1.3.jar

- name: Build native wolfSSL
uses: wolfSSL/actions-build-autotools-project@v1
with:
repository: wolfSSL/wolfssl
ref: master
path: wolfssl
configure: --enable-jni
check: false
install: true

- name: Setup Java 8
uses: actions/setup-java@v4
with:
distribution: 'zulu'
java-version: '8'

- name: Set JUNIT_HOME
run: |
echo "JUNIT_HOME=$GITHUB_WORKSPACE/junit" >> "$GITHUB_ENV"

- name: Set LD_LIBRARY_PATH
run: |
echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$GITHUB_WORKSPACE/build-dir/lib" >> "$GITHUB_ENV"

- name: Build JNI library
run: ./java.sh $GITHUB_WORKSPACE/build-dir

- name: Build JAR without module support (ant on Java 8)
run: ant

- name: Verify module-info.class is NOT in JAR (Java 8 build)
run: |
echo "Checking that module-info.class is NOT in wolfssl-jsse.jar (Java 8 build)..."
if jar tf lib/wolfssl-jsse.jar | grep -q "module-info.class"; then
echo "FAILURE: module-info.class should NOT be in JAR when built with Java 8"
exit 1
else
echo "SUCCESS: module-info.class correctly excluded from Java 8 build"
fi

- name: Run tests to verify Java 8 build works correctly
run: ant test

- name: Maven build and verify NO module-info in JAR (Java 8)
run: |
echo "Building with Maven on Java 8..."
mvn package -DskipTests -q
echo ""
MAVEN_JAR=$(ls target/wolfssl-jsse-*.jar)
echo "Maven JAR: $MAVEN_JAR"
echo ""
echo "Checking that module-info.class is NOT in Maven-built JAR..."
if jar tf "$MAVEN_JAR" | grep -q "module-info.class"; then
echo "FAILURE: module-info.class should NOT be in Maven JAR on Java 8"
exit 1
else
echo "SUCCESS: module-info.class correctly excluded from Maven Java 8 build"
fi
mvn clean -q

- name: Show logs on failure
if: failure() || cancelled()
run: |
cat build/reports/*.txt 2>/dev/null || echo "No test reports found"

79 changes: 79 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,85 @@ an application can include this as a dependency in the application's
</project>
```

## Java 9+ Module Support (JPMS)

wolfSSL JNI/JSSE supports the Java Platform Module System (JPMS) introduced in
Java 9. This allows the library to be used with `jlink` to create custom Java
runtimes.

### How It Works

The build system uses conditional compilation to include module support only
when building with Java 9 or later:

| JDK Used to Build | Resulting JAR |
| --- | --- |
| Java 8 | Standard JAR (classpath only) |
| Java 9+ | Modular JAR (works with both classpath and module path) |

When building with Java 9+, a `module-info.class` is included in the JAR that:
- Declares the module as `com.wolfssl`
- Exports `com.wolfssl` and `com.wolfssl.provider.jsse` packages
- Registers `WolfSSLProvider` as a `java.security.Provider` service

### Building a Modular JAR

To build a modular JAR, simply use Java 9 or later when building. Both Ant and
Maven builds support automatic module-info compilation.

**Using Ant:**

```
$ export JAVA_HOME=/path/to/jdk11 # or any JDK 9+
$ ./java.sh
$ ant
```

**Using Maven:**

```
$ export JAVA_HOME=/path/to/jdk11 # or any JDK 9+
$ ./java.sh
$ mvn package
```

Maven uses a profile (`java9-module`) that automatically activates on Java 9+
to compile and include `module-info.class` in the JAR.

You can verify module support with:

```
$ jar --describe-module --file=lib/wolfssl-jsse.jar
com.wolfssl jar:file:///path/to/lib/wolfssl-jsse.jar/!module-info.class
exports com.wolfssl
exports com.wolfssl.provider.jsse
requires java.logging
provides java.security.Provider with com.wolfssl.provider.jsse.WolfSSLProvider
```

### Using with jlink

Once built with Java 9+, the JAR can be used with `jlink` to create custom
Java runtimes:

```
$ jlink \
--module-path lib/wolfssl-jsse.jar \
--add-modules com.wolfssl \
--output custom-runtime \
--no-header-files \
--no-man-pages
```

This creates a minimal Java runtime with wolfJSSE included, which can be
deployed independently.

### Java 8 Compatibility

Java 8 users can still build and use wolfSSL JNI/JSSE normally. When building
with Java 8, the `module-info.java` is automatically excluded from compilation,
and the resulting JAR works as a standard classpath JAR.

## Examples

Examples of using wolfssljni can be found in the `./examples` subdirectory.
Expand Down
Loading
Loading