diff --git a/LICENSE.txt b/LICENSE.txt index d64569567..eb4c56f95 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -187,7 +187,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright (c) 2014-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. diff --git a/redisson/src/main/java/org/redisson/client/codec/JsonJacksonMapCodec.java b/redisson/src/main/java/org/redisson/client/codec/JsonJacksonMapCodec.java index 9fae54634..bddd7ffd8 100644 --- a/redisson/src/main/java/org/redisson/client/codec/JsonJacksonMapCodec.java +++ b/redisson/src/main/java/org/redisson/client/codec/JsonJacksonMapCodec.java @@ -33,7 +33,7 @@ import io.netty.buffer.ByteBufInputStream; import io.netty.buffer.ByteBufOutputStream; /** - * Type based codec for RMap objects + * @deprecated Use org.redisson.codec.TypedJsonJacksonCodec instead * * @author Nikita Koksharov * @author Andrej Kazakov diff --git a/redisson/src/main/java/org/redisson/codec/DefaultReferenceCodecProvider.java b/redisson/src/main/java/org/redisson/codec/DefaultReferenceCodecProvider.java index 715571ec1..d0573ab14 100644 --- a/redisson/src/main/java/org/redisson/codec/DefaultReferenceCodecProvider.java +++ b/redisson/src/main/java/org/redisson/codec/DefaultReferenceCodecProvider.java @@ -82,11 +82,6 @@ public class DefaultReferenceCodecProvider implements ReferenceCodecProvider { return getCodec(codecClass, rObjectClass); } - @Override - public T getCodec(Class codecClass, RObject rObject) { - return getCodec(codecClass, rObject.getClass(), rObject.getName()); - } - @Override public void registerCodec(Class cls, T codec) { if (!cls.isInstance(codec)) { diff --git a/redisson/src/main/java/org/redisson/codec/ReferenceCodecProvider.java b/redisson/src/main/java/org/redisson/codec/ReferenceCodecProvider.java index 3d561a84a..e334f864c 100644 --- a/redisson/src/main/java/org/redisson/codec/ReferenceCodecProvider.java +++ b/redisson/src/main/java/org/redisson/codec/ReferenceCodecProvider.java @@ -89,16 +89,6 @@ public interface ReferenceCodecProvider { */ T getCodec(Class codecClass, Class rObjectClass, String name); - /** - * Get a codec instance by its class and an instance of the RObject. - * - * @param the expected codec type. - * @param codecClass the codec class used to lookup the codec. - * @param rObject instance of the RObject implementation. - * @return the cached codec instance. - */ - T getCodec(Class codecClass, RObject rObject); - /** * Register a codec by its class or super class. * diff --git a/redisson/src/main/java/org/redisson/codec/TypedJsonJacksonCodec.java b/redisson/src/main/java/org/redisson/codec/TypedJsonJacksonCodec.java new file mode 100644 index 000000000..5ee255fa5 --- /dev/null +++ b/redisson/src/main/java/org/redisson/codec/TypedJsonJacksonCodec.java @@ -0,0 +1,170 @@ +/** + * 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 java.io.InputStream; +import java.io.OutputStream; + +import org.redisson.client.handler.State; +import org.redisson.client.protocol.Decoder; +import org.redisson.client.protocol.Encoder; +import org.redisson.codec.JsonJacksonCodec; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufInputStream; +import io.netty.buffer.ByteBufOutputStream; + +/** + * Json Jackson Type codec. Doesn't include `@class` field during data encoding, and doesn't require it for data decoding. + * + * @author Nikita Koksharov + * @author Andrej Kazakov + * + */ +public class TypedJsonJacksonCodec extends JsonJacksonCodec { + + private final Encoder encoder = new Encoder() { + @Override + public ByteBuf encode(Object in) throws IOException { + ByteBuf out = ByteBufAllocator.DEFAULT.buffer(); + try { + ByteBufOutputStream os = new ByteBufOutputStream(out); + mapObjectMapper.writeValue((OutputStream)os, in); + return os.buffer(); + } catch (IOException e) { + out.release(); + throw e; + } + } + }; + + private Decoder createDecoder(final Class valueClass, final TypeReference valueTypeReference) { + return new Decoder() { + @Override + public Object decode(ByteBuf buf, State state) throws IOException { + if (valueClass != null) { + return mapObjectMapper.readValue((InputStream)new ByteBufInputStream(buf), valueClass); + } + if (valueTypeReference != null) { + return mapObjectMapper.readValue((InputStream)new ByteBufInputStream(buf), valueTypeReference); + } + return mapObjectMapper.readValue((InputStream)new ByteBufInputStream(buf), Object.class); + } + }; + } + + private final Decoder valueDecoder; + private final Decoder mapValueDecoder; + private final Decoder mapKeyDecoder; + + public TypedJsonJacksonCodec(Class valueClass) { + this(valueClass, new ObjectMapper()); + } + + public TypedJsonJacksonCodec(Class valueClass, ObjectMapper mapper) { + this(valueClass, null, null, mapper); + } + + public TypedJsonJacksonCodec(Class mapKeyClass, Class mapValueClass) { + this(null, mapKeyClass, mapValueClass, new ObjectMapper()); + } + + public TypedJsonJacksonCodec(Class mapKeyClass, Class mapValueClass, ObjectMapper mapper) { + this(null, mapKeyClass, mapValueClass, mapper); + } + + public TypedJsonJacksonCodec(Class valueClass, Class mapKeyClass, Class mapValueClass) { + this(null, null, null, valueClass, mapKeyClass, mapValueClass, new ObjectMapper()); + } + + public TypedJsonJacksonCodec(Class valueClass, Class mapKeyClass, Class mapValueClass, ObjectMapper mapper) { + this(null, null, null, valueClass, mapKeyClass, mapValueClass, mapper); + } + + public TypedJsonJacksonCodec(TypeReference valueTypeReference) { + this(valueTypeReference, new ObjectMapper()); + } + + public TypedJsonJacksonCodec(TypeReference valueTypeReference, ObjectMapper mapper) { + this(valueTypeReference, null, null, mapper); + } + + public TypedJsonJacksonCodec(TypeReference mapKeyTypeReference, TypeReference mapValueTypeReference) { + this(null, mapKeyTypeReference, mapValueTypeReference); + } + + public TypedJsonJacksonCodec(TypeReference mapKeyTypeReference, TypeReference mapValueTypeReference, ObjectMapper mapper) { + this(null, mapKeyTypeReference, mapValueTypeReference, mapper); + } + + public TypedJsonJacksonCodec(TypeReference valueTypeReference, TypeReference mapKeyTypeReference, TypeReference mapValueTypeReference) { + this(valueTypeReference, mapKeyTypeReference, mapValueTypeReference, null, null, null, new ObjectMapper()); + } + + public TypedJsonJacksonCodec(TypeReference valueTypeReference, TypeReference mapKeyTypeReference, TypeReference mapValueTypeReference, ObjectMapper mapper) { + this(valueTypeReference, mapKeyTypeReference, mapValueTypeReference, null, null, null, mapper); + } + + TypedJsonJacksonCodec( + TypeReference valueTypeReference, TypeReference mapKeyTypeReference, TypeReference mapValueTypeReference, + Class valueClass, Class mapKeyClass, Class mapValueClass, ObjectMapper mapper) { + super(mapper); + this.mapValueDecoder = createDecoder(mapValueClass, mapValueTypeReference); + this.mapKeyDecoder = createDecoder(mapKeyClass, mapKeyTypeReference); + this.valueDecoder = createDecoder(valueClass, valueTypeReference); + } + + @Override + protected void initTypeInclusion(ObjectMapper mapObjectMapper) { + // avoid type inclusion + } + + @Override + public Decoder getValueDecoder() { + return valueDecoder; + } + + @Override + public Encoder getValueEncoder() { + return encoder; + } + + @Override + public Decoder getMapKeyDecoder() { + return mapKeyDecoder; + } + + @Override + public Encoder getMapValueEncoder() { + return encoder; + } + + @Override + public Encoder getMapKeyEncoder() { + return encoder; + } + + @Override + public Decoder getMapValueDecoder() { + return mapValueDecoder; + } + +} \ No newline at end of file diff --git a/redisson/src/test/java/org/redisson/client/codec/JsonJacksonMapValueCodecTest.java b/redisson/src/test/java/org/redisson/codec/TypedJsonJacksonCodecTest.java similarity index 54% rename from redisson/src/test/java/org/redisson/client/codec/JsonJacksonMapValueCodecTest.java rename to redisson/src/test/java/org/redisson/codec/TypedJsonJacksonCodecTest.java index cc59e8041..ebc1b7439 100644 --- a/redisson/src/test/java/org/redisson/client/codec/JsonJacksonMapValueCodecTest.java +++ b/redisson/src/test/java/org/redisson/codec/TypedJsonJacksonCodecTest.java @@ -1,4 +1,4 @@ -package org.redisson.client.codec; +package org.redisson.codec; import static org.assertj.core.api.Assertions.assertThat; @@ -10,6 +10,7 @@ import java.util.Map; import org.junit.Test; import org.redisson.BaseTest; +import org.redisson.api.RBucket; import org.redisson.api.RMap; import org.redisson.client.handler.State; @@ -17,16 +18,39 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import io.netty.buffer.ByteBuf; -import io.netty.buffer.PooledByteBufAllocator; +import io.netty.buffer.ByteBufAllocator; import io.netty.util.CharsetUtil; -public class JsonJacksonMapValueCodecTest extends BaseTest { +public class TypedJsonJacksonCodecTest extends BaseTest { - private final JsonJacksonMapCodec mapCodec = new JsonJacksonMapCodec(null, new TypeReference>>() { - }); + public static class Simple { + + private String value; - private final JsonJacksonMapCodec stringCodec = new JsonJacksonMapCodec(null, String.class); + public Simple() { + } + + public Simple(String value) { + this.value = value; + } + public String getValue() { + return value; + } + public void setValue(String value) { + this.value = value; + } + + } + + private final TypedJsonJacksonCodec valueCodec = new TypedJsonJacksonCodec(new TypeReference() {}); + + private final TypedJsonJacksonCodec mapCodec = new TypedJsonJacksonCodec(null, new TypeReference>>() {}); + + private final TypedJsonJacksonCodec stringCodec = new TypedJsonJacksonCodec(null, String.class); + + private Simple value = new Simple("test"); + private HashMap> map = new HashMap>(); { @@ -35,20 +59,34 @@ public class JsonJacksonMapValueCodecTest extends BaseTest { @Test public void testMap() { - RMap map = redisson.getMap("anyMap", new JsonJacksonMapCodec(String.class, byte[].class)); + RMap map = redisson.getMap("anyMap", new TypedJsonJacksonCodec(String.class, byte[].class)); map.put(String.valueOf("2"), new byte[]{1, 2, 3}); assertThat(map.get("2")).isEqualTo(new byte[] {1, 2, 3}); } + @Test + public void testBucket() { + RBucket bucket = redisson.getBucket("anyMap", new TypedJsonJacksonCodec(String.class)); + bucket.set(String.valueOf("2")); + assertThat(bucket.get()).isEqualTo("2"); + } + @Test public void shouldDeserializeTheMapCorrectly() throws Exception { - ByteBuf buf = new PooledByteBufAllocator(true).buffer(); + ByteBuf buf = ByteBufAllocator.DEFAULT.buffer(); buf.writeBytes(new ObjectMapper().writeValueAsBytes(map)); assertThat(mapCodec.getMapValueDecoder().decode(buf, new State(false))) .isInstanceOf(Map.class) .isEqualTo(map); + buf.release(); } + @Test + public void shouldSerializeValueCorrectly() throws Exception { + assertThat(valueCodec.getValueEncoder().encode(value).toString(CharsetUtil.UTF_8)) + .isEqualTo("{\"value\":\"test\"}"); + } + @Test public void shouldSerializeTheMapCorrectly() throws Exception { assertThat(mapCodec.getMapValueEncoder().encode(map).toString(CharsetUtil.UTF_8)) @@ -57,11 +95,12 @@ public class JsonJacksonMapValueCodecTest extends BaseTest { @Test public void shouldDeserializeTheStringCorrectly() throws Exception { - ByteBuf buf = new PooledByteBufAllocator(true).buffer(); + ByteBuf buf = ByteBufAllocator.DEFAULT.buffer(); buf.writeBytes(new ObjectMapper().writeValueAsBytes("axk")); assertThat(stringCodec.getMapValueDecoder().decode(buf, new State(false))) .isInstanceOf(String.class) .isEqualTo("axk"); + buf.release(); } @Test