Skip to content

Commit 4ce1aa6

Browse files
authored
New Serializer APIs, consolidation of ContentCodec, and gRPC MethodDescriptor (#1673)
Motivation: Supporting a custom transport for gRPC currently requires reflection and special knowledge of types for serialization. The generated code has information related to types and serialization that can be exposed to the runtime which also allows supporting custom transports. This task requires exposing serializer APIs into the public API. Our existing serializer APIs were heavily influced by streaming use cases and JSON serialization which can serialize any type and generally doesn't have type restrictions. This lead to a general SerializationProvider API which is impossible to constrain types due to the generics being at the method level, which doesn't account for implementing serialization for type constrained approached (protobuf MessageLite). Also the serialization APIs couple scalar and streaming use cases which in practice are more commonly decoupled into scalar (individual objects) and streaming (which applies some framing around individual objects). These concepts are coupled which leads to confusing specializations (deserializeAggregatedSingle, deserializeAggregated) which are easy to misuse and lead to invalid serialization in practice (streaming {form url, string} encoding are not properly framed and may not be deserialized correctly). The existing Serializer APIs also do not promote composability in that if you can serialize one object you should be able to re-use that serialization for a stream of objects with some frameing applied on top (required for gRPC). Modifications: - Introduce a new servicetalk-serializer-api package with new Serializer APIs. - Introduce a new servicetalk-serializer-utils package with common utilities for serialization such as streaming framing (fixed and varint length prefixed) - Introduce BufferEncoder APIs in servicetalk-encoding-api for compression and decompression. This also comes with NettyBufferEncoders and NettyCompression to create Netty backed implementations. - Introduce HttpStreamingSerializer and new HttpSerializer APIs in servicetalk-http-api, and modify all request/response APIs to use the new serializer APIs. Introduce new methods to deserialize and process trailers. - Introduce HttpSerializers in servicetalk-http-api for implementations of the new APIs. - Introduce JacksonSerializerCache in servicetalk-http-api as the new entry point to create/cache serializers for JSON. - Introduce ProtobufSerializerCache in servicetalk-data-protobuf as the new entry point to create/cache serializers for protobuf. - Introduce MethodDescriptor API into servicetalk-grpc-api and update code generation to use this new API. - Update all examples avoid usage of deprecated APIs and leverage new APIs. - Deprecate the following APIs and related methods in favor of the new types descrbied above: - SerializationProvider, JacksonSerializationProvider, ProtobufSerializationProvider, GrpcSerializationProvider, HttpSerializationProvider - ContentCodec, CodecDecodingException, CodecEncodingException, ContentCodings - GrpcMetadata#path(), code generated types that extend DefaultGrpcClientMetadata Result: gRPC API supports MethodDescriptor, which uses new Serializer APIs, and the entire code base has been updated to use the new APIs consistently.
1 parent c1db214 commit 4ce1aa6

File tree

327 files changed

+12164
-3105
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

327 files changed

+12164
-3105
lines changed

servicetalk-buffer-api/src/main/java/io/servicetalk/buffer/api/Buffer.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1657,6 +1657,21 @@ default boolean tryEnsureWritable(int minWritableBytes, boolean force) {
16571657
*/
16581658
Buffer writeUtf8(CharSequence seq, int ensureWritable);
16591659

1660+
/**
1661+
* Encode a {@link CharSequence} encoded in {@link Charset} and write it to this buffer starting at
1662+
* {@code writerIndex} and increases the {@code writerIndex} by the number of the transferred bytes.
1663+
*
1664+
* @param seq the source of the data.
1665+
* @param charset the charset used for encoding.
1666+
* @return self.
1667+
* @throws ReadOnlyBufferException if this buffer is read-only
1668+
*/
1669+
default Buffer writeCharSequence(CharSequence seq, Charset charset) {
1670+
byte[] bytes = seq.toString().getBytes(charset);
1671+
writeBytes(bytes);
1672+
return this;
1673+
}
1674+
16601675
/**
16611676
* Locates the first occurrence of the specified {@code value} in this
16621677
* buffer. The search takes place from the specified {@code fromIndex}

servicetalk-buffer-api/src/main/java/io/servicetalk/buffer/api/EmptyBuffer.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,11 @@ public Buffer writeUtf8(CharSequence seq, int ensureWritable) {
644644
throw new IndexOutOfBoundsException();
645645
}
646646

647+
@Override
648+
public Buffer writeCharSequence(CharSequence seq, Charset charset) {
649+
throw new IndexOutOfBoundsException();
650+
}
651+
647652
@Override
648653
public int indexOf(int fromIndex, int toIndex, byte value) {
649654
checkIndex(fromIndex);

servicetalk-buffer-api/src/main/java/io/servicetalk/buffer/api/ReadOnlyByteBuffer.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,11 @@ public Buffer writeUtf8(CharSequence seq, int ensureWritable) {
375375
throw new ReadOnlyBufferException();
376376
}
377377

378+
@Override
379+
public Buffer writeCharSequence(CharSequence seq, Charset charset) {
380+
throw new ReadOnlyBufferException();
381+
}
382+
378383
@Override
379384
public Buffer readSlice(int length) {
380385
checkReadableBytes0(length);

servicetalk-buffer-netty/src/main/java/io/servicetalk/buffer/netty/NettyBuffer.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,12 @@ public Buffer writeUtf8(CharSequence seq, int ensureWritable) {
710710
return this;
711711
}
712712

713+
@Override
714+
public Buffer writeCharSequence(CharSequence seq, Charset charset) {
715+
buffer.writeCharSequence(seq, charset);
716+
return this;
717+
}
718+
713719
@Override
714720
public int indexOf(int fromIndex, int toIndex, byte value) {
715721
return buffer.indexOf(fromIndex, toIndex, value);

servicetalk-buffer-netty/src/main/java/io/servicetalk/buffer/netty/NettyCompositeBuffer.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import io.netty.buffer.CompositeByteBuf;
2222

2323
import java.nio.ByteBuffer;
24+
import java.nio.charset.Charset;
2425

2526
final class NettyCompositeBuffer extends NettyBuffer<CompositeByteBuf> implements CompositeBuffer {
2627

@@ -363,4 +364,10 @@ public CompositeBuffer writeUtf8(CharSequence seq, int ensureWritable) {
363364
super.writeUtf8(seq, ensureWritable);
364365
return this;
365366
}
367+
368+
@Override
369+
public CompositeBuffer writeCharSequence(CharSequence seq, Charset charset) {
370+
super.writeCharSequence(seq, charset);
371+
return this;
372+
}
366373
}

servicetalk-buffer-netty/src/main/java/io/servicetalk/buffer/netty/ReadOnlyBuffer.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.io.InputStream;
2121
import java.nio.ByteBuffer;
2222
import java.nio.ReadOnlyBufferException;
23+
import java.nio.charset.Charset;
2324

2425
final class ReadOnlyBuffer extends WrappedBuffer {
2526

@@ -302,6 +303,11 @@ public Buffer writeUtf8(CharSequence seq, int ensureWritable) {
302303
throw new ReadOnlyBufferException();
303304
}
304305

306+
@Override
307+
public Buffer writeCharSequence(CharSequence seq, Charset charset) {
308+
throw new ReadOnlyBufferException();
309+
}
310+
305311
@Override
306312
public Buffer readSlice(int length) {
307313
return buffer.readSlice(length).asReadOnly();

servicetalk-buffer-netty/src/main/java/io/servicetalk/buffer/netty/WrappedBuffer.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,12 @@ public Buffer writeUtf8(CharSequence seq, int ensureWritable) {
658658
return this;
659659
}
660660

661+
@Override
662+
public Buffer writeCharSequence(CharSequence seq, Charset charset) {
663+
buffer.writeCharSequence(seq, charset);
664+
return this;
665+
}
666+
661667
@Override
662668
public int indexOf(int fromIndex, int toIndex, byte value) {
663669
return buffer.indexOf(fromIndex, toIndex, value);

servicetalk-concurrent-reactivestreams/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ dependencies {
2121
api "org.reactivestreams:reactive-streams:$reactiveStreamsVersion"
2222

2323
implementation project(":servicetalk-annotations")
24+
implementation project(":servicetalk-serializer-utils")
25+
implementation project(":servicetalk-buffer-netty")
2426
implementation "com.google.code.findbugs:jsr305:$jsr305Version"
2527
implementation "org.slf4j:slf4j-api:$slf4jVersion"
2628

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright © 2021 Apple Inc. and the ServiceTalk project authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.servicetalk.concurrent.reactivestreams.tck;
17+
18+
import io.servicetalk.concurrent.api.Publisher;
19+
import io.servicetalk.serializer.utils.FramedDeserializerOperator;
20+
21+
import org.testng.annotations.Test;
22+
23+
import static io.servicetalk.buffer.netty.BufferAllocators.DEFAULT_ALLOCATOR;
24+
import static java.util.function.Function.identity;
25+
26+
@Test
27+
public class FramedDeserializerOperatorTckTest extends AbstractPublisherTckTest<Integer> {
28+
@Override
29+
public Publisher<Integer> createServiceTalkPublisher(final long elements) {
30+
return Publisher.range(0, TckUtils.requestNToInt(elements))
31+
.map(i -> DEFAULT_ALLOCATOR.newBuffer().writeInt(i))
32+
.liftSync(new FramedDeserializerOperator<>(
33+
(serializedData, allocator) -> serializedData.readInt(),
34+
() -> (buffer, bufferAllocator) ->
35+
buffer.readableBytes() < Integer.BYTES ? null : buffer.readBytes(Integer.BYTES),
36+
DEFAULT_ALLOCATOR))
37+
.flatMapConcatIterable(identity());
38+
}
39+
40+
@Override
41+
public long maxElementsFromPublisher() {
42+
return TckUtils.maxElementsFromPublisher();
43+
}
44+
}

servicetalk-data-jackson-jersey/src/main/java/io/servicetalk/data/jackson/jersey/JacksonSerializationProviderContextResolver.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
import javax.annotation.Nullable;
2121
import javax.ws.rs.ext.ContextResolver;
2222

23+
/**
24+
* @deprecated Use {@link JacksonSerializerFactoryContextResolver}.
25+
*/
26+
@Deprecated
2327
final class JacksonSerializationProviderContextResolver implements ContextResolver<JacksonSerializationProvider> {
2428
private final JacksonSerializationProvider jacksonSerializationProvider;
2529

0 commit comments

Comments
 (0)