-
Notifications
You must be signed in to change notification settings - Fork 14
Expand file tree
/
Copy pathSerde.java
More file actions
171 lines (146 loc) · 4.78 KB
/
Serde.java
File metadata and controls
171 lines (146 loc) · 4.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// Copyright (c) 2023 - Restate Software, Inc., Restate GmbH
//
// This file is part of the Restate Java SDK,
// which is released under the MIT license.
//
// You can find a copy of the license in file LICENSE in the root
// directory of this repository or package, or at
// https://github.com/restatedev/sdk-java/blob/main/LICENSE
package dev.restate.serde;
import dev.restate.common.Slice;
import dev.restate.common.function.ThrowingFunction;
import java.util.Objects;
import org.jspecify.annotations.*;
/**
* Interface defining serialization and deserialization of concrete types.
*
* <p>For more info on the serialization stack, and how to customize it, see {@link SerdeFactory}.
*
* <p>Implementations <b>MUST</b> be thread safe.
*
* <p>You can create a custom one using {@link #using(String, ThrowingFunction, ThrowingFunction)}.
*
* @see SerdeFactory
*/
public interface Serde<T extends @Nullable Object> extends TypeTag<T> {
Slice serialize(T value);
T deserialize(@NonNull Slice value);
// --- Metadata about the serialized/deserialized content
/**
* Content-type to use in request/responses.
*
* <p>If null, the SDK assumes the produced output is empty. This might change in the future.
*/
default @Nullable String contentType() {
return "application/octet-stream";
}
/**
* @return a Draft 2020-12 Json Schema. It should be self-contained, and MUST not contain refs to
* files or HTTP. The schema is currently used by Restate to introspect the service contract
* and generate an OpenAPI definition.
*/
default @Nullable Schema jsonSchema() {
return null;
}
sealed interface Schema {}
/** Schema to be serialized using internal Jackson mapper. */
record JsonSchema(Object schema) implements Schema {}
/** Schema already serialized to String. The string should be a valid json schema. */
record StringifiedJsonSchema(String schema) implements Schema {}
/**
* Like {@link #using(String, ThrowingFunction, ThrowingFunction)}, using content-type {@code
* application/octet-stream}.
*/
static <T extends @NonNull Object> Serde<@NonNull T> using(
ThrowingFunction<T, byte[]> serializer, ThrowingFunction<byte[], T> deserializer) {
return new Serde<>() {
@Override
public Slice serialize(T value) {
return Slice.wrap(serializer.asFunction().apply(Objects.requireNonNull(value)));
}
@Override
public T deserialize(@NonNull Slice value) {
return deserializer.asFunction().apply(value.toByteArray());
}
};
}
/**
* Create a {@link Serde} from {@code serializer}/{@code deserializer} lambdas, tagging with
* {@code contentType}. Before invoking the serializer, we check that {@code value} is non-null.
*/
static <T extends @NonNull Object> Serde<@NonNull T> using(
String contentType,
ThrowingFunction<T, byte[]> serializer,
ThrowingFunction<byte[], T> deserializer) {
return new Serde<>() {
@Override
public Slice serialize(T value) {
return Slice.wrap(serializer.asFunction().apply(Objects.requireNonNull(value)));
}
@Override
public T deserialize(@NonNull Slice value) {
return deserializer.asFunction().apply(value.toByteArray());
}
@Override
public String contentType() {
return contentType;
}
};
}
static <T> Serde<T> withContentType(String contentType, Serde<T> inner) {
return new Serde<>() {
@Override
public Slice serialize(T value) {
return inner.serialize(value);
}
@Override
public T deserialize(@NonNull Slice value) {
return inner.deserialize(value);
}
@Override
public String contentType() {
return contentType;
}
};
}
/** Noop {@link Serde} for void. */
Serde<@Nullable Void> VOID =
new Serde<>() {
@Override
public Slice serialize(Void value) {
return Slice.EMPTY;
}
@Override
public Void deserialize(@NonNull Slice value) {
return null;
}
@Override
public String contentType() {
return null;
}
};
/** Pass through {@link Serde} for byte array. */
Serde<byte[]> RAW =
new Serde<>() {
@Override
public Slice serialize(byte[] value) {
return Slice.wrap(Objects.requireNonNull(value));
}
@Override
public byte[] deserialize(@NonNull Slice value) {
return value.toByteArray();
}
};
/** Passthrough serializer/deserializer */
Serde<Slice> SLICE =
new Serde<>() {
@Override
public Slice serialize(Slice value) {
return value;
}
@Override
public Slice deserialize(@NonNull Slice value) {
return value;
}
};
}