From 6b25a23a3d93479635736aadad87649c92946028 Mon Sep 17 00:00:00 2001 From: Nikita Date: Tue, 26 Jun 2018 17:50:53 +0300 Subject: [PATCH 1/3] Fixed - SerializationCodec doesn't support proxied classes. #1518 --- .../redisson/codec/CustomObjectInputStream.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/redisson/src/main/java/org/redisson/codec/CustomObjectInputStream.java b/redisson/src/main/java/org/redisson/codec/CustomObjectInputStream.java index 273c21037..b77afac55 100644 --- a/redisson/src/main/java/org/redisson/codec/CustomObjectInputStream.java +++ b/redisson/src/main/java/org/redisson/codec/CustomObjectInputStream.java @@ -19,6 +19,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectStreamClass; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.List; /** * @@ -27,7 +30,7 @@ import java.io.ObjectStreamClass; */ public class CustomObjectInputStream extends ObjectInputStream { - private ClassLoader classLoader; + private final ClassLoader classLoader; public CustomObjectInputStream(ClassLoader classLoader, InputStream in) throws IOException { super(in); @@ -44,4 +47,16 @@ public class CustomObjectInputStream extends ObjectInputStream { } } + @Override + protected Class resolveProxyClass(String[] interfaces) throws IOException, ClassNotFoundException { + List> loadedClasses = new ArrayList>(interfaces.length); + + for (String name : interfaces) { + Class clazz = Class.forName(name, false, classLoader); + loadedClasses.add(clazz); + } + + return Proxy.getProxyClass(classLoader, loadedClasses.toArray(new Class[loadedClasses.size()])); + } + } From 3e3008a58312f5eddd396e99f42e0c13c63dde57 Mon Sep 17 00:00:00 2001 From: Nikita Date: Tue, 26 Jun 2018 18:17:18 +0300 Subject: [PATCH 2/3] SnappyCodecV2 codec added --- .../org/redisson/codec/SnappyCodecV2.java | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 redisson/src/main/java/org/redisson/codec/SnappyCodecV2.java diff --git a/redisson/src/main/java/org/redisson/codec/SnappyCodecV2.java b/redisson/src/main/java/org/redisson/codec/SnappyCodecV2.java new file mode 100644 index 000000000..92e9201eb --- /dev/null +++ b/redisson/src/main/java/org/redisson/codec/SnappyCodecV2.java @@ -0,0 +1,103 @@ +/** + * Copyright 2018 Nikita Koksharov + * + * 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 org.redisson.codec; + +import java.io.IOException; + +import org.redisson.client.codec.BaseCodec; +import org.redisson.client.codec.Codec; +import org.redisson.client.handler.State; +import org.redisson.client.protocol.Decoder; +import org.redisson.client.protocol.Encoder; +import org.xerial.snappy.SnappyInputStream; +import org.xerial.snappy.SnappyOutputStream; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufInputStream; +import io.netty.buffer.ByteBufOutputStream; + +/** + * Google's Snappy compression codec. + * Uses inner Codec to convert object to binary stream. + * FstCodec used by default. + *

+ * Based on https://github.com/xerial/snappy-java + * + * @see org.redisson.codec.FstCodec + * + * @author Nikita Koksharov + * + */ +public class SnappyCodecV2 extends BaseCodec { + + private final Codec innerCodec; + + public SnappyCodecV2() { + this(new FstCodec()); + } + + public SnappyCodecV2(Codec innerCodec) { + this.innerCodec = innerCodec; + } + + public SnappyCodecV2(ClassLoader classLoader) { + this(new FstCodec(classLoader)); + } + + private final Decoder decoder = new Decoder() { + + @Override + public Object decode(ByteBuf buf, State state) throws IOException { + SnappyInputStream input = new SnappyInputStream(new ByteBufInputStream(buf)); + ByteBuf bf = ByteBufAllocator.DEFAULT.buffer(input.available()); + bf.writeBytes(input, input.available()); + try { + return innerCodec.getValueDecoder().decode(bf, state); + } finally { + bf.release(); + } + } + }; + + private final Encoder encoder = new Encoder() { + + @Override + public ByteBuf encode(Object in) throws IOException { + ByteBuf encoded = innerCodec.getValueEncoder().encode(in); + ByteBuf out = ByteBufAllocator.DEFAULT.buffer(encoded.readableBytes()); + try { + SnappyOutputStream output = new SnappyOutputStream(new ByteBufOutputStream(out)); + encoded.readBytes(output, encoded.readableBytes()); + output.flush(); + } finally { + encoded.release(); + } + return out; + } + }; + + @Override + public Decoder getValueDecoder() { + return decoder; + } + + @Override + public Encoder getValueEncoder() { + return encoder; + } + +} From 66dc33d690785ba979fb30ad28eaa98b1163b8f5 Mon Sep 17 00:00:00 2001 From: Nikita Date: Tue, 26 Jun 2018 18:50:40 +0300 Subject: [PATCH 3/3] SnappyCodecV2 tests added --- .../org/redisson/codec/SnappyCodecV2.java | 4 ++-- .../java/org/redisson/RedissonCodecTest.java | 22 ++++++++++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/redisson/src/main/java/org/redisson/codec/SnappyCodecV2.java b/redisson/src/main/java/org/redisson/codec/SnappyCodecV2.java index 92e9201eb..0dba27d3e 100644 --- a/redisson/src/main/java/org/redisson/codec/SnappyCodecV2.java +++ b/redisson/src/main/java/org/redisson/codec/SnappyCodecV2.java @@ -63,8 +63,8 @@ public class SnappyCodecV2 extends BaseCodec { @Override public Object decode(ByteBuf buf, State state) throws IOException { SnappyInputStream input = new SnappyInputStream(new ByteBufInputStream(buf)); - ByteBuf bf = ByteBufAllocator.DEFAULT.buffer(input.available()); - bf.writeBytes(input, input.available()); + ByteBuf bf = ByteBufAllocator.DEFAULT.buffer(buf.readableBytes()); + bf.writeBytes(input, buf.readableBytes()); try { return innerCodec.getValueDecoder().decode(bf, state); } finally { diff --git a/redisson/src/test/java/org/redisson/RedissonCodecTest.java b/redisson/src/test/java/org/redisson/RedissonCodecTest.java index 395a109f1..cf9e3bd8a 100644 --- a/redisson/src/test/java/org/redisson/RedissonCodecTest.java +++ b/redisson/src/test/java/org/redisson/RedissonCodecTest.java @@ -23,10 +23,10 @@ import org.redisson.codec.FstCodec; import org.redisson.codec.JsonJacksonCodec; import org.redisson.codec.KryoCodec; import org.redisson.codec.LZ4Codec; -import org.redisson.codec.MsgPackJacksonCodec; import org.redisson.codec.SerializationCodec; import org.redisson.codec.SmileJacksonCodec; import org.redisson.codec.SnappyCodec; +import org.redisson.codec.SnappyCodecV2; import org.redisson.config.Config; import com.fasterxml.jackson.core.type.TypeReference; @@ -44,6 +44,7 @@ public class RedissonCodecTest extends BaseTest { private Codec cborCodec = new CborJacksonCodec(); private Codec fstCodec = new FstCodec(); private Codec snappyCodec = new SnappyCodec(); + private Codec snappyCodecV2 = new SnappyCodecV2(); // private Codec msgPackCodec = new MsgPackJacksonCodec(); private Codec lz4Codec = new LZ4Codec(); private Codec jsonListOfStringCodec = new JsonJacksonMapCodec( @@ -127,6 +128,25 @@ public class RedissonCodecTest extends BaseTest { test(redisson); } + + @Test + public void testSnappyV2() { + Config config = createConfig(); + config.setCodec(snappyCodecV2); + RedissonClient redisson = Redisson.create(config); + + test(redisson); + } + + @Test + public void testSnappyBigV2() throws IOException { + Codec sc = new SnappyCodecV2(); + String randomData = RandomString.make(Short.MAX_VALUE*2 + 142); + ByteBuf g = sc.getValueEncoder().encode(randomData); + String decompressedData = (String) sc.getValueDecoder().decode(g, null); + assertThat(decompressedData).isEqualTo(randomData); + } + @Test public void testJson() {