From 41f69f0769eada6b2c1613da1c7a94ab7fcaec75 Mon Sep 17 00:00:00 2001
From: linbin <495561397@qq.com>
Date: Thu, 11 Apr 2024 18:04:16 +0800
Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E7=A8=BF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 38 ++
.idea/.gitignore | 6 +
pom.xml | 48 ++
src/main/java/com/jfirer/se/ByteArray.java | 103 ++++
src/main/java/com/jfirer/se/ClassInfo.java | 130 +++++
.../java/com/jfirer/se/ClassInfoResolver.java | 83 +++
.../java/com/jfirer/se/InternalByteArray.java | 539 ++++++++++++++++++
src/main/java/com/jfirer/se/JfireSE.java | 46 ++
.../com/jfirer/se/serializer/Serializer.java | 8 +
.../se/serializer/SerializerResolver.java | 25 +
.../se/serializer/impl/ObjectSerializer.java | 232 ++++++++
src/test/java/org/example/AppTest.java | 38 ++
12 files changed, 1296 insertions(+)
create mode 100644 .gitignore
create mode 100644 .idea/.gitignore
create mode 100644 pom.xml
create mode 100644 src/main/java/com/jfirer/se/ByteArray.java
create mode 100644 src/main/java/com/jfirer/se/ClassInfo.java
create mode 100644 src/main/java/com/jfirer/se/ClassInfoResolver.java
create mode 100644 src/main/java/com/jfirer/se/InternalByteArray.java
create mode 100644 src/main/java/com/jfirer/se/JfireSE.java
create mode 100644 src/main/java/com/jfirer/se/serializer/Serializer.java
create mode 100644 src/main/java/com/jfirer/se/serializer/SerializerResolver.java
create mode 100644 src/main/java/com/jfirer/se/serializer/impl/ObjectSerializer.java
create mode 100644 src/test/java/org/example/AppTest.java
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5ff6309
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,38 @@
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### IntelliJ IDEA ###
+.idea/modules.xml
+.idea/jarRepositories.xml
+.idea/compiler.xml
+.idea/libraries/
+*.iws
+*.iml
+*.ipr
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..8bf4d45
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,6 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..7b64f1a
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,48 @@
+
+ 4.0.0
+
+ org.example
+ JfireSE
+ 1.0-SNAPSHOT
+ jar
+
+ JfireSE
+ http://maven.apache.org
+
+
+ UTF-8
+
+
+
+
+ junit
+ junit
+ 4.13.1
+ test
+
+
+ com.jfirer
+ baseutil
+ 1.1.7-SNAPSHOT
+
+
+ org.projectlombok
+ lombok
+ 1.18.30
+ provided
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ 16
+
+
+
+
+
diff --git a/src/main/java/com/jfirer/se/ByteArray.java b/src/main/java/com/jfirer/se/ByteArray.java
new file mode 100644
index 0000000..1b79b62
--- /dev/null
+++ b/src/main/java/com/jfirer/se/ByteArray.java
@@ -0,0 +1,103 @@
+package com.jfirer.se;
+
+public class ByteArray
+{
+ protected byte[] array;
+ protected int writePosi = 0;
+ protected int readIndex = 0;
+ protected boolean needCheck = true;
+
+ protected ByteArray(int size)
+ {
+ array = new byte[size];
+ }
+
+ protected ByteArray(byte[] array)
+ {
+ this.array = array;
+ }
+
+ public static ByteArray allocate(int size)
+ {
+ return new InternalByteArray(size);
+ }
+
+ public static ByteArray allocate()
+ {
+ return new InternalByteArray(1024);
+ }
+
+ public static ByteArray wrap(byte[] array)
+ {
+ return new InternalByteArray(array);
+ }
+
+ public void setNeedCheck(boolean needCheck)
+ {
+ this.needCheck = needCheck;
+ }
+
+ protected void ensureCapacity(int len)
+ {
+ if (needCheck && len > array.length - writePosi)
+ {
+ int newLen = len + writePosi > (array.length << 1) ? len + writePosi + array.length : (array.length << 1);
+ byte[] tmp = new byte[newLen];
+ System.arraycopy(array, 0, tmp, 0, array.length);
+ array = tmp;
+ }
+ }
+
+ public void clear()
+ {
+ writePosi = readIndex = 0;
+ }
+
+ public void put(byte value)
+ {
+ ensureCapacity(1);
+ array[writePosi] = value;
+ writePosi += 1;
+ }
+
+ public void setByte(int off, byte b)
+ {
+ array[off] = b;
+ }
+
+ public void put(byte[] data)
+ {
+ ensureCapacity(data.length);
+ System.arraycopy(data, 0, array, writePosi, data.length);
+ writePosi += data.length;
+ }
+
+ public byte get()
+ {
+ byte result = array[readIndex];
+ readIndex += 1;
+ return result;
+ }
+
+ public byte[] toArray()
+ {
+ byte[] result = new byte[writePosi];
+ System.arraycopy(array, 0, result, 0, writePosi);
+ return result;
+ }
+
+ public int getWritePosi()
+ {
+ return writePosi;
+ }
+
+ public void setWritePosi(int writePosi)
+ {
+ this.writePosi = writePosi;
+ }
+
+ public void setReadPosi(int readPosi)
+ {
+ this.readIndex = readPosi;
+ }
+}
diff --git a/src/main/java/com/jfirer/se/ClassInfo.java b/src/main/java/com/jfirer/se/ClassInfo.java
new file mode 100644
index 0000000..25295d5
--- /dev/null
+++ b/src/main/java/com/jfirer/se/ClassInfo.java
@@ -0,0 +1,130 @@
+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[] refTracking;
+ private int refTrackingIndex = 0;
+
+ public void writeBytes(InternalByteArray byteArray, Object instance, boolean knownClazz)
+ {
+ if (instance == null)
+ {
+ byteArray.put(JfireSE.NULL);
+ return;
+ }
+ if (serializer == null)
+ {
+ serializer = jfireSE.getSerializer(clazz);
+ }
+ if (knownClazz)
+ {
+ if (jfireSE.isCycleSupport())
+ {
+ int tracking = addTracking(instance);
+ if (tracking == -1)
+ {
+ byteArray.put((byte) 7);
+ serializer.writeBytes(byteArray, instance);
+ }
+ else
+ {
+ byteArray.put((byte) 9);
+ byteArray.writeVarInt(tracking);
+ }
+ }
+ else
+ {
+ byteArray.put((byte) 8);
+ serializer.writeBytes(byteArray, instance);
+ }
+ }
+ else
+ {
+ if (jfireSE.isCycleSupport())
+ {
+ 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()
+ {
+ classId = ClassInfoResolver.NO_CLASS_ID;
+ refTrackingIndex = 0;
+ }
+
+ public int addTracking(Object instance)
+ {
+ if (refTracking == null)
+ {
+ refTracking = new Object[4];
+ }
+ for (int i = 0; i < refTrackingIndex; i++)
+ {
+ if (refTracking[i] == instance)
+ {
+ return i;
+ }
+ }
+ if (refTrackingIndex == refTracking.length)
+ {
+ Object[] newRefTracking = new Object[refTracking.length * 2];
+ System.arraycopy(refTracking, 0, newRefTracking, 0, refTracking.length);
+ refTracking = newRefTracking;
+ }
+ refTracking[refTrackingIndex++] = instance;
+ return -1;
+ }
+}
diff --git a/src/main/java/com/jfirer/se/ClassInfoResolver.java b/src/main/java/com/jfirer/se/ClassInfoResolver.java
new file mode 100644
index 0000000..df80678
--- /dev/null
+++ b/src/main/java/com/jfirer/se/ClassInfoResolver.java
@@ -0,0 +1,83 @@
+package com.jfirer.se;
+
+import com.jfirer.se.serializer.SerializerResolver;
+
+import java.util.IdentityHashMap;
+import java.util.Map;
+
+public class ClassInfoResolver
+{
+ public static int NO_CLASS_ID = 0;
+ private Map store = new IdentityHashMap<>();
+ private int currentClassId = 1;
+ private int fixedClassId = 1;
+ private ClassInfo[] tracking = new ClassInfo[32];
+ private JfireSE jfireSE;
+ private SerializerResolver resolver;
+
+ public ClassInfoResolver(SerializerResolver resolver, JfireSE jfireSE)
+ {
+ this.resolver = resolver;
+ this.jfireSE = jfireSE;
+ }
+
+ public void getClassId(ClassInfo classInfo)
+ {
+ if (currentClassId > tracking.length)
+ {
+ ClassInfo[] newTracking = new ClassInfo[tracking.length << 1];
+ System.arraycopy(tracking, 0, newTracking, 0, tracking.length);
+ tracking = newTracking;
+ }
+ tracking[currentClassId] = classInfo;
+ classInfo.setClassId(currentClassId);
+ currentClassId += 1;
+ }
+
+ public void reset()
+ {
+ for (int i = currentClassId - 1; i > fixedClassId; i--)
+ {
+ tracking[i].reset();
+ }
+ currentClassId = fixedClassId;
+ }
+
+ public ClassInfo getClassInfo(Class clazz)
+ {
+ ClassInfo classInfo = store.get(clazz);
+ if (classInfo == null)
+ {
+ classInfo = new ClassInfo().setClassName(clazz.getName()).setJfireSE(jfireSE).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).setClazz(clazz);
+ store.put(clazz, classInfo);
+ }
+ for (int i = 1; i < fixedClassId; i++)
+ {
+ if (tracking[i].getClazz() == clazz)
+ {
+ return;
+ }
+ }
+ if (fixedClassId > tracking.length)
+ {
+ ClassInfo[] newTracking = new ClassInfo[tracking.length << 1];
+ System.arraycopy(tracking, 0, newTracking, 0, tracking.length);
+ tracking = newTracking;
+ }
+ tracking[fixedClassId] = classInfo;
+ classInfo.setClassId(fixedClassId++);
+ currentClassId = fixedClassId;
+ }
+}
diff --git a/src/main/java/com/jfirer/se/InternalByteArray.java b/src/main/java/com/jfirer/se/InternalByteArray.java
new file mode 100644
index 0000000..7c144cd
--- /dev/null
+++ b/src/main/java/com/jfirer/se/InternalByteArray.java
@@ -0,0 +1,539 @@
+package com.jfirer.se;
+
+public class InternalByteArray extends ByteArray
+{
+ public InternalByteArray(int size)
+ {
+ super(size);
+ }
+
+ public InternalByteArray(byte[] array)
+ {
+ super(array);
+ }
+
+ public void writeVarInt(int i)
+ {
+ if (i >= -120 && i <= 127)
+ {
+ ensureCapacity(1);
+ array[writePosi] = (byte) i;
+ writePosi += 1;
+ }
+ else
+ {
+ int head = -120;
+ if (i < 0)
+ {
+ i = ~i;
+ head = -124;
+ }
+ if (i <= 255)
+ {
+ ensureCapacity(2);
+ array[writePosi] = (byte) (head - 1);
+ array[writePosi + 1] = (byte) i;
+ writePosi += 2;
+ }
+ else if (i <= 65535)
+ {
+ ensureCapacity(3);
+ array[writePosi] = (byte) (head - 2);
+ array[writePosi + 1] = (byte) (i >>> 8);
+ array[writePosi + 2] = (byte) i;
+ writePosi += 3;
+ }
+ else if (i <= 16777215)
+ {
+ ensureCapacity(4);
+ array[writePosi] = (byte) (head - 3);
+ array[writePosi + 1] = (byte) (i >>> 16);
+ array[writePosi + 2] = (byte) (i >>> 8);
+ array[writePosi + 3] = (byte) i;
+ writePosi += 4;
+ }
+ else
+ {
+ ensureCapacity(5);
+ array[writePosi] = (byte) (head - 4);
+ array[writePosi + 1] = (byte) (i >>> 24);
+ array[writePosi + 2] = (byte) (i >>> 16);
+ array[writePosi + 3] = (byte) (i >>> 8);
+ array[writePosi + 4] = (byte) i;
+ writePosi += 5;
+ }
+ }
+ }
+
+ public int readVarInt()
+ {
+ byte b = array[readIndex++];
+ if (b >= -120 && b <= 127)
+ {
+ return b;
+ }
+ else
+ {
+ switch (b)
+ {
+ case -128:
+ return ~((array[readIndex++] & 255) << 24 | (array[readIndex++] & 255) << 16 | (array[readIndex++] & 255) << 8 | array[readIndex++] & 255);
+ case -127:
+ return ~((array[readIndex++] & 255) << 16 | (array[readIndex++] & 255) << 8 | array[readIndex++] & 255);
+ case -126:
+ return ~((array[readIndex++] & 255) << 8 | array[readIndex++] & 255);
+ case -125:
+ return ~(array[readIndex++] & 255);
+ case -124:
+ return (array[readIndex++] & 255) << 24 | (array[readIndex++] & 255) << 16 | (array[readIndex++] & 255) << 8 | array[readIndex++] & 255;
+ case -123:
+ return (array[readIndex++] & 255) << 16 | (array[readIndex++] & 255) << 8 | array[readIndex++] & 255;
+ case -122:
+ return (array[readIndex++] & 255) << 8 | array[readIndex++] & 255;
+ case -121:
+ return array[readIndex++] & 255;
+ default:
+ throw new IllegalArgumentException("not here");
+ }
+ }
+ }
+
+ public void writeVarLong(long i)
+ {
+ if (i >= -112L && i <= 127L)
+ {
+ ensureCapacity(1);
+ array[writePosi] = (byte) ((int) i);
+ writePosi += 1;
+ }
+ else
+ {
+ int head = -112;
+ if (i < 0L)
+ {
+ i = ~i;
+ head = -120;
+ }
+ if (i <= 255L)
+ {
+ ensureCapacity(2);
+ array[writePosi] = (byte) (head - 1);
+ array[writePosi + 1] = (byte) ((int) i);
+ writePosi += 2;
+ }
+ else if (i <= 65535L)
+ {
+ ensureCapacity(3);
+ array[writePosi] = (byte) (head - 2);
+ array[writePosi + 1] = (byte) ((int) (i >>> 8));
+ array[writePosi + 2] = (byte) ((int) i);
+ writePosi += 3;
+ }
+ else if (i <= 16777215L)
+ {
+ ensureCapacity(4);
+ array[writePosi] = (byte) (head - 3);
+ array[writePosi + 1] = (byte) ((int) (i >>> 16));
+ array[writePosi + 2] = (byte) ((int) (i >>> 8));
+ array[writePosi + 3] = (byte) ((int) i);
+ writePosi += 4;
+ }
+ else if (i <= -1L)
+ {
+ ensureCapacity(5);
+ array[writePosi] = (byte) (head - 4);
+ array[writePosi + 1] = (byte) ((int) (i >>> 24));
+ array[writePosi + 2] = (byte) ((int) (i >>> 16));
+ array[writePosi + 3] = (byte) ((int) (i >>> 8));
+ array[writePosi + 4] = (byte) ((int) i);
+ writePosi += 5;
+ }
+ else if (i <= 1099511627775L)
+ {
+ ensureCapacity(6);
+ array[writePosi] = (byte) (head - 5);
+ array[writePosi + 1] = (byte) ((int) (i >>> 32));
+ array[writePosi + 2] = (byte) ((int) (i >>> 24));
+ array[writePosi + 3] = (byte) ((int) (i >>> 16));
+ array[writePosi + 4] = (byte) ((int) (i >>> 8));
+ array[writePosi + 5] = (byte) ((int) i);
+ writePosi += 6;
+ }
+ else if (i <= 281474976710655L)
+ {
+ ensureCapacity(7);
+ array[writePosi] = (byte) (head - 6);
+ array[writePosi + 1] = (byte) ((int) (i >>> 40));
+ array[writePosi + 2] = (byte) ((int) (i >>> 32));
+ array[writePosi + 3] = (byte) ((int) (i >>> 24));
+ array[writePosi + 4] = (byte) ((int) (i >>> 16));
+ array[writePosi + 5] = (byte) ((int) (i >>> 8));
+ array[writePosi + 6] = (byte) ((int) i);
+ writePosi += 7;
+ }
+ else if (i <= 72057594037927935L)
+ {
+ ensureCapacity(8);
+ array[writePosi] = (byte) (head - 7);
+ array[writePosi + 1] = (byte) ((int) (i >>> 48));
+ array[writePosi + 2] = (byte) ((int) (i >>> 40));
+ array[writePosi + 3] = (byte) ((int) (i >>> 32));
+ array[writePosi + 4] = (byte) ((int) (i >>> 24));
+ array[writePosi + 5] = (byte) ((int) (i >>> 16));
+ array[writePosi + 6] = (byte) ((int) (i >>> 8));
+ array[writePosi + 7] = (byte) ((int) i);
+ writePosi += 8;
+ }
+ else
+ {
+ ensureCapacity(9);
+ array[writePosi] = (byte) (head - 8);
+ array[writePosi + 1] = (byte) ((int) (i >>> 56));
+ array[writePosi + 2] = (byte) ((int) (i >>> 48));
+ array[writePosi + 3] = (byte) ((int) (i >>> 40));
+ array[writePosi + 4] = (byte) ((int) (i >>> 32));
+ array[writePosi + 5] = (byte) ((int) (i >>> 24));
+ array[writePosi + 6] = (byte) ((int) (i >>> 16));
+ array[writePosi + 7] = (byte) ((int) (i >>> 8));
+ array[writePosi + 8] = (byte) ((int) i);
+ writePosi += 9;
+ }
+ }
+ }
+
+ public long readVarLong()
+ {
+ byte b = array[readIndex++];
+ if (b >= -112 && b <= 127)
+ {
+ return (long) b;
+ }
+ else
+ {
+ switch (b)
+ {
+ case -128:
+ return ~(((long) array[readIndex++] & 255L) << 56 | ((long) array[readIndex++] & 255L) << 48 | ((long) array[readIndex++] & 255L) << 40 | ((long) array[readIndex++] & 255L) << 32 | ((long) array[readIndex++] & 255L) << 24 | ((long) array[readIndex++] & 255L) << 16 | ((long) array[readIndex++] & 255L) << 8 | (long) array[readIndex++] & 255L);
+ case -127:
+ return ~(((long) array[readIndex++] & 255L) << 48 | ((long) array[readIndex++] & 255L) << 40 | ((long) array[readIndex++] & 255L) << 32 | ((long) array[readIndex++] & 255L) << 24 | ((long) array[readIndex++] & 255L) << 16 | ((long) array[readIndex++] & 255L) << 8 | (long) array[readIndex++] & 255L);
+ case -126:
+ return ~(((long) array[readIndex++] & 255L) << 40 | ((long) array[readIndex++] & 255L) << 32 | ((long) array[readIndex++] & 255L) << 24 | ((long) array[readIndex++] & 255L) << 16 | ((long) array[readIndex++] & 255L) << 8 | (long) array[readIndex++] & 255L);
+ case -125:
+ return ~(((long) array[readIndex++] & 255L) << 32 | ((long) array[readIndex++] & 255L) << 24 | ((long) array[readIndex++] & 255L) << 16 | ((long) array[readIndex++] & 255L) << 8 | (long) array[readIndex++] & 255L);
+ case -124:
+ return ~(((long) array[readIndex++] & 255L) << 24 | ((long) array[readIndex++] & 255L) << 16 | ((long) array[readIndex++] & 255L) << 8 | (long) array[readIndex++] & 255L);
+ case -123:
+ return ~(((long) array[readIndex++] & 255L) << 16 | ((long) array[readIndex++] & 255L) << 8 | (long) array[readIndex++] & 255L);
+ case -122:
+ return ~(((long) array[readIndex++] & 255L) << 8 | (long) array[readIndex++] & 255L);
+ case -121:
+ return ~((long) array[readIndex++] & 255L);
+ case -120:
+ return ((long) array[readIndex++] & 255L) << 56 | ((long) array[readIndex++] & 255L) << 48 | ((long) array[readIndex++] & 255L) << 40 | ((long) array[readIndex++] & 255L) << 32 | ((long) array[readIndex++] & 255L) << 24 | ((long) array[readIndex++] & 255L) << 16 | ((long) array[readIndex++] & 255L) << 8 | (long) array[readIndex++] & 255L;
+ case -119:
+ return ((long) array[readIndex++] & 255L) << 48 | ((long) array[readIndex++] & 255L) << 40 | ((long) array[readIndex++] & 255L) << 32 | ((long) array[readIndex++] & 255L) << 24 | ((long) array[readIndex++] & 255L) << 16 | ((long) array[readIndex++] & 255L) << 8 | (long) array[readIndex++] & 255L;
+ case -118:
+ return ((long) array[readIndex++] & 255L) << 40 | ((long) array[readIndex++] & 255L) << 32 | ((long) array[readIndex++] & 255L) << 24 | ((long) array[readIndex++] & 255L) << 16 | ((long) array[readIndex++] & 255L) << 8 | (long) array[readIndex++] & 255L;
+ case -117:
+ return ((long) array[readIndex++] & 255L) << 32 | ((long) array[readIndex++] & 255L) << 24 | ((long) array[readIndex++] & 255L) << 16 | ((long) array[readIndex++] & 255L) << 8 | (long) array[readIndex++] & 255L;
+ case -116:
+ return ((long) array[readIndex++] & 255L) << 24 | ((long) array[readIndex++] & 255L) << 16 | ((long) array[readIndex++] & 255L) << 8 | (long) array[readIndex++] & 255L;
+ case -115:
+ return ((long) array[readIndex++] & 255L) << 16 | ((long) array[readIndex++] & 255L) << 8 | (long) array[readIndex++] & 255L;
+ case -114:
+ return ((long) array[readIndex++] & 255L) << 8 | (long) array[readIndex++] & 255L;
+ case -113:
+ return (long) array[readIndex++] & 255L;
+ default:
+ throw new IllegalArgumentException("not here");
+ }
+ }
+ }
+
+ public void writeVarCharWithoutCheck(char c)
+ {
+ if (c <= 251)
+ {
+ array[writePosi] = (byte) c;
+ writePosi += 1;
+ }
+ else if (c <= 255)
+ {
+ array[writePosi] = -4;
+ array[writePosi + 1] = (byte) c;
+ writePosi += 2;
+ }
+ else if (c <= '\uffff')
+ {
+ array[writePosi] = -3;
+ array[writePosi + 1] = (byte) (c >>> 8);
+ array[writePosi + 2] = (byte) c;
+ writePosi += 3;
+ }
+ }
+
+ public void writeVarChar(char c)
+ {
+ if (c <= 251)
+ {
+ ensureCapacity(1);
+ array[writePosi] = (byte) c;
+ ++writePosi;
+ }
+ else if (c <= 255)
+ {
+ ensureCapacity(2);
+ array[writePosi] = -4;
+ array[writePosi + 1] = (byte) c;
+ writePosi += 2;
+ }
+ else if (c <= '\uffff')
+ {
+ ensureCapacity(3);
+ array[writePosi] = -3;
+ array[writePosi + 1] = (byte) (c >>> 8);
+ array[writePosi + 2] = (byte) c;
+ writePosi += 3;
+ }
+ }
+
+ public char readVarChar()
+ {
+ int length = array[readIndex++] & 255;
+ if (length <= 251)
+ {
+ return (char) length;
+ }
+ else if (length == 252)
+ {
+ length = array[readIndex++] & 255;
+ return (char) length;
+ }
+ else if (length == 253)
+ {
+ length = (array[readIndex++] & 255) << 8;
+ length |= array[readIndex++] & 255;
+ return (char) length;
+ }
+ else
+ {
+ throw new IllegalArgumentException("not here");
+ }
+ }
+
+ public void writePositive(int positive)
+ {
+ if (positive < 0)
+ {
+ throw new UnsupportedOperationException();
+ }
+ else
+ {
+ if (positive <= 251)
+ {
+ ensureCapacity(1);
+ array[writePosi] = (byte) positive;
+ ++writePosi;
+ }
+ else if (positive <= 255)
+ {
+ ensureCapacity(2);
+ array[writePosi] = -4;
+ array[writePosi + 1] = (byte) positive;
+ writePosi += 2;
+ }
+ else if (positive <= 65535)
+ {
+ ensureCapacity(3);
+ array[writePosi] = -3;
+ array[writePosi + 1] = (byte) (positive >>> 8);
+ array[writePosi + 2] = (byte) positive;
+ writePosi += 3;
+ }
+ else if (positive <= 16777215)
+ {
+ ensureCapacity(4);
+ array[writePosi] = -2;
+ array[writePosi + 1] = (byte) (positive >>> 16);
+ array[writePosi + 2] = (byte) (positive >>> 8);
+ array[writePosi + 3] = (byte) positive;
+ writePosi += 4;
+ }
+ else
+ {
+ ensureCapacity(5);
+ array[writePosi] = -1;
+ array[writePosi + 1] = (byte) (positive >>> 24);
+ array[writePosi + 2] = (byte) (positive >>> 16);
+ array[writePosi + 3] = (byte) (positive >>> 8);
+ array[writePosi + 4] = (byte) positive;
+ writePosi += 5;
+ }
+ }
+ }
+
+ public int readPositive()
+ {
+ int length = array[readIndex++] & 255;
+ if (length <= 251)
+ {
+ return length;
+ }
+ else if (length == 252)
+ {
+ length = array[readIndex++] & 255;
+ return length;
+ }
+ else if (length == 253)
+ {
+ length = (array[readIndex++] & 255) << 8;
+ length |= array[readIndex++] & 255;
+ return length;
+ }
+ else if (length == 254)
+ {
+ length = (array[readIndex++] & 255) << 16;
+ length |= (array[readIndex++] & 255) << 8;
+ length |= array[readIndex++] & 255;
+ return length;
+ }
+ else if (length == 255)
+ {
+ length = (array[readIndex++] & 255) << 24;
+ length |= (array[readIndex++] & 255) << 16;
+ length |= (array[readIndex++] & 255) << 8;
+ length |= array[readIndex++] & 255;
+ return length;
+ }
+ else
+ {
+ throw new RuntimeException("wrong data");
+ }
+ }
+
+ public void writeInt(int i)
+ {
+ ensureCapacity(4);
+ array[writePosi] = (byte) (i >> 24);
+ array[writePosi + 1] = (byte) (i >> 16);
+ array[writePosi + 2] = (byte) (i >> 8);
+ array[writePosi + 3] = (byte) i;
+ writePosi += 4;
+ }
+
+ public void writeShort(short s)
+ {
+ ensureCapacity(2);
+ array[writePosi] = (byte) (s >> 8);
+ array[writePosi + 1] = (byte) s;
+ writePosi += 2;
+ }
+
+ public void writeLong(long l)
+ {
+ ensureCapacity(8);
+ array[writePosi] = (byte) ((int) (l >> 56));
+ array[writePosi + 1] = (byte) ((int) (l >> 48));
+ array[writePosi + 2] = (byte) ((int) (l >> 40));
+ array[writePosi + 3] = (byte) ((int) (l >> 32));
+ array[writePosi + 4] = (byte) ((int) (l >> 24));
+ array[writePosi + 5] = (byte) ((int) (l >> 16));
+ array[writePosi + 6] = (byte) ((int) (l >> 8));
+ array[writePosi + 7] = (byte) ((int) l);
+ writePosi += 8;
+ }
+
+ public int readInt()
+ {
+ int i = (array[readIndex] & 255) << 24;
+ i |= (array[readIndex + 1] & 255) << 16;
+ i |= (array[readIndex + 2] & 255) << 8;
+ i |= array[readIndex + 3] & 255;
+ this.readIndex += 4;
+ return i;
+ }
+
+ public short readShort()
+ {
+ short s = (short) ((array[readIndex] & 255) << 8);
+ s = (short) (s | array[readIndex + 1] & 255);
+ this.readIndex += 2;
+ return s;
+ }
+
+ public long readLong()
+ {
+ long l = (long) array[readIndex] << 56 | ((long) array[readIndex + 1] & 255L) << 48 | ((long) array[readIndex + 2] & 255L) << 40 | ((long) array[readIndex + 3] & 255L) << 32 | ((long) array[readIndex + 4] & 255L) << 24 | ((long) array[readIndex + 5] & 255L) << 16 | ((long) array[readIndex + 6] & 255L) << 8 | (long) array[readIndex + 7] & 255L;
+ this.readIndex += 8;
+ return l;
+ }
+
+ public void writeFloat(float f)
+ {
+ writeInt(Float.floatToRawIntBits(f));
+ }
+
+ public void writeDouble(double d)
+ {
+ writeLong(Double.doubleToRawLongBits(d));
+ }
+
+ public float readFloat()
+ {
+ int i = readInt();
+ return Float.intBitsToFloat(i);
+ }
+
+ public double readDouble()
+ {
+ long l = readLong();
+ return Double.longBitsToDouble(l);
+ }
+
+ public void skipWrite(int len)
+ {
+ ensureCapacity(len);
+ writePosi += len;
+ }
+
+ public void writeString(String value)
+ {
+ if (value == null)
+ {
+ writeVarInt(-1);
+ }
+ else
+ {
+ int length = value.length();
+ writeVarInt(length);
+ ensureCapacity(3 * length);
+ for (int i = 0; i < length; ++i)
+ {
+ writeVarCharWithoutCheck(value.charAt(i));
+ }
+ }
+ }
+
+ public String readString()
+ {
+ int length = readVarInt();
+ if (length == -1)
+ {
+ return null;
+ }
+ else
+ {
+ char[] src = new char[length];
+ for (int i = 0; i < length; ++i)
+ {
+ src[i] = this.readVarChar();
+ }
+ return new String(src);
+ }
+ }
+
+ public boolean remainRead()
+ {
+ return readIndex < writePosi;
+ }
+}
diff --git a/src/main/java/com/jfirer/se/JfireSE.java b/src/main/java/com/jfirer/se/JfireSE.java
new file mode 100644
index 0000000..82e998d
--- /dev/null
+++ b/src/main/java/com/jfirer/se/JfireSE.java
@@ -0,0 +1,46 @@
+package com.jfirer.se;
+
+import com.jfirer.se.serializer.Serializer;
+import com.jfirer.se.serializer.SerializerResolver;
+
+public class JfireSE
+{
+ public static final byte NULL = 0;
+ private boolean CYCLE_SUPPORT = true;
+ private SerializerResolver serializerResolver;
+ private ClassInfoResolver classInfoResolver;
+ private int depth = 1;
+
+ public boolean isCycleSupport()
+ {
+ return CYCLE_SUPPORT;
+ }
+
+ public Serializer getSerializer(Class clazz)
+ {
+ return serializerResolver.getSerializer(clazz, this);
+ }
+
+ public ClassInfo getClassInfo(Class clazz)
+ {
+ return classInfoResolver.getClassInfo(clazz);
+ }
+
+ public void getClassId(ClassInfo classInfo)
+ {
+ classInfoResolver.getClassId(classInfo);
+ }
+
+ public void incrDepth()
+ {
+ if (depth++ > 256)
+ {
+ throw new IllegalStateException("序列化深度超过256,可能存在循环引用,请开启循环引用设置");
+ }
+ }
+
+ public void reduceDepth()
+ {
+ depth--;
+ }
+}
diff --git a/src/main/java/com/jfirer/se/serializer/Serializer.java b/src/main/java/com/jfirer/se/serializer/Serializer.java
new file mode 100644
index 0000000..0b60278
--- /dev/null
+++ b/src/main/java/com/jfirer/se/serializer/Serializer.java
@@ -0,0 +1,8 @@
+package com.jfirer.se.serializer;
+
+import com.jfirer.se.InternalByteArray;
+
+public interface Serializer
+{
+ void writeBytes(InternalByteArray byteArray, Object instance);
+}
diff --git a/src/main/java/com/jfirer/se/serializer/SerializerResolver.java b/src/main/java/com/jfirer/se/serializer/SerializerResolver.java
new file mode 100644
index 0000000..28dfd16
--- /dev/null
+++ b/src/main/java/com/jfirer/se/serializer/SerializerResolver.java
@@ -0,0 +1,25 @@
+package com.jfirer.se.serializer;
+
+import com.jfirer.se.JfireSE;
+
+import java.util.IdentityHashMap;
+import java.util.Map;
+
+public class SerializerResolver
+{
+ private Map store = new IdentityHashMap<>();
+
+ public Serializer getSerializer(Class clazz, JfireSE jfireSE)
+ {
+ Serializer serializer = store.get(clazz);
+ if (serializer != null)
+ {
+ return serializer;
+ }
+
+ }
+ public void registerSerializer(Class clazz, Serializer serializer)
+ {
+ store.put(clazz, serializer);
+ }
+}
diff --git a/src/main/java/com/jfirer/se/serializer/impl/ObjectSerializer.java b/src/main/java/com/jfirer/se/serializer/impl/ObjectSerializer.java
new file mode 100644
index 0000000..73df80a
--- /dev/null
+++ b/src/main/java/com/jfirer/se/serializer/impl/ObjectSerializer.java
@@ -0,0 +1,232 @@
+package com.jfirer.se.serializer.impl;
+
+import com.jfirer.baseutil.reflect.ReflectUtil;
+import com.jfirer.baseutil.reflect.ValueAccessor;
+import com.jfirer.se.ClassInfo;
+import com.jfirer.se.InternalByteArray;
+import com.jfirer.se.JfireSE;
+import com.jfirer.se.serializer.Serializer;
+import lombok.Data;
+
+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;
+
+public class ObjectSerializer implements Serializer
+{
+ private FieldInfo[] primitiveFieldInfos;
+ private FieldInfo[] boxFieldInfos;
+ private FinalFieldInfo[] finalFieldInfos;
+ private JfireSE jfireSE;
+ private Class clazz;
+
+ public ObjectSerializer(Class clazz, JfireSE jfireSE)
+ {
+ this.clazz = clazz;
+ this.jfireSE = jfireSE;
+ Class type = clazz;
+ List fields = new ArrayList<>();
+ while (type != Object.class)
+ {
+ fields.addAll(Arrays.stream(type.getDeclaredFields()).filter(Predicate.not(field -> Modifier.isStatic(field.getModifiers()))).toList());
+ type = type.getComponentType();
+ }
+ 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() != 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);
+ }
+
+ @Override
+ public void writeBytes(InternalByteArray byteArray, Object instance)
+ {
+ }
+
+ @Data
+ class FieldInfo
+ {
+ int classId;
+ ValueAccessor accessor;
+
+ FieldInfo(Field field)
+ {
+ classId = ReflectUtil.getClassId(field.getType());
+ accessor = new ValueAccessor(field);
+ }
+
+ void write(InternalByteArray 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.writePositive(accessor.getBoolean(instance) ? 1 : 0);
+ case ReflectUtil.PRIMITIVE_CHAR -> byteArray.writeVarChar(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((byte) 01);
+ byteArray.writeVarInt(value);
+ }
+ }
+ case ReflectUtil.CLASS_LONG ->
+ {
+ Long value = accessor.getLongObject(instance);
+ if (value == null)
+ {
+ byteArray.put(JfireSE.NULL);
+ }
+ else
+ {
+ byteArray.put((byte) 01);
+ byteArray.writeVarLong(value);
+ }
+ }
+ case ReflectUtil.CLASS_FLOAT ->
+ {
+ Float value = accessor.getFloatObject(instance);
+ if (value == null)
+ {
+ byteArray.put(JfireSE.NULL);
+ }
+ else
+ {
+ byteArray.put((byte) 01);
+ byteArray.writeFloat(value);
+ }
+ }
+ case ReflectUtil.CLASS_DOUBLE ->
+ {
+ Double value = accessor.getDoubleObject(instance);
+ if (value == null)
+ {
+ byteArray.put(JfireSE.NULL);
+ }
+ else
+ {
+ byteArray.put((byte) 01);
+ byteArray.writeDouble(value);
+ }
+ }
+ case ReflectUtil.CLASS_BOOL ->
+ {
+ Boolean value = accessor.getBooleanObject(instance);
+ if (value == null)
+ {
+ byteArray.put(JfireSE.NULL);
+ }
+ else
+ {
+ byteArray.put((byte) 01);
+ byteArray.writePositive(value ? 1 : 0);
+ }
+ }
+ case ReflectUtil.CLASS_CHAR ->
+ {
+ Character value = accessor.getCharObject(instance);
+ if (value == null)
+ {
+ byteArray.put(JfireSE.NULL);
+ }
+ else
+ {
+ byteArray.put((byte) 01);
+ byteArray.writeVarChar(value);
+ }
+ }
+ case ReflectUtil.CLASS_SHORT ->
+ {
+ Short value = accessor.getShortObject(instance);
+ if (value == null)
+ {
+ byteArray.put(JfireSE.NULL);
+ }
+ else
+ {
+ byteArray.put((byte) 01);
+ byteArray.writeShort(value);
+ }
+ }
+ case ReflectUtil.CLASS_BYTE ->
+ {
+ Byte value = accessor.getByteObject(instance);
+ if (value == null)
+ {
+ byteArray.put(JfireSE.NULL);
+ }
+ else
+ {
+ byteArray.put((byte) 01);
+ byteArray.put(value);
+ }
+ }
+ case ReflectUtil.CLASS_STRING ->
+ {
+ String value = (String) accessor.get(instance);
+ if (value == null)
+ {
+ byteArray.put(JfireSE.NULL);
+ }
+ else
+ {
+ byteArray.put((byte) 01);
+ byteArray.writeString(value);
+ }
+ }
+ }
+ }
+ }
+
+ class FinalFieldInfo
+ {
+ ValueAccessor accessor;
+ ClassInfo classInfo;
+
+ FinalFieldInfo(Field field)
+ {
+ accessor = new ValueAccessor(field);
+ classInfo = jfireSE.getClassInfo(field.getType());
+ }
+
+ void write(InternalByteArray byteArray, Object instance)
+ {
+ Object value = accessor.get(instance);
+ if (value == null)
+ {
+ byteArray.put(JfireSE.NULL);
+ }
+ else
+ {
+ byteArray.put((byte) 07);
+
+ }
+ }
+ }
+
+ class VariableFieldInfo
+ {
+ ValueAccessor accessor;
+ ClassInfo classInfo;
+
+ VariableFieldInfo(Field field)
+ {
+ accessor = new ValueAccessor(field);
+ }
+ }
+}
diff --git a/src/test/java/org/example/AppTest.java b/src/test/java/org/example/AppTest.java
new file mode 100644
index 0000000..d5f435d
--- /dev/null
+++ b/src/test/java/org/example/AppTest.java
@@ -0,0 +1,38 @@
+package org.example;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * Unit test for simple App.
+ */
+public class AppTest
+ extends TestCase
+{
+ /**
+ * Create the test case
+ *
+ * @param testName name of the test case
+ */
+ public AppTest( String testName )
+ {
+ super( testName );
+ }
+
+ /**
+ * @return the suite of tests being tested
+ */
+ public static Test suite()
+ {
+ return new TestSuite( AppTest.class );
+ }
+
+ /**
+ * Rigourous Test :-)
+ */
+ public void testApp()
+ {
+ assertTrue( true );
+ }
+}