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 6 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,129 @@
/*
* 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 类型不为 char[] 时需要使用
* @return
*/
private static boolean judgeAvailability() {
Field field;
try {
field = String.class.getDeclaredField("value");
} catch (Throwable t) {
return false;

Check warning on line 33 in src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java#L32-L33

Added lines #L32 - L33 were not covered by tests
}

if (char[].class.equals(field.getType())) {
return false;
}

return true;

Check warning on line 40 in src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java#L40

Added line #L40 was not covered by tests
}

public static boolean isEnable() {
return ENABLE;
}

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

Check warning on line 49 in src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java#L48-L49

Added lines #L48 - L49 were not covered by tests

@Override
protected HashMap getFieldMap(Class cl) {
HashMap fieldMap = super.getFieldMap(cl);
Field valueField = null;

Check warning on line 54 in src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java#L53-L54

Added lines #L53 - L54 were not covered by tests
try {
valueField = cl.getSuperclass().getDeclaredField("value");
valueField.setAccessible(true);
} catch (Throwable t) {
log.log(Level.WARNING, "get value field failed", t);
return fieldMap;
}

Check warning on line 61 in src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java#L56-L61

Added lines #L56 - L61 were not covered by tests

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

Check warning on line 64 in src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java#L63-L64

Added lines #L63 - L64 were not covered by tests
}

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

StringBuilderValueFieldDeserializer(Field field) {
_field = field;
}

Check warning on line 76 in src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java#L74-L76

Added lines #L74 - L76 were not covered by tests

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

Check warning on line 80 in src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java#L80

Added line #L80 was not covered by tests

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

Check warning on line 84 in src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java#L84

Added line #L84 was not covered by tests
if (value == null) {
return;

Check warning on line 86 in src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java#L86

Added line #L86 was not covered by tests
}

// 理论上获取到的值有两种情况: String 或者 byte[]
if (value instanceof String) {
byte[] res = hessianString2Bytes((String) value);
_field.set(obj, res);

Check warning on line 92 in src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java#L91-L92

Added lines #L91 - L92 were not covered by tests
} else if (value instanceof byte[]) {
_field.set(obj, value);

Check warning on line 94 in src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java#L94

Added line #L94 was not covered by tests
} else {
throw new UnsupportedEncodingException("未知的编码类型" + value.getClass());

Check warning on line 96 in src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java#L96

Added line #L96 was not covered by tests
}
} catch (Exception e) {
logDeserializeError(_field, obj, value, e);
}
}

Check warning on line 101 in src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java#L98-L101

Added lines #L98 - L101 were not covered by tests

/**
* 按照 hessian 序列化的处理方式将 String 还原为 byte[]
* {@link Hessian2Output#printString(java.lang.String, int, int)}
* @param str
* @return
*/
private byte[] hessianString2Bytes(String str) {
byte[] buffer = new byte[str.length()];

Check warning on line 110 in src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java#L110

Added line #L110 was not covered by tests
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);

Check warning on line 112 in src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java#L112

Added line #L112 was not covered by tests

if (ch < 0x80)
buffer[i] = (byte) (ch);

Check warning on line 115 in src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java#L115

Added line #L115 was not covered by tests
else if (ch < 0x800) {
buffer[i] = (byte) (0xc0 + ((ch >> 6) & 0x1f));
buffer[i] = (byte) (0x80 + (ch & 0x3f));

Check warning on line 118 in src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java#L117-L118

Added lines #L117 - L118 were not covered by tests
} else {
buffer[i] = (byte) (0xe0 + ((ch >> 12) & 0xf));
buffer[i] = (byte) (0x80 + ((ch >> 6) & 0x3f));
buffer[i] = (byte) (0x80 + (ch & 0x3f));

Check warning on line 122 in src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java#L120-L122

Added lines #L120 - L122 were not covered by tests
}
}
return buffer;

Check warning on line 125 in src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/AbstractStringBuilderDeserializer.java#L125

Added line #L125 was not covered by tests
}
}

}
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.INFO, "unable to set field {} accessible", field.getName());

Check warning on line 30 in src/main/java/com/caucho/hessian/io/AbstractStringBuilderSerializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/AbstractStringBuilderSerializer.java#L29-L30

Added lines #L29 - L30 were not covered by tests
EvenLjj marked this conversation as resolved.
Show resolved Hide resolved
}
}

}

@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);

Check warning on line 66 in src/main/java/com/caucho/hessian/io/AbstractStringBuilderSerializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/AbstractStringBuilderSerializer.java#L64-L66

Added lines #L64 - L66 were not covered by tests

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

Check warning on line 70 in src/main/java/com/caucho/hessian/io/AbstractStringBuilderSerializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/AbstractStringBuilderSerializer.java#L68-L70

Added lines #L68 - L70 were not covered by tests
}
}

/**
* 常规字段以 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);

Check warning on line 87 in src/main/java/com/caucho/hessian/io/AbstractStringBuilderSerializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/AbstractStringBuilderSerializer.java#L86-L87

Added lines #L86 - L87 were not covered by tests
}

out.writeObject(value);
}

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

Check warning on line 102 in src/main/java/com/caucho/hessian/io/AbstractStringBuilderSerializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/AbstractStringBuilderSerializer.java#L101-L102

Added lines #L101 - L102 were not covered by tests
}

if (char[].class.equals(field.getType())) {
return false;
}

return true;

Check warning on line 109 in src/main/java/com/caucho/hessian/io/AbstractStringBuilderSerializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/AbstractStringBuilderSerializer.java#L109

Added line #L109 was not covered by tests
}
}
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 @@
addCurrencySupport();
}

addAbstractStringBuilderSupport();

}

/**
Expand Down Expand Up @@ -740,6 +742,24 @@
}
}

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

Check warning on line 749 in src/main/java/com/caucho/hessian/io/SerializerFactory.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/SerializerFactory.java#L748-L749

Added lines #L748 - L749 were not covered by tests
}

if (AbstractStringBuilderDeserializer.isEnable()) {
_staticDeserializerMap.put(StringBuilder.class, new AbstractStringBuilderDeserializer(

Check warning on line 753 in src/main/java/com/caucho/hessian/io/SerializerFactory.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/SerializerFactory.java#L753

Added line #L753 was not covered by tests
StringBuilder.class));
_staticDeserializerMap.put(StringBuffer.class,

Check warning on line 755 in src/main/java/com/caucho/hessian/io/SerializerFactory.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/SerializerFactory.java#L755

Added line #L755 was not covered by tests
new AbstractStringBuilderDeserializer(StringBuffer.class));
}
} catch (Throwable t) {
log.info(String.valueOf(t.getCause()));

Check warning on line 759 in src/main/java/com/caucho/hessian/io/SerializerFactory.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/SerializerFactory.java#L758-L759

Added lines #L758 - L759 were not covered by tests
}
}

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 @@

@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 @@
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);

Check warning on line 112 in src/main/java/com/caucho/hessian/io/throwable/StackTraceElementSerializer.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/caucho/hessian/io/throwable/StackTraceElementSerializer.java#L112

Added line #L112 was not covered by tests
}
}
List<Field> fields = new ArrayList<Field>();
fields.addAll(primitiveFields);
fields.addAll(compoundFields);
return fields.toArray(new Field[0]);
}
}
Loading
Loading