All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.servicetalk.serialization.api.DefaultSerializer Maven / Gradle / Ivy

There is a newer version: 0.42.52
Show newest version
/*
 * Copyright © 2018 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.serialization.api;

import io.servicetalk.buffer.api.Buffer;
import io.servicetalk.buffer.api.BufferAllocator;
import io.servicetalk.concurrent.BlockingIterable;
import io.servicetalk.concurrent.BlockingIterator;
import io.servicetalk.concurrent.CloseableIterable;
import io.servicetalk.concurrent.CloseableIterator;
import io.servicetalk.concurrent.PublisherSource.Subscriber;
import io.servicetalk.concurrent.api.Publisher;
import io.servicetalk.concurrent.api.internal.SubscribablePublisher;
import io.servicetalk.concurrent.internal.AbstractCloseableIterable;

import java.util.Iterator;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Function;
import java.util.function.IntUnaryOperator;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import static io.servicetalk.concurrent.api.SourceAdapters.toSource;
import static io.servicetalk.utils.internal.ThrowableUtils.addSuppressed;
import static java.lang.Integer.MAX_VALUE;
import static java.lang.Math.max;
import static java.lang.Math.min;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toList;
import static java.util.stream.StreamSupport.stream;

/**
 * Default implementation for {@link Serializer}.
 * @deprecated Use implementations of following types:
 * 
    *
  • {@link io.servicetalk.serializer.api.Serializer}
  • *
  • {@link io.servicetalk.serializer.api.StreamingSerializer}
  • *
  • {@link io.servicetalk.serializer.api.Deserializer}
  • *
  • {@link io.servicetalk.serializer.api.StreamingDeserializer}
  • *
*/ @Deprecated public final class DefaultSerializer implements Serializer { /** * This applies a somewhat arbitrary limit (around 500kb) on the auto scaling of the next buffer allocation. */ private static final int MAX_READABLE_BYTES_TO_ADJUST = MAX_VALUE >>> 12; private static final int DEFAULT_SERIALIZATION_SIZE_BYTES_ESTIMATE = 512; private static final IntUnaryOperator DEFAULT_SIZE_ESTIMATOR = lastSize -> { // Approximate the next buffer will be ~33% bigger than the current buffer as a best effort to avoid // re-allocation and copy. return max(DEFAULT_SERIALIZATION_SIZE_BYTES_ESTIMATE, (min(MAX_READABLE_BYTES_TO_ADJUST, lastSize) << 2) / 3); }; private final SerializationProvider serializationProvider; /** * New instance. * * @param serializationProvider {@link SerializationProvider} to use. */ public DefaultSerializer(final SerializationProvider serializationProvider) { this.serializationProvider = requireNonNull(serializationProvider); } @Override public Publisher serialize(final Publisher source, final BufferAllocator allocator, final Class type) { return serialize(source, allocator, type, DEFAULT_SIZE_ESTIMATOR); } @Override public Iterable serialize(final Iterable source, final BufferAllocator allocator, final Class type) { return serialize(source, allocator, type, DEFAULT_SIZE_ESTIMATOR); } @Override public BlockingIterable serialize(final BlockingIterable source, final BufferAllocator allocator, final Class type) { return serialize(source, allocator, type, DEFAULT_SIZE_ESTIMATOR); } @Override public Publisher serialize(final Publisher source, final BufferAllocator allocator, final Class type, final IntUnaryOperator bytesEstimator) { return new SubscribablePublisher() { @Override protected void handleSubscribe(final Subscriber subscriber) { applySerializer0(subscriber, allocator, bytesEstimator, serializationProvider.getSerializer(type), source); } }; } @Override public Iterable serialize(final Iterable source, final BufferAllocator allocator, final Class type, final IntUnaryOperator bytesEstimator) { return applySerializer0(allocator, bytesEstimator, source, serializationProvider.getSerializer(type)); } @Override public BlockingIterable serialize(final BlockingIterable source, final BufferAllocator allocator, final Class type, final IntUnaryOperator bytesEstimator) { return applySerializer0(allocator, bytesEstimator, source, serializationProvider.getSerializer(type)); } @Override public Publisher serialize(final Publisher source, final BufferAllocator allocator, final TypeHolder typeHolder) { return serialize(source, allocator, typeHolder, DEFAULT_SIZE_ESTIMATOR); } @Override public Iterable serialize(final Iterable source, final BufferAllocator allocator, final TypeHolder typeHolder) { return serialize(source, allocator, typeHolder, DEFAULT_SIZE_ESTIMATOR); } @Override public BlockingIterable serialize(final BlockingIterable source, final BufferAllocator allocator, final TypeHolder typeHolder) { return serialize(source, allocator, typeHolder, DEFAULT_SIZE_ESTIMATOR); } @Override public Publisher serialize(final Publisher source, final BufferAllocator allocator, final TypeHolder typeHolder, final IntUnaryOperator bytesEstimator) { return new SubscribablePublisher() { @Override protected void handleSubscribe(final Subscriber subscriber) { applySerializer0(subscriber, allocator, bytesEstimator, serializationProvider.getSerializer(typeHolder), source); } }; } @Override public Iterable serialize(final Iterable source, final BufferAllocator allocator, final TypeHolder typeHolder, final IntUnaryOperator bytesEstimator) { final StreamingSerializer serializer = serializationProvider.getSerializer(typeHolder); return applySerializer0(allocator, bytesEstimator, source, serializer); } @Override public BlockingIterable serialize(final BlockingIterable source, final BufferAllocator allocator, final TypeHolder typeHolder, final IntUnaryOperator bytesEstimator) { return applySerializer0(allocator, bytesEstimator, source, serializationProvider.getSerializer(typeHolder)); } @Override public Buffer serialize(final T toSerialize, final BufferAllocator allocator) { return serialize(toSerialize, allocator, DEFAULT_SERIALIZATION_SIZE_BYTES_ESTIMATE); } @Override public Buffer serialize(final T toSerialize, final BufferAllocator allocator, final int bytesEstimate) { final Buffer destination = allocator.newBuffer(bytesEstimate); serializationProvider.serialize(toSerialize, destination); return destination; } @Override public void serialize(final T toSerialize, final Buffer destination) { serializationProvider.serialize(toSerialize, destination); } @Override public Publisher deserialize(final Publisher source, final TypeHolder typeHolder) { return new SubscribablePublisher() { @Override protected void handleSubscribe(final Subscriber subscriber) { applyDeserializer0(source, subscriber, serializationProvider.getDeserializer(typeHolder)); } }; } @Override public CloseableIterable deserialize(final Iterable source, final TypeHolder typeHolder) { return applyDeserializer0(source, serializationProvider.getDeserializer(typeHolder)); } @Override public BlockingIterable deserialize(final BlockingIterable source, final TypeHolder typeHolder) { return serializationProvider.getDeserializer(typeHolder).deserialize(source); } @Override public Publisher deserialize(final Publisher source, final Class type) { return new SubscribablePublisher() { @Override protected void handleSubscribe(final Subscriber subscriber) { applyDeserializer0(source, subscriber, serializationProvider.getDeserializer(type)); } }; } @Override public CloseableIterable deserialize(final Iterable source, final Class type) { return applyDeserializer0(source, serializationProvider.getDeserializer(type)); } @Override public BlockingIterable deserialize(final BlockingIterable source, final Class type) { return serializationProvider.getDeserializer(type).deserialize(source); } @Override public CloseableIterable deserializeAggregated(final Buffer serializedData, final Class type) { return deserializeAggregated0(serializedData, serializationProvider.getDeserializer(type)); } @Override public CloseableIterable deserializeAggregated(final Buffer serializedData, final TypeHolder typeHolder) { return deserializeAggregated0(serializedData, serializationProvider.getDeserializer(typeHolder)); } @Override public T deserializeAggregatedSingle(final Buffer serializedData, final Class type) { return getSingleValueOnly(deserializeAggregated(serializedData, type)); } @Override public T deserializeAggregatedSingle(final Buffer serializedData, final TypeHolder typeHolder) { return getSingleValueOnly(deserializeAggregated(serializedData, typeHolder)); } private static void applySerializer0(final Subscriber subscriber, final BufferAllocator allocator, final IntUnaryOperator bytesEstimator, final StreamingSerializer serializer, final Publisher source) { toSource(source.map(new SerializerFunction<>(bytesEstimator, allocator, serializer))).subscribe(subscriber); } private static Iterable applySerializer0(final BufferAllocator allocator, final IntUnaryOperator bytesEstimator, final Iterable source, final StreamingSerializer serializer) { return stream(source.spliterator(), false) .map(new SerializerFunction<>(bytesEstimator, allocator, serializer)) .collect(toList()); } @Nonnull private static BlockingIterable applySerializer0(final BufferAllocator allocator, final IntUnaryOperator bytesEstimator, final BlockingIterable source, final StreamingSerializer serializer) { SerializerFunction serializerFunction = new SerializerFunction<>(bytesEstimator, allocator, serializer); return () -> { final BlockingIterator iterator = source.iterator(); return new BlockingIterator() { @Override public boolean hasNext(final long timeout, final TimeUnit unit) throws TimeoutException { return iterator.hasNext(timeout, unit); } @Override public Buffer next(final long timeout, final TimeUnit unit) throws TimeoutException { return serializerFunction.apply(iterator.next(timeout, unit)); } @Override public void close() throws Exception { iterator.close(); } @Override public boolean hasNext() { return iterator.hasNext(); } @Override public Buffer next() { return serializerFunction.apply(iterator.next()); } }; }; } private static void applyDeserializer0(final Publisher source, final Subscriber subscriber, final StreamingDeserializer deSerializer) { // The StreamingDeserializer will be used to buffer data in between Buffers. It is not thread safe but // the concatMap should ensure there is no concurrency, and will ensure visibility when transitioning // between Buffers. toSource(source.flatMapConcatIterable(deSerializer::deserialize) .beforeOnComplete(deSerializer::close)) .subscribe(subscriber); } @Nonnull private static CloseableIterable applyDeserializer0(final Iterable source, final StreamingDeserializer deSerializer) { return deserializeAndClose(source, deSerializer::deserialize, deSerializer); } @Nonnull private static CloseableIterable deserializeAggregated0(final Buffer serializedData, final StreamingDeserializer deSerializer) { return deserializeAndClose(serializedData, deSerializer::deserialize, deSerializer); } private static CloseableIterable deserializeAndClose(final S source, final Function> doDeserialize, final StreamingDeserializer deSerializer) { final Iterable deserialized; try { deserialized = doDeserialize.apply(source); } catch (Throwable throwable) { try { deSerializer.close(); } catch (SerializationException e) { addSuppressed(throwable, e); } throw throwable; } return new AbstractCloseableIterable(deserialized) { @Override protected void closeIterator(final Iterator iterator) { deSerializer.close(); } }; } private static T getSingleValueOnly(CloseableIterable iterable) { final CloseableIterator iterator = iterable.iterator(); final T value = iterator.next(); closeIterator(iterator, iterator.hasNext() ? new SerializationException("More than one value was deserialized.") : null); return value; } private static void closeIterator(CloseableIterator iterator, @Nullable SerializationException cause) { try { iterator.close(); // May throw in case of incomplete accumulated data } catch (Exception e) { if (cause != null) { addSuppressed(cause, e); throw cause; } if (e instanceof SerializationException) { throw (SerializationException) e; } throw new SerializationException("Failed to close iterator", e); } if (cause != null) { throw cause; } } private static class SerializerFunction implements Function { private final IntUnaryOperator bytesEstimator; private final BufferAllocator allocator; private final StreamingSerializer serializer; private int lastSize; SerializerFunction(final IntUnaryOperator bytesEstimator, final BufferAllocator allocator, final StreamingSerializer serializer) { this.bytesEstimator = bytesEstimator; this.allocator = allocator; this.serializer = serializer; } @Override public Buffer apply(final T t) { lastSize = bytesEstimator.applyAsInt(lastSize); final Buffer destination = allocator.newBuffer(lastSize); serializer.serialize(t, destination); return destination; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy