最近在项目当中遇到一个问题,就是使用Dubbo进行调用服务时,实体类中使用 jackson 的JsonNode进行数据传送时,导致序列化失败的问题。这里记录一下Dubbo是如何进行自定义反序列化的。
借鉴于Dubbo自带JavaSerializer器,自己修改了源码
public class CustomizeDataDeserializer extends AbstractMapDeserializer {
private static final Logger LOG = Logger.getLogger(CustomizeDataDeserializer.class.getName());
//序列化对象的类型
private final Class<?> type;
//实体类中字段所需要的类型
private final Map<String, FieldDeserializer> fieldMap;
//获取实体类中readResolve方法
private final Method readResolve;
//获取构造函数
private Constructor constructor;
//获取构造函数的参数
private Object[] constructorArgs;
static final Map<String, Boolean> PRIMITIVE_TYPE = new HashMap<String, Boolean>(9) {
private static final long serialVersionUID = -3972519966755913466L;
{
put(Boolean.class.getName(), true);
put(Character.class.getName(), true);
put(Byte.class.getName(), true);
put(Short.class.getName(), true);
put(Integer.class.getName(), true);
put(Long.class.getName(), true);
put(Float.class.getName(), true);
put(Double.class.getName(), true);
put(Void.class.getName(), true);
}
};
public CustomizeDataDeserializer(Class<?> cl) {
type = cl;
//解析字段中所需要的反序列化器
this.fieldMap = new HashMap<>();
getFieldMap(cl, this.fieldMap);
//解析readReolve方法
readResolve = getReadResolve(cl);
if (readResolve != null) {
readResolve.setAccessible(true);
}
//获取所有的构造函数
Constructor[] constructors = cl.getDeclaredConstructors();
long bestCost = Long.MAX_VALUE;
for (int i = 0; i < constructors.length; i++) {
Class[] param = constructors[i].getParameterTypes();
long cost = 0;
for (int j = 0; j < param.length; j++) {
cost = 4 * cost;
if (Object.class.equals(param[j])) {
cost += 1;
} else if (String.class.equals(param[j])) {
cost += 2;
} else if (int.class.equals(param[j])) {
cost += 3;
} else if (long.class.equals(param[j])) {
cost += 4;
} else if (param[j].isPrimitive()) {
cost += 5;
} else {
cost += 6;
}
}
if (cost < 0 || cost > (1 << 48)) {
cost = 1 << 48;
}
cost += (long) param.length << 48;
if (cost < bestCost) {
constructor = constructors[i];
bestCost = cost;
}
}
//设置构造函数的权限以及获取参数
if (constructor != null) {
constructor.setAccessible(true);
Class[] params = constructor.getParameterTypes();
constructorArgs = new Object[params.length];
for (int i = 0; i < params.length; i++) {
constructorArgs[i] = getParamArg(params[i]);
}
}
}
protected static Object getParamArg(Class cl) {
if (!cl.isPrimitive()) {
return null;
} else if (boolean.class.equals(cl)) {
return Boolean.FALSE;
} else if (byte.class.equals(cl)) {
return new Byte((byte) 0);
} else if (short.class.equals(cl)) {
return new Short((short) 0);
} else if (char.class.equals(cl)) {
return new Character((char) 0);
} else if (int.class.equals(cl)) {
return Integer.valueOf(0);
} else if (long.class.equals(cl)) {
return Long.valueOf(0);
} else if (float.class.equals(cl)) {
return Float.valueOf(0);
} else if (double.class.equals(cl)) {
return Double.valueOf(0);
} else {
throw new UnsupportedOperationException();
}
}
static void logDeserializeError(Field field, Object obj, Object value,
Throwable e)
throws IOException {
String fieldName = (field.getDeclaringClass().getName()
+ "." + field.getName());
if (e instanceof HessianFieldException) {
throw (HessianFieldException) e;
} else if (e instanceof IOException) {
throw new HessianFieldException(fieldName + ": " + e.getMessage(), e);
}
if (value != null) {
throw new HessianFieldException(fieldName + ": " + value.getClass().getName() + " (" + value + ")"
+ " cannot be assigned to '" + field.getType().getName() + "'", e);
} else {
throw new HessianFieldException(fieldName + ": " + field.getType().getName() + " cannot be assigned from null", e);
}
}
@Override
public Class<?> getType() {
return type;
}
@Override
public Object readMap(AbstractHessianInput in)
throws IOException {
try {
//实例化对象出来
Object obj = instantiate();
return readMap(in, obj);
} catch (IOException | RuntimeException e) {
throw e;
} catch (Exception e) {
throw new IOExceptionWrapper(type.getName() + ":" + e.getMessage(), e);
}
}
@Override
public Object readObject(AbstractHessianInput in, String[] fieldNames)
throws IOException {
try {
//实例化对象
Object obj = instantiate();
return readObject(in, obj, fieldNames);
} catch (IOException | RuntimeException e) {
throw e;
} catch (Exception e) {
throw new IOExceptionWrapper(type.getName() + ":" + e.getMessage(), e);
}
}
protected Method getReadResolve(Class<?> cl) {
for (; cl != null; cl = cl.getSuperclass()) {
Method[] methods = cl.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
if (method.getName().equals("readResolve") && method.getParameterTypes().length == 0) {
return method;
}
}
}
return null;
}
public Object readMap(AbstractHessianInput in, Object obj)
throws IOException {
try {
int ref = in.addRef(obj);
while (!in.isEnd()) {
Object key = in.readObject();
FieldDeserializer deser = fieldMap.get(key);
if (deser != null) {
deser.deserialize(in, obj);
} else {
in.readObject();
}
}
in.readMapEnd();
Object resolve = resolve(obj);
if (obj != resolve) {
in.setRef(ref, resolve);
}
return resolve;
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new IOExceptionWrapper(e);
}
}
public Object readObject(AbstractHessianInput in,
Object obj,
String[] fieldNames)
throws IOException {
try {
//将实例化的对象添加到HessianInput引用中去
int ref = in.addRef(obj);
//编译反序列化器,根据对应的数据类型取出
for (int i = 0; i < fieldNames.length; i++) {
String name = fieldNames[i];
FieldDeserializer deser = fieldMap.get(name);
//如果缓存的map中没有找到反序列化器,直接到序列化工厂中查询序列化器
if (deser != null) {
deser.deserialize(in, obj);
} else {
//序列化工厂中查询反序列化器(还是当前类,并且调用readObject()方法)
in.readObject();
}
}
Object resolve = resolve(obj);
if (obj != resolve) {
in.setRef(ref, resolve);
}
return resolve;
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new IOExceptionWrapper(obj.getClass().getName() + ":" + e, e);
}
}
private Object resolve(Object obj)
throws Exception {
try {
if (readResolve != null) {
return readResolve.invoke(obj, new Object[0]);
}
} catch (InvocationTargetException e) {
if (e.getTargetException() != null) {
throw e;
}
}
return obj;
}
protected Object instantiate()
throws Exception {
try {
if (constructor != null) {
//通过构造函数创建实例对象
return constructor.newInstance(constructorArgs);
} else {
return type.newInstance();
}
} catch (Exception e) {
throw new HessianProtocolException("'" + type.getName() + "' could not be instantiated", e);
}
}
//读取实体类中字段的类型,并且创建对应的解析器
protected void getFieldMap(Class<?> cl, Map<String, FieldDeserializer> fieldMap) {
for (; cl != null; cl = cl.getSuperclass()) {
Field[] fields = cl.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
if (Modifier.isTransient(field.getModifiers()) || Modifier.isStatic(field.getModifiers())) {
continue;
} else if (fieldMap.get(field.getName()) != null) {
continue;
}
try {
field.setAccessible(true);
} catch (Throwable e) {
LOG.warning("字段权限设置失败");
}
Class<?> type = field.getType();
FieldDeserializer deser;
if (String.class.equals(type)) {
deser = new StringFieldDeserializer(field);
} else if (byte.class.equals(type)) {
deser = new ByteFieldDeserializer(field);
} else if (short.class.equals(type)) {
deser = new ShortFieldDeserializer(field);
} else if (int.class.equals(type)) {
deser = new IntFieldDeserializer(field);
} else if (long.class.equals(type)) {
deser = new LongFieldDeserializer(field);
} else if (float.class.equals(type)) {
deser = new FloatFieldDeserializer(field);
} else if (double.class.equals(type)) {
deser = new DoubleFieldDeserializer(field);
} else if (boolean.class.equals(type)) {
deser = new BooleanFieldDeserializer(field);
} else if (java.sql.Date.class.equals(type)) {
deser = new SqlDateFieldDeserializer(field);
} else if (java.sql.Timestamp.class.equals(type)) {
deser = new SqlTimestampFieldDeserializer(field);
} else if (java.sql.Time.class.equals(type)) {
deser = new SqlTimeFieldDeserializer(field);
} else if (Map.class.equals(type)
&& field.getGenericType() != field.getType()) {
deser = new ObjectMapFieldDeserializer(field);
} else if (List.class.equals(type)
&& field.getGenericType() != field.getType()) {
deser = new ObjectListFieldDeserializer(field);
} else if (Set.class.equals(type)
&& field.getGenericType() != field.getType()) {
deser = new ObjectSetFieldDeserializer(field);
} else if (JsonNode.class.equals(type)) {
//如果是JsonNode,使用对应的反序列化方式
deser = new JsonNodeDeserializer(field);
} else {
deser = new ObjectFieldDeserializer(field);
}
fieldMap.putIfAbsent(field.getName(), deser);
}
}
}
//抽象反序列化器
abstract static class FieldDeserializer {
abstract void deserialize(AbstractHessianInput in, Object obj)
throws IOException;
}
//对象反序列化器
static class ObjectFieldDeserializer extends FieldDeserializer {
private final Field field;
ObjectFieldDeserializer(Field field) {
this.field = field;
}
@Override
void deserialize(AbstractHessianInput in, Object obj)
throws IOException {
Object value = null;
try {
value = in.readObject(field.getType());
field.set(obj, value);
} catch (Exception e) {
logDeserializeError(field, obj, value, e);
}
}
}
static class BooleanFieldDeserializer extends FieldDeserializer {
private final Field field;
BooleanFieldDeserializer(Field field) {
this.field = field;
}
@Override
void deserialize(AbstractHessianInput in, Object obj)
throws IOException {
boolean value = false;
try {
value = in.readBoolean();
field.setBoolean(obj, value);
} catch (Exception e) {
logDeserializeError(field, obj, value, e);
}
}
}
static class ByteFieldDeserializer extends FieldDeserializer {
private final Field field;
ByteFieldDeserializer(Field field) {
this.field = field;
}
@Override
void deserialize(AbstractHessianInput in, Object obj)
throws IOException {
int value = 0;
try {
value = in.readInt();
field.setByte(obj, (byte) value);
} catch (Exception e) {
logDeserializeError(field, obj, value, e);
}
}
}
static class ShortFieldDeserializer extends FieldDeserializer {
private final Field field;
ShortFieldDeserializer(Field field) {
this.field = field;
}
@Override
void deserialize(AbstractHessianInput in, Object obj)
throws IOException {
int value = 0;
try {
value = in.readInt();
field.setShort(obj, (short) value);
} catch (Exception e) {
logDeserializeError(field, obj, value, e);
}
}
}
static class ObjectMapFieldDeserializer extends FieldDeserializer {
private final Field field;
ObjectMapFieldDeserializer(Field field) {
this.field = field;
}
@Override
void deserialize(AbstractHessianInput in, Object obj)
throws IOException {
Object value = null;
try {
Type[] types = ((ParameterizedType) field.getGenericType()).getActualTypeArguments();
value = in.readObject(field.getType(),
isPrimitive(types[0]) ? (Class<?>) types[0] : null,
isPrimitive(types[1]) ? (Class<?>) types[1] : null
);
field.set(obj, value);
} catch (Exception e) {
logDeserializeError(field, obj, value, e);
}
}
}
static class ObjectListFieldDeserializer extends FieldDeserializer {
private final Field field;
ObjectListFieldDeserializer(Field field) {
this.field = field;
}
@Override
void deserialize(AbstractHessianInput in, Object obj)
throws IOException {
Object value = null;
try {
Type[] types = ((ParameterizedType) field.getGenericType()).getActualTypeArguments();
value = in.readObject(field.getType(),
isPrimitive(types[0]) ? (Class<?>) types[0] : null
);
field.set(obj, value);
} catch (Exception e) {
logDeserializeError(field, obj, value, e);
}
}
}
static class ObjectSetFieldDeserializer extends FieldDeserializer {
private final Field field;
ObjectSetFieldDeserializer(Field field) {
this.field = field;
}
@Override
void deserialize(AbstractHessianInput in, Object obj)
throws IOException {
Object value = null;
try {
Type[] types = ((ParameterizedType) field.getGenericType()).getActualTypeArguments();
value = in.readObject(field.getType(),
isPrimitive(types[0]) ? (Class<?>) types[0] : null
);
field.set(obj, value);
} catch (Exception e) {
logDeserializeError(field, obj, value, e);
}
}
}
static class IntFieldDeserializer extends FieldDeserializer {
private final Field field;
IntFieldDeserializer(Field field) {
this.field = field;
}
@Override
void deserialize(AbstractHessianInput in, Object obj)
throws IOException {
int value = 0;
try {
value = in.readInt();
field.setInt(obj, value);
} catch (Exception e) {
logDeserializeError(field, obj, value, e);
}
}
}
static class LongFieldDeserializer extends FieldDeserializer {
private final Field field;
LongFieldDeserializer(Field field) {
this.field = field;
}
@Override
void deserialize(AbstractHessianInput in, Object obj)
throws IOException {
long value = 0;
try {
value = in.readLong();
field.setLong(obj, value);
} catch (Exception e) {
logDeserializeError(field, obj, value, e);
}
}
}
static class FloatFieldDeserializer extends FieldDeserializer {
private final Field field;
FloatFieldDeserializer(Field field) {
this.field = field;
}
@Override
void deserialize(AbstractHessianInput in, Object obj)
throws IOException {
double value = 0;
try {
value = in.readDouble();
field.setFloat(obj, (float) value);
} catch (Exception e) {
logDeserializeError(field, obj, value, e);
}
}
}
static class DoubleFieldDeserializer extends FieldDeserializer {
private final Field field;
DoubleFieldDeserializer(Field field) {
this.field = field;
}
@Override
void deserialize(AbstractHessianInput in, Object obj)
throws IOException {
double value = 0;
try {
value = in.readDouble();
field.setDouble(obj, value);
} catch (Exception e) {
logDeserializeError(field, obj, value, e);
}
}
}
static class StringFieldDeserializer extends FieldDeserializer {
private final Field field;
StringFieldDeserializer(Field field) {
this.field = field;
}
@Override
void deserialize(AbstractHessianInput in, Object obj)
throws IOException {
String value = null;
try {
value = in.readString();
field.set(obj, value);
} catch (Exception e) {
logDeserializeError(field, obj, value, e);
}
}
}
static class SqlDateFieldDeserializer extends FieldDeserializer {
private final Field field;
SqlDateFieldDeserializer(Field field) {
this.field = field;
}
@Override
void deserialize(AbstractHessianInput in, Object obj)
throws IOException {
java.sql.Date value = null;
try {
java.util.Date date = (java.util.Date) in.readObject();
if (date != null) {
value = new java.sql.Date(date.getTime());
}
field.set(obj, value);
} catch (Exception e) {
logDeserializeError(field, obj, value, e);
}
}
}
static class SqlTimestampFieldDeserializer extends FieldDeserializer {
private final Field field;
SqlTimestampFieldDeserializer(Field field) {
this.field = field;
}
@Override
void deserialize(AbstractHessianInput in, Object obj)
throws IOException {
java.sql.Timestamp value = null;
try {
java.util.Date date = (java.util.Date) in.readObject();
if (date != null) {
value = new java.sql.Timestamp(date.getTime());
}
field.set(obj, value);
} catch (Exception e) {
logDeserializeError(field, obj, value, e);
}
}
}
static class SqlTimeFieldDeserializer extends FieldDeserializer {
private final Field field;
SqlTimeFieldDeserializer(Field field) {
this.field = field;
}
@Override
void deserialize(AbstractHessianInput in, Object obj)
throws IOException {
java.sql.Time value = null;
try {
java.util.Date date = (java.util.Date) in.readObject();
if (date != null) {
value = new java.sql.Time(date.getTime());
}
field.set(obj, value);
} catch (Exception e) {
logDeserializeError(field, obj, value, e);
}
}
}
//JsonNode 数据反序列化方式
static class JsonNodeDeserializer extends FieldDeserializer {
private final Field field;
JsonNodeDeserializer(Field field) {
this.field = field;
}
@Override
void deserialize(AbstractHessianInput in, Object obj) throws IOException {
JsonNode value = null;
try {
//直接将数据读取出来后强制转换成JsonNode,因为Dubbo序列化时会把类型一起写如到流中,读取出来数据会转换成指定的类型
value = (JsonNode) in.readObject();
field.set(obj, value);
} catch (Exception e) {
logDeserializeError(field, obj, value, e);
}
}
}
private static boolean isPrimitive(Type type) {
try {
if (type != null) {
if (type instanceof Class<?>) {
Class<?> clazz = (Class<?>) type;
return clazz.isPrimitive() || PRIMITIVE_TYPE.containsKey(clazz.getName());
}
}
} catch (Exception e) {
// ignore exception
}
return false;
}
}
public class DubboSerializerFactory extends SerializerFactory {
/** SERIALIZER_FACTORY */
public static final SerializerFactory SERIALIZER_FACTORY = new DubboSerializerFactory();
/**
* Fkh dubbo serializer factory
*
* @since 1.3.0
*/
public DubboSerializerFactory() {
}
/**
* Gets default deserializer *
*
* @param cl cl
* @return the default deserializer
* @since 1.3.0
*/
@Override
public Deserializer getDefaultDeserializer(Class cl) {
return new CustomizeDataDeserializer(cl);
}
}
public class DubboSeiralizerObjectInput implements ObjectInput {
/** H 2 i */
private final Hessian2Input h2i;
/**
* Fkh dubbo seiralizer object input
*
* @param is is
* @since 1.3.0
*/
public DubboSeiralizerObjectInput(InputStream is) {
h2i = new Hessian2Input(is);
//设置反序列化工厂
h2i.setSerializerFactory(DubboSerializerFactory.SERIALIZER_FACTORY);
}
/**
* Read bool
*
* @return the boolean
* @throws IOException io exception
* @since 1.3.0
*/
@Override
public boolean readBool() throws IOException {
return this.h2i.readBoolean();
}
/**
* Read byte
*
* @return the byte
* @throws IOException io exception
* @since 1.3.0
*/
@Override
public byte readByte() throws IOException {
return (byte) h2i.readInt();
}
/**
* Read short
*
* @return the short
* @throws IOException io exception
* @since 1.3.0
*/
@Override
public short readShort() throws IOException {
return (short) h2i.readInt();
}
/**
* Read int
*
* @return the int
* @throws IOException io exception
* @since 1.3.0
*/
@Override
public int readInt() throws IOException {
return h2i.readInt();
}
/**
* Read long
*
* @return the long
* @throws IOException io exception
* @since 1.3.0
*/
@Override
public long readLong() throws IOException {
return h2i.readLong();
}
/**
* Read float
*
* @return the float
* @throws IOException io exception
* @since 1.3.0
*/
@Override
public float readFloat() throws IOException {
return (float) h2i.readDouble();
}
/**
* Read double
*
* @return the double
* @throws IOException io exception
* @since 1.3.0
*/
@Override
public double readDouble() throws IOException {
return h2i.readDouble();
}
/**
* Read bytes
*
* @return the byte [ ]
* @throws IOException io exception
* @since 1.3.0
*/
@Override
public byte[] readBytes() throws IOException {
return h2i.readBytes();
}
/**
* Read utf
*
* @return the string
* @throws IOException io exception
* @since 1.3.0
*/
@Override
@SuppressWarnings({"checkstyle:LowerCamelCaseVariableNamingRule",
"PMD.LowerCamelCaseVariableNamingRule"})
public String readUTF() throws IOException {
return h2i.readString();
}
/**
* Read object
*
* @return the object
* @throws IOException io exception
* @since 1.3.0
*/
@Override
public Object readObject() throws IOException {
return h2i.readObject();
}
/**
* Read object
*
* @param parameter
* @param cls cls
* @return the t
* @throws IOException io exception
* @since 1.3.0
*/
@Override
@SuppressWarnings("unchecked")
public <T> T readObject(Class<T> cls) throws IOException {
return (T) h2i.readObject(cls);
}
/**
* Read object
*
* @param parameter
* @param cls cls
* @param type type
* @return the t
* @throws IOException io exception
* @since 1.3.0
*/
@Override
public <T> T readObject(Class<T> cls, Type type) throws IOException {
return readObject(cls);
}
}
这里只实现了反序列化方式,并没有自定义序列化方式
public class CustomizeDataSerialization implements Serialization {
/**
* 每个序列化器都有一个自己的编号
*
* @return the content type id
* @since 1.3.0
*/
@Override
public byte getContentTypeId() {
return 26;
}
/**
* Gets content type *
*
* @return the content type
* @since 1.3.0
*/
@Override
public String getContentType() {
return "x-application/customize";
}
/**
* 使用hessian的序列化方式,暂时不需要自定义
*
* @param url url
* @param output output
* @return the object output
* @throws IOException io exception
* @since 1.3.0
*/
@Override
public ObjectOutput serialize(URL url, OutputStream output) throws IOException {
return new Hessian2ObjectOutput(output);
}
/**
* Deserialize
*
* @param url url
* @param input input
* @return the object input
* @throws IOException io exception
* @since 1.3.0
*/
@Override
public ObjectInput deserialize(URL url, InputStream input) throws IOException {
return new DubboSeiralizerObjectInput(input);
}
}
在resources文件下创建路径:
内容:序列化名称+类路径
customize=com.xxx.client.dubbo.serialization.CustomizeDataSerialization
配置文件中引用就可以了
server:
port: 18104
dubbo:
protocol:
port: 28033
provider:
serialization: customize #自定义序列化方式