package io.datakernel.stream.net; import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; import io.datakernel.bytebuf.ByteBuf; import io.datakernel.bytebuf.ByteBufPool; import io.datakernel.bytebuf.ByteBufStrings; import io.datakernel.exception.ParseException; import static io.datakernel.bytebuf.ByteBufStrings.putUtf8; @SuppressWarnings("ThrowableInstanceNeverThrown, WeakerAccess") public final class MessagingSerializers { public static final ParseException DESERIALIZE_ERR = new ParseException("Can't deserialize message"); private MessagingSerializers() { } public static <I, O> MessagingSerializer<I, O> ofGson(final Gson in, final Class<I> inputClass, final Gson out, final Class<O> outputClass) { return new MessagingSerializer<I, O>() { @Override public I tryDeserialize(ByteBuf buf) throws ParseException { for (int len = 0; len < buf.readRemaining(); len++) { if (buf.peek(len) == '\0') { try { I item = in.fromJson(ByteBufStrings.decodeUtf8(buf.array(), buf.readPosition(), len), inputClass); buf.moveReadPosition(len + 1); // skipping msg + delimiter return item; } catch (JsonSyntaxException e) { throw DESERIALIZE_ERR; } } } return null; } @Override public ByteBuf serialize(O item) { ByteBufPoolAppendable appendable = new ByteBufPoolAppendable(); out.toJson(item, outputClass, appendable); appendable.append("\0"); return appendable.get(); } }; } static class ByteBufPoolAppendable implements Appendable { static final int INITIAL_BUF_SIZE = 2 * 1024; ByteBuf container; ByteBufPoolAppendable() {this(INITIAL_BUF_SIZE);} ByteBufPoolAppendable(int size) { this.container = ByteBufPool.allocate(size); } @Override public Appendable append(CharSequence csq) { container = ByteBufPool.ensureTailRemaining(container, csq.length() * 3); for (int i = 0; i < csq.length(); i++) { putUtf8(container, csq.charAt(i)); } return this; } @Override public Appendable append(CharSequence csq, int start, int end) { return append(csq.subSequence(start, end)); } @Override public Appendable append(char c) { container = ByteBufPool.ensureTailRemaining(container, 3); putUtf8(container, c); return this; } public ByteBuf get() { return container; } } }