@ -1,17 +1,15 @@
package org.redisson.codec ;
package org.redisson.codec ;
import com.fasterxml.jackson.databind.ObjectMapper ;
import com.fasterxml.jackson.databind.ser.BasicSerializerFactory ;
import com.fasterxml.jackson.databind.ser.BasicSerializerFactory ;
import com.google.protobuf.MessageLite ;
import com.google.protobuf.MessageLite ;
import io.netty.buffer.ByteBuf ;
import io.netty.buffer.ByteBuf ;
import io.netty.buffer.ByteBufAllocator ;
import io.netty.buffer.ByteBufAllocator ;
import io.netty.buffer.ByteBufInputStream ;
import io.netty.buffer.ByteBufOutputStream ;
import io.protostuff.LinkedBuffer ;
import io.protostuff.LinkedBuffer ;
import io.protostuff.ProtostuffIOUtil ;
import io.protostuff.ProtostuffIOUtil ;
import io.protostuff.Schema ;
import io.protostuff.Schema ;
import io.protostuff.runtime.RuntimeSchema ;
import io.protostuff.runtime.RuntimeSchema ;
import org.redisson.client.codec.BaseCodec ;
import org.redisson.client.codec.BaseCodec ;
import org.redisson.client.codec.Codec ;
import org.redisson.client.handler.State ;
import org.redisson.client.handler.State ;
import org.redisson.client.protocol.Decoder ;
import org.redisson.client.protocol.Decoder ;
import org.redisson.client.protocol.Encoder ;
import org.redisson.client.protocol.Encoder ;
@ -19,8 +17,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory ;
import org.slf4j.LoggerFactory ;
import java.io.IOException ;
import java.io.IOException ;
import java.io.InputStream ;
import java.io.OutputStream ;
import java.lang.reflect.Field ;
import java.lang.reflect.Field ;
import java.lang.reflect.InvocationTargetException ;
import java.lang.reflect.InvocationTargetException ;
import java.util.HashSet ;
import java.util.HashSet ;
@ -33,41 +29,64 @@ public class ProtobufCodec extends BaseCodec {
private final Class < ? > mapValueClass ;
private final Class < ? > mapValueClass ;
private final Class < ? > valueClass ;
private final Class < ? > valueClass ;
private final ObjectMapper objectMapper = new ObjectMapper ( ) ;
//classes in blacklist will not be serialized using protobuf ,but instead will use blacklistCodec
//classes in blacklist will not be serialized using protobuf ,but instead will use jackson
private final Set < String > protobufBlacklist ;
private final Set < String > protobufBlacklist ;
//default value is JsonJacksonCodec
private final Codec blacklistCodec ;
private final static Set < String > CLASSES_OWN_JACKSON_SERIALIZER = new HashSet < > ( ) ;
private final static Set < String > CLASSES_ NOT_SUITABLE_FOR_PROTOBUF = new HashSet < > ( ) ;
static {
static {
try {
try {
Field concreteField = BasicSerializerFactory . class . getDeclaredField ( "_concrete" ) ;
Field concreteField = BasicSerializerFactory . class . getDeclaredField ( "_concrete" ) ;
concreteField . setAccessible ( true ) ;
concreteField . setAccessible ( true ) ;
CLASSES_ OWN_JACKSON_SERIALIZER . addAll ( ( ( Map ) concreteField . get ( BasicSerializerFactory . class ) ) . keySet ( ) ) ;
CLASSES_ NOT_SUITABLE_FOR_PROTOBUF . addAll ( ( ( Map ) concreteField . get ( BasicSerializerFactory . class ) ) . keySet ( ) ) ;
Field _concreteLazyField = BasicSerializerFactory . class . getDeclaredField ( "_concreteLazy" ) ;
Field _concreteLazyField = BasicSerializerFactory . class . getDeclaredField ( "_concreteLazy" ) ;
_concreteLazyField . setAccessible ( true ) ;
_concreteLazyField . setAccessible ( true ) ;
CLASSES_ OWN_JACKSON_SERIALIZER . addAll ( ( ( Map ) concreteField . get ( BasicSerializerFactory . class ) ) . keySet ( ) ) ;
CLASSES_ NOT_SUITABLE_FOR_PROTOBUF . addAll ( ( ( Map ) concreteField . get ( BasicSerializerFactory . class ) ) . keySet ( ) ) ;
} catch ( NoSuchFieldException | IllegalAccessException ignored ) {
} catch ( NoSuchFieldException | IllegalAccessException ignored ) {
log . warn ( "ProtobufCodec failed to retrieve Jackson serializers. Maybe some objects (like String which using StringSerializer is better) will be serialized with protobuf unless the protobuf blacklist is explicitly set.") ;
log . warn ( "ProtobufCodec failed to retrieve classes not suitable for protobuf. Maybe some objects (like String which using StringSerializer is better) will be serialized with protobuf unless the protobuf blacklist is explicitly set.") ;
}
}
}
}
public ProtobufCodec ( Class < ? > mapKeyClass , Class < ? > mapValueClass ) {
public ProtobufCodec ( Class < ? > mapKeyClass , Class < ? > mapValueClass ) {
this ( mapKeyClass , mapValueClass , null ) ;
this ( mapKeyClass , mapValueClass , null , null ) ;
}
/ * *
* @param blacklistCodec classes in protobufBlacklist will use this codec
* /
public ProtobufCodec ( Class < ? > mapKeyClass , Class < ? > mapValueClass , Codec blacklistCodec ) {
this ( mapKeyClass , mapValueClass , null , blacklistCodec ) ;
}
}
public ProtobufCodec ( Class < ? > valueClass ) {
public ProtobufCodec ( Class < ? > valueClass ) {
this ( null , null , valueClass ) ;
this ( null , null , valueClass , null );
}
}
private ProtobufCodec ( Class < ? > mapKeyClass , Class < ? > mapValueClass , Class < ? > valueClass ) {
/ * *
* @param blacklistCodec classes in protobufBlacklist will use this codec
* /
public ProtobufCodec ( Class < ? > valueClass , Codec blacklistCodec ) {
this ( null , null , valueClass , blacklistCodec ) ;
}
private ProtobufCodec ( Class < ? > mapKeyClass , Class < ? > mapValueClass , Class < ? > valueClass , Codec blacklistCodec ) {
this . mapKeyClass = mapKeyClass ;
this . mapKeyClass = mapKeyClass ;
this . mapValueClass = mapValueClass ;
this . mapValueClass = mapValueClass ;
this . valueClass = valueClass ;
this . valueClass = valueClass ;
if ( blacklistCodec = = null ) {
this . blacklistCodec = new JsonJacksonCodec ( ) ;
} else {
if ( blacklistCodec instanceof ProtobufCodec ) {
//will loop infinitely when encode or decode
throw new IllegalArgumentException ( "BlacklistCodec can not be ProtobufCodec" ) ;
}
this . blacklistCodec = blacklistCodec ;
}
protobufBlacklist = new HashSet < > ( ) ;
protobufBlacklist = new HashSet < > ( ) ;
protobufBlacklist . addAll ( CLASSES_OWN_JACKSON_SERIALIZER ) ;
protobufBlacklist . addAll ( CLASSES_ NOT_SUITABLE_FOR_PROTOBUF ) ;
protobufBlacklist . add ( "java.util.ArrayList" ) ;
protobufBlacklist . add ( "java.util.ArrayList" ) ;
protobufBlacklist . add ( "java.util.HashSet" ) ;
protobufBlacklist . add ( "java.util.HashSet" ) ;
protobufBlacklist . add ( "java.util.HashMap" ) ;
protobufBlacklist . add ( "java.util.HashMap" ) ;
@ -83,35 +102,35 @@ public class ProtobufCodec extends BaseCodec {
@Override
@Override
public Decoder < Object > getValueDecoder ( ) {
public Decoder < Object > getValueDecoder ( ) {
return createDecoder ( valueClass );
return createDecoder ( valueClass , blacklistCodec . getValueDecoder ( ) );
}
}
@Override
@Override
public Encoder getValueEncoder ( ) {
public Encoder getValueEncoder ( ) {
return createEncoder ( valueClass );
return createEncoder ( valueClass , blacklistCodec . getValueEncoder ( ) );
}
}
@Override
@Override
public Decoder < Object > getMapValueDecoder ( ) {
public Decoder < Object > getMapValueDecoder ( ) {
return createDecoder ( mapValueClass );
return createDecoder ( mapValueClass , blacklistCodec . getMapValueDecoder ( ) );
}
}
@Override
@Override
public Encoder getMapValueEncoder ( ) {
public Encoder getMapValueEncoder ( ) {
return createEncoder ( mapValueClass );
return createEncoder ( mapValueClass , blacklistCodec . getMapValueEncoder ( ) );
}
}
@Override
@Override
public Decoder < Object > getMapKeyDecoder ( ) {
public Decoder < Object > getMapKeyDecoder ( ) {
return createDecoder ( mapKeyClass );
return createDecoder ( mapKeyClass , blacklistCodec . getMapKeyDecoder ( ) );
}
}
@Override
@Override
public Encoder getMapKeyEncoder ( ) {
public Encoder getMapKeyEncoder ( ) {
return createEncoder ( mapKeyClass );
return createEncoder ( mapKeyClass , blacklistCodec . getMapKeyEncoder ( ) );
}
}
private Decoder < Object > createDecoder ( Class < ? > clazz ) {
private Decoder < Object > createDecoder ( Class < ? > clazz , Decoder < Object > blacklistDecoder ) {
if ( clazz = = null ) {
if ( clazz = = null ) {
throw new IllegalArgumentException ( "class to create protobuf decoder can not be null" ) ;
throw new IllegalArgumentException ( "class to create protobuf decoder can not be null" ) ;
}
}
@ -119,9 +138,9 @@ public class ProtobufCodec extends BaseCodec {
return new Decoder < Object > ( ) {
return new Decoder < Object > ( ) {
@Override
@Override
public Object decode ( ByteBuf buf , State state ) throws IOException {
public Object decode ( ByteBuf buf , State state ) throws IOException {
//use jackson deserializ er
//use blacklistDecod er
if ( protobufBlacklist . contains ( clazz . getName ( ) ) ) {
if ( protobufBlacklist . contains ( clazz . getName ( ) ) ) {
return objectMapper. readValue ( ( InputStream ) new ByteBufInputStream ( buf ) , clazz ) ;
return blacklistDecoder. decode ( buf , state ) ;
}
}
byte [ ] bytes = new byte [ buf . readableBytes ( ) ] ;
byte [ ] bytes = new byte [ buf . readableBytes ( ) ] ;
@ -141,26 +160,19 @@ public class ProtobufCodec extends BaseCodec {
} ;
} ;
}
}
private Encoder createEncoder ( Class < ? > clazz ) {
private Encoder createEncoder ( Class < ? > clazz , Encoder blacklistEncoder ) {
if ( clazz = = null ) {
if ( clazz = = null ) {
throw new IllegalArgumentException ( "class to create protobuf encoder can not be null" ) ;
throw new IllegalArgumentException ( "class to create protobuf encoder can not be null" ) ;
}
}
return new Encoder ( ) {
return new Encoder ( ) {
@Override
@Override
public ByteBuf encode ( Object in ) throws IOException {
public ByteBuf encode ( Object in ) throws IOException {
//use jackson serializer
//use blacklistEncoder
ByteBuf out = ByteBufAllocator . DEFAULT . buffer ( ) ;
if ( protobufBlacklist . contains ( clazz . getName ( ) ) ) {
if ( protobufBlacklist . contains ( clazz . getName ( ) ) ) {
try {
return blacklistEncoder . encode ( in ) ;
ByteBufOutputStream os = new ByteBufOutputStream ( out ) ;
objectMapper . writeValue ( ( OutputStream ) os , in ) ;
return os . buffer ( ) ;
} catch ( IOException e ) {
out . release ( ) ;
throw e ;
}
}
}
ByteBuf out = ByteBufAllocator . DEFAULT . buffer ( ) ;
if ( MessageLite . class . isAssignableFrom ( clazz ) ) {
if ( MessageLite . class . isAssignableFrom ( clazz ) ) {
//native serialize
//native serialize
out . writeBytes ( ( ( MessageLite ) in ) . toByteArray ( ) ) ;
out . writeBytes ( ( ( MessageLite ) in ) . toByteArray ( ) ) ;