Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/sb compatible #107

Merged
merged 12 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -93,17 +93,27 @@ public void writeInstance(Object obj, AbstractHessianOutput out)
* @return
*/
protected Field[] getFieldsForSerialize(Class cl) {
List<Field> fields = new ArrayList<Field>();
ArrayList primitiveFields = new ArrayList();
ArrayList compoundFields = new ArrayList();
for (; cl != null; cl = cl.getSuperclass()) {
Field[] originFields = cl.getDeclaredFields();
for (int i = 0; i < originFields.length; i++) {
Field field = originFields[i];
if (Modifier.isTransient(field.getModifiers()) || Modifier.isStatic(field.getModifiers())) {
continue;
}
fields.add(field);

if (field.getType().isPrimitive() ||
field.getType().getName().startsWith("java.lang.") &&
!field.getType().equals(Object.class))
primitiveFields.add(field);
else
compoundFields.add(field);
}
}
List<Field> fields = new ArrayList<Field>();
fields.addAll(primitiveFields);
fields.addAll(compoundFields);
return fields.toArray(new Field[0]);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
/*
* Ant Group
* Copyright (c) 2004-2023 All Rights Reserved.
*/
package com.caucho.hessian.io;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
*
* @author junyuan
* @version AbstractStringBuilderDeserializer.java, v 0.1 2023年10月20日 11:31 junyuan Exp $
*/
public class AbstractStringBuilderDeserializer extends JavaDeserializer {
private static final Logger log = Logger.getLogger(AbstractStringBuilderDeserializer.class.getName());

private static final boolean ENABLE = judgeAvailability();
/** String 的 value field, 用以判断是否需要用当前 deserializer */
private static Field stringValueField;
/** String 的 coder field, 用以从中间 String 变量中获取 coder */
private static Field stringCoderField;

static {
try {
stringCoderField = String.class.getDeclaredField("coder");
stringCoderField.setAccessible(true);
} catch (Throwable t) {
log.log(Level.WARNING,
"coder field not found or not accessible, will skip coder check, error is " + t.getMessage());
}
}

/**
* 判断是否要使用该反序列化器, 当 String.value 类型不为 char[] 时需要使用
* @return
*/
private static boolean judgeAvailability() {
try {
stringValueField = String.class.getDeclaredField("value");
stringValueField.setAccessible(true);
} catch (Throwable t) {
return false;
}

if (byte[].class.equals(stringValueField.getType())) {
return true;
}

return false;
}

public static boolean isEnable() {
return ENABLE;
}

public AbstractStringBuilderDeserializer(Class<?> cl) {
super(cl);
}

@Override
protected HashMap getFieldMap(Class cl) {
HashMap fieldMap = super.getFieldMap(cl);
Field valueField = null;
valueField = getAbstractStringBuilderField(cl, "value");
if (valueField == null) {
log.log(Level.WARNING, "get value field failed");
return fieldMap;
}

Field coderField = null;
if (fieldMap.containsKey("coder")) {
coderField = getAbstractStringBuilderField(cl, "coder");
}

fieldMap.put("value", new StringBuilderValueFieldDeserializer(valueField, coderField));
return fieldMap;
}

/**
* 获取 AbstractStingBuilder 类内的 field
* @param cl
* @param fieldName
* @return
*/
private Field getAbstractStringBuilderField(Class cl, String fieldName) {
Field field = null;
try {
field = cl.getSuperclass().getDeclaredField(fieldName);
field.setAccessible(true);
} catch (Throwable t) {
log.log(Level.WARNING, "get " + fieldName + " field failed", t);
return null;
}
return field;
}

/**
* 针对 value field 定制的 field deserializer
* 读取 value field 时, 根据传入数据进行读取, 读取到值后进行转换
*/
static class StringBuilderValueFieldDeserializer extends FieldDeserializer {
/**
* 这个 _field 会是 AbstractStringBuilder.value
*/
private final Field _field;

/**
* _coderField 会是 AbstractStringBuilder.coder 字段
*/
private final Field _coderField;

StringBuilderValueFieldDeserializer(Field value, Field coder) {
_field = value;
_coderField = coder;
}

@Override
void deserialize(AbstractHessianInput in, Object obj) throws IOException {
Object value = null;

try {
// hessian 在读取 char 时会用 utf-8 编码
value = in.readObject();
if (value == null) {
return;
}

// 理论上获取到的值有两种情况: String 或者 byte[]
if (value instanceof String) {
dealWithStringValue((String) value, obj);
} else if (value instanceof byte[]) {
_field.set(obj, value);
} else {
throw new UnsupportedEncodingException("未知的编码类型" + value.getClass());
}
} catch (Exception e) {
logDeserializeError(_field, obj, value, e);
}
}

/**
* 如果读取到的是 String, 需要通过 String.coder 进行编码
*/
public void dealWithStringValue(String value, Object obj) {
try {
byte[] res = (byte[]) stringValueField.get(value);
_field.set(obj, res);

if (stringCoderField != null) {
byte coder = (byte) stringCoderField.getByte(value);
_coderField.set(obj, coder);
}
} catch (Throwable t) {

}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Ant Group
* Copyright (c) 2004-2023 All Rights Reserved.
*/
package com.caucho.hessian.io;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.logging.Level;

/**
*
* @author junyuan
* @version AbstractStringBuilderSerializer.java, v 0.1 2023年10月20日 11:31 junyuan Exp $
*/
public class AbstractStringBuilderSerializer extends AbstractFieldAdaptorSerializer {

private static final boolean ENABLE = judgeAvailability();

public static boolean isEnable() {
return ENABLE;
}

public AbstractStringBuilderSerializer(Class cl) {
super(cl);
for (Field field : _fields) {
try {
field.setAccessible(true);
} catch (Throwable t) {
log.log(Level.WARNING, "unable to set field {} accessible", field.getName());
}
}

}

@Override
protected void serializeField(AbstractHessianOutput out, Object obj, Field field)
throws IOException {
if ("value".equals(field.getName())) {
serializeValueArray(out, obj);
} else {
serializeNormalField(out, obj, field);
}
}

/**
* 将底层 value 数组转为 char数组, 并以 writeString 方式进行序列化
* 保证序列化结果与普通 JavaSerializer 保持一致
*
* @param out
* @param obj
* @throws IOException
*/
protected void serializeValueArray(AbstractHessianOutput out, Object obj)
throws IOException {
if (obj instanceof StringBuilder) {
StringBuilder sb = (StringBuilder) obj;
// 要用实际底层 value 数据的长度以保持一致
char[] dst = new char[sb.capacity()];
sb.getChars(0, sb.length(), dst, 0);

out.writeString(dst, 0, dst.length);
} else if (obj instanceof StringBuffer) {
StringBuffer sb = (StringBuffer) obj;
char[] dst = new char[sb.capacity()];
sb.getChars(0, sb.length(), dst, 0);

out.writeString(dst, 0, dst.length);
} else {
throw new UnsupportedOperationException("only support AbstractStringBuilder but got " + obj.getClass());
}
}

/**
* 常规字段以 object 的方式序列化
* @param out
* @param obj
* @param field
* @throws IOException
*/
private void serializeNormalField(AbstractHessianOutput out, Object obj, Field field) throws IOException {
Object value = null;

try {
value = field.get(obj);
} catch (IllegalAccessException e) {
log.log(Level.FINE, e.toString(), e);
}

out.writeObject(value);
}

/**
* 判断是否要使用该反序列化器, 当 String.value 类型为 byte[] 时需要使用
* @return
*/
private static boolean judgeAvailability() {
Field field = null;
try {
field = String.class.getDeclaredField("value");
} catch (Throwable t) {
return false;
}

if (byte[].class.equals(field.getType())) {
return true;
}

return false;
}
}
20 changes: 20 additions & 0 deletions src/main/java/com/caucho/hessian/io/SerializerFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,8 @@ protected static void addBasic(Class cl, String typeName, int type)
addCurrencySupport();
}

addAbstractStringBuilderSupport();

}

/**
Expand Down Expand Up @@ -740,6 +742,24 @@ protected static void addCurrencySupport() {
}
}

protected static void addAbstractStringBuilderSupport() {
try {
if (AbstractStringBuilderSerializer.isEnable()) {
_staticSerializerMap.put(StringBuilder.class, new AbstractStringBuilderSerializer(StringBuilder.class));
_staticSerializerMap.put(StringBuffer.class, new AbstractStringBuilderSerializer(StringBuffer.class));
}

if (AbstractStringBuilderDeserializer.isEnable()) {
_staticDeserializerMap.put(StringBuilder.class, new AbstractStringBuilderDeserializer(
StringBuilder.class));
_staticDeserializerMap.put(StringBuffer.class,
new AbstractStringBuilderDeserializer(StringBuffer.class));
}
} catch (Throwable t) {
log.info(String.valueOf(t.getCause()));
}
}

private static boolean isZoneId(Class cl) {
try {
return isHigherThanJdk8 && Class.forName("java.time.ZoneId").isAssignableFrom(cl);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ protected void serializeField(AbstractHessianOutput out, Object obj, Field field

@Override
protected Field[] getFieldsForSerialize(Class cl) {
List<Field> fields = new ArrayList<Field>();
ArrayList primitiveFields = new ArrayList();
ArrayList compoundFields = new ArrayList();
for (; cl != null; cl = cl.getSuperclass()) {
Field[] originFields = cl.getDeclaredFields();
for (int i = 0; i < originFields.length; i++) {
Expand All @@ -102,9 +103,18 @@ protected Field[] getFieldsForSerialize(Class cl) {
if ("format".equals(field.getName())) {
continue;
}
fields.add(field);

if (field.getType().isPrimitive() ||
field.getType().getName().startsWith("java.lang.") &&
!field.getType().equals(Object.class))
primitiveFields.add(field);
else
compoundFields.add(field);
}
}
List<Field> fields = new ArrayList<Field>();
fields.addAll(primitiveFields);
fields.addAll(compoundFields);
return fields.toArray(new Field[0]);
}
}
Loading