diff --git a/sa-token-bom/pom.xml b/sa-token-bom/pom.xml
index 4c69c691..2cfacc31 100644
--- a/sa-token-bom/pom.xml
+++ b/sa-token-bom/pom.xml
@@ -209,6 +209,11 @@
sa-token-redis-template-jdk-serializer
${revision}
+
+ cn.dev33
+ sa-token-serializer-features
+ ${revision}
+
diff --git a/sa-token-test/pom.xml b/sa-token-test/pom.xml
index 6a336c45..fee39985 100644
--- a/sa-token-test/pom.xml
+++ b/sa-token-test/pom.xml
@@ -25,6 +25,7 @@
sa-token-jwt-test
sa-token-json-test
+ sa-token-serializer-test
diff --git a/sa-token-test/sa-token-serializer-test/pom.xml b/sa-token-test/sa-token-serializer-test/pom.xml
new file mode 100644
index 00000000..bd64dda9
--- /dev/null
+++ b/sa-token-test/sa-token-serializer-test/pom.xml
@@ -0,0 +1,26 @@
+
+
+ 4.0.0
+
+
+ cn.dev33
+ sa-token-test
+ ${revision}
+ ../pom.xml
+
+ jar
+
+ sa-token-serializer-test
+ sa-token-serializer-test
+ sa-token-serializer-test
+
+
+
+ cn.dev33
+ sa-token-serializer-features
+
+
+
+
diff --git a/sa-token-test/sa-token-serializer-test/src/test/java/com/pj/test/SaSerializerTemplateTest.java b/sa-token-test/sa-token-serializer-test/src/test/java/com/pj/test/SaSerializerTemplateTest.java
new file mode 100644
index 00000000..2ff23687
--- /dev/null
+++ b/sa-token-test/sa-token-serializer-test/src/test/java/com/pj/test/SaSerializerTemplateTest.java
@@ -0,0 +1,177 @@
+package com.pj.test;
+
+import cn.dev33.satoken.SaManager;
+import cn.dev33.satoken.serializer.SaSerializerForBase64UseEmoji;
+import cn.dev33.satoken.serializer.SaSerializerForBase64UsePeriodicTable;
+import cn.dev33.satoken.serializer.SaSerializerForBase64UseSpecialSymbols;
+import cn.dev33.satoken.serializer.SaSerializerForBase64UseTianGan;
+import cn.dev33.satoken.serializer.impl.SaSerializerTemplateForJdkUseBase64;
+import cn.dev33.satoken.serializer.impl.SaSerializerTemplateForJdkUseHex;
+import cn.dev33.satoken.serializer.impl.SaSerializerTemplateForJdkUseISO_8859_1;
+import com.pj.test.model.SysUser;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Sa-Token Serializer 序列化模块测试
+ *
+ * @author click33
+ *
+ */
+public class SaSerializerTemplateTest {
+
+ // 开始
+ @BeforeAll
+ public static void beforeClass() {
+ System.out.println("\n\n------------------------ SaSerializerTemplateTest star ...");
+ }
+
+ // 结束
+ @AfterAll
+ public static void afterClass() {
+ System.out.println("\n\n------------------------ SaSerializerTemplateTest end ... \n");
+ }
+
+ // 测试:SaSerializerTemplateForJdkUseBase64
+ @Test
+ public void testSaSerializerTemplateForJdkUseBase64() {
+ SaManager.setSaSerializerTemplate(new SaSerializerTemplateForJdkUseBase64());
+ Assertions.assertEquals(SaManager.getSaSerializerTemplate().getClass(), SaSerializerTemplateForJdkUseBase64.class);
+
+ // test Object -> String
+ SysUser user = new SysUser(10001, "张三", 18);
+ String objectString = SaManager.getSaSerializerTemplate().objectToString(user);
+ Assertions.assertEquals("rO0ABXNyABljb20ucGoudGVzdC5tb2RlbC5TeXNVc2Vy0MeZoPBtVUwCAARJAANhZ2VKAAJpZEwABG5hbWV0ABJMamF2YS9sYW5nL1N0cmluZztMAARyb2xldAAbTGNvbS9wai90ZXN0L21vZGVsL1N5c1JvbGU7eHAAAAASAAAAAAAAJxF0AAblvKDkuIlw", objectString);
+
+ // test String -> Object
+ SysUser user2 = SaManager.getSaSerializerTemplate().stringToObject(objectString, SysUser.class);
+ Assertions.assertEquals(user2.toString(), user.toString());
+
+ // more
+ testNull();
+ }
+
+ // 测试:SaSerializerTemplateForJdkUseHex
+ @Test
+ public void testSaSerializerTemplateForJdkUseHex() {
+ SaManager.setSaSerializerTemplate(new SaSerializerTemplateForJdkUseHex());
+ Assertions.assertEquals(SaManager.getSaSerializerTemplate().getClass(), SaSerializerTemplateForJdkUseHex.class);
+
+ // test Object -> String
+ SysUser user = new SysUser(10001, "张三", 18);
+ String objectString = SaManager.getSaSerializerTemplate().objectToString(user);
+ Assertions.assertEquals("ACED000573720019636F6D2E706A2E746573742E6D6F64656C2E53797355736572D0C799A0F06D554C0200044900036167654A000269644C00046E616D657400124C6A6176612F6C616E672F537472696E673B4C0004726F6C6574001B4C636F6D2F706A2F746573742F6D6F64656C2F537973526F6C653B7870000000120000000000002711740006E5BCA0E4B88970", objectString);
+
+ // test String -> Object
+ SysUser user2 = SaManager.getSaSerializerTemplate().stringToObject(objectString, SysUser.class);
+ Assertions.assertEquals(user2.toString(), user.toString());
+
+ // more
+ testNull();
+ }
+
+ // 测试:SaSerializerTemplateForJdkUseISO_8859_1
+ @Test
+ public void testSaSerializerTemplateForJdkUseISO_8859_1() {
+ SaManager.setSaSerializerTemplate(new SaSerializerTemplateForJdkUseISO_8859_1());
+ Assertions.assertEquals(SaManager.getSaSerializerTemplate().getClass(), SaSerializerTemplateForJdkUseISO_8859_1.class);
+
+ // test Object -> String
+ SysUser user = new SysUser(10001, "张三", 18);
+ String objectString = SaManager.getSaSerializerTemplate().objectToString(user);
+ // Assertions.assertEquals("xxxx", objectString); // 太过奇形怪状,无法直接断言
+
+ // test String -> Object
+ SysUser user2 = SaManager.getSaSerializerTemplate().stringToObject(objectString, SysUser.class);
+ Assertions.assertEquals(user2.toString(), user.toString());
+
+ // more
+ testNull();
+ }
+
+ // 测试:SaSerializerForBase64UseTianGan
+ @Test
+ public void testSaSerializerForBase64UseTianGan() {
+ SaManager.setSaSerializerTemplate(new SaSerializerForBase64UseTianGan());
+ Assertions.assertEquals(SaManager.getSaSerializerTemplate().getClass(), SaSerializerForBase64UseTianGan.class);
+
+ // test Object -> String
+ SysUser user = new SysUser(10001, "张三", 18);
+ String objectString = SaManager.getSaSerializerTemplate().objectToString(user);
+ Assertions.assertEquals("雷辰中甲乙坤卯西甲乙日天离谷中雾艮庚石雾兑庚亥北兑丙宙霜离谷未日离丙宙酉金坤卯亥艮谷亥西中寅金巽石巳乙霜亥戌东丙甲甲未癸甲甲卯火巽谷亥子甲甲癸田巽戊东甲乙庚宙火离乾亥中甲乙癸寅坎月己谷震申安电震乾宙山丑信卯中艮月日雾巽北霜寅甲甲未西离谷南日兑甲甲离酉庚卯露离申安东坎土安中巽坤卯中丑谷信露巽庚亥电丑信卯宙艮信癸露离庚戌泰金辛甲甲甲甲甲申甲甲甲甲甲甲甲甲癸南己中甲甲离日露子丁地雾壬日东", objectString);
+
+ // test String -> Object
+ SysUser user2 = SaManager.getSaSerializerTemplate().stringToObject(objectString, SysUser.class);
+ Assertions.assertEquals(user2.toString(), user.toString());
+
+ // more
+ testNull();
+ }
+
+ // 测试:SaSerializerForBase64UsePeriodicTable
+ @Test
+ public void testSaSerializerForBase64UsePeriodicTable() {
+ SaManager.setSaSerializerTemplate(new SaSerializerForBase64UsePeriodicTable());
+ Assertions.assertEquals(SaManager.getSaSerializerTemplate().getClass(), SaSerializerForBase64UsePeriodicTable.class);
+
+ // test Object -> String
+ SysUser user = new SysUser(10001, "张三", 18);
+ String objectString = SaManager.getSaSerializerTemplate().objectToString(user);
+ Assertions.assertEquals("钌磷碘氢氦铬硅锑氢氦锶氪镍铯碘银铜氮铌银锌氮钛碲锌锂铈钯镍铯氩锶镍锂铈钙镓铬硅钛铜铯钛锑碘铝镓铁铌硫氦钯钛钪铟锂氢氢氩氖氢氢硅硒铁铯钛钠氢氢氖钼铁硼铟氢氦氮铈硒镍钒钛碘氢氦氖铝钴钇碳铯锰钾钐铑锰钒铈锆镁氙硅碘铜钇锶银铁碲钯铝氢氢氩锑镍铯锡锶锌氢氢镍钙氮硅镉镍钾钐铟钴溴钐碘铁铬硅碘镁铯氙镉铁氮钛铑镁氙硅铈铜氙氖镉镍氮钪钕镓氧氢氢氢氢氢钾氢氢氢氢氢氢氢氢氖锡碳碘氢氢镍锶镉钠铍铷银氟锶铟", objectString);
+
+ // test String -> Object
+ SysUser user2 = SaManager.getSaSerializerTemplate().stringToObject(objectString, SysUser.class);
+ Assertions.assertEquals(user2.toString(), user.toString());
+
+ // more
+ testNull();
+ }
+
+ // 测试:SaSerializerForBase64UseSpecialSymbols
+ @Test
+ public void testSaSerializerForBase64UseSpecialSymbols() {
+ SaManager.setSaSerializerTemplate(new SaSerializerForBase64UseSpecialSymbols());
+ Assertions.assertEquals(SaManager.getSaSerializerTemplate().getClass(), SaSerializerForBase64UseSpecialSymbols.class);
+
+ // test Object -> String
+ SysUser user = new SysUser(10001, "张三", 18);
+ String objectString = SaManager.getSaSerializerTemplate().objectToString(user);
+ Assertions.assertEquals("→▃☶▲▼▌▂☳▲▼§♫▬☰☶↘〓▶↑↘◤▶▎☱◤●☀↓▬☰▆§▬●☀█◥▌▂▎〓☰▎☳☶▁◥▊↑▄▼↓▎▏☲●▲▲▆♥▲▲▂♩▊☰▎♦▲▲♥↗▊■☲▲▼▶☀♩▬▍▎☶▲▼♥▁▉〼★☰▋▇‥↙▋▍☀↖♣☵▂☶〓〼§↘▊☱↓▁▲▲▆☳▬☰☷§◤▲▲▬█▶▂☴▬▇‥☲▉♪‥☶▊▌▂☶♣☰☵☴▊▶▎↙♣☵▂☀〓☵♥☴▬▶▏▪◥◀▲▲▲▲▲▇▲▲▲▲▲▲▲▲♥☷★☶▲▲▬§☴♦◆♬↘♠§☲", objectString);
+
+ // test String -> Object
+ SysUser user2 = SaManager.getSaSerializerTemplate().stringToObject(objectString, SysUser.class);
+ Assertions.assertEquals(user2.toString(), user.toString());
+
+ // more
+ testNull();
+ }
+
+ // 测试:SaSerializerForBase64UseEmoji
+ @Test
+ public void testSaSerializerForBase64UseEmoji() {
+ SaManager.setSaSerializerTemplate(new SaSerializerForBase64UseEmoji());
+ Assertions.assertEquals(SaManager.getSaSerializerTemplate().getClass(), SaSerializerForBase64UseEmoji.class);
+
+ // test Object -> String
+ SysUser user = new SysUser(10001, "张三", 18);
+ String objectString = SaManager.getSaSerializerTemplate().objectToString(user);
+ Assertions.assertEquals("😫😎😴😀😁😗😍😲😀😁😥😣😛😶😴😮😜😆😨😮😝😆😕😳😝😂😹😭😛😶😑😥😛😂😹😓😞😗😍😕😜😶😕😲😴😌😞😙😨😏😁😭😕😔😰😂😀😀😑😉😀😀😍😡😙😶😕😊😀😀😉😩😙😄😰😀😁😆😹😡😛😖😕😴😀😁😉😌😚😦😅😶😘😒😽😬😘😖😹😧😋😵😍😴😜😦😥😮😙😳😭😌😀😀😑😲😛😶😱😥😝😀😀😛😓😆😍😯😛😒😽😰😚😢😽😴😙😗😍😴😋😶😵😯😙😆😕😬😋😵😍😹😜😵😉😯😛😆😔😻😞😇😀😀😀😀😀😒😀😀😀😀😀😀😀😀😉😱😅😴😀😀😛😥😯😊😃😤😮😈😥😰", objectString);
+
+ // test String -> Object
+ SysUser user2 = SaManager.getSaSerializerTemplate().stringToObject(objectString, SysUser.class);
+ Assertions.assertEquals(user2.toString(), user.toString());
+
+ // more
+ testNull();
+ }
+
+ // 测试 Null 值
+ private void testNull() {
+ Assertions.assertNull(SaManager.getSaSerializerTemplate().objectToString(null));
+ Assertions.assertNull(SaManager.getSaSerializerTemplate().stringToObject(null, SysUser.class));
+ Assertions.assertNull(SaManager.getSaSerializerTemplate().stringToObject(null));
+ }
+
+}
diff --git a/sa-token-test/sa-token-serializer-test/src/test/java/com/pj/test/model/SysRole.java b/sa-token-test/sa-token-serializer-test/src/test/java/com/pj/test/model/SysRole.java
new file mode 100644
index 00000000..f86ba408
--- /dev/null
+++ b/sa-token-test/sa-token-serializer-test/src/test/java/com/pj/test/model/SysRole.java
@@ -0,0 +1,66 @@
+package com.pj.test.model;
+
+import java.io.Serializable;
+
+/**
+ * Role 实体类
+ *
+ * @author click33
+ * @since 2022-10-15
+ */
+public class SysRole implements Serializable {
+//
+// public SysRole() {
+// }
+//
+// public SysRole(long id, String name) {
+// super();
+// this.id = id;
+// this.name = name;
+// }
+//
+//
+// /**
+// * 角色id
+// */
+// private long id;
+//
+// /**
+// * 角色名称
+// */
+// private String name;
+//
+// /**
+// * @return id
+// */
+// public long getId() {
+// return id;
+// }
+//
+// /**
+// * @param id 要设置的 id
+// */
+// public void setId(long id) {
+// this.id = id;
+// }
+//
+// /**
+// * @return name
+// */
+// public String getName() {
+// return name;
+// }
+//
+// /**
+// * @param name 要设置的 name
+// */
+// public void setName(String name) {
+// this.name = name;
+// }
+//
+// @Override
+// public String toString() {
+// return "SysRole [id=" + id + ", name=" + name + "]";
+// }
+//
+}
diff --git a/sa-token-test/sa-token-serializer-test/src/test/java/com/pj/test/model/SysUser.java b/sa-token-test/sa-token-serializer-test/src/test/java/com/pj/test/model/SysUser.java
new file mode 100644
index 00000000..bf07fb6b
--- /dev/null
+++ b/sa-token-test/sa-token-serializer-test/src/test/java/com/pj/test/model/SysUser.java
@@ -0,0 +1,105 @@
+package com.pj.test.model;
+
+import java.io.Serializable;
+
+/**
+ * User 实体类
+ *
+ * @author click33
+ * @since 2022-10-15
+ */
+public class SysUser implements Serializable {
+
+ public SysUser() {
+ }
+
+ public SysUser(long id, String name, int age) {
+ super();
+ this.id = id;
+ this.name = name;
+ this.age = age;
+ }
+
+
+ /**
+ * 用户id
+ */
+ private long id;
+
+ /**
+ * 用户名称
+ */
+ private String name;
+
+ /**
+ * 用户年龄
+ */
+ private int age;
+
+ /**
+ * 用户角色
+ */
+ private SysRole role;
+
+ /**
+ * @return id
+ */
+ public long getId() {
+ return id;
+ }
+
+ /**
+ * @param id 要设置的 id
+ */
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ /**
+ * @return name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @param name 要设置的 name
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * @return age
+ */
+ public int getAge() {
+ return age;
+ }
+
+ /**
+ * @param age 要设置的 age
+ */
+ public void setAge(int age) {
+ this.age = age;
+ }
+
+ public SysRole getRole() {
+ return role;
+ }
+
+ public SysUser setRole(SysRole role) {
+ this.role = role;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return "SysUser{" +
+ "id=" + id +
+ ", name='" + name + '\'' +
+ ", age=" + age +
+ ", role=" + role +
+ '}';
+ }
+
+}