Skip to content
Open
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
107 changes: 107 additions & 0 deletions .github/workflows/java8-artifact.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
name: Java 8 artefact compatibility
on:
push:
branches: [ea, develop]
pull_request:
types: [opened, synchronize, reopened]
jobs:
package:
name: Package on Java 8 and repeat without clean
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v6
with:
distribution: zulu
java-version: '8'
cache: maven
- name: Verify and retain the Java 8 binary
run: |
./mvnw -B -ntp verify -l java8-verify.log
mkdir -p target/java8-artifact
python3 - <<'PY'
import shutil
import xml.etree.ElementTree as ET

pom = ET.parse('pom.xml').getroot()
ns = {'m': 'http://maven.apache.org/POM/4.0.0'}
name = pom.findtext('m:artifactId', namespaces=ns)
version = pom.findtext('m:version', namespaces=ns)
shutil.copyfile('target/' + name + '-' + version + '.jar',
'target/java8-artifact/library.jar')
PY
sha256sum target/java8-artifact/library.jar > target/java8-artifact/SHA256SUMS
git rev-parse HEAD > target/java8-artifact/revision.txt
java -version 2> target/java8-artifact/build-jdk.txt
- name: Repeat package without cleaning generated modules
run: ./mvnw -B -ntp -DskipTests package -l repeat-package.log
- uses: actions/upload-artifact@v7
with:
name: java8-library
path: target/java8-artifact
if-no-files-found: error
- uses: actions/upload-artifact@v7
if: always()
with:
name: java8-build-evidence
path: |
java8-verify.log
repeat-package.log
target/surefire-reports
target/failsafe-reports
target/invoker-reports
target/it/**/build.log
target/it/**/target/surefire-reports
consumers:
name: Java 8 binary on JDK ${{ matrix.java }}
needs: package
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
java: ['8', '9', '10', '11', '17', '21', '25']
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v6
with:
distribution: zulu
java-version: ${{ matrix.java }}
cache: maven
- uses: actions/download-artifact@v8
with:
name: java8-library
path: target/java8-artifact
- name: Install the retained binary without rebuilding the library
run: |
sha256sum --check target/java8-artifact/SHA256SUMS
test "$(cat target/java8-artifact/revision.txt)" = "$(git rev-parse HEAD)"
./mvnw -B -ntp org.apache.maven.plugins:maven-install-plugin:3.1.4:install-file \
-Dfile=target/java8-artifact/library.jar -DpomFile=pom.xml \
-DlocalRepositoryPath=target/local-repo -DgeneratePom=false
- name: Run class-path and module-path consumers
run: |
./mvnw -B -ntp invoker:run invoker:verify -Dinvoker.failIfNoProjects=true -l consumers.log
installed=(target/local-repo/net/openhft/zero-allocation-hashing/*/zero-allocation-hashing-*.jar)
test "${#installed[@]}" = 1
cmp target/java8-artifact/library.jar "${installed[0]}"
- name: Check annotation and JDK dependencies
if: matrix.java == '21'
run: |
./mvnw -B -ntp dependency:copy -Dartifact=com.google.code.findbugs:jsr305:3.0.2 \
-DoutputDirectory=target/jdeps
jdeps --multi-release 9 -verbose:class --add-modules jsr305 \
--module-path target/jdeps/jsr305-3.0.2.jar \
target/java8-artifact/library.jar | tee jdeps.log
! grep -F 'not found' jdeps.log
grep -E 'net.openhft.hashing.* -> javax.annotation.ParametersAreNonnullByDefault +jsr305$' jdeps.log
- uses: actions/upload-artifact@v7
if: always()
with:
name: consumers-jdk-${{ matrix.java }}
path: |
consumers.log
jdeps.log
target/java8-artifact/SHA256SUMS
target/invoker-reports
target/it/**/build.log
target/it/**/target/surefire-reports
2 changes: 1 addition & 1 deletion .mvn/wrapper/maven-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
68 changes: 67 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@

<doclint>all,-missing</doclint>
<jmh.version>1.37</jmh.version>
<!-- ModiTect 1.3 requires Java 11; this build must also run on Java 8. -->
<!-- //! Keep descriptor generation runnable on Java 8; the newer plugin needs Java 11 before tests start. -->
<!-- //! AutomaticModuleNameIT#java8BuildProducesJava9ModuleDescriptor checks the resulting Java 9 descriptor. -->
<moditect.version>1.2.2.Final</moditect.version>
<sonar.organization>openhft</sonar.organization>
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
</properties>
Expand Down Expand Up @@ -292,6 +296,33 @@
</executions>
</plugin>

<plugin>
<groupId>org.moditect</groupId>
<artifactId>moditect-maven-plugin</artifactId>
<version>${moditect.version}</version>
<executions>
<execution>
<id>add-module-info</id>
<phase>package</phase>
<goals>
<goal>add-module-info</goal>
</goals>
<configuration>
<!-- //! Generate a version-9 descriptor during packaging without compiling ordinary classes above Java 8. -->
<!-- //! AutomaticModuleNameIT#java8BuildProducesJava9ModuleDescriptor asserts its versioned path and class major 53. -->
<jvmVersion>9</jvmVersion>
<!-- //! Repeated packaging must replace ModiTect output left by the first lifecycle. -->
<!-- //! Without overwrite the second package fails on existing generated output. -->
<!-- //! RepeatPackageTest#testPackageWithoutClean runs verify/package and an overwrite-disabled control. -->
<overwriteExistingFiles>true</overwriteExistingFiles>
<module>
<moduleInfoFile>${project.basedir}/src/main/java9/module-info.java</moduleInfoFile>
</module>
</configuration>
</execution>
</executions>
</plugin>

<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.2.5</version>
Expand All @@ -309,6 +340,33 @@
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-invoker-plugin</artifactId>
<version>3.9.1</version>
<configuration>
<cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
<localRepositoryPath>${project.build.directory}/local-repo</localRepositoryPath>
<postBuildHookScript>verify</postBuildHookScript>
<streamLogs>false</streamLogs>
<streamLogsOnFailures>true</streamLogsOnFailures>
<goals>
<goal>clean</goal>
<goal>test</goal>
</goals>
</configuration>
<executions>
<execution>
<id>integration-test</id>
<goals>
<goal>install</goal>
<goal>run</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

Expand Down Expand Up @@ -344,13 +402,21 @@
<profile>
<id>jdk9+-profile</id>
<activation>
<jdk>[9,21)</jdk>
<jdk>[9,17)</jdk>
</activation>
<properties>
<maven.compiler.release>${project.target.release}</maven.compiler.release>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<additionalOptions>
<additionalOption>-html5</additionalOption>
</additionalOptions>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
Expand Down
53 changes: 53 additions & 0 deletions src/it/README.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
= Integration Tests

The Maven Invoker fixtures use JUnit 4:

* `simple-usage` targets Java 8 and checks public hash functions across arrays,
buffers and character sequences.
* `module-test` targets Java 9 and checks the explicit descriptor, public API,
runtime paths and encapsulation. Invoker skips it on Java 8.

== Build and repeat packaging

[source,bash]
----
./mvnw -B -ntp verify -l java8-verify.log
./mvnw -B -ntp -DskipTests package -l repeat-package.log
----

The wrapper pins Maven 3.9.11; ModiTect 1.2.2.Final supports Java 8 and requires
Maven 3.9.6 or later. Ordinary classes target Java 8; the multi-release JAR places
its Java 9 descriptor in `META-INF/versions/9/module-info.class`.
The second command retains generated output to exercise `overwriteExistingFiles`.
`AutomaticModuleNameIT` checks the finished JAR, not the repeated lifecycle.
With Java 8 selected, `python3 src/it/repeat-package.py ../repeat-package-proof`
runs this sequence in fresh enabled/disabled-overwrite copies, retaining logs and
requiring the disabled second package to fail specifically on existing output.

`verify` installs the library in `target/local-repo` before running the fixtures.
A fresh checkout cannot start with `invoker:run` alone. Invoker inherits Maven
settings (including mirrors, proxies and credentials), with its own local repository.
Reports remain under `target`; tests use assertions rather than console output.

== Retained Java 8 binary

The `Java 8 artefact compatibility` workflow retains the JAR, SHA-256, source
revision and build-JDK identity from `verify`, then repeats `package` without
cleaning. Separate jobs install that retained binary with `install:install-file`
and run `invoker:run invoker:verify`, without rebuilding it. They compare installed
and retained JAR bytes and retain logs/reports on JDK 8/9/10/11/17/21/25.
The JDK 21 job also resolves JSR-305 with `jdeps` and rejects unresolved annotations.
These source-compiled fixtures do not establish compatibility for old binaries.

== Runtime contract

The explicit `net.openhft.hashing` module exports only its public hashing package,
requires `jdk.unsupported` at runtime and declares optional `requires static jsr305`.
See link:../main/docs/unsafe-and-platform-notes.adoc[Unsafe and platform notes]
for annotation resolution and the required direct-buffer exports for named and
class-path consumers; the modular fixture supplies the named-module export.

The library's `LongHashFunctionTest` and `LongTupleHashFunctionTest` put guard bytes
around direct-buffer payloads and request a range different from the cursor window.
They assert the hash and unchanged cursor, then restore the payload window before
the whole-buffer byte-order check. Substituting position/remaining must fail them.
3 changes: 3 additions & 0 deletions src/it/module-test/invoker.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
invoker.goals=clean test
invoker.buildResult=success
invoker.java.version=9+
45 changes: 45 additions & 0 deletions src/it/module-test/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>net.openhft.it</groupId>
<artifactId>module-test</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>9</maven.compiler.release>
</properties>

<dependencies>
<dependency>
<groupId>@project.groupId@</groupId>
<artifactId>@project.artifactId@</artifactId>
<version>@project.version@</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.4</version>
<configuration>
<argLine>--add-exports java.base/sun.nio.ch=net.openhft.hashing</argLine>
</configuration>
</plugin>
</plugins>
</build>
</project>
9 changes: 9 additions & 0 deletions src/it/module-test/src/test/java/module-info.java
Original file line number Diff line number Diff line change
@@ -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;
}
Loading
Loading