diff --git a/pom.xml b/pom.xml
index 714398b..0863fbd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -31,8 +31,7 @@
${project.target.release}
3.5.0
- ${project.target.release}
- ${project.target.release}
+ ${project.target.release}
5.1.1
@@ -191,6 +190,17 @@
+
+ maven-jar-plugin
+
+
+
+ true
+
+
+
+
+
maven-source-plugin
@@ -259,6 +269,11 @@
!java.*,!sun.*
*
+ true
+
+ {maven-resources},
+ META-INF/versions/=${project.build.outputDirectory}/META-INF/versions/
+
@@ -274,6 +289,34 @@
+
+ org.apache.maven.plugins
+ maven-invoker-plugin
+ 3.9.1
+
+ ${project.build.directory}/it
+ ${project.build.directory}/local-repo
+ src/it/settings.xml
+ verify
+ false
+ true
+
+ clean
+ test
+
+
+
+
+ integration-test
+
+ install
+ run
+ verify
+
+
+
+
+
@@ -309,13 +352,29 @@
jdk9+-profile
- [9,21)
+ [9,)
-
- ${project.target.release}
-
+
+ maven-compiler-plugin
+
+
+ compile-java9
+ compile
+
+ compile
+
+
+ 9
+
+ ${project.basedir}/src/main/java9
+
+ true
+
+
+
+
maven-surefire-plugin
diff --git a/src/it/README.adoc b/src/it/README.adoc
new file mode 100644
index 0000000..004e7cf
--- /dev/null
+++ b/src/it/README.adoc
@@ -0,0 +1,66 @@
+= Integration Tests
+
+This directory contains integration tests for the Zero-Allocation-Hashing library using the Maven Invoker Plugin and JUnit 4.
+
+== Test Cases
+
+=== 1. simple-usage
+
+Tests basic usage of the hashing library without modules.
+
+- Tests various hash functions (XxHash, CityHash, MurmurHash3, FarmHash)
+- Verifies hash consistency across byte arrays, ByteBuffers, and CharSequences
+- Ensures public API is accessible
+- Uses JUnit 4 assertions
+
+=== 2. module-test
+
+Tests proper module encapsulation on Java 9+.
+
+- Uses `module-info.java` to require the `net.openhft.hashing` module
+- Verifies that only exported packages are accessible
+- Tests are compiled and run with module path
+- Demonstrates module system working correctly
+- Uses JUnit 4 assertions
+
+== Running Integration Tests
+
+Integration tests run automatically during the build with:
+
+[source,bash]
+----
+./mvnw clean verify
+----
+
+Or run them separately with:
+
+[source,bash]
+----
+./mvnw invoker:run
+----
+
+== Module Encapsulation
+
+The library exports only the `net.openhft.hashing` package via module-info.java:
+
+[source,java]
+----
+module net.openhft.hashing {
+ requires jdk.unsupported;
+ exports net.openhft.hashing;
+}
+----
+
+Internal packages (like sun.nio.ch) are not exported and cannot be accessed by consuming modules.
+
+== Multi-Release JAR
+
+The library is built as a multi-release JAR with module-info.class in META-INF/versions/9/:
+
+- Java 8: Works as a regular JAR without module system
+- Java 9+: Works as a named module with proper encapsulation
+
+== Test Framework
+
+All integration tests use JUnit 4 (same as the main project tests) and do not print to System.out.
+Test results are reported through Maven Surefire plugin output only.
diff --git a/src/it/module-test/invoker.properties b/src/it/module-test/invoker.properties
new file mode 100644
index 0000000..ac71e23
--- /dev/null
+++ b/src/it/module-test/invoker.properties
@@ -0,0 +1,2 @@
+invoker.goals=clean test
+invoker.buildResult=success
diff --git a/src/it/module-test/pom.xml b/src/it/module-test/pom.xml
new file mode 100644
index 0000000..3a90660
--- /dev/null
+++ b/src/it/module-test/pom.xml
@@ -0,0 +1,42 @@
+
+
+ 4.0.0
+
+ net.openhft.it
+ module-test
+ 1.0-SNAPSHOT
+
+
+ UTF-8
+ 11
+
+
+
+
+ @project.groupId@
+ @project.artifactId@
+ @project.version@
+
+
+ junit
+ junit
+ 4.13.2
+ test
+
+
+
+
+
+
+ maven-compiler-plugin
+ 3.14.0
+
+
+ maven-surefire-plugin
+ 3.5.4
+
+
+
+
diff --git a/src/it/module-test/src/test/java/module-info.java b/src/it/module-test/src/test/java/module-info.java
new file mode 100644
index 0000000..7cc33d5
--- /dev/null
+++ b/src/it/module-test/src/test/java/module-info.java
@@ -0,0 +1,9 @@
+/*
+ * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0
+ */
+module net.openhft.it.module {
+ requires net.openhft.hashing;
+ requires junit;
+ exports net.openhft.it.module;
+ opens net.openhft.it.module to junit;
+}
diff --git a/src/it/module-test/src/test/java/net/openhft/it/module/ModuleTest.java b/src/it/module-test/src/test/java/net/openhft/it/module/ModuleTest.java
new file mode 100644
index 0000000..45add4e
--- /dev/null
+++ b/src/it/module-test/src/test/java/net/openhft/it/module/ModuleTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0
+ */
+package net.openhft.it.module;
+
+import net.openhft.hashing.LongHashFunction;
+import org.junit.Test;
+
+import java.nio.charset.StandardCharsets;
+
+import static org.junit.Assert.*;
+
+/**
+ * Integration test verifying proper module encapsulation.
+ * This test ensures that only exported packages are accessible.
+ */
+public class ModuleTest {
+
+ private static final String TEST_DATA = "Module Test Data";
+ private static final byte[] TEST_BYTES = TEST_DATA.getBytes(StandardCharsets.UTF_8);
+
+ @Test
+ public void testPublicAPIAccessible() {
+ long xxHash = LongHashFunction.xx().hashBytes(TEST_BYTES);
+ long cityHash = LongHashFunction.city_1_1().hashBytes(TEST_BYTES);
+ long murmurHash = LongHashFunction.murmur_3().hashBytes(TEST_BYTES);
+
+ assertTrue("XxHash should produce non-zero result", xxHash != 0);
+ assertTrue("CityHash should produce non-zero result", cityHash != 0);
+ assertTrue("MurmurHash should produce non-zero result", murmurHash != 0);
+ }
+
+ @Test
+ public void testMainAPIClassAccessible() {
+ try {
+ Class.forName("net.openhft.hashing.LongHashFunction");
+ } catch (ClassNotFoundException e) {
+ fail("Public API net.openhft.hashing.LongHashFunction should be accessible");
+ }
+ }
+}
diff --git a/src/it/settings.xml b/src/it/settings.xml
new file mode 100644
index 0000000..8bd5dac
--- /dev/null
+++ b/src/it/settings.xml
@@ -0,0 +1,6 @@
+
+
+ @localRepositoryPath@
+
diff --git a/src/it/simple-usage/invoker.properties b/src/it/simple-usage/invoker.properties
new file mode 100644
index 0000000..ac71e23
--- /dev/null
+++ b/src/it/simple-usage/invoker.properties
@@ -0,0 +1,2 @@
+invoker.goals=clean test
+invoker.buildResult=success
diff --git a/src/it/simple-usage/pom.xml b/src/it/simple-usage/pom.xml
new file mode 100644
index 0000000..98a41e4
--- /dev/null
+++ b/src/it/simple-usage/pom.xml
@@ -0,0 +1,42 @@
+
+
+ 4.0.0
+
+ net.openhft.it
+ simple-usage
+ 1.0-SNAPSHOT
+
+
+ UTF-8
+ 11
+
+
+
+
+ @project.groupId@
+ @project.artifactId@
+ @project.version@
+
+
+ junit
+ junit
+ 4.13.2
+ test
+
+
+
+
+
+
+ maven-compiler-plugin
+ 3.14.0
+
+
+ maven-surefire-plugin
+ 3.5.4
+
+
+
+
diff --git a/src/it/simple-usage/src/test/java/net/openhft/it/HashingTest.java b/src/it/simple-usage/src/test/java/net/openhft/it/HashingTest.java
new file mode 100644
index 0000000..d2f1f50
--- /dev/null
+++ b/src/it/simple-usage/src/test/java/net/openhft/it/HashingTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0
+ */
+package net.openhft.it;
+
+import net.openhft.hashing.LongHashFunction;
+import org.junit.Test;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+
+import static org.junit.Assert.*;
+
+/**
+ * Integration test demonstrating usage of Zero-Allocation-Hashing library.
+ */
+public class HashingTest {
+
+ private static final String TEST_STRING = "Hello, World!";
+ private static final byte[] TEST_BYTES = TEST_STRING.getBytes(StandardCharsets.UTF_8);
+
+ @Test
+ public void testXxHash() {
+ LongHashFunction xxHash = LongHashFunction.xx();
+ ByteBuffer buffer = ByteBuffer.wrap(TEST_BYTES);
+
+ long hashFromBytes = xxHash.hashBytes(TEST_BYTES);
+ long hashFromBuffer = xxHash.hashBytes(buffer);
+ buffer.rewind();
+ long hashFromChars = xxHash.hashChars(TEST_STRING);
+
+ assertEquals("XxHash: byte[] and ByteBuffer hashes should match", hashFromBytes, hashFromBuffer);
+ assertTrue("XxHash from bytes should be non-zero", hashFromBytes != 0);
+ assertTrue("XxHash from chars should be non-zero", hashFromChars != 0);
+ }
+
+ @Test
+ public void testCityHash() {
+ LongHashFunction cityHash = LongHashFunction.city_1_1();
+ ByteBuffer buffer = ByteBuffer.wrap(TEST_BYTES);
+
+ long hashFromBytes = cityHash.hashBytes(TEST_BYTES);
+ long hashFromBuffer = cityHash.hashBytes(buffer);
+ buffer.rewind();
+ long hashFromChars = cityHash.hashChars(TEST_STRING);
+
+ assertEquals("CityHash: byte[] and ByteBuffer hashes should match", hashFromBytes, hashFromBuffer);
+ assertTrue("CityHash from bytes should be non-zero", hashFromBytes != 0);
+ assertTrue("CityHash from chars should be non-zero", hashFromChars != 0);
+ }
+
+ @Test
+ public void testMurmurHash() {
+ LongHashFunction murmur = LongHashFunction.murmur_3();
+ ByteBuffer buffer = ByteBuffer.wrap(TEST_BYTES);
+
+ long hashFromBytes = murmur.hashBytes(TEST_BYTES);
+ long hashFromBuffer = murmur.hashBytes(buffer);
+ buffer.rewind();
+ long hashFromChars = murmur.hashChars(TEST_STRING);
+
+ assertEquals("MurmurHash3: byte[] and ByteBuffer hashes should match", hashFromBytes, hashFromBuffer);
+ assertTrue("MurmurHash3 from bytes should be non-zero", hashFromBytes != 0);
+ assertTrue("MurmurHash3 from chars should be non-zero", hashFromChars != 0);
+ }
+
+ @Test
+ public void testFarmHash() {
+ LongHashFunction farmHash = LongHashFunction.farmUo();
+ ByteBuffer buffer = ByteBuffer.wrap(TEST_BYTES);
+
+ long hashFromBytes = farmHash.hashBytes(TEST_BYTES);
+ long hashFromBuffer = farmHash.hashBytes(buffer);
+ buffer.rewind();
+ long hashFromChars = farmHash.hashChars(TEST_STRING);
+
+ assertEquals("FarmHash: byte[] and ByteBuffer hashes should match", hashFromBytes, hashFromBuffer);
+ assertTrue("FarmHash from bytes should be non-zero", hashFromBytes != 0);
+ assertTrue("FarmHash from chars should be non-zero", hashFromChars != 0);
+ }
+
+ @Test
+ public void testPublicAPIAccessible() {
+ try {
+ Class.forName("net.openhft.hashing.LongHashFunction");
+ } catch (ClassNotFoundException e) {
+ fail("Public API net.openhft.hashing.LongHashFunction should be accessible");
+ }
+ }
+}
diff --git a/src/main/java9/module-info.java b/src/main/java9/module-info.java
new file mode 100644
index 0000000..4d505e3
--- /dev/null
+++ b/src/main/java9/module-info.java
@@ -0,0 +1,7 @@
+/*
+ * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0
+ */
+module net.openhft.hashing {
+ requires jdk.unsupported;
+ exports net.openhft.hashing;
+}