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
1 change: 1 addition & 0 deletions ZENOH_FLAT_TRANSITION.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ zenoh (Rust)
| --- | --- | --- |
| [#481](https://github.com/eclipse-zenoh/zenoh-java/pull/481) | Use receiver-style zenoh-flat-jni bindings (generated Session/Query/Publisher methods, split key-expr overloads, de-prefixed callback names); +61–83% subscriber throughput | merged |
| [#484](https://github.com/eclipse-zenoh/zenoh-java/pull/484) | `Encoding`/`ZenohId.toString` become pure JVM values (fixes a per-message native leak); the conversion logic lives in the **shared tier** (`EncodingCodec`/`zidString` in zenoh-flat-jni, correspondence-tested against native, reusable by zenoh-kotlin) with only a thin facade here; publisher **default encoding set natively at declare** (plain puts cross no encoding data). Pairs with [zenoh-flat-jni#4](https://github.com/ZettaScaleLabs/zenoh-flat-jni/pull/4), [zenoh-flat#3](https://github.com/ZettaScaleLabs/zenoh-flat/pull/3) (merged), [prebindgen#80](https://github.com/milyin/prebindgen/pull/80) (merged) | in progress |
| [#491](https://github.com/eclipse-zenoh/zenoh-java/pull/491) | `Session.undeclare` detaches the key-expr handle even when the native undeclare fails (the generated wrapper consumes it either way); found on the zenoh-kotlin port ([zenoh-kotlin#668](https://github.com/eclipse-zenoh/zenoh-kotlin/pull/668)) | open |

Companion PRs in the upstream repos are coordinated per constituent PR (e.g.
[ZettaScaleLabs/zenoh-flat-jni#3](https://github.com/ZettaScaleLabs/zenoh-flat-jni/pull/3)
Expand Down
9 changes: 7 additions & 2 deletions zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt
Original file line number Diff line number Diff line change
Expand Up @@ -421,10 +421,15 @@ class Session private constructor(private val config: Config) : AutoCloseable {
if (handle == null || handle.isClosed()) {
throw ZError("Attempting to undeclare a non declared key expression.")
}
run {
try {
zSession.undeclareKeyexpr(handle, throwZError)
} finally {
// The generated wrapper consumes the handle even when the native
// undeclare fails (the Rust side takes it by value) — detach it
// either way, degrading the KeyExpr to its string form instead of
// leaving a dead handle to be selected by later operations.
keyExpr.handle = null
}
keyExpr.handle = null
}

/**
Expand Down
25 changes: 25 additions & 0 deletions zenoh-java/src/jvmTest/kotlin/io/zenoh/KeyExprHandleTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package io.zenoh

import io.zenoh.bytes.ZBytes
import io.zenoh.exceptions.ZError
import io.zenoh.keyexpr.KeyExpr
import io.zenoh.sample.Sample
import org.junit.Assert.assertEquals
Expand Down Expand Up @@ -62,6 +63,30 @@ class KeyExprHandleTest {
session.close()
}

@Test
fun failedUndeclarationStillDetachesTheConsumedHandle() {
// Undeclaring through the WRONG session makes the native undeclare
// fail — and the generated wrapper consumes the handle even then. The
// KeyExpr must degrade to its string form (handle detached), not keep
// selecting a dead handle.
val session1 = Zenoh.open(Config.loadDefault())
val session2 = Zenoh.open(Config.loadDefault())
val declared = session1.declareKeyExpr("example/testing/keyexpr/wrongsession")
var failed = false
try {
session2.undeclare(declared)
} catch (e: ZError) {
failed = true
}
assertTrue(failed)
assertNull(declared.handle)
// String-backed operation keeps working after the failed undeclare.
assertTrue(declared.intersects(KeyExpr.tryFrom("example/testing/**")))
session1.put(declared, ZBytes.from("test"))
session1.close()
session2.close()
}

@Test
fun receivedKeyExprIsStringBackedAndReusable() {
val session = Zenoh.open(Config.loadDefault())
Expand Down
Loading