diff --git a/servicetalk-examples/docs/modules/ROOT/pages/_partials/nav-versioned.adoc b/servicetalk-examples/docs/modules/ROOT/pages/_partials/nav-versioned.adoc
index 6881a6db46..22ff8df5a5 100644
--- a/servicetalk-examples/docs/modules/ROOT/pages/_partials/nav-versioned.adoc
+++ b/servicetalk-examples/docs/modules/ROOT/pages/_partials/nav-versioned.adoc
@@ -5,6 +5,7 @@
** xref:{page-version}@servicetalk-examples::http/index.adoc#Debugging[Debugging]
** xref:{page-version}@servicetalk-examples::http/index.adoc#Timeout[Timeout]
** xref:{page-version}@servicetalk-examples::http/index.adoc#SerializationJson[Serialization: JSON]
+** xref:{page-version}@servicetalk-examples::http/index.adoc#SerializationProtobuf[Serialization: Protobuf]
** xref:{page-version}@servicetalk-examples::http/index.adoc#JAXRS[JAX-RS]
** xref:{page-version}@servicetalk-examples::http/index.adoc#MetaData[MetaData]
** xref:{page-version}@servicetalk-examples::http/index.adoc#HTTP2[HTTP/2]
diff --git a/servicetalk-examples/docs/modules/ROOT/pages/http/index.adoc b/servicetalk-examples/docs/modules/ROOT/pages/http/index.adoc
index f90705d6e3..023ef14700 100644
--- a/servicetalk-examples/docs/modules/ROOT/pages/http/index.adoc
+++ b/servicetalk-examples/docs/modules/ROOT/pages/http/index.adoc
@@ -118,6 +118,22 @@ with `Content-Type: application/json` and link:{source-root}/servicetalk-example
All serializers and deserializers defined in
link:{source-root}/servicetalk-examples/http/serialization/json/src/main/java/io/servicetalk/examples/http/serialization/json/SerializerUtils.java[SerializerUtils].
+[#SerializationProtobuf]
+== Serialization: Protobuf
+
+An example similar to "Hello World" examples, which demonstrates
+link:{source-root}/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/async[asynchronous-aggregated],
+link:{source-root}/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/async/streaming[asynchronous-streaming],
+link:{source-root}/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/blocking[blocking-aggregated], and
+link:{source-root}/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/blocking/streaming[blocking-streaming]
+client and server with Protobuf serialization of simple proto objects.
+
+Client sends a `POST` request with a Protobuf payload `RequestMessage` and expects a response with
+`Content-Type: application/protobuf` and `ResponseMessage` as a payload
+(link:{source-root}/servicetalk-examples/http/serialization/protobuf/src/main/proto/message.proto[message.proto]).
+All serializers and deserializers defined in
+link:{source-root}/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/SerializerUtils.java[SerializerUtils].
+
[#JAXRS]
== JAX-RS
diff --git a/servicetalk-examples/http/serialization/protobuf/build.gradle b/servicetalk-examples/http/serialization/protobuf/build.gradle
new file mode 100644
index 0000000000..9a186f88e6
--- /dev/null
+++ b/servicetalk-examples/http/serialization/protobuf/build.gradle
@@ -0,0 +1,44 @@
+/*
+ * Copyright © 2022 Apple Inc. and the ServiceTalk project authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+buildscript {
+ dependencies {
+ classpath "com.google.protobuf:protobuf-gradle-plugin:$protobufGradlePluginVersion"
+ }
+}
+
+apply plugin: "java"
+apply from: "../../../gradle/idea.gradle"
+apply plugin: "com.google.protobuf"
+
+dependencies {
+ implementation project(":servicetalk-annotations")
+ implementation project(":servicetalk-data-protobuf")
+ implementation project(":servicetalk-http-netty")
+ implementation "com.google.protobuf:protobuf-java:$protobufVersion"
+
+ runtimeOnly "org.apache.logging.log4j:log4j-slf4j-impl:$log4jVersion"
+}
+
+protobuf {
+ protoc {
+ artifact = "com.google.protobuf:protoc:$protobufVersion"
+ }
+}
+
+clean {
+ delete protobuf.generatedFilesBaseDir
+}
diff --git a/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/SerializerUtils.java b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/SerializerUtils.java
new file mode 100644
index 0000000000..c92cea662b
--- /dev/null
+++ b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/SerializerUtils.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright © 2022 Apple Inc. and the ServiceTalk project authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.servicetalk.examples.http.serialization.protobuf;
+
+import io.servicetalk.data.protobuf.ProtobufSerializerFactory;
+import io.servicetalk.examples.http.serialization.protobuf.ExampleProtos.RequestMessage;
+import io.servicetalk.examples.http.serialization.protobuf.ExampleProtos.ResponseMessage;
+import io.servicetalk.http.api.HttpHeaders;
+import io.servicetalk.http.api.HttpSerializerDeserializer;
+import io.servicetalk.http.api.HttpSerializers;
+import io.servicetalk.http.api.HttpStreamingSerializerDeserializer;
+
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+import static io.servicetalk.buffer.api.CharSequences.newAsciiString;
+import static io.servicetalk.data.protobuf.ProtobufSerializerFactory.PROTOBUF;
+import static io.servicetalk.http.api.HeaderUtils.hasContentType;
+import static io.servicetalk.http.api.HttpHeaderNames.CONTENT_TYPE;
+import static io.servicetalk.http.api.HttpSerializers.serializer;
+import static io.servicetalk.http.api.HttpSerializers.streamingSerializer;
+
+/**
+ * Utilities to cache serializer instances for request/response protos.
+ *
+ * {@link ProtobufSerializerFactory} produces protocol-agnostic serializer/deserializer. We use {@link HttpSerializers}
+ * utilities to concert it to HTTP-aware variants.
+ */
+public final class SerializerUtils {
+
+ private static final CharSequence APPLICATION_PROTOBUF = newAsciiString("application/protobuf");
+ private static final Consumer CONTENT_TYPE_SETTER =
+ headers -> headers.set(CONTENT_TYPE, APPLICATION_PROTOBUF);
+ private static final Predicate CONTENT_TYPE_VALIDATOR =
+ headers -> hasContentType(headers, APPLICATION_PROTOBUF, null);
+
+ public static final HttpSerializerDeserializer REQ_SERIALIZER =
+ serializer(PROTOBUF.serializerDeserializer(RequestMessage.parser()),
+ CONTENT_TYPE_SETTER, CONTENT_TYPE_VALIDATOR);
+
+ public static final HttpStreamingSerializerDeserializer REQ_STREAMING_SERIALIZER =
+ streamingSerializer(PROTOBUF.streamingSerializerDeserializer(RequestMessage.parser()),
+ CONTENT_TYPE_SETTER, CONTENT_TYPE_VALIDATOR);
+
+ public static final HttpSerializerDeserializer RESP_SERIALIZER =
+ serializer(PROTOBUF.serializerDeserializer(ResponseMessage.parser()),
+ CONTENT_TYPE_SETTER, CONTENT_TYPE_VALIDATOR);
+
+ public static final HttpStreamingSerializerDeserializer RESP_STREAMING_SERIALIZER =
+ streamingSerializer(PROTOBUF.streamingSerializerDeserializer(ResponseMessage.parser()),
+ CONTENT_TYPE_SETTER, CONTENT_TYPE_VALIDATOR);
+
+ private SerializerUtils() {
+ // No instances.
+ }
+}
diff --git a/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/async/ProtobufClient.java b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/async/ProtobufClient.java
new file mode 100644
index 0000000000..200a4060e9
--- /dev/null
+++ b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/async/ProtobufClient.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright © 2022 Apple Inc. and the ServiceTalk project authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.servicetalk.examples.http.serialization.protobuf.async;
+
+import io.servicetalk.examples.http.serialization.protobuf.ExampleProtos.RequestMessage;
+import io.servicetalk.http.api.HttpClient;
+import io.servicetalk.http.netty.HttpClients;
+
+import static io.servicetalk.examples.http.serialization.protobuf.SerializerUtils.REQ_SERIALIZER;
+import static io.servicetalk.examples.http.serialization.protobuf.SerializerUtils.RESP_SERIALIZER;
+
+public final class ProtobufClient {
+ public static void main(String[] args) throws Exception {
+ try (HttpClient client = HttpClients.forSingleAddress("localhost", 8080).build()) {
+ client.request(client.post("/protobuf")
+ .payloadBody(RequestMessage.newBuilder().setMessage("value").build(), REQ_SERIALIZER))
+ .whenOnSuccess(resp -> {
+ System.out.println(resp.toString((name, value) -> value));
+ System.out.println(resp.payloadBody(RESP_SERIALIZER));
+ })
+ // This example is demonstrating asynchronous execution, but needs to prevent the main thread from exiting
+ // before the response has been processed. This isn't typical usage for an asynchronous API but is useful
+ // for demonstration purposes.
+ .toFuture().get();
+ }
+ }
+}
diff --git a/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/async/ProtobufServer.java b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/async/ProtobufServer.java
new file mode 100644
index 0000000000..685ca545c6
--- /dev/null
+++ b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/async/ProtobufServer.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright © 2022 Apple Inc. and the ServiceTalk project authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.servicetalk.examples.http.serialization.protobuf.async;
+
+import io.servicetalk.examples.http.serialization.protobuf.ExampleProtos.RequestMessage;
+import io.servicetalk.examples.http.serialization.protobuf.ExampleProtos.ResponseMessage;
+import io.servicetalk.http.netty.HttpServers;
+
+import static io.servicetalk.concurrent.api.Single.succeeded;
+import static io.servicetalk.examples.http.serialization.protobuf.SerializerUtils.REQ_SERIALIZER;
+import static io.servicetalk.examples.http.serialization.protobuf.SerializerUtils.RESP_SERIALIZER;
+import static io.servicetalk.http.api.HttpHeaderNames.ALLOW;
+import static io.servicetalk.http.api.HttpRequestMethod.POST;
+
+public final class ProtobufServer {
+ public static void main(String[] args) throws Exception {
+ HttpServers.forPort(8080)
+ .listenAndAwait((ctx, request, responseFactory) -> {
+ if (!"/protobuf".equals(request.requestTarget())) {
+ return succeeded(responseFactory.notFound());
+ }
+ if (!POST.equals(request.method())) {
+ return succeeded(responseFactory.methodNotAllowed().addHeader(ALLOW, POST.name()));
+ }
+ RequestMessage req = request.payloadBody(REQ_SERIALIZER);
+ ResponseMessage resp = ResponseMessage.newBuilder().setLength(req.getMessage().length()).build();
+ return succeeded(responseFactory.created()
+ .payloadBody(resp, RESP_SERIALIZER));
+ })
+ .awaitShutdown();
+ }
+}
diff --git a/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/async/ProtobufUrlClient.java b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/async/ProtobufUrlClient.java
new file mode 100644
index 0000000000..da1208d2bf
--- /dev/null
+++ b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/async/ProtobufUrlClient.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright © 2022 Apple Inc. and the ServiceTalk project authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.servicetalk.examples.http.serialization.protobuf.async;
+
+import io.servicetalk.examples.http.serialization.protobuf.ExampleProtos;
+import io.servicetalk.http.api.HttpClient;
+import io.servicetalk.http.netty.HttpClients;
+
+import static io.servicetalk.examples.http.serialization.protobuf.SerializerUtils.REQ_SERIALIZER;
+import static io.servicetalk.examples.http.serialization.protobuf.SerializerUtils.RESP_SERIALIZER;
+
+public final class ProtobufUrlClient {
+ public static void main(String[] args) throws Exception {
+ try (HttpClient client = HttpClients.forMultiAddressUrl().build()) {
+ client.request(client.post("http://localhost:8080/protobuf")
+ .payloadBody(ExampleProtos.RequestMessage.newBuilder().setMessage("hello").build(), REQ_SERIALIZER))
+ .whenOnSuccess(resp -> {
+ System.out.println(resp.toString((name, value) -> value));
+ System.out.println(resp.payloadBody(RESP_SERIALIZER));
+ })
+ // This example is demonstrating asynchronous execution, but needs to prevent the main thread from exiting
+ // before the response has been processed. This isn't typical usage for an asynchronous API but is useful
+ // for demonstration purposes.
+ .toFuture().get();
+ }
+ }
+}
diff --git a/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/async/package-info.java b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/async/package-info.java
new file mode 100644
index 0000000000..b4e245f6e0
--- /dev/null
+++ b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/async/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright © 2022 Apple Inc. and the ServiceTalk project authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+@ElementsAreNonnullByDefault
+package io.servicetalk.examples.http.serialization.protobuf.async;
+
+import io.servicetalk.annotations.ElementsAreNonnullByDefault;
diff --git a/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/async/streaming/ProtobufStreamingClient.java b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/async/streaming/ProtobufStreamingClient.java
new file mode 100644
index 0000000000..4a4b8e1c3c
--- /dev/null
+++ b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/async/streaming/ProtobufStreamingClient.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright © 2022 Apple Inc. and the ServiceTalk project authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.servicetalk.examples.http.serialization.protobuf.async.streaming;
+
+import io.servicetalk.examples.http.serialization.protobuf.ExampleProtos.RequestMessage;
+import io.servicetalk.http.api.StreamingHttpClient;
+import io.servicetalk.http.netty.HttpClients;
+
+import static io.servicetalk.concurrent.api.Publisher.from;
+import static io.servicetalk.examples.http.serialization.protobuf.SerializerUtils.REQ_STREAMING_SERIALIZER;
+import static io.servicetalk.examples.http.serialization.protobuf.SerializerUtils.RESP_STREAMING_SERIALIZER;
+
+public final class ProtobufStreamingClient {
+ public static void main(String[] args) throws Exception {
+ try (StreamingHttpClient client = HttpClients.forSingleAddress("localhost", 8080).buildStreaming()) {
+ client.request(client.post("/protobuf")
+ .payloadBody(from("value1", "value22", "value333")
+ .map(message -> RequestMessage.newBuilder().setMessage(message).build()),
+ REQ_STREAMING_SERIALIZER))
+ .beforeOnSuccess(response -> System.out.println(response.toString((name, value) -> value)))
+ .flatMapPublisher(resp -> resp.payloadBody(RESP_STREAMING_SERIALIZER))
+ .whenOnNext(System.out::println)
+ // This example is demonstrating asynchronous execution, but needs to prevent the main thread from exiting
+ // before the response has been processed. This isn't typical usage for an asynchronous API but is useful
+ // for demonstration purposes.
+ .toFuture().get();
+ }
+ }
+}
diff --git a/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/async/streaming/ProtobufStreamingServer.java b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/async/streaming/ProtobufStreamingServer.java
new file mode 100644
index 0000000000..d961c2deaf
--- /dev/null
+++ b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/async/streaming/ProtobufStreamingServer.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright © 2022 Apple Inc. and the ServiceTalk project authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.servicetalk.examples.http.serialization.protobuf.async.streaming;
+
+import io.servicetalk.examples.http.serialization.protobuf.ExampleProtos.ResponseMessage;
+import io.servicetalk.http.netty.HttpServers;
+
+import static io.servicetalk.concurrent.api.Single.succeeded;
+import static io.servicetalk.examples.http.serialization.protobuf.SerializerUtils.REQ_STREAMING_SERIALIZER;
+import static io.servicetalk.examples.http.serialization.protobuf.SerializerUtils.RESP_STREAMING_SERIALIZER;
+import static io.servicetalk.http.api.HttpHeaderNames.ALLOW;
+import static io.servicetalk.http.api.HttpRequestMethod.POST;
+
+public final class ProtobufStreamingServer {
+ public static void main(String[] args) throws Exception {
+ HttpServers.forPort(8080)
+ .listenStreamingAndAwait((ctx, request, responseFactory) -> {
+ if (!"/protobuf".equals(request.requestTarget())) {
+ return succeeded(responseFactory.notFound());
+ }
+ if (!POST.equals(request.method())) {
+ return succeeded(responseFactory.methodNotAllowed().addHeader(ALLOW, POST.name()));
+ }
+ return succeeded(responseFactory.created()
+ .payloadBody(request.payloadBody(REQ_STREAMING_SERIALIZER)
+ .map(req -> ResponseMessage.newBuilder().setLength(req.getMessage().length()).build()),
+ RESP_STREAMING_SERIALIZER));
+ })
+ .awaitShutdown();
+ }
+}
diff --git a/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/async/streaming/ProtobufStreamingUrlClient.java b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/async/streaming/ProtobufStreamingUrlClient.java
new file mode 100644
index 0000000000..512357a78b
--- /dev/null
+++ b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/async/streaming/ProtobufStreamingUrlClient.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright © 2022 Apple Inc. and the ServiceTalk project authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.servicetalk.examples.http.serialization.protobuf.async.streaming;
+
+import io.servicetalk.examples.http.serialization.protobuf.ExampleProtos.RequestMessage;
+import io.servicetalk.http.api.StreamingHttpClient;
+import io.servicetalk.http.netty.HttpClients;
+
+import static io.servicetalk.concurrent.api.Publisher.from;
+import static io.servicetalk.examples.http.serialization.protobuf.SerializerUtils.REQ_STREAMING_SERIALIZER;
+import static io.servicetalk.examples.http.serialization.protobuf.SerializerUtils.RESP_STREAMING_SERIALIZER;
+
+public final class ProtobufStreamingUrlClient {
+ public static void main(String[] args) throws Exception {
+ try (StreamingHttpClient client = HttpClients.forMultiAddressUrl().buildStreaming()) {
+ client.request(client.post("http://localhost:8080/protobuf")
+ .payloadBody(from("value1", "value22", "value333")
+ .map(message -> RequestMessage.newBuilder().setMessage(message).build()),
+ REQ_STREAMING_SERIALIZER))
+ .beforeOnSuccess(response -> System.out.println(response.toString((name, value) -> value)))
+ .flatMapPublisher(resp -> resp.payloadBody(RESP_STREAMING_SERIALIZER))
+ .whenOnNext(System.out::println)
+ // This example is demonstrating asynchronous execution, but needs to prevent the main thread from exiting
+ // before the response has been processed. This isn't typical usage for an asynchronous API but is useful
+ // for demonstration purposes.
+ .toFuture().get();
+ }
+ }
+}
diff --git a/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/async/streaming/package-info.java b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/async/streaming/package-info.java
new file mode 100644
index 0000000000..a85fcba2f6
--- /dev/null
+++ b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/async/streaming/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright © 2022 Apple Inc. and the ServiceTalk project authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+@ElementsAreNonnullByDefault
+package io.servicetalk.examples.http.serialization.protobuf.async.streaming;
+
+import io.servicetalk.annotations.ElementsAreNonnullByDefault;
diff --git a/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/blocking/BlockingProtobufClient.java b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/blocking/BlockingProtobufClient.java
new file mode 100644
index 0000000000..870db1c795
--- /dev/null
+++ b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/blocking/BlockingProtobufClient.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2022 Apple Inc. and the ServiceTalk project authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.servicetalk.examples.http.serialization.protobuf.blocking;
+
+import io.servicetalk.examples.http.serialization.protobuf.ExampleProtos.RequestMessage;
+import io.servicetalk.http.api.BlockingHttpClient;
+import io.servicetalk.http.api.HttpResponse;
+import io.servicetalk.http.netty.HttpClients;
+
+import static io.servicetalk.examples.http.serialization.protobuf.SerializerUtils.REQ_SERIALIZER;
+import static io.servicetalk.examples.http.serialization.protobuf.SerializerUtils.RESP_SERIALIZER;
+
+public final class BlockingProtobufClient {
+ public static void main(String[] args) throws Exception {
+ try (BlockingHttpClient client = HttpClients.forSingleAddress("localhost", 8080).buildBlocking()) {
+ HttpResponse resp = client.request(client.post("/protobuf")
+ .payloadBody(RequestMessage.newBuilder().setMessage("value").build(), REQ_SERIALIZER));
+ System.out.println(resp.toString((name, value) -> value));
+ System.out.println(resp.payloadBody(RESP_SERIALIZER));
+ }
+ }
+}
diff --git a/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/blocking/BlockingProtobufServer.java b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/blocking/BlockingProtobufServer.java
new file mode 100644
index 0000000000..2e207d497c
--- /dev/null
+++ b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/blocking/BlockingProtobufServer.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright © 2022 Apple Inc. and the ServiceTalk project authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.servicetalk.examples.http.serialization.protobuf.blocking;
+
+import io.servicetalk.examples.http.serialization.protobuf.ExampleProtos.RequestMessage;
+import io.servicetalk.examples.http.serialization.protobuf.ExampleProtos.ResponseMessage;
+import io.servicetalk.http.netty.HttpServers;
+
+import static io.servicetalk.examples.http.serialization.protobuf.SerializerUtils.REQ_SERIALIZER;
+import static io.servicetalk.examples.http.serialization.protobuf.SerializerUtils.RESP_SERIALIZER;
+import static io.servicetalk.http.api.HttpHeaderNames.ALLOW;
+import static io.servicetalk.http.api.HttpRequestMethod.POST;
+
+public final class BlockingProtobufServer {
+ public static void main(String[] args) throws Exception {
+ HttpServers.forPort(8080)
+ .listenBlockingAndAwait((ctx, request, responseFactory) -> {
+ if (!"/protobuf".equals(request.requestTarget())) {
+ return responseFactory.notFound();
+ }
+ if (!POST.equals(request.method())) {
+ return responseFactory.methodNotAllowed().addHeader(ALLOW, POST.name());
+ }
+
+ RequestMessage req = request.payloadBody(REQ_SERIALIZER);
+ ResponseMessage resp = ResponseMessage.newBuilder().setLength(req.getMessage().length()).build();
+ return responseFactory.created()
+ .payloadBody(resp, RESP_SERIALIZER);
+ })
+ .awaitShutdown();
+ }
+}
diff --git a/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/blocking/BlockingProtobufUrlClient.java b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/blocking/BlockingProtobufUrlClient.java
new file mode 100644
index 0000000000..72cfe83550
--- /dev/null
+++ b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/blocking/BlockingProtobufUrlClient.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2022 Apple Inc. and the ServiceTalk project authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.servicetalk.examples.http.serialization.protobuf.blocking;
+
+import io.servicetalk.examples.http.serialization.protobuf.ExampleProtos.RequestMessage;
+import io.servicetalk.http.api.BlockingHttpClient;
+import io.servicetalk.http.api.HttpResponse;
+import io.servicetalk.http.netty.HttpClients;
+
+import static io.servicetalk.examples.http.serialization.protobuf.SerializerUtils.REQ_SERIALIZER;
+import static io.servicetalk.examples.http.serialization.protobuf.SerializerUtils.RESP_SERIALIZER;
+
+public final class BlockingProtobufUrlClient {
+ public static void main(String[] args) throws Exception {
+ try (BlockingHttpClient client = HttpClients.forMultiAddressUrl().buildBlocking()) {
+ HttpResponse resp = client.request(client.post("http://localhost:8080/protobuf")
+ .payloadBody(RequestMessage.newBuilder().setMessage("value").build(), REQ_SERIALIZER));
+ System.out.println(resp.toString((name, value) -> value));
+ System.out.println(resp.payloadBody(RESP_SERIALIZER));
+ }
+ }
+}
diff --git a/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/blocking/package-info.java b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/blocking/package-info.java
new file mode 100644
index 0000000000..9d5871561e
--- /dev/null
+++ b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/blocking/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright © 2022 Apple Inc. and the ServiceTalk project authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+@ElementsAreNonnullByDefault
+package io.servicetalk.examples.http.serialization.protobuf.blocking;
+
+import io.servicetalk.annotations.ElementsAreNonnullByDefault;
diff --git a/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/blocking/streaming/BlockingProtobufStreamingClient.java b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/blocking/streaming/BlockingProtobufStreamingClient.java
new file mode 100644
index 0000000000..821f80b8ee
--- /dev/null
+++ b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/blocking/streaming/BlockingProtobufStreamingClient.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2022 Apple Inc. and the ServiceTalk project authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.servicetalk.examples.http.serialization.protobuf.blocking.streaming;
+
+import io.servicetalk.concurrent.BlockingIterator;
+import io.servicetalk.examples.http.serialization.protobuf.ExampleProtos.RequestMessage;
+import io.servicetalk.examples.http.serialization.protobuf.ExampleProtos.ResponseMessage;
+import io.servicetalk.http.api.BlockingStreamingHttpClient;
+import io.servicetalk.http.api.BlockingStreamingHttpResponse;
+import io.servicetalk.http.netty.HttpClients;
+
+import static io.servicetalk.examples.http.serialization.protobuf.SerializerUtils.REQ_STREAMING_SERIALIZER;
+import static io.servicetalk.examples.http.serialization.protobuf.SerializerUtils.RESP_STREAMING_SERIALIZER;
+import static java.util.Arrays.asList;
+
+public final class BlockingProtobufStreamingClient {
+ public static void main(String[] args) throws Exception {
+ try (BlockingStreamingHttpClient client =
+ HttpClients.forSingleAddress("localhost", 8080).buildBlockingStreaming()) {
+ BlockingStreamingHttpResponse response = client.request(client.post("/protobuf")
+ .payloadBody(asList(
+ RequestMessage.newBuilder().setMessage("value1").build(),
+ RequestMessage.newBuilder().setMessage("value22").build(),
+ RequestMessage.newBuilder().setMessage("value333").build()),
+ REQ_STREAMING_SERIALIZER));
+ System.out.println(response.toString((name, value) -> value));
+ // While it's also possible to use for-each, it's recommended to use try-with-resources to make sure that
+ // the full response payload body is drained in case of exceptions
+ try (BlockingIterator payload =
+ response.payloadBody(RESP_STREAMING_SERIALIZER).iterator()) {
+ while (payload.hasNext()) {
+ System.out.println(payload.next());
+ }
+ }
+ }
+ }
+}
diff --git a/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/blocking/streaming/BlockingProtobufStreamingServer.java b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/blocking/streaming/BlockingProtobufStreamingServer.java
new file mode 100644
index 0000000000..c031810cb9
--- /dev/null
+++ b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/blocking/streaming/BlockingProtobufStreamingServer.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright © 2022 Apple Inc. and the ServiceTalk project authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.servicetalk.examples.http.serialization.protobuf.blocking.streaming;
+
+import io.servicetalk.concurrent.BlockingIterable;
+import io.servicetalk.examples.http.serialization.protobuf.ExampleProtos.RequestMessage;
+import io.servicetalk.examples.http.serialization.protobuf.ExampleProtos.ResponseMessage;
+import io.servicetalk.http.api.HttpPayloadWriter;
+import io.servicetalk.http.netty.HttpServers;
+
+import static io.servicetalk.examples.http.serialization.protobuf.SerializerUtils.REQ_STREAMING_SERIALIZER;
+import static io.servicetalk.examples.http.serialization.protobuf.SerializerUtils.RESP_STREAMING_SERIALIZER;
+import static io.servicetalk.http.api.HttpHeaderNames.ALLOW;
+import static io.servicetalk.http.api.HttpRequestMethod.POST;
+import static io.servicetalk.http.api.HttpResponseStatus.CREATED;
+import static io.servicetalk.http.api.HttpResponseStatus.METHOD_NOT_ALLOWED;
+import static io.servicetalk.http.api.HttpResponseStatus.NOT_FOUND;
+
+public final class BlockingProtobufStreamingServer {
+ public static void main(String[] args) throws Exception {
+ HttpServers.forPort(8080)
+ .listenBlockingStreamingAndAwait((ctx, request, response) -> {
+ if (!"/protobuf".equals(request.requestTarget())) {
+ response.status(NOT_FOUND)
+ .sendMetaData()
+ .close();
+ } else if (!POST.equals(request.method())) {
+ response.status(METHOD_NOT_ALLOWED)
+ .addHeader(ALLOW, POST.name())
+ .sendMetaData()
+ .close();
+ } else {
+ BlockingIterable values = request.payloadBody(REQ_STREAMING_SERIALIZER);
+
+ response.status(CREATED);
+ try (HttpPayloadWriter writer =
+ response.sendMetaData(RESP_STREAMING_SERIALIZER)) {
+ for (RequestMessage req : values) {
+ writer.write(ResponseMessage.newBuilder().setLength(req.getMessage().length()).build());
+ }
+ }
+ }
+ })
+ .awaitShutdown();
+ }
+}
diff --git a/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/blocking/streaming/BlockingProtobufStreamingUrlClient.java b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/blocking/streaming/BlockingProtobufStreamingUrlClient.java
new file mode 100644
index 0000000000..dcd76a47f4
--- /dev/null
+++ b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/blocking/streaming/BlockingProtobufStreamingUrlClient.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright © 2022 Apple Inc. and the ServiceTalk project authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.servicetalk.examples.http.serialization.protobuf.blocking.streaming;
+
+import io.servicetalk.concurrent.BlockingIterator;
+import io.servicetalk.examples.http.serialization.protobuf.ExampleProtos.RequestMessage;
+import io.servicetalk.examples.http.serialization.protobuf.ExampleProtos.ResponseMessage;
+import io.servicetalk.http.api.BlockingStreamingHttpClient;
+import io.servicetalk.http.api.BlockingStreamingHttpResponse;
+import io.servicetalk.http.netty.HttpClients;
+
+import static io.servicetalk.examples.http.serialization.protobuf.SerializerUtils.REQ_STREAMING_SERIALIZER;
+import static io.servicetalk.examples.http.serialization.protobuf.SerializerUtils.RESP_STREAMING_SERIALIZER;
+import static java.util.Arrays.asList;
+
+public final class BlockingProtobufStreamingUrlClient {
+ public static void main(String[] args) throws Exception {
+ try (BlockingStreamingHttpClient client = HttpClients.forMultiAddressUrl().buildBlockingStreaming()) {
+ BlockingStreamingHttpResponse response = client.request(client.post("http://localhost:8080/protobuf")
+ .payloadBody(asList(
+ RequestMessage.newBuilder().setMessage("value1").build(),
+ RequestMessage.newBuilder().setMessage("value22").build(),
+ RequestMessage.newBuilder().setMessage("value333").build()),
+ REQ_STREAMING_SERIALIZER));
+ System.out.println(response.toString((name, value) -> value));
+ // While it's also possible to use for-each, it's recommended to use try-with-resources to make sure that
+ // the full response payload body is drained in case of exceptions
+ try (BlockingIterator payload =
+ response.payloadBody(RESP_STREAMING_SERIALIZER).iterator()) {
+ while (payload.hasNext()) {
+ System.out.println(payload.next());
+ }
+ }
+ }
+ }
+}
diff --git a/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/blocking/streaming/package-info.java b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/blocking/streaming/package-info.java
new file mode 100644
index 0000000000..e51a0ead22
--- /dev/null
+++ b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/blocking/streaming/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright © 2022 Apple Inc. and the ServiceTalk project authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+@ElementsAreNonnullByDefault
+package io.servicetalk.examples.http.serialization.protobuf.blocking.streaming;
+
+import io.servicetalk.annotations.ElementsAreNonnullByDefault;
diff --git a/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/package-info.java b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/package-info.java
new file mode 100644
index 0000000000..97b1be9296
--- /dev/null
+++ b/servicetalk-examples/http/serialization/protobuf/src/main/java/io/servicetalk/examples/http/serialization/protobuf/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright © 2022 Apple Inc. and the ServiceTalk project authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+@ElementsAreNonnullByDefault
+package io.servicetalk.examples.http.serialization.protobuf;
+
+import io.servicetalk.annotations.ElementsAreNonnullByDefault;
diff --git a/servicetalk-examples/http/serialization/protobuf/src/main/proto/message.proto b/servicetalk-examples/http/serialization/protobuf/src/main/proto/message.proto
new file mode 100644
index 0000000000..596411ebc7
--- /dev/null
+++ b/servicetalk-examples/http/serialization/protobuf/src/main/proto/message.proto
@@ -0,0 +1,30 @@
+//
+// Copyright © 2022 Apple Inc. and the ServiceTalk project authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+package test.shared;
+
+option java_multiple_files = false;
+option java_package = "io.servicetalk.examples.http.serialization.protobuf";
+option java_outer_classname = "ExampleProtos";
+
+message RequestMessage {
+ string message = 1;
+}
+
+message ResponseMessage {
+ int32 length = 1;
+}
diff --git a/servicetalk-examples/http/serialization/protobuf/src/main/resources/log4j2.xml b/servicetalk-examples/http/serialization/protobuf/src/main/resources/log4j2.xml
new file mode 100644
index 0000000000..3e1a0311eb
--- /dev/null
+++ b/servicetalk-examples/http/serialization/protobuf/src/main/resources/log4j2.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/settings.gradle b/settings.gradle
index d09a0bf066..40f166e56c 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -58,6 +58,7 @@ include "servicetalk-annotations",
"servicetalk-examples:http:observer",
"servicetalk-examples:http:retry",
"servicetalk-examples:http:serialization:json",
+ "servicetalk-examples:http:serialization:protobuf",
"servicetalk-examples:http:service-composition",
"servicetalk-examples:http:uds",
"servicetalk-examples:http:compression",
@@ -122,6 +123,7 @@ project(":servicetalk-examples:http:opentracing").name = "servicetalk-examples-h
project(":servicetalk-examples:http:observer").name = "servicetalk-examples-http-observer"
project(":servicetalk-examples:http:retry").name = "servicetalk-examples-http-retry"
project(":servicetalk-examples:http:serialization:json").name = "servicetalk-examples-http-serialization-json"
+project(":servicetalk-examples:http:serialization:protobuf").name = "servicetalk-examples-http-serialization-protobuf"
project(":servicetalk-examples:http:service-composition").name = "servicetalk-examples-http-service-composition"
project(":servicetalk-examples:http:uds").name = "servicetalk-examples-http-uds"
project(":servicetalk-examples:http:mutual-tls").name = "servicetalk-examples-http-mutual-tls"