Skip to content

Commit baaebe7

Browse files
authored
Merge pull request #324 from cconlon/moduleInfo
Add Java 9+ module support (JPMS) for jlink compatibility
2 parents 96f1fdb + 97f7523 commit baaebe7

5 files changed

Lines changed: 456 additions & 1 deletion

File tree

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
name: Java 9+ Module Support
2+
3+
on:
4+
push:
5+
branches: [ 'master', 'main', 'release/**' ]
6+
pull_request:
7+
branches: [ '*' ]
8+
9+
jobs:
10+
# Test Java 9+ module support (JPMS)
11+
# Verifies that module-info.java is properly compiled and the resulting
12+
# JAR can be used with jlink to create custom Java runtimes.
13+
# See GitHub issue #85 for background.
14+
module-test:
15+
strategy:
16+
matrix:
17+
os: [ 'ubuntu-latest' ]
18+
jdk_version: [ '11', '17', '21' ]
19+
runs-on: ${{ matrix.os }}
20+
name: Module Test (JDK ${{ matrix.jdk_version }})
21+
22+
steps:
23+
- uses: actions/checkout@v4
24+
25+
- name: Cache JUnit dependencies
26+
uses: actions/cache@v4
27+
id: cache-junit
28+
with:
29+
path: junit
30+
key: junit-jars-v1
31+
32+
- name: Download junit-4.13.2.jar
33+
if: steps.cache-junit.outputs.cache-hit != 'true'
34+
run: wget --directory-prefix=$GITHUB_WORKSPACE/junit https://repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar
35+
36+
- name: Download hamcrest-all-1.3.jar
37+
if: steps.cache-junit.outputs.cache-hit != 'true'
38+
run: wget --directory-prefix=$GITHUB_WORKSPACE/junit https://repo1.maven.org/maven2/org/hamcrest/hamcrest-all/1.3/hamcrest-all-1.3.jar
39+
40+
- name: Build native wolfSSL
41+
uses: wolfSSL/actions-build-autotools-project@v1
42+
with:
43+
repository: wolfSSL/wolfssl
44+
ref: master
45+
path: wolfssl
46+
configure: --enable-jni
47+
check: false
48+
install: true
49+
50+
- name: Setup Java
51+
uses: actions/setup-java@v4
52+
with:
53+
distribution: 'zulu'
54+
java-version: ${{ matrix.jdk_version }}
55+
56+
- name: Set JUNIT_HOME
57+
run: |
58+
echo "JUNIT_HOME=$GITHUB_WORKSPACE/junit" >> "$GITHUB_ENV"
59+
60+
- name: Set LD_LIBRARY_PATH
61+
run: |
62+
echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$GITHUB_WORKSPACE/build-dir/lib" >> "$GITHUB_ENV"
63+
64+
- name: Build JNI library
65+
run: ./java.sh $GITHUB_WORKSPACE/build-dir
66+
67+
- name: Build JAR with module support (ant)
68+
run: ant
69+
70+
- name: Verify module-info.class exists in JAR
71+
run: |
72+
echo "Checking for module-info.class in wolfssl-jsse.jar..."
73+
if jar tf lib/wolfssl-jsse.jar | grep -q "module-info.class"; then
74+
echo "SUCCESS: module-info.class found in JAR"
75+
else
76+
echo "FAILURE: module-info.class not found in JAR"
77+
echo "JAR contents:"
78+
jar tf lib/wolfssl-jsse.jar | head -20
79+
exit 1
80+
fi
81+
82+
- name: Verify module descriptor with jar --describe-module
83+
run: |
84+
echo "Describing module in wolfssl-jsse.jar..."
85+
jar --describe-module --file=lib/wolfssl-jsse.jar
86+
echo ""
87+
echo "Verifying module name is 'com.wolfssl'..."
88+
MODULE_NAME=$(jar --describe-module --file=lib/wolfssl-jsse.jar 2>&1 | head -1 | cut -d' ' -f1)
89+
if [ "$MODULE_NAME" = "com.wolfssl" ]; then
90+
echo "SUCCESS: Module name is correct: $MODULE_NAME"
91+
else
92+
echo "FAILURE: Expected module name 'com.wolfssl', got '$MODULE_NAME'"
93+
exit 1
94+
fi
95+
96+
- name: Verify module exports correct packages
97+
run: |
98+
echo "Verifying module exports..."
99+
EXPORTS=$(jar --describe-module --file=lib/wolfssl-jsse.jar 2>&1)
100+
echo "$EXPORTS"
101+
echo ""
102+
if echo "$EXPORTS" | grep -q "exports com.wolfssl"; then
103+
echo "SUCCESS: exports com.wolfssl"
104+
else
105+
echo "FAILURE: missing 'exports com.wolfssl'"
106+
exit 1
107+
fi
108+
if echo "$EXPORTS" | grep -q "exports com.wolfssl.provider.jsse"; then
109+
echo "SUCCESS: exports com.wolfssl.provider.jsse"
110+
else
111+
echo "FAILURE: missing 'exports com.wolfssl.provider.jsse'"
112+
exit 1
113+
fi
114+
115+
- name: Test jlink can create runtime with module
116+
run: |
117+
echo "Testing jlink integration..."
118+
jlink \
119+
--module-path lib/wolfssl-jsse.jar \
120+
--add-modules com.wolfssl \
121+
--output test-jlink-runtime \
122+
--no-header-files \
123+
--no-man-pages
124+
echo ""
125+
echo "SUCCESS: jlink created custom runtime"
126+
echo "Runtime modules:"
127+
./test-jlink-runtime/bin/java --list-modules
128+
echo ""
129+
echo "Verifying com.wolfssl module is present..."
130+
if ./test-jlink-runtime/bin/java --list-modules | grep -q "com.wolfssl"; then
131+
echo "SUCCESS: com.wolfssl module found in custom runtime"
132+
else
133+
echo "FAILURE: com.wolfssl module not found in custom runtime"
134+
exit 1
135+
fi
136+
137+
- name: Clean up jlink test runtime
138+
run: rm -rf test-jlink-runtime
139+
140+
- name: Run standard tests to verify module doesn't break functionality
141+
run: ant test
142+
143+
- name: Clean ant build for Maven test
144+
run: ant clean
145+
146+
- name: Maven build and verify module-info in JAR
147+
run: |
148+
echo "Building with Maven..."
149+
mvn package -DskipTests -q
150+
echo ""
151+
MAVEN_JAR=$(ls target/wolfssl-jsse-*.jar)
152+
echo "Maven JAR: $MAVEN_JAR"
153+
echo ""
154+
echo "Checking for module-info.class in Maven-built JAR..."
155+
if jar tf "$MAVEN_JAR" | grep -q "module-info.class"; then
156+
echo "SUCCESS: module-info.class found in Maven JAR"
157+
else
158+
echo "FAILURE: module-info.class not found in Maven JAR"
159+
jar tf "$MAVEN_JAR" | head -20
160+
exit 1
161+
fi
162+
echo ""
163+
echo "Verifying Maven JAR module descriptor..."
164+
jar --describe-module --file="$MAVEN_JAR"
165+
166+
- name: Clean Maven build
167+
run: mvn clean -q
168+
169+
- name: Show logs on failure
170+
if: failure() || cancelled()
171+
run: |
172+
cat build/reports/*.txt 2>/dev/null || echo "No test reports found"
173+
174+
# Verify Java 8 builds do NOT include module-info.class
175+
# This ensures the conditional compilation works correctly for Java 8 users
176+
java8-no-module-test:
177+
runs-on: ubuntu-latest
178+
name: Java 8 No Module Test
179+
180+
steps:
181+
- uses: actions/checkout@v4
182+
183+
- name: Cache JUnit dependencies
184+
uses: actions/cache@v4
185+
id: cache-junit
186+
with:
187+
path: junit
188+
key: junit-jars-v1
189+
190+
- name: Download junit-4.13.2.jar
191+
if: steps.cache-junit.outputs.cache-hit != 'true'
192+
run: wget --directory-prefix=$GITHUB_WORKSPACE/junit https://repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar
193+
194+
- name: Download hamcrest-all-1.3.jar
195+
if: steps.cache-junit.outputs.cache-hit != 'true'
196+
run: wget --directory-prefix=$GITHUB_WORKSPACE/junit https://repo1.maven.org/maven2/org/hamcrest/hamcrest-all/1.3/hamcrest-all-1.3.jar
197+
198+
- name: Build native wolfSSL
199+
uses: wolfSSL/actions-build-autotools-project@v1
200+
with:
201+
repository: wolfSSL/wolfssl
202+
ref: master
203+
path: wolfssl
204+
configure: --enable-jni
205+
check: false
206+
install: true
207+
208+
- name: Setup Java 8
209+
uses: actions/setup-java@v4
210+
with:
211+
distribution: 'zulu'
212+
java-version: '8'
213+
214+
- name: Set JUNIT_HOME
215+
run: |
216+
echo "JUNIT_HOME=$GITHUB_WORKSPACE/junit" >> "$GITHUB_ENV"
217+
218+
- name: Set LD_LIBRARY_PATH
219+
run: |
220+
echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$GITHUB_WORKSPACE/build-dir/lib" >> "$GITHUB_ENV"
221+
222+
- name: Build JNI library
223+
run: ./java.sh $GITHUB_WORKSPACE/build-dir
224+
225+
- name: Build JAR without module support (ant on Java 8)
226+
run: ant
227+
228+
- name: Verify module-info.class is NOT in JAR (Java 8 build)
229+
run: |
230+
echo "Checking that module-info.class is NOT in wolfssl-jsse.jar (Java 8 build)..."
231+
if jar tf lib/wolfssl-jsse.jar | grep -q "module-info.class"; then
232+
echo "FAILURE: module-info.class should NOT be in JAR when built with Java 8"
233+
exit 1
234+
else
235+
echo "SUCCESS: module-info.class correctly excluded from Java 8 build"
236+
fi
237+
238+
- name: Run tests to verify Java 8 build works correctly
239+
run: ant test
240+
241+
- name: Maven build and verify NO module-info in JAR (Java 8)
242+
run: |
243+
echo "Building with Maven on Java 8..."
244+
mvn package -DskipTests -q
245+
echo ""
246+
MAVEN_JAR=$(ls target/wolfssl-jsse-*.jar)
247+
echo "Maven JAR: $MAVEN_JAR"
248+
echo ""
249+
echo "Checking that module-info.class is NOT in Maven-built JAR..."
250+
if jar tf "$MAVEN_JAR" | grep -q "module-info.class"; then
251+
echo "FAILURE: module-info.class should NOT be in Maven JAR on Java 8"
252+
exit 1
253+
else
254+
echo "SUCCESS: module-info.class correctly excluded from Maven Java 8 build"
255+
fi
256+
mvn clean -q
257+
258+
- name: Show logs on failure
259+
if: failure() || cancelled()
260+
run: |
261+
cat build/reports/*.txt 2>/dev/null || echo "No test reports found"
262+

README.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,85 @@ an application can include this as a dependency in the application's
231231
</project>
232232
```
233233

234+
## Java 9+ Module Support (JPMS)
235+
236+
wolfSSL JNI/JSSE supports the Java Platform Module System (JPMS) introduced in
237+
Java 9. This allows the library to be used with `jlink` to create custom Java
238+
runtimes.
239+
240+
### How It Works
241+
242+
The build system uses conditional compilation to include module support only
243+
when building with Java 9 or later:
244+
245+
| JDK Used to Build | Resulting JAR |
246+
| --- | --- |
247+
| Java 8 | Standard JAR (classpath only) |
248+
| Java 9+ | Modular JAR (works with both classpath and module path) |
249+
250+
When building with Java 9+, a `module-info.class` is included in the JAR that:
251+
- Declares the module as `com.wolfssl`
252+
- Exports `com.wolfssl` and `com.wolfssl.provider.jsse` packages
253+
- Registers `WolfSSLProvider` as a `java.security.Provider` service
254+
255+
### Building a Modular JAR
256+
257+
To build a modular JAR, simply use Java 9 or later when building. Both Ant and
258+
Maven builds support automatic module-info compilation.
259+
260+
**Using Ant:**
261+
262+
```
263+
$ export JAVA_HOME=/path/to/jdk11 # or any JDK 9+
264+
$ ./java.sh
265+
$ ant
266+
```
267+
268+
**Using Maven:**
269+
270+
```
271+
$ export JAVA_HOME=/path/to/jdk11 # or any JDK 9+
272+
$ ./java.sh
273+
$ mvn package
274+
```
275+
276+
Maven uses a profile (`java9-module`) that automatically activates on Java 9+
277+
to compile and include `module-info.class` in the JAR.
278+
279+
You can verify module support with:
280+
281+
```
282+
$ jar --describe-module --file=lib/wolfssl-jsse.jar
283+
com.wolfssl jar:file:///path/to/lib/wolfssl-jsse.jar/!module-info.class
284+
exports com.wolfssl
285+
exports com.wolfssl.provider.jsse
286+
requires java.logging
287+
provides java.security.Provider with com.wolfssl.provider.jsse.WolfSSLProvider
288+
```
289+
290+
### Using with jlink
291+
292+
Once built with Java 9+, the JAR can be used with `jlink` to create custom
293+
Java runtimes:
294+
295+
```
296+
$ jlink \
297+
--module-path lib/wolfssl-jsse.jar \
298+
--add-modules com.wolfssl \
299+
--output custom-runtime \
300+
--no-header-files \
301+
--no-man-pages
302+
```
303+
304+
This creates a minimal Java runtime with wolfJSSE included, which can be
305+
deployed independently.
306+
307+
### Java 8 Compatibility
308+
309+
Java 8 users can still build and use wolfSSL JNI/JSSE normally. When building
310+
with Java 8, the `module-info.java` is automatically excluded from compilation,
311+
and the resulting JAR works as a standard classpath JAR.
312+
234313
## Examples
235314

236315
Examples of using wolfssljni can be found in the `./examples` subdirectory.

0 commit comments

Comments
 (0)