From cc3675fef9b88eb7c854979b74cbc6b5a5180e76 Mon Sep 17 00:00:00 2001 From: Michael Ilyin Date: Fri, 17 Jul 2026 11:56:01 +0200 Subject: [PATCH 1/2] Received preset encodings are value-only end to end MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit zenoh-flat-jni#6 makes the delivered encoding handle CONDITIONAL on schema presence (binding-local encoding_if_schema behind prebindgen#84's field! leaf): a received preset re-sends through the id arm for free, so no per-message native handle — clone + Box + JVM wrapper + gc-Cleaner registration + Cleaner free — is ever materialized for it. Schema- carrying encodings keep the send-ready handle. Adapt the delivery plumbing: Sample.fromParts encH becomes nullable (Query's already was), the reply callback drops its non-null assertion, and EncodingHandleTest's preset round-trip flips to assert the received copy has NO handle — the new contract. CI pin bumped to the flat-jni#6 tip. Co-Authored-By: Claude Fable 5 --- .github/workflows/ci.yml | 2 +- .../commonMain/kotlin/io/zenoh/FlatCallbacks.kt | 2 +- .../commonMain/kotlin/io/zenoh/sample/Sample.kt | 6 ++++-- .../kotlin/io/zenoh/EncodingHandleTest.kt | 16 ++++++++++------ 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c2122f30..ab0e3991 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: uses: actions/checkout@v4 with: repository: ZettaScaleLabs/zenoh-flat-jni - ref: e8023170c0be3d8e5cd2cee17487870b27af6728 + ref: af690927669551791fda895e5af98ef7bc1220d6 path: zenoh-flat-jni - name: Check out zenoh-flat diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/FlatCallbacks.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/FlatCallbacks.kt index 94741393..c8581fbe 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/FlatCallbacks.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/FlatCallbacks.kt @@ -66,7 +66,7 @@ internal fun replyCallbackOf( if (isOk) { Reply.Success( replierId, - Sample.fromParts(keH!!, payloadH!!, encId!!, encSchema, encH!!, kindInt!!, ntp64, express!!, prioInt!!, ccInt!!, attachH, reliabilityInt!!, sourceZid, sourceEid!!, sourceSn!!) + Sample.fromParts(keH!!, payloadH!!, encId!!, encSchema, encH, kindInt!!, ntp64, express!!, prioInt!!, ccInt!!, attachH, reliabilityInt!!, sourceZid, sourceEid!!, sourceSn!!) ) } else { Reply.Error( diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/Sample.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/Sample.kt index 78edc600..e3cc70a4 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/Sample.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/Sample.kt @@ -59,7 +59,9 @@ data class Sample( * callbacks), in record order. The whole graph arrives in ONE JNI * crossing; the [KeyExpr] retains the delivered handle leaf, and the * [Encoding] retains its delivered handle (`encH`) so re-sending it - * crosses a bare `jlong` instead of rebuilding the native value. The + * crosses a bare `jlong` instead of rebuilding the native value — + * delivered ONLY for schema-carrying encodings (a preset re-sends + * through the id arm for free, so it arrives value-only). The * trailing `reliability` / `source*` leaves are part of the generated * decomposition but are not surfaced on the public [Sample] type. */ @@ -69,7 +71,7 @@ data class Sample( payloadH: io.zenoh.jni.bytes.ZBytes, encId: Int, encSchema: String?, - encH: io.zenoh.jni.bytes.Encoding, + encH: io.zenoh.jni.bytes.Encoding?, kindInt: Int, ntp64: Long?, express: Boolean, diff --git a/zenoh-java/src/jvmTest/kotlin/io/zenoh/EncodingHandleTest.kt b/zenoh-java/src/jvmTest/kotlin/io/zenoh/EncodingHandleTest.kt index d7685186..ac835c0e 100644 --- a/zenoh-java/src/jvmTest/kotlin/io/zenoh/EncodingHandleTest.kt +++ b/zenoh-java/src/jvmTest/kotlin/io/zenoh/EncodingHandleTest.kt @@ -33,9 +33,11 @@ import org.junit.Test * the send call itself, no handle ever exists; * - custom (schema-carrying) encodings own a handle from construction — * construction is the one crossing, every send after is a bare jlong; - * - received encodings arrive WITH their handle in the same delivery - * crossing, so re-sending one (the save-and-republish scenario) never - * rebuilds the native value from its schema string. + * - received SCHEMA-CARRYING encodings arrive WITH their handle in the same + * delivery crossing, so re-sending one (the save-and-republish scenario) + * never rebuilds the native value from its schema string; a received + * PRESET arrives value-only — its handle would buy nothing (the id arm is + * free), so the binding never materializes one (`encoding_if_schema`). */ class EncodingHandleTest { @@ -95,7 +97,7 @@ class EncodingHandleTest { } @Test - fun predefinedRoundTripStaysValueOnSendAndHandleOnReceive() { + fun predefinedRoundTripStaysValueOnlyEndToEnd() { val session = Zenoh.open(Config.loadDefault()) val keyExpr = KeyExpr.tryFrom("example/testing/encoding/preset") val received = mutableListOf() @@ -110,8 +112,10 @@ class EncodingHandleTest { assertNull(Encoding.TEXT_PLAIN.handle) assertEquals(1, received.size) assertEquals(Encoding.TEXT_PLAIN, received[0].encoding) - // …while the received copy arrived send-ready. - assertNotNull(received[0].encoding.handle) + // …and the received copy is value-only too: a schema-less encoding + // re-sends through the id arm for free, so no per-message native + // handle (clone + Box + wrapper + Cleaner) is ever materialized. + assertNull(received[0].encoding.handle) subscriber.close() session.close() From 86d0fe9ebf949661505a6304263ae10b748ab7bc Mon Sep 17 00:00:00 2001 From: Michael Ilyin Date: Fri, 17 Jul 2026 15:40:40 +0200 Subject: [PATCH 2/2] CI: bump zenoh-flat-jni pin to the #6 merge commit The previous pin was a branch commit deleted on merge; 1e040c9 is ZettaScaleLabs/zenoh-flat-jni#6 on main (conditional encoding handle, final fun!+sig! syntax). Co-Authored-By: Claude Fable 5 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ab0e3991..d28833d5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: uses: actions/checkout@v4 with: repository: ZettaScaleLabs/zenoh-flat-jni - ref: af690927669551791fda895e5af98ef7bc1220d6 + ref: 1e040c96d0729c387d411a2356f361e9ea420877 path: zenoh-flat-jni - name: Check out zenoh-flat