开发完成写出功能。现在正在开发读取功能。
parent
c1882f5362
commit
5862c362f3
10
pom.xml
10
pom.xml
|
@ -12,6 +12,8 @@
|
|||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
</properties>
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
|
@ -69,14 +71,6 @@
|
|||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>16</source>
|
||||
<target>16</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
|
@ -1,166 +0,0 @@
|
|||
package com.jfirer.se;
|
||||
|
||||
import com.jfirer.se.serializer.Serializer;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class ClassInfo
|
||||
{
|
||||
private int classId = ClassInfoResolver.NO_CLASS_ID;
|
||||
private Class clazz;
|
||||
private String className;
|
||||
private Serializer serializer;
|
||||
private JfireSE jfireSE;
|
||||
private Object[] tracking;
|
||||
private boolean refTracking;
|
||||
private int refTrackingIndex = 0;
|
||||
|
||||
public void writeBytes(ByteArray byteArray, Object instance, boolean knownClazz)
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
return;
|
||||
}
|
||||
if (serializer == null)
|
||||
{
|
||||
serializer = jfireSE.getSerializer(clazz);
|
||||
}
|
||||
if (knownClazz)
|
||||
{
|
||||
if (refTracking)
|
||||
{
|
||||
int tracking = addTracking(instance);
|
||||
if (tracking == -1)
|
||||
{
|
||||
byteArray.put((byte) 7);
|
||||
serializer.writeBytes(byteArray, instance);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put((byte) 9);
|
||||
byteArray.writeVarInt(tracking);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
jfireSE.incrDepth();
|
||||
byteArray.put((byte) 8);
|
||||
serializer.writeBytes(byteArray, instance);
|
||||
jfireSE.reduceDepth();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (refTracking)
|
||||
{
|
||||
if (classId == ClassInfoResolver.NO_CLASS_ID)
|
||||
{
|
||||
byteArray.put((byte) 1);
|
||||
byteArray.writeString(className);
|
||||
jfireSE.getClassId(this);
|
||||
addTracking(instance);
|
||||
serializer.writeBytes(byteArray, instance);
|
||||
}
|
||||
else
|
||||
{
|
||||
int tracking = addTracking(instance);
|
||||
if (tracking == -1)
|
||||
{
|
||||
byteArray.put((byte) 4);
|
||||
byteArray.writeVarInt(classId);
|
||||
serializer.writeBytes(byteArray, instance);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put((byte) 6);
|
||||
byteArray.writeVarInt(classId);
|
||||
byteArray.writeVarInt(tracking);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
jfireSE.incrDepth();
|
||||
if (classId == ClassInfoResolver.NO_CLASS_ID)
|
||||
{
|
||||
byteArray.put((byte) 2);
|
||||
byteArray.writeString(className);
|
||||
jfireSE.getClassId(this);
|
||||
serializer.writeBytes(byteArray, instance);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put((byte) 5);
|
||||
byteArray.writeVarInt(classId);
|
||||
serializer.writeBytes(byteArray, instance);
|
||||
}
|
||||
jfireSE.reduceDepth();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void reset(int tempClassIdStart)
|
||||
{
|
||||
if (classId < tempClassIdStart)
|
||||
{
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
classId = ClassInfoResolver.NO_CLASS_ID;
|
||||
}
|
||||
refTrackingIndex = 0;
|
||||
}
|
||||
|
||||
public int addTracking(Object instance)
|
||||
{
|
||||
if (tracking == null)
|
||||
{
|
||||
tracking = new Object[4];
|
||||
}
|
||||
for (int i = 0; i < refTrackingIndex; i++)
|
||||
{
|
||||
if (tracking[i] == instance)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
if (refTrackingIndex == tracking.length)
|
||||
{
|
||||
Object[] newRefTracking = new Object[tracking.length * 2];
|
||||
System.arraycopy(tracking, 0, newRefTracking, 0, tracking.length);
|
||||
tracking = newRefTracking;
|
||||
}
|
||||
tracking[refTrackingIndex++] = instance;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析的是序列化协议中序号 3 的内容
|
||||
*
|
||||
* @param byteArray
|
||||
* @param refTracking
|
||||
* @return
|
||||
*/
|
||||
public Object readBytes(ByteArray byteArray, boolean refTracking)
|
||||
{
|
||||
if (serializer == null)
|
||||
{
|
||||
serializer = jfireSE.getSerializer(clazz);
|
||||
}
|
||||
Object instance = serializer.readBytes(byteArray);
|
||||
if (refTracking)
|
||||
{
|
||||
addTracking(instance);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public Object getTracking(int instanceId)
|
||||
{
|
||||
return tracking[instanceId];
|
||||
}
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
package com.jfirer.se;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ClassInfoResolver
|
||||
{
|
||||
public static int NO_CLASS_ID = 0;
|
||||
private Map<Class, ClassInfo> store = new IdentityHashMap<>();
|
||||
private int nextTempClassId = 1;
|
||||
private int tempClassIdStart = 1;
|
||||
private ClassInfo[] tracking = new ClassInfo[32];
|
||||
private JfireSE jfireSE;
|
||||
|
||||
public ClassInfoResolver(JfireSE jfireSE)
|
||||
{
|
||||
this.jfireSE = jfireSE;
|
||||
registerClass(int[].class);
|
||||
registerClass(long[].class);
|
||||
registerClass(short[].class);
|
||||
registerClass(float[].class);
|
||||
registerClass(double[].class);
|
||||
registerClass(char[].class);
|
||||
registerClass(boolean[].class);
|
||||
registerClass(byte[].class);
|
||||
registerClass(String[].class);
|
||||
registerClass(Integer[].class);
|
||||
registerClass(Long[].class);
|
||||
registerClass(Short[].class);
|
||||
registerClass(Float[].class);
|
||||
registerClass(Double[].class);
|
||||
registerClass(Character[].class);
|
||||
registerClass(Boolean[].class);
|
||||
registerClass(ByteArray[].class);
|
||||
registerClass(String.class);
|
||||
registerClass(Integer.class);
|
||||
registerClass(Long.class);
|
||||
registerClass(Short.class);
|
||||
registerClass(Float.class);
|
||||
registerClass(Double.class);
|
||||
registerClass(Character.class);
|
||||
registerClass(Boolean.class);
|
||||
registerClass(ByteArray.class);
|
||||
registerClass(Date.class);
|
||||
registerClass(java.sql.Date.class);
|
||||
registerClass(LocalDateTime.class);
|
||||
}
|
||||
|
||||
public void getClassId(ClassInfo classInfo)
|
||||
{
|
||||
if (nextTempClassId > tracking.length)
|
||||
{
|
||||
ClassInfo[] newTracking = new ClassInfo[tracking.length << 1];
|
||||
System.arraycopy(tracking, 0, newTracking, 0, tracking.length);
|
||||
tracking = newTracking;
|
||||
}
|
||||
tracking[nextTempClassId] = classInfo;
|
||||
classInfo.setClassId(nextTempClassId);
|
||||
nextTempClassId += 1;
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
for (int i = 1; i < nextTempClassId; i++)
|
||||
{
|
||||
tracking[i].reset(tempClassIdStart);
|
||||
}
|
||||
nextTempClassId = tempClassIdStart;
|
||||
}
|
||||
|
||||
public ClassInfo getClassInfo(Class clazz)
|
||||
{
|
||||
ClassInfo classInfo = store.get(clazz);
|
||||
if (classInfo == null)
|
||||
{
|
||||
classInfo = new ClassInfo().setClassName(clazz.getName()).setJfireSE(jfireSE).setRefTracking(jfireSE.isRefTracking()).setClazz(clazz);
|
||||
store.put(clazz, classInfo);
|
||||
return classInfo;
|
||||
}
|
||||
return classInfo;
|
||||
}
|
||||
|
||||
public void registerClass(Class clazz)
|
||||
{
|
||||
ClassInfo classInfo = getClassInfo(clazz);
|
||||
if (classInfo == null)
|
||||
{
|
||||
classInfo = new ClassInfo().setClassName(clazz.getName()).setJfireSE(jfireSE).setRefTracking(jfireSE.isRefTracking()).setClazz(clazz);
|
||||
store.put(clazz, classInfo);
|
||||
}
|
||||
for (int i = 1; i < tempClassIdStart; i++)
|
||||
{
|
||||
if (tracking[i].getClazz() == clazz)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (tempClassIdStart > tracking.length)
|
||||
{
|
||||
ClassInfo[] newTracking = new ClassInfo[tracking.length << 1];
|
||||
System.arraycopy(tracking, 0, newTracking, 0, tracking.length);
|
||||
tracking = newTracking;
|
||||
}
|
||||
tracking[tempClassIdStart] = classInfo;
|
||||
classInfo.setClassId(tempClassIdStart);
|
||||
tempClassIdStart += 1;
|
||||
nextTempClassId = tempClassIdStart;
|
||||
}
|
||||
|
||||
public ClassInfo getClassInfo(int classId)
|
||||
{
|
||||
return tracking[classId];
|
||||
}
|
||||
}
|
|
@ -1,140 +0,0 @@
|
|||
package com.jfirer.se;
|
||||
|
||||
import com.jfirer.se.serializer.Serializer;
|
||||
import com.jfirer.se.serializer.SerializerResolver;
|
||||
import lombok.Getter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Accessors(chain = true)
|
||||
public class JfireSE
|
||||
{
|
||||
public static final byte NULL = 0;
|
||||
public static final byte NOT_NULL = 1;
|
||||
@Getter
|
||||
private boolean refTracking = true;
|
||||
private SerializerResolver serializerResolver = new SerializerResolver();
|
||||
private ClassInfoResolver classInfoResolver = new ClassInfoResolver(this);
|
||||
private int depth = 1;
|
||||
private Map<String, Class<?>> classNameMap = new HashMap<>();
|
||||
private ByteArray byteArray = new ByteArray(1024);
|
||||
|
||||
public Serializer getSerializer(Class clazz)
|
||||
{
|
||||
return serializerResolver.getSerializer(clazz, this);
|
||||
}
|
||||
|
||||
public ClassInfo getClassInfo(Class clazz)
|
||||
{
|
||||
return classInfoResolver.getClassInfo(clazz);
|
||||
}
|
||||
|
||||
public ClassInfo getClassInfo(String className)
|
||||
{
|
||||
Class<?> clazz = classNameMap.computeIfAbsent(className, name -> {
|
||||
try
|
||||
{
|
||||
return Class.forName(name);
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
ClassInfo classInfo = getClassInfo(clazz);
|
||||
getClassId(classInfo);
|
||||
return classInfo;
|
||||
}
|
||||
|
||||
public void getClassId(ClassInfo classInfo)
|
||||
{
|
||||
classInfoResolver.getClassId(classInfo);
|
||||
}
|
||||
|
||||
public void incrDepth()
|
||||
{
|
||||
if (depth++ > 256)
|
||||
{
|
||||
throw new IllegalStateException("序列化深度超过256,可能存在循环引用,请开启循环引用设置");
|
||||
}
|
||||
}
|
||||
|
||||
public void reduceDepth()
|
||||
{
|
||||
depth--;
|
||||
}
|
||||
|
||||
public byte[] writeBytes(Object instance)
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
byteArray.put(NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
ClassInfo classInfo = getClassInfo(instance.getClass());
|
||||
classInfo.writeBytes(byteArray, instance, false);
|
||||
classInfoResolver.reset();
|
||||
}
|
||||
byte[] result = byteArray.toArray();
|
||||
byteArray.setWriterIndex(0);
|
||||
return result;
|
||||
}
|
||||
|
||||
public Object readBytes(byte[] bytes)
|
||||
{
|
||||
return readBytes(new ByteArray(bytes));
|
||||
}
|
||||
|
||||
public Object readBytes(ByteArray byteArray)
|
||||
{
|
||||
byte flag = byteArray.get();
|
||||
switch (flag)
|
||||
{
|
||||
case 0 -> {return null;}
|
||||
case 1 ->
|
||||
{
|
||||
String className = byteArray.readString();
|
||||
ClassInfo classInfo = getClassInfo(className);
|
||||
return classInfo.readBytes(byteArray, true);
|
||||
}
|
||||
case 2 ->
|
||||
{
|
||||
String className = byteArray.readString();
|
||||
ClassInfo classInfo = getClassInfo(className);
|
||||
return classInfo.readBytes(byteArray, false);
|
||||
}
|
||||
case 3, 7, 8, 9 ->
|
||||
{
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
case 4 ->
|
||||
{
|
||||
int classId = byteArray.readVarInt();
|
||||
ClassInfo classInfo = classInfoResolver.getClassInfo(classId);
|
||||
return classInfo.readBytes(byteArray, true);
|
||||
}
|
||||
case 5 ->
|
||||
{
|
||||
int classId = byteArray.readVarInt();
|
||||
ClassInfo classInfo = classInfoResolver.getClassInfo(classId);
|
||||
return classInfo.readBytes(byteArray, false);
|
||||
}
|
||||
case 6 ->
|
||||
{
|
||||
int classId = byteArray.readVarInt();
|
||||
int instanceId = byteArray.readVarInt();
|
||||
ClassInfo classInfo = classInfoResolver.getClassInfo(classId);
|
||||
return classInfo.getTracking(instanceId);
|
||||
}
|
||||
default -> throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
public void registerClass(Class clazz)
|
||||
{
|
||||
classInfoResolver.registerClass(clazz);
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package com.jfirer.se.serializer;
|
||||
|
||||
import com.jfirer.se.ByteArray;
|
||||
|
||||
public interface Serializer
|
||||
{
|
||||
void writeBytes(ByteArray byteArray, Object instance);
|
||||
|
||||
Object readBytes(ByteArray byteArray);
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
package com.jfirer.se.serializer;
|
||||
|
||||
import com.jfirer.se.JfireSE;
|
||||
import com.jfirer.se.serializer.impl.ArraySerializer;
|
||||
import com.jfirer.se.serializer.impl.ObjectSerializer;
|
||||
import io.github.karlatemp.unsafeaccessor.Unsafe;
|
||||
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class SerializerResolver
|
||||
{
|
||||
private Map<Class, Serializer> store = new IdentityHashMap<>();
|
||||
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
|
||||
|
||||
public SerializerResolver()
|
||||
{
|
||||
}
|
||||
|
||||
public Serializer getSerializer(Class clazz, JfireSE jfireSE)
|
||||
{
|
||||
Serializer serializer = store.get(clazz);
|
||||
if (serializer != null)
|
||||
{
|
||||
return serializer;
|
||||
}
|
||||
if (clazz.isArray())
|
||||
{
|
||||
serializer = new ArraySerializer(clazz, jfireSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
serializer = new ObjectSerializer(clazz, jfireSE);
|
||||
}
|
||||
store.put(clazz, serializer);
|
||||
return serializer;
|
||||
}
|
||||
|
||||
public void registerSerializer(Class clazz, Serializer serializer)
|
||||
{
|
||||
store.put(clazz, serializer);
|
||||
}
|
||||
|
||||
private static int getShift(int value)
|
||||
{
|
||||
int count = 0;
|
||||
while (value != 0)
|
||||
{
|
||||
count++;
|
||||
value >>= 1;
|
||||
}
|
||||
return count - 1;
|
||||
}
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
package com.jfirer.se.serializer.impl;
|
||||
|
||||
import com.jfirer.se.ByteArray;
|
||||
import com.jfirer.se.ClassInfo;
|
||||
import com.jfirer.se.JfireSE;
|
||||
import com.jfirer.se.serializer.Serializer;
|
||||
import io.github.karlatemp.unsafeaccessor.Unsafe;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class ArraySerializer implements Serializer
|
||||
{
|
||||
private Class componentType;
|
||||
private int arrayBaseOffset;
|
||||
private int arrayIndexScale;
|
||||
private int arrayIndexScaleShift;
|
||||
private boolean componentTypeFinal;
|
||||
private ClassInfo classInfoOfComponentTypeFinal;
|
||||
private ClassInfo cachedClassInfo;
|
||||
private JfireSE jfireSE;
|
||||
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
|
||||
|
||||
public ArraySerializer(Class clazz, JfireSE jfireSE)
|
||||
{
|
||||
this.jfireSE = jfireSE;
|
||||
componentType = clazz.getComponentType();
|
||||
arrayBaseOffset = UNSAFE.arrayBaseOffset(clazz);
|
||||
arrayIndexScale = UNSAFE.arrayIndexScale(clazz);
|
||||
arrayIndexScaleShift = arrayIndexScale == 4 ? 2 : 3;
|
||||
componentTypeFinal = Modifier.isFinal(componentType.getModifiers());
|
||||
if (componentTypeFinal)
|
||||
{
|
||||
classInfoOfComponentTypeFinal = jfireSE.getClassInfo(componentType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBytes(ByteArray byteArray, Object instance)
|
||||
{
|
||||
int length = ((Object[]) instance).length;
|
||||
byteArray.writeVarInt(length);
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
Object element = UNSAFE.getReference(instance, arrayBaseOffset + ((long) i << arrayIndexScaleShift));
|
||||
if (element == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (componentTypeFinal)
|
||||
{
|
||||
classInfoOfComponentTypeFinal.writeBytes(byteArray, element, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cachedClassInfo != null && cachedClassInfo.getClazz() == element.getClass())
|
||||
{
|
||||
cachedClassInfo.writeBytes(byteArray, element, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
cachedClassInfo = jfireSE.getClassInfo(element.getClass());
|
||||
cachedClassInfo.writeBytes(byteArray, element, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readBytes(ByteArray byteArray)
|
||||
{
|
||||
int length = byteArray.readVarInt();
|
||||
Object array = Array.newInstance(componentType, length);
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
if (componentTypeFinal)
|
||||
{
|
||||
int flag = byteArray.readVarInt();
|
||||
switch (flag)
|
||||
{
|
||||
case JfireSE.NULL -> UNSAFE.putReference(array, arrayBaseOffset + ((long) i << arrayIndexScaleShift), null);
|
||||
case 7 -> UNSAFE.putReference(array, arrayBaseOffset + ((long) i << arrayIndexScaleShift), classInfoOfComponentTypeFinal.readBytes(byteArray, true));
|
||||
case 8 -> UNSAFE.putReference(array, arrayBaseOffset + ((long) i << arrayIndexScaleShift), classInfoOfComponentTypeFinal.readBytes(byteArray, false));
|
||||
case 9 -> UNSAFE.putReference(array, arrayBaseOffset + ((long) i << arrayIndexScaleShift), classInfoOfComponentTypeFinal.getTracking(byteArray.readVarInt()));
|
||||
default -> throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UNSAFE.putReference(array, arrayBaseOffset + ((long) i << arrayIndexScaleShift), jfireSE.readBytes(byteArray));
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
|
@ -1,440 +0,0 @@
|
|||
package com.jfirer.se.serializer.impl;
|
||||
|
||||
import com.jfirer.baseutil.reflect.ReflectUtil;
|
||||
import com.jfirer.baseutil.reflect.ValueAccessor;
|
||||
import com.jfirer.se.ByteArray;
|
||||
import com.jfirer.se.ClassInfo;
|
||||
import com.jfirer.se.JfireSE;
|
||||
import com.jfirer.se.serializer.Serializer;
|
||||
import io.github.karlatemp.unsafeaccessor.Unsafe;
|
||||
import lombok.Data;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class ObjectSerializer implements Serializer
|
||||
{
|
||||
private FieldInfo[] primitiveFieldInfos;
|
||||
private FieldInfo[] boxFieldInfos;
|
||||
private FinalFieldInfo[] finalFieldInfos;
|
||||
private VariableFieldInfo[] variableFieldInfos;
|
||||
private JfireSE jfireSE;
|
||||
private Class clazz;
|
||||
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
|
||||
|
||||
public ObjectSerializer(Class clazz, JfireSE jfireSE)
|
||||
{
|
||||
this.clazz = clazz;
|
||||
this.jfireSE = jfireSE;
|
||||
Class type = clazz;
|
||||
List<Field> fields = new ArrayList<>();
|
||||
while (type != Object.class)
|
||||
{
|
||||
fields.addAll(Arrays.stream(type.getDeclaredFields()).filter(Predicate.not(field -> Modifier.isStatic(field.getModifiers()))).toList());
|
||||
type = type.getSuperclass();
|
||||
}
|
||||
primitiveFieldInfos = fields.stream().filter(field -> field.getType().isPrimitive()).sorted(Comparator.comparing(o -> o.getType().getName())).map(FieldInfo::new).toArray(FieldInfo[]::new);
|
||||
boxFieldInfos = fields.stream().filter(field -> ReflectUtil.isPrimitiveBox(field.getType()) || field.getType() == String.class).sorted(Comparator.comparing(o -> o.getType().getName())).map(FieldInfo::new).toArray(FieldInfo[]::new);
|
||||
finalFieldInfos = fields.stream().filter(Predicate.not(field -> ReflectUtil.isPrimitiveBox(field.getType())))//
|
||||
.filter(Predicate.not(field -> ReflectUtil.isPrimitive(field.getType())))//
|
||||
.filter(field -> field.getType() != String.class)//
|
||||
.filter(field -> field.getType() != void.class && field.getType() != Void.class)//
|
||||
.filter(field -> Modifier.isFinal(field.getType().getModifiers()))//
|
||||
.sorted(Comparator.comparing(o -> o.getType().getName()))//
|
||||
.map(FinalFieldInfo::new).toArray(FinalFieldInfo[]::new);
|
||||
variableFieldInfos = fields.stream().filter(Predicate.not(field -> ReflectUtil.isPrimitiveBox(field.getType())))//
|
||||
.filter(Predicate.not(field -> ReflectUtil.isPrimitive(field.getType())))//
|
||||
.filter(field -> field.getType() != String.class)//
|
||||
.filter(field -> field.getType() != void.class && field.getType() != Void.class)//
|
||||
.filter(field -> !Modifier.isFinal(field.getType().getModifiers()))//
|
||||
.sorted(Comparator.comparing(o -> o.getType().getName()))//
|
||||
.map(VariableFieldInfo::new).toArray(VariableFieldInfo[]::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBytes(ByteArray byteArray, Object instance)
|
||||
{
|
||||
for (FieldInfo primitiveFieldInfo : primitiveFieldInfos)
|
||||
{
|
||||
primitiveFieldInfo.write(byteArray, instance);
|
||||
}
|
||||
for (FieldInfo boxFieldInfo : boxFieldInfos)
|
||||
{
|
||||
boxFieldInfo.write(byteArray, instance);
|
||||
}
|
||||
for (FinalFieldInfo finalFieldInfo : finalFieldInfos)
|
||||
{
|
||||
finalFieldInfo.write(byteArray, instance);
|
||||
}
|
||||
for (VariableFieldInfo variableFieldInfo : variableFieldInfos)
|
||||
{
|
||||
variableFieldInfo.write(byteArray, instance);
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public Object readBytes(ByteArray byteArray)
|
||||
{
|
||||
Object instance = UNSAFE.allocateInstance(clazz);
|
||||
for (FieldInfo primitiveFieldInfo : primitiveFieldInfos)
|
||||
{
|
||||
primitiveFieldInfo.read(byteArray, instance);
|
||||
}
|
||||
for (FieldInfo boxFieldInfo : boxFieldInfos)
|
||||
{
|
||||
boxFieldInfo.read(byteArray, instance);
|
||||
}
|
||||
for (FinalFieldInfo finalFieldInfo : finalFieldInfos)
|
||||
{
|
||||
finalFieldInfo.read(byteArray, instance);
|
||||
}
|
||||
for (VariableFieldInfo variableFieldInfo : variableFieldInfos)
|
||||
{
|
||||
variableFieldInfo.read(byteArray, instance);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Data
|
||||
class FieldInfo
|
||||
{
|
||||
int classId;
|
||||
ValueAccessor accessor;
|
||||
|
||||
FieldInfo(Field field)
|
||||
{
|
||||
classId = ReflectUtil.getClassId(field.getType());
|
||||
accessor = new ValueAccessor(field);
|
||||
}
|
||||
|
||||
void read(ByteArray byteArray, Object instance)
|
||||
{
|
||||
switch (classId)
|
||||
{
|
||||
case ReflectUtil.PRIMITIVE_INT -> accessor.set(instance, byteArray.readVarInt());
|
||||
case ReflectUtil.PRIMITIVE_LONG -> accessor.set(instance, byteArray.readVarLong());
|
||||
case ReflectUtil.PRIMITIVE_FLOAT -> accessor.set(instance, byteArray.readFloat());
|
||||
case ReflectUtil.PRIMITIVE_DOUBLE -> accessor.set(instance, byteArray.readDouble());
|
||||
case ReflectUtil.PRIMITIVE_BOOL -> accessor.set(instance, byteArray.readBoolean() );
|
||||
case ReflectUtil.PRIMITIVE_CHAR -> accessor.set(instance, byteArray.readChar());
|
||||
case ReflectUtil.PRIMITIVE_SHORT -> accessor.set(instance, byteArray.readShort());
|
||||
case ReflectUtil.PRIMITIVE_BYTE -> accessor.set(instance, byteArray.get());
|
||||
case ReflectUtil.CLASS_INT ->
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NULL)
|
||||
{
|
||||
accessor.setObject(instance, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
accessor.set(instance, byteArray.readVarInt());
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_LONG ->
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NULL)
|
||||
{
|
||||
accessor.setObject(instance, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
accessor.set(instance, byteArray.readVarLong());
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_FLOAT ->
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NULL)
|
||||
{
|
||||
accessor.setObject(instance, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
accessor.set(instance, byteArray.readFloat());
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_DOUBLE ->
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NULL)
|
||||
{
|
||||
accessor.setObject(instance, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
accessor.set(instance, byteArray.readDouble());
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_BOOL ->
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NULL)
|
||||
{
|
||||
accessor.setObject(instance, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
accessor.set(instance, byteArray.readBoolean());
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_CHAR ->
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NULL)
|
||||
{
|
||||
accessor.setObject(instance, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
accessor.set(instance, byteArray.readChar());
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_SHORT ->
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NULL)
|
||||
{
|
||||
accessor.setObject(instance, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
accessor.set(instance, byteArray.readShort());
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_BYTE ->
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NULL)
|
||||
{
|
||||
accessor.setObject(instance, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
accessor.set(instance, byteArray.get());
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_STRING ->
|
||||
{
|
||||
if (byteArray.get() == JfireSE.NULL)
|
||||
{
|
||||
accessor.setObject(instance, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
accessor.setObject(instance, byteArray.readString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void write(ByteArray byteArray, Object instance)
|
||||
{
|
||||
switch (classId)
|
||||
{
|
||||
case ReflectUtil.PRIMITIVE_INT -> byteArray.writeVarInt(accessor.getInt(instance));
|
||||
case ReflectUtil.PRIMITIVE_LONG -> byteArray.writeVarLong(accessor.getLong(instance));
|
||||
case ReflectUtil.PRIMITIVE_FLOAT -> byteArray.writeFloat(accessor.getFloat(instance));
|
||||
case ReflectUtil.PRIMITIVE_DOUBLE -> byteArray.writeDouble(accessor.getDouble(instance));
|
||||
case ReflectUtil.PRIMITIVE_BOOL -> byteArray.writeBoolean(accessor.getBoolean(instance));
|
||||
case ReflectUtil.PRIMITIVE_CHAR -> byteArray.writeChar(accessor.getChar(instance));
|
||||
case ReflectUtil.PRIMITIVE_SHORT -> byteArray.writeShort(accessor.getShort(instance));
|
||||
case ReflectUtil.PRIMITIVE_BYTE -> byteArray.put(accessor.getByte(instance));
|
||||
case ReflectUtil.CLASS_INT ->
|
||||
{
|
||||
Integer value = accessor.getIntObject(instance);
|
||||
if (value == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeVarInt(value);
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_LONG ->
|
||||
{
|
||||
Long value = accessor.getLongObject(instance);
|
||||
if (value == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeVarLong(value);
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_FLOAT ->
|
||||
{
|
||||
Float value = accessor.getFloatObject(instance);
|
||||
if (value == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeFloat(value);
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_DOUBLE ->
|
||||
{
|
||||
Double value = accessor.getDoubleObject(instance);
|
||||
if (value == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeDouble(value);
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_BOOL ->
|
||||
{
|
||||
Boolean value = accessor.getBooleanObject(instance);
|
||||
if (value == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.put((byte) (value ? 1 : 0));
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_CHAR ->
|
||||
{
|
||||
Character value = accessor.getCharObject(instance);
|
||||
if (value == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeChar(value);
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_SHORT ->
|
||||
{
|
||||
Short value = accessor.getShortObject(instance);
|
||||
if (value == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeShort(value);
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_BYTE ->
|
||||
{
|
||||
Byte value = accessor.getByteObject(instance);
|
||||
if (value == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.put(value);
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_STRING ->
|
||||
{
|
||||
String value = (String) accessor.get(instance);
|
||||
if (value == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeString(value);
|
||||
}
|
||||
}
|
||||
default -> throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class FinalFieldInfo
|
||||
{
|
||||
ValueAccessor accessor;
|
||||
ClassInfo classInfo;
|
||||
|
||||
FinalFieldInfo(Field field)
|
||||
{
|
||||
accessor = new ValueAccessor(field);
|
||||
classInfo = jfireSE.getClassInfo(field.getType());
|
||||
}
|
||||
|
||||
void write(ByteArray byteArray, Object instance)
|
||||
{
|
||||
Object value = accessor.get(instance);
|
||||
if (value == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
classInfo.writeBytes(byteArray, value, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void read(ByteArray byteArray, Object instance)
|
||||
{
|
||||
byte flag = byteArray.get();
|
||||
switch (flag)
|
||||
{
|
||||
case JfireSE.NULL -> accessor.setObject(instance, null);
|
||||
case 7 -> accessor.setObject(instance, classInfo.readBytes(byteArray, true));
|
||||
case 8 -> accessor.setObject(instance, classInfo.readBytes(byteArray, false));
|
||||
case 9 -> accessor.setObject(instance, classInfo.getTracking(byteArray.readVarInt()));
|
||||
default -> throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class VariableFieldInfo
|
||||
{
|
||||
ValueAccessor accessor;
|
||||
ClassInfo classInfo;
|
||||
|
||||
VariableFieldInfo(Field field)
|
||||
{
|
||||
accessor = new ValueAccessor(field);
|
||||
}
|
||||
|
||||
void write(ByteArray byteArray, Object instance)
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
return;
|
||||
}
|
||||
Class<?> clazz = instance.getClass();
|
||||
if (classInfo != null && classInfo.getClazz() == clazz)
|
||||
{
|
||||
classInfo.writeBytes(byteArray, instance, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
classInfo = jfireSE.getClassInfo(clazz);
|
||||
classInfo.writeBytes(byteArray, instance, false);
|
||||
}
|
||||
}
|
||||
|
||||
void read(ByteArray byteArray, Object instance)
|
||||
{
|
||||
accessor.setObject(instance, jfireSE.readBytes(byteArray));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package com.jfirer.se;
|
||||
package com.jfirer.se2;
|
||||
|
||||
import com.jfirer.baseutil.reflect.ReflectUtil;
|
||||
import com.jfirer.fse.InternalByteArray;
|
|
@ -0,0 +1,39 @@
|
|||
package com.jfirer.se2;
|
||||
|
||||
public interface JfireSE
|
||||
{
|
||||
byte NULL = 0;
|
||||
byte NOT_NULL = 1;
|
||||
byte NAME_ID_CONTENT_TRACK = 2;
|
||||
byte NAME_ID_CONTENT_UN_TRACK = 3;
|
||||
byte ID_INSTANCE_ID = 4;
|
||||
byte id_content_track = 5;
|
||||
byte id_content_un_track = 6;
|
||||
byte instance_id = 7;
|
||||
byte content_track = 8;
|
||||
byte content_un_track = 9;
|
||||
|
||||
static JfireSEConfig supportRefTracking(boolean support)
|
||||
{
|
||||
return new JfireSEConfig().setRefTracking(support);
|
||||
}
|
||||
|
||||
static JfireSEConfig useCompile()
|
||||
{
|
||||
return new JfireSEConfig().useCompile();
|
||||
}
|
||||
|
||||
static JfireSEConfig staticRegisterClass(Class<?> clazz)
|
||||
{
|
||||
return new JfireSEConfig().staticRegisterClass(clazz);
|
||||
}
|
||||
|
||||
static JfireSE build()
|
||||
{
|
||||
return new JfireSEConfig().build();
|
||||
}
|
||||
|
||||
byte[] write(Object instance);
|
||||
|
||||
Object read(byte[] bytes);
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package com.jfirer.se2;
|
||||
|
||||
import com.jfirer.se2.classinfo.StaticClasInfo;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class JfireSEConfig
|
||||
{
|
||||
private boolean refTracking = false;
|
||||
private boolean useCompile = false;
|
||||
private short staticClassId = 0;
|
||||
private StaticClasInfo[] clasInfos = new StaticClasInfo[10];
|
||||
private List<Class<?>> list = new LinkedList<>();
|
||||
private Set<Class<?>> set = new HashSet<>();
|
||||
|
||||
public JfireSEConfig()
|
||||
{
|
||||
staticRegisterClass(ArrayList.class);
|
||||
staticRegisterClass(HashSet.class);
|
||||
staticRegisterClass(HashMap.class);
|
||||
staticRegisterClass(LinkedList.class);
|
||||
}
|
||||
|
||||
public JfireSEConfig useCompile()
|
||||
{
|
||||
useCompile = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public JfireSEConfig refTracking()
|
||||
{
|
||||
refTracking = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public JfireSEConfig staticRegisterClass(Class<?> clazz)
|
||||
{
|
||||
if (set.add(clazz))
|
||||
{
|
||||
list.add(clazz);
|
||||
return this;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("重复添加");
|
||||
}
|
||||
}
|
||||
|
||||
public JfireSE build()
|
||||
{
|
||||
StaticClasInfo[] array = list.stream().map(this::resolve).toArray(StaticClasInfo[]::new);
|
||||
return new JfireSEImpl(refTracking, array);
|
||||
}
|
||||
|
||||
private StaticClasInfo resolve(Class<?> clazz)
|
||||
{
|
||||
StaticClasInfo staticClasInfo = new StaticClasInfo(staticClassId, clazz.getName(), clazz, refTracking);
|
||||
staticClassId++;
|
||||
return staticClasInfo;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
package com.jfirer.se2;
|
||||
|
||||
import com.jfirer.se2.classinfo.ClassInfo;
|
||||
import com.jfirer.se2.classinfo.DynamicClassInfo;
|
||||
import com.jfirer.se2.classinfo.StaticClasInfo;
|
||||
import com.jfirer.se2.serializer.Serializer;
|
||||
import com.jfirer.se2.serializer.SerializerFactory;
|
||||
|
||||
public class JfireSEImpl implements JfireSE
|
||||
{
|
||||
private final boolean refTracking;
|
||||
private final int staticClassId;
|
||||
private int dyncmicClassId;
|
||||
/**
|
||||
* 用于存储序列化相关的 classInfo
|
||||
*/
|
||||
private ClassInfo[] serializedClassInfos;
|
||||
/**
|
||||
* 用于存储逆序列化过程中的临时信息
|
||||
*/
|
||||
private ClassInfo[] deSerializedClassInfos;
|
||||
private SerializerFactory serializerFactory = new SerializerFactory();
|
||||
private ByteArray byteArray = new ByteArray(1000);
|
||||
|
||||
public JfireSEImpl(boolean refTracking, StaticClasInfo[] staticClasInfos)
|
||||
{
|
||||
this.refTracking = refTracking;
|
||||
this.staticClassId = staticClasInfos.length - 1;
|
||||
serializedClassInfos = new ClassInfo[staticClasInfos.length * 2];
|
||||
deSerializedClassInfos = new ClassInfo[serializedClassInfos.length];
|
||||
System.arraycopy(staticClasInfos, 0, serializedClassInfos, 0, staticClasInfos.length);
|
||||
System.arraycopy(staticClasInfos, 0, deSerializedClassInfos, 0, staticClasInfos.length);
|
||||
dyncmicClassId = staticClassId + 1;
|
||||
}
|
||||
|
||||
public ClassInfo getForSerialize(Class<?> clazz)
|
||||
{
|
||||
for (int i = 0; i < dyncmicClassId; i++)
|
||||
{
|
||||
if (serializedClassInfos[i].getClazz() == clazz)
|
||||
{
|
||||
return serializedClassInfos[i];
|
||||
}
|
||||
}
|
||||
if (dyncmicClassId == serializedClassInfos.length)
|
||||
{
|
||||
ClassInfo[] tmp = new ClassInfo[serializedClassInfos.length * 2];
|
||||
System.arraycopy(serializedClassInfos, 0, tmp, 0, serializedClassInfos.length);
|
||||
serializedClassInfos = tmp;
|
||||
}
|
||||
DynamicClassInfo dynamicClassInfo = new DynamicClassInfo((short) dyncmicClassId, clazz.getName(), clazz, refTracking);
|
||||
serializedClassInfos[dyncmicClassId] = dynamicClassInfo;
|
||||
dyncmicClassId++;
|
||||
Serializer serializer = serializerFactory.getSerializer(clazz, this);
|
||||
dynamicClassInfo.setSerializer(serializer);
|
||||
return dynamicClassInfo;
|
||||
}
|
||||
|
||||
private void resetSerialized()
|
||||
{
|
||||
for (int i = staticClassId; i < dyncmicClassId; i++)
|
||||
{
|
||||
serializedClassInfos[i].reset();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] write(Object instance)
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
byte[] array = byteArray.toArray();
|
||||
byteArray.clear();
|
||||
return array;
|
||||
}
|
||||
ClassInfo classInfo = getForSerialize(instance.getClass());
|
||||
classInfo.write(byteArray, instance);
|
||||
byte[] array = byteArray.toArray();
|
||||
byteArray.clear();
|
||||
resetSerialized();
|
||||
return array;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object read(byte[] bytes)
|
||||
{
|
||||
ByteArray stream = new ByteArray(bytes);
|
||||
byte b = stream.get();
|
||||
if (b == JfireSE.NULL)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
switch (b)
|
||||
{
|
||||
case JfireSE.NAME_ID_CONTENT_TRACK ->
|
||||
{
|
||||
String className = byteArray.readString();
|
||||
int classId = byteArray.readVarInt();
|
||||
try
|
||||
{
|
||||
Class<?> clazz = Class.forName(className);
|
||||
ClassInfo classInfo = getForSerialize(clazz);
|
||||
if (deSerializedClassInfos == null)
|
||||
{
|
||||
deSerializedClassInfos = new ClassInfo[classId + 1];
|
||||
deSerializedClassInfos[classId] = classInfo;
|
||||
}
|
||||
else if (classId >= deSerializedClassInfos.length)
|
||||
{
|
||||
int newLen = deSerializedClassInfos.length * 2;
|
||||
newLen = newLen > classId ? newLen : classId + 1;
|
||||
ClassInfo[] tmp = new ClassInfo[newLen];
|
||||
System.arraycopy(deSerializedClassInfos, 0, tmp, 0, deSerializedClassInfos.length);
|
||||
deSerializedClassInfos = tmp;
|
||||
deSerializedClassInfos[classId] = classInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
deSerializedClassInfos[classId] = classInfo;
|
||||
}
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package com.jfirer.se2.classinfo;
|
||||
|
||||
import com.jfirer.se2.ByteArray;
|
||||
import com.jfirer.se2.JfireSE;
|
||||
import com.jfirer.se2.serializer.Serializer;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@Data
|
||||
public abstract class ClassInfo
|
||||
{
|
||||
protected final short classId;
|
||||
protected final String className;
|
||||
protected final Class<?> clazz;
|
||||
protected final boolean refTrack;
|
||||
protected Object[] tracking;
|
||||
protected int refTrackingIndex = 0;
|
||||
protected Serializer serializer;
|
||||
|
||||
public int addTracking(Object instance)
|
||||
{
|
||||
if (tracking == null)
|
||||
{
|
||||
tracking = new Object[4];
|
||||
}
|
||||
for (int i = 0; i < refTrackingIndex; i++)
|
||||
{
|
||||
if (tracking[i] == instance)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
if (refTrackingIndex == tracking.length)
|
||||
{
|
||||
Object[] newRefTracking = new Object[tracking.length * 2];
|
||||
System.arraycopy(tracking, 0, newRefTracking, 0, tracking.length);
|
||||
tracking = newRefTracking;
|
||||
}
|
||||
tracking[refTrackingIndex++] = instance;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
if (refTrackingIndex != 0)
|
||||
{
|
||||
Arrays.fill(tracking, 0, refTrackingIndex, null);
|
||||
refTrackingIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void write(ByteArray byteArray, Object instance);
|
||||
|
||||
public void writeKnownClazz(ByteArray byteArray, Object instance)
|
||||
{
|
||||
if (refTrack)
|
||||
{
|
||||
int index = addTracking(instance);
|
||||
if (index == -1)
|
||||
{
|
||||
byteArray.put(JfireSE.content_track);
|
||||
serializer.writeBytes(byteArray, instance);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.instance_id);
|
||||
byteArray.writeVarInt(index);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.content_un_track);
|
||||
serializer.writeBytes(byteArray, instance);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void readWithTrack(ByteArray byteArray);
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package com.jfirer.se2.classinfo;
|
||||
|
||||
import com.jfirer.se2.ByteArray;
|
||||
import com.jfirer.se2.JfireSE;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Getter
|
||||
@Setter
|
||||
public class DynamicClassInfo extends ClassInfo
|
||||
{
|
||||
/**
|
||||
* 首次输出的情况下需要输出类名
|
||||
*/
|
||||
private boolean firstSerialized = true;
|
||||
|
||||
public DynamicClassInfo(short classId, String className, Class<?> clazz, boolean refTracking)
|
||||
{
|
||||
super(classId, className, clazz, refTracking);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
super.reset();
|
||||
firstSerialized = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteArray byteArray, Object instance)
|
||||
{
|
||||
if (refTrack)
|
||||
{
|
||||
if (firstSerialized)
|
||||
{
|
||||
firstSerialized = true;
|
||||
addTracking(instance);
|
||||
byteArray.put(JfireSE.NAME_ID_CONTENT_TRACK);
|
||||
byteArray.writeString(className);
|
||||
byteArray.writeVarInt(classId);
|
||||
serializer.writeBytes(byteArray, instance);
|
||||
}
|
||||
else
|
||||
{
|
||||
int i = addTracking(instance);
|
||||
if (i == -1)
|
||||
{
|
||||
byteArray.put(JfireSE.id_content_track);
|
||||
byteArray.writeVarInt(classId);
|
||||
serializer.writeBytes(byteArray, instance);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.ID_INSTANCE_ID);
|
||||
byteArray.writeVarInt(classId);
|
||||
byteArray.writeVarInt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (firstSerialized)
|
||||
{
|
||||
firstSerialized = true;
|
||||
byteArray.put(JfireSE.NAME_ID_CONTENT_UN_TRACK);
|
||||
byteArray.writeString(className);
|
||||
byteArray.writeVarInt(classId);
|
||||
serializer.writeBytes(byteArray, instance);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.id_content_un_track);
|
||||
byteArray.writeVarInt(classId);
|
||||
serializer.writeBytes(byteArray, instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package com.jfirer.se2.classinfo;
|
||||
|
||||
import com.jfirer.se2.ByteArray;
|
||||
import com.jfirer.se2.JfireSE;
|
||||
|
||||
public class StaticClasInfo extends ClassInfo
|
||||
{
|
||||
public StaticClasInfo(short classId, String className, Class<?> clazz, boolean refTracking)
|
||||
{
|
||||
super(classId, className, clazz, refTracking);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteArray byteArray, Object instance)
|
||||
{
|
||||
if (refTrack)
|
||||
{
|
||||
int i = addTracking(instance);
|
||||
if (i == -1)
|
||||
{
|
||||
byteArray.put(JfireSE.id_content_track);
|
||||
byteArray.writeVarInt(classId);
|
||||
serializer.writeBytes(byteArray, instance);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.ID_INSTANCE_ID);
|
||||
byteArray.writeVarInt(classId);
|
||||
byteArray.writeVarInt(i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.id_content_un_track);
|
||||
byteArray.writeVarInt(classId);
|
||||
serializer.writeBytes(byteArray, instance);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.jfirer.se2.serializer;
|
||||
|
||||
import com.jfirer.se2.ByteArray;
|
||||
|
||||
public interface Serializer
|
||||
{
|
||||
void writeBytes(ByteArray byteArray, Object instance);
|
||||
|
||||
Object read(ByteArray stream);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.jfirer.se2.serializer;
|
||||
|
||||
import com.jfirer.se2.JfireSEImpl;
|
||||
import com.jfirer.se2.serializer.impl.ObjectSerializer.ObjectSerializer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class SerializerFactory
|
||||
{
|
||||
private Map<Class<?>, Serializer> store = new HashMap<>();
|
||||
|
||||
public Serializer getSerializer(Class<?> clazz, JfireSEImpl jfireSE)
|
||||
{
|
||||
return store.putIfAbsent(clazz, new ObjectSerializer(clazz, jfireSE));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
package com.jfirer.se2.serializer.impl.ObjectSerializer;
|
||||
|
||||
import com.jfirer.baseutil.reflect.ReflectUtil;
|
||||
import com.jfirer.baseutil.reflect.ValueAccessor;
|
||||
import com.jfirer.se2.ByteArray;
|
||||
import com.jfirer.se2.JfireSE;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class BoxedFieldInfo extends FieldInfo
|
||||
{
|
||||
public BoxedFieldInfo(Field field)
|
||||
{
|
||||
super(ReflectUtil.getClassId(field.getType()), new ValueAccessor(field));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteArray byteArray, Object instance)
|
||||
{
|
||||
switch (classId)
|
||||
{
|
||||
case ReflectUtil.CLASS_BOOL ->
|
||||
{
|
||||
Boolean obj = accessor.getBooleanObject(instance);
|
||||
if (obj == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeBoolean(obj);
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_BYTE ->
|
||||
{
|
||||
Byte obj = accessor.getByteObject(instance);
|
||||
if (obj == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.put(obj);
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_CHAR ->
|
||||
{
|
||||
Character obj = accessor.getCharObject(instance);
|
||||
if (obj == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeChar(obj);
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_SHORT ->
|
||||
{
|
||||
Short obj = accessor.getShortObject(instance);
|
||||
if (obj == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeVarInt(obj);
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_INT ->
|
||||
{
|
||||
Integer obj = accessor.getIntObject(instance);
|
||||
if (obj == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeVarInt(obj);
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_LONG ->
|
||||
{
|
||||
Long obj = accessor.getLongObject(instance);
|
||||
if (obj == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeVarLong(obj);
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_FLOAT ->
|
||||
{
|
||||
Float obj = accessor.getFloatObject(instance);
|
||||
if (obj == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeFloat(obj);
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_DOUBLE ->
|
||||
{
|
||||
Double obj = accessor.getDoubleObject(instance);
|
||||
if (obj == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeDouble(obj);
|
||||
}
|
||||
}
|
||||
case ReflectUtil.CLASS_STRING ->
|
||||
{
|
||||
String obj = (String) accessor.get(instance);
|
||||
if (obj == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.NOT_NULL);
|
||||
byteArray.writeString(obj);
|
||||
}
|
||||
}
|
||||
default -> throw new RuntimeException("不支持的类型");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.jfirer.se2.serializer.impl.ObjectSerializer;
|
||||
|
||||
import com.jfirer.baseutil.reflect.ValueAccessor;
|
||||
import com.jfirer.se2.ByteArray;
|
||||
|
||||
public abstract class FieldInfo
|
||||
{
|
||||
protected int classId;
|
||||
protected ValueAccessor accessor;
|
||||
|
||||
public FieldInfo(int classId, ValueAccessor accessor)
|
||||
{
|
||||
this.classId = classId;
|
||||
this.accessor = accessor;
|
||||
}
|
||||
|
||||
public abstract void write(ByteArray byteArray, Object instance);
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package com.jfirer.se2.serializer.impl.ObjectSerializer;
|
||||
|
||||
import com.jfirer.baseutil.reflect.ReflectUtil;
|
||||
import com.jfirer.baseutil.reflect.ValueAccessor;
|
||||
import com.jfirer.se2.ByteArray;
|
||||
import com.jfirer.se2.JfireSE;
|
||||
import com.jfirer.se2.JfireSEImpl;
|
||||
import com.jfirer.se2.classinfo.ClassInfo;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class FinalFieldInfo extends FieldInfo
|
||||
{
|
||||
private ClassInfo classInfo;
|
||||
|
||||
public FinalFieldInfo(Field field, JfireSEImpl jfireSE)
|
||||
{
|
||||
super(ReflectUtil.getClassId(field.getType()), new ValueAccessor(field));
|
||||
classInfo = jfireSE.getForSerialize(field.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteArray byteArray, Object instance)
|
||||
{
|
||||
Object obj = accessor.get(instance);
|
||||
if (obj == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
classInfo.writeKnownClazz(byteArray, obj);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package com.jfirer.se2.serializer.impl.ObjectSerializer;
|
||||
|
||||
import com.jfirer.baseutil.reflect.ReflectUtil;
|
||||
import com.jfirer.se2.ByteArray;
|
||||
import com.jfirer.se2.JfireSEImpl;
|
||||
import com.jfirer.se2.serializer.Serializer;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class ObjectSerializer implements Serializer
|
||||
{
|
||||
private Class<?> clazz;
|
||||
private FieldInfo[] fieldInfos;
|
||||
|
||||
public ObjectSerializer(Class<?> clazz, JfireSEImpl jfireSE)
|
||||
{
|
||||
Class type = clazz;
|
||||
List<Field> fields = new ArrayList<>();
|
||||
while (type != Object.class)
|
||||
{
|
||||
fields.addAll(Arrays.stream(type.getDeclaredFields()).filter(Predicate.not(field -> Modifier.isStatic(field.getModifiers()))).toList());
|
||||
type = type.getSuperclass();
|
||||
}
|
||||
List<PrimitiveFieldInfo> primitiveFieldInfos = fields.stream().filter(field -> field.getType().isPrimitive())//
|
||||
.sorted(Comparator.comparing(o -> o.getType().getName()))//
|
||||
.map(PrimitiveFieldInfo::new)//
|
||||
.toList();
|
||||
List<BoxedFieldInfo> boxedFieldInfos = fields.stream().filter(field -> ReflectUtil.isPrimitiveBox(field.getType()) || field.getType() == String.class)//
|
||||
.sorted(Comparator.comparing(o -> o.getType().getName()))//
|
||||
.map(BoxedFieldInfo::new)//
|
||||
.toList();
|
||||
List<FinalFieldInfo> finalFieldInfos = fields.stream().filter(Predicate.not(field -> ReflectUtil.isPrimitiveBox(field.getType())))//
|
||||
.filter(Predicate.not(field -> ReflectUtil.isPrimitive(field.getType())))//
|
||||
.filter(field -> field.getType() != String.class)//
|
||||
.filter(field -> field.getType() != void.class && field.getType() != Void.class)//
|
||||
.filter(field -> Modifier.isFinal(field.getType().getModifiers()))//
|
||||
.sorted(Comparator.comparing(o -> o.getType().getName()))//
|
||||
.map(field -> new FinalFieldInfo(field, jfireSE))//
|
||||
.toList();
|
||||
List<VariableFieldInfo> variableFieldInfos = fields.stream().filter(Predicate.not(field -> ReflectUtil.isPrimitiveBox(field.getType())))//
|
||||
.filter(Predicate.not(field -> ReflectUtil.isPrimitive(field.getType())))//
|
||||
.filter(field -> field.getType() != String.class)//
|
||||
.filter(field -> field.getType() != void.class && field.getType() != Void.class)//
|
||||
.filter(field -> !Modifier.isFinal(field.getType().getModifiers()))//
|
||||
.sorted(Comparator.comparing(o -> o.getType().getName()))//
|
||||
.map(field -> new VariableFieldInfo(field, jfireSE))//
|
||||
.toList();
|
||||
List<FieldInfo> list = new LinkedList<>();
|
||||
list.addAll(primitiveFieldInfos);
|
||||
list.addAll(boxedFieldInfos);
|
||||
list.addAll(finalFieldInfos);
|
||||
list.addAll(variableFieldInfos);
|
||||
fieldInfos = list.toArray(FieldInfo[]::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBytes(ByteArray byteArray, Object instance)
|
||||
{
|
||||
for (FieldInfo each : fieldInfos)
|
||||
{
|
||||
each.write(byteArray, instance);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package com.jfirer.se2.serializer.impl.ObjectSerializer;
|
||||
|
||||
import com.jfirer.baseutil.reflect.ReflectUtil;
|
||||
import com.jfirer.baseutil.reflect.ValueAccessor;
|
||||
import com.jfirer.se2.ByteArray;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class PrimitiveFieldInfo extends FieldInfo
|
||||
{
|
||||
public PrimitiveFieldInfo(Field field)
|
||||
{
|
||||
super(ReflectUtil.getClassId(field.getType()), new ValueAccessor(field));
|
||||
}
|
||||
|
||||
public void write(ByteArray byteArray, Object instance)
|
||||
{
|
||||
switch (classId)
|
||||
{
|
||||
case ReflectUtil.PRIMITIVE_BYTE -> byteArray.put(accessor.getByte(instance));
|
||||
case ReflectUtil.PRIMITIVE_INT -> byteArray.writeVarInt(accessor.getInt(instance));
|
||||
case ReflectUtil.PRIMITIVE_SHORT -> byteArray.writeVarInt(accessor.getShort(instance));
|
||||
case ReflectUtil.PRIMITIVE_LONG -> byteArray.writeVarLong(accessor.getLong(instance));
|
||||
case ReflectUtil.PRIMITIVE_FLOAT -> byteArray.writeFloat(accessor.getFloat(instance));
|
||||
case ReflectUtil.PRIMITIVE_DOUBLE -> byteArray.writeDouble(accessor.getDouble(instance));
|
||||
case ReflectUtil.PRIMITIVE_BOOL -> byteArray.writeBoolean(accessor.getBoolean(instance));
|
||||
case ReflectUtil.PRIMITIVE_CHAR -> byteArray.writeChar(accessor.getChar(instance));
|
||||
default -> throw new RuntimeException("不支持的类型");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package com.jfirer.se2.serializer.impl.ObjectSerializer;
|
||||
|
||||
import com.jfirer.baseutil.reflect.ReflectUtil;
|
||||
import com.jfirer.baseutil.reflect.ValueAccessor;
|
||||
import com.jfirer.se2.ByteArray;
|
||||
import com.jfirer.se2.JfireSE;
|
||||
import com.jfirer.se2.JfireSEImpl;
|
||||
import com.jfirer.se2.classinfo.ClassInfo;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class VariableFieldInfo extends FieldInfo
|
||||
{
|
||||
private final JfireSEImpl jfireSE;
|
||||
private ClassInfo classInfo;
|
||||
|
||||
public VariableFieldInfo(Field field, JfireSEImpl jfireSE)
|
||||
{
|
||||
super(ReflectUtil.getClassId(field.getType()), new ValueAccessor(field));
|
||||
classInfo = jfireSE.getForSerialize(field.getType());
|
||||
this.jfireSE = jfireSE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteArray byteArray, Object instance)
|
||||
{
|
||||
Object obj = accessor.get(instance);
|
||||
if (obj == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
Class<?> objClass = obj.getClass();
|
||||
if (objClass == classInfo.getClazz())
|
||||
{
|
||||
classInfo.write(byteArray, obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
classInfo = jfireSE.getForSerialize(objClass);
|
||||
classInfo.write(byteArray, instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ package org.example;
|
|||
|
||||
import com.jfirer.fse.ByteArray;
|
||||
import com.jfirer.fse.Fse;
|
||||
import com.jfirer.se.JfireSE;
|
||||
import com.jfirer.se2.JfireSE;
|
||||
import io.fury.Fury;
|
||||
import io.fury.config.Language;
|
||||
import org.openjdk.jmh.annotations.*;
|
||||
|
@ -28,7 +28,7 @@ public class BenchMark
|
|||
Fury fury = Fury.builder().withLanguage(Language.JAVA)//
|
||||
.requireClassRegistration(false)//
|
||||
.withRefTracking(true).build();
|
||||
JfireSE jfireSE = new JfireSE();
|
||||
JfireSE jfireSE = JfireSE.build();
|
||||
|
||||
@Benchmark
|
||||
public void testNoCompile()
|
||||
|
@ -53,7 +53,7 @@ public class BenchMark
|
|||
@Benchmark
|
||||
public void testJfireSE()
|
||||
{
|
||||
jfireSE.writeBytes(data);
|
||||
jfireSE.write(data);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws RunnerException
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
package org.example;
|
||||
|
||||
import io.github.karlatemp.unsafeaccessor.Unsafe;
|
||||
import org.openjdk.jmh.annotations.*;
|
||||
import org.openjdk.jmh.runner.Runner;
|
||||
import org.openjdk.jmh.runner.RunnerException;
|
||||
import org.openjdk.jmh.runner.options.Options;
|
||||
import org.openjdk.jmh.runner.options.OptionsBuilder;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@BenchmarkMode(Mode.Throughput)
|
||||
@Warmup(iterations = 2, time = 1)
|
||||
@Measurement(iterations = 3, time = 10)
|
||||
@OutputTimeUnit(TimeUnit.SECONDS)
|
||||
@Fork(1)
|
||||
@State(Scope.Benchmark)
|
||||
public class BenchMarkUnsafe
|
||||
{
|
||||
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
|
||||
char c = '你';
|
||||
char Rec = Character.reverseBytes(c);
|
||||
private byte[] array = new byte[2];
|
||||
private long offset = UNSAFE.arrayBaseOffset(byte[].class);
|
||||
|
||||
@Benchmark
|
||||
public void write()
|
||||
{
|
||||
UNSAFE.putChar(array, offset, c);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void writeRe()
|
||||
{
|
||||
UNSAFE.putChar(array, offset, Rec);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws RunnerException
|
||||
{
|
||||
Options opt = new OptionsBuilder().include(BenchMarkUnsafe.class.getSimpleName()).build();
|
||||
new Runner(opt).run();
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package org.example;
|
||||
|
||||
import com.jfirer.se.ByteArray;
|
||||
import com.jfirer.se2.ByteArray;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
package org.example;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class TestData implements Serializable
|
||||
{
|
||||
private int a = 213212312;
|
||||
|
@ -12,7 +15,7 @@ public class TestData implements Serializable
|
|||
private long f = 1213124131312321L;
|
||||
private double g = 231321.2132;
|
||||
private float h = (float) 4986.2;
|
||||
// private String i = "123452312316789a";
|
||||
private String i = "123452312316789a";
|
||||
// private int[] j = new int[]{1, 2, 4, 5};
|
||||
// private boolean[] k = new boolean[]{true, false, true, false, false, false, true};
|
||||
// private char[] l = new char[]{'a', 'v', 'q', 'j', 'h', 'e', 'f'};
|
||||
|
|
Loading…
Reference in New Issue