Skip to content

Commit 9f9ddae

Browse files
authored
Serialization feature (#158)
* Alignment: bytes package * Alignment: encoding update * Alignment: config package * Alignment: replacing all exceptions with ZError * Alignment: ext package * Alignment: jni callbacks * Alignment: config * Alignment: JNIKeyExpr * Alignment: JNIPublisher * Alignment: JNIQuery * Alignment: JNIScout * Alignment: JNISession * Alignment JNIZBytes & JNIZenohId * Alignment: KeyExpr & SetIntersectionLevel * Alignment: pubsub package * Alignment: Publisher & qos package * Alignment: query package - wip * Alignment: adding scouting package * Alignment: removing Value * Alignment: logger * Alignmment: Zenoh.kt - wip * Alignment: publisher - adding encoding and reliability to builder * Alignment: subscriber * Alignment: sample * Alignment: query & reply - wip * Alignment: Put & Session * Alignment: fix 'IntoSelector' * Alignment: updating zenoh-jni * Alignment: wip - converting tests to java tests. Added config tests. * Alignment: wip - converting tests to java tests. Added delete test. * Alignment: wip - converting tests to java tests. Added encoding tests. * Alignment: wip - converting tests to java tests. Added get tests. * Alignment: wip - converting tests to java tests. Added key expr tests. * Alignment: wip - converting tests to java tests. Added parameters tests. * Alignment: wip - converting tests to java tests. Added publisher tests. * Alignment: wip - converting tests to java tests. Added Queryable tests. * Alignment: wip - converting tests to java tests. Added Put tests. * Alignment: wip - Added Scouting tests + adding scouting builder. * Alignment: wrapping up scouting, closing queue upon scout close. * Alignment: adding selector tests * Alignment: fix SessionInfo + adding tests * Alignment: fix Scouting queue test * amend! Alignment: fix SessionInfo + adding tests Alignment: fix SessionInfo + adding tests * Alignment: session tests * Alignment: user attachment tests * Alignment: subscriber tests * Alignment: removing the zenoh-ext package (to be added later in another PR) * Alignment: Publisher config params * Alignment: Subscriber config params * Alignment: Queryable config params * Alignment: Subscriber config params refactor * Alignment: Queryable declaration and Query.reply config params. * Alignment: Get config params * Alignment: Subscriber config params refactor * Fix config test * Alignment - Scouting config params * Alignment: adding Liveliness * Gitignore update * Alignment: fix logging * Alignment: publisher put and delete config param * Alignment: examples - adding picocli for CLI args * Alignment: examples - adding missing examples * Alignment: examples - adding ping and pong examples * Alignment: examples refactor + refactor queryable config logic * Alignment: fix publisher put encoding fallback * Alignment: removing SubscriberConfig.kt * Alignment: renaming PublisherConfig to PublisherOptions * Alignment: renaming DeleteConfig to DeleteOptions and removing 'builder' functions in it. * Alignment: renaming GetConfig to GetOptions and removing 'builder' functions in it. * Alignment: renaming PutConfig to PutOptions and removing 'builder' functions in it. * Alignment: renaming ReplyConfig to ReplyOptions and removing 'builder' functions in it. * Alignment: renaming ReplyDelConfig to ReplyDelOptions and removing 'builder' functions in it. * Alignment: renaming ReplyErrConfig to ReplyErrOptions and removing 'builder' functions in it. * Alignment: renaming QueryableConfig to QueryableOptions and removing 'builder' functions in it. * Alignment: renaming ScoutConfig to ScoutOptions and removing 'builder' functions in it. * Alignment: renaming Liveliness.SubscriberConfig + renaming variables * Alignment: queryable options refactor * Alignment: removing Resolvable * Alignment: splitting Queryable, Subscriber and Get into Handler and Callback subclasses + tidying up documentation. * Alignment: removing JNIZBytes * Alignment: removing unused kotlin json dependency * feat(serialization): implementation of the serialization * feat(serialization): implementation of the deserialization * feat(serialization): adding ZBytes examples. * feat(serialization): cargo clippy * feat(serialization): ZSerializer and ZDeserializer classes * serialization: zenoh-ext cfg feature for zbytes on zenoh-jni
1 parent 3a23afa commit 9f9ddae

File tree

10 files changed

+1102
-1
lines changed

10 files changed

+1102
-1
lines changed

examples/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,12 @@ dependencies {
2626
implementation("commons-net:commons-net:3.9.0")
2727
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
2828
implementation("info.picocli:picocli:4.7.4")
29+
implementation("com.google.guava:guava:33.3.1-jre")
2930
}
3031

3132
tasks {
3233
val examples = listOf(
34+
"ZBytesExamples",
3335
"ZDelete",
3436
"ZGet",
3537
"ZGetLiveliness",
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
//
2+
// Copyright (c) 2023 ZettaScale Technology
3+
//
4+
// This program and the accompanying materials are made available under the
5+
// terms of the Eclipse Public License 2.0 which is available at
6+
// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7+
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
8+
//
9+
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10+
//
11+
// Contributors:
12+
// ZettaScale Zenoh Team, <[email protected]>
13+
//
14+
15+
package io.zenoh;
16+
17+
import io.zenoh.bytes.ZBytes;
18+
import io.zenoh.ext.ZDeserializer;
19+
import io.zenoh.ext.ZSerializer;
20+
21+
import java.util.Arrays;
22+
import java.util.List;
23+
import java.util.Map;
24+
25+
public class ZBytesExamples {
26+
27+
public static void main(String[] args) {
28+
29+
/*
30+
* ZBytes
31+
*
32+
* A ZBytes instance can be created from a String and from a Byte Array with the `ZBytes.from(string: String)`
33+
* and `ZBytes.from(bytes: byte[])` functions.
34+
*
35+
* A ZBytes can be converted back into a [String] with the functions [ZBytes.toString] and [ZBytes.tryToString].
36+
* Similarly, with [ZBytes.toBytes] you can get the inner byte representation.
37+
*/
38+
39+
var exampleString = "example string";
40+
var zbytesA = ZBytes.from(exampleString);
41+
var outputA = zbytesA.toString();
42+
assert exampleString.equals(outputA);
43+
44+
var exampleBytes = new byte[]{1, 2, 3, 4, 5};
45+
var zbytesB = ZBytes.from(exampleBytes);
46+
var outputB = zbytesB.toBytes();
47+
assert Arrays.equals(exampleBytes, outputB);
48+
49+
/*
50+
* Serialization and deserialization.
51+
*
52+
* Additionally, the Zenoh API provides a series of serialization and deserialization utilities for processing
53+
* the received payloads.
54+
*
55+
* Serialization and deserialization supports the following types:
56+
* - Boolean
57+
* - Byte
58+
* - Byte Array
59+
* - Short
60+
* - Int
61+
* - Long
62+
* - Float
63+
* - Double
64+
* - String
65+
* - List
66+
* - Map
67+
*
68+
* For List and Map, the inner types can be a combination of the above types, including themselves.
69+
*
70+
* These serialization and deserialization utilities can be used across the Zenoh ecosystem with Zenoh
71+
* versions based on other supported languages such as Rust, Python, C and C++.
72+
* This works when the types are equivalent (a `Byte` corresponds to an `i8` in Rust, a `Short` to an `i16`, etc).
73+
*/
74+
75+
// Boolean example
76+
Boolean input1 = true;
77+
ZSerializer<Boolean> serializer1 = new ZSerializer<>() {};
78+
ZBytes zbytes1 = serializer1.serialize(input1);
79+
80+
ZDeserializer<Boolean> deserializer1 = new ZDeserializer<>() {};
81+
Boolean output1 = deserializer1.deserialize(zbytes1);
82+
assert input1.equals(output1);
83+
84+
// Byte example
85+
Byte input2 = 126;
86+
ZSerializer<Byte> serializer2 = new ZSerializer<>() {};
87+
ZBytes zbytes2 = serializer2.serialize(input2);
88+
89+
ZDeserializer<Byte> deserializer2 = new ZDeserializer<>() {};
90+
Byte output2 = deserializer2.deserialize(zbytes2);
91+
assert input2.equals(output2);
92+
93+
// Short example
94+
Short input3 = 256;
95+
ZSerializer<Short> serializer3 = new ZSerializer<>() {};
96+
ZBytes zbytes3 = serializer3.serialize(input3);
97+
98+
ZDeserializer<Short> deserializer3 = new ZDeserializer<>() {};
99+
Short output3 = deserializer3.deserialize(zbytes3);
100+
assert input3.equals(output3);
101+
102+
// Int example
103+
Integer input4 = 123456;
104+
ZSerializer<Integer> serializer4 = new ZSerializer<>() {};
105+
ZBytes zbytes4 = serializer4.serialize(input4);
106+
107+
ZDeserializer<Integer> deserializer4 = new ZDeserializer<>() {};
108+
Integer output4 = deserializer4.deserialize(zbytes4);
109+
assert input4.equals(output4);
110+
111+
// Long example
112+
Long input5 = 123456789L;
113+
ZSerializer<Long> serializer5 = new ZSerializer<>() {};
114+
ZBytes zbytes5 = serializer5.serialize(input5);
115+
116+
ZDeserializer<Long> deserializer5 = new ZDeserializer<>() {};
117+
Long output5 = deserializer5.deserialize(zbytes5);
118+
assert input5.equals(output5);
119+
120+
// Float example
121+
Float input6 = 123.45f;
122+
ZSerializer<Float> serializer6 = new ZSerializer<>() {};
123+
ZBytes zbytes6 = serializer6.serialize(input6);
124+
125+
ZDeserializer<Float> deserializer6 = new ZDeserializer<>() {};
126+
Float output6 = deserializer6.deserialize(zbytes6);
127+
assert input6.equals(output6);
128+
129+
// Double example
130+
Double input7 = 12345.6789;
131+
ZSerializer<Double> serializer7 = new ZSerializer<>() {};
132+
ZBytes zbytes7 = serializer7.serialize(input7);
133+
134+
ZDeserializer<Double> deserializer7 = new ZDeserializer<>() {};
135+
Double output7 = deserializer7.deserialize(zbytes7);
136+
assert input7.equals(output7);
137+
138+
// List example
139+
List<Integer> input12 = List.of(1, 2, 3, 4, 5);
140+
ZSerializer<List<Integer>> serializer12 = new ZSerializer<>() {};
141+
ZBytes zbytes12 = serializer12.serialize(input12);
142+
143+
ZDeserializer<List<Integer>> deserializer12 = new ZDeserializer<>() {};
144+
List<Integer> output12 = deserializer12.deserialize(zbytes12);
145+
assert input12.equals(output12);
146+
147+
// String example
148+
String input13 = "Hello, World!";
149+
ZSerializer<String> serializer13 = new ZSerializer<>() {};
150+
ZBytes zbytes13 = serializer13.serialize(input13);
151+
152+
ZDeserializer<String> deserializer13 = new ZDeserializer<>() {};
153+
String output13 = deserializer13.deserialize(zbytes13);
154+
assert input13.equals(output13);
155+
156+
// ByteArray example
157+
byte[] input14 = new byte[]{1, 2, 3, 4, 5};
158+
ZSerializer<byte[]> serializer14 = new ZSerializer<>() {};
159+
ZBytes zbytes14 = serializer14.serialize(input14);
160+
161+
ZDeserializer<byte[]> deserializer14 = new ZDeserializer<>() {};
162+
byte[] output14 = deserializer14.deserialize(zbytes14);
163+
assert Arrays.equals(input14, output14);
164+
165+
// Map example
166+
Map<String, Integer> input15 = Map.of("one", 1, "two", 2, "three", 3);
167+
ZSerializer<Map<String, Integer>> serializer15 = new ZSerializer<>() {};
168+
ZBytes zbytes15 = serializer15.serialize(input15);
169+
170+
ZDeserializer<Map<String, Integer>> deserializer15 = new ZDeserializer<>() {};
171+
Map<String, Integer> output15 = deserializer15.deserialize(zbytes15);
172+
assert input15.equals(output15);
173+
174+
// Nested List example
175+
List<List<Integer>> input18 = List.of(List.of(1, 2, 3));
176+
ZSerializer<List<List<Integer>>> serializer18 = new ZSerializer<>() {};
177+
ZBytes zbytes18 = serializer18.serialize(input18);
178+
179+
ZDeserializer<List<List<Integer>>> deserializer18 = new ZDeserializer<>() {};
180+
List<List<Integer>> output18 = deserializer18.deserialize(zbytes18);
181+
assert input18.equals(output18);
182+
183+
// Combined types example
184+
List<Map<String, Integer>> input19 = List.of(Map.of("a", 1, "b", 2));
185+
ZSerializer<List<Map<String, Integer>>> serializer19 = new ZSerializer<>() {};
186+
ZBytes zbytes19 = serializer19.serialize(input19);
187+
188+
ZDeserializer<List<Map<String, Integer>>> deserializer19 = new ZDeserializer<>() {};
189+
List<Map<String, Integer>> output19 = deserializer19.deserialize(zbytes19);
190+
assert input19.equals(output19);
191+
}
192+
}

zenoh-java/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ kotlin {
6363
val commonMain by getting {
6464
dependencies {
6565
implementation("commons-net:commons-net:3.9.0")
66+
implementation("com.google.guava:guava:33.3.1-jre")
6667
}
6768
}
6869
val commonTest by getting {
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
//
2+
// Copyright (c) 2023 ZettaScale Technology
3+
//
4+
// This program and the accompanying materials are made available under the
5+
// terms of the Eclipse Public License 2.0 which is available at
6+
// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7+
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
8+
//
9+
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10+
//
11+
// Contributors:
12+
// ZettaScale Zenoh Team, <[email protected]>
13+
//
14+
15+
package io.zenoh.ext
16+
17+
import com.google.common.reflect.TypeToken
18+
import io.zenoh.bytes.ZBytes
19+
import io.zenoh.jni.JNIZBytes
20+
21+
/**
22+
* Zenoh deserializer.
23+
*
24+
* This class is a utility for deserializing [ZBytes] into elements of type [T].
25+
*
26+
* This class supports the following types:
27+
* - [Boolean]
28+
* - [Byte]
29+
* - [Short]
30+
* - [Int]
31+
* - [Long]
32+
* - [Float]
33+
* - [Double]
34+
* - [List]
35+
* - [String]
36+
* - [ByteArray]
37+
* - [Map]
38+
*
39+
* For List and Map, the inner types can be a combination of the above types, including themselves.
40+
*
41+
* Due to Java's type erasure, an actual implementation of this abstract class needs to be created (see the examples below).
42+
*
43+
* This deserialization utility can be used across the Zenoh ecosystem with Zenoh
44+
* versions based on other supported languages such as Rust, Python, C and C++.
45+
* This works when the types are equivalent (a `Byte` corresponds to an `i8` in Rust, a `Short` to an `i16`, etc).
46+
*
47+
* # Examples
48+
*
49+
* Example for a basic type, in this case an integer:
50+
* ```java
51+
* Integer input = 123456;
52+
* ZSerializer<Integer> serializer = new ZSerializer<>() {};
53+
* ZBytes zbytes = serializer.serialize(input);
54+
*
55+
* ZDeserializer<Integer> deserializer = new ZDeserializer<>() {};
56+
* Integer output = deserializer.deserialize(zbytes);
57+
* assert input.equals(output);
58+
* ```
59+
*
60+
* Examples for parameterized types:
61+
* - List
62+
* ```java
63+
* List<Integer> input = List.of(1, 2, 3, 4, 5);
64+
* ZSerializer<List<Integer>> serializer = new ZSerializer<>() {};
65+
* ZBytes zbytes = serializer.serialize(input12);
66+
*
67+
* ZDeserializer<List<Integer>> deserializer = new ZDeserializer<>() {};
68+
* List<Integer> output = deserializer.deserialize(zbytes);
69+
* assert input.equals(output);
70+
* ```
71+
*
72+
* - Map
73+
* ```java
74+
* Map<String, Integer> input = Map.of("one", 1, "two", 2, "three", 3);
75+
* ZSerializer<Map<String, Integer>> serializer = new ZSerializer<>() {};
76+
* ZBytes zbytes = serializer.serialize(input);
77+
*
78+
* ZDeserializer<Map<String, Integer>> deserializer = new ZDeserializer<>() {};
79+
* Map<String, Integer> output = deserializer.deserialize(zbytes);
80+
* assert input.equals(output);
81+
* ```
82+
*
83+
* As mentioned, for List and Map, the inner types can be a combination of the above types, including themselves.
84+
* Here's an example with a List of Maps:
85+
* ```java
86+
* List<Map<String, Integer>> input = List.of(Map.of("a", 1, "b", 2));
87+
* ZSerializer<List<Map<String, Integer>>> serializer = new ZSerializer<>() {};
88+
* ZBytes zbytes = serializer.serialize(input);
89+
*
90+
* ZDeserializer<List<Map<String, Integer>>> deserializer = new ZDeserializer<>() {};
91+
* List<Map<String, Integer>> output = deserializer.deserialize(zbytes);
92+
* assert input.equals(output);
93+
* ```
94+
*
95+
* For more examples, see the ZBytesExamples in the examples.
96+
*
97+
* @param T The deserialization type.
98+
* @see ZBytes
99+
* @see ZSerializer
100+
*/
101+
abstract class ZDeserializer<T>: TypeToken<T>() {
102+
103+
/**
104+
* Deserialize the [zbytes] into an element of type [T].
105+
*/
106+
fun deserialize(zbytes: ZBytes): T {
107+
@Suppress("UNCHECKED_CAST")
108+
return JNIZBytes.deserializeViaJNI(zbytes, this.type) as T
109+
}
110+
}

0 commit comments

Comments
 (0)