snack4 - Json 序列化之枚举的编解码
枚举(Enum)看是一个值,但又可以是各种不同的值。比如有 ordinal,有 name,还可以有结构。之于序列化,用况就特别多。特此专门作说明。
- 主要的编码控制方式有:
| 方式 | 描述 | 编码(序列化)效果 | 影响范围 |
|---|---|---|---|
| A | 默认 | 输出枚举 ordinal | 执行相关的所有枚举 |
| B1 | 选项特性 Write_EnumUsingName | 输出枚举 name | 执行相关的所有枚举 |
| B2 | 选项特性 Write_EnumUsingToString | 输出 toString() 结果 | 同上 |
| B3 | 选项特性 Write_EnumShapeAsObject | 如果有字段?输出 json object 风格 | 同上 |
| C1 | 类型特性 Write_EnumUsingName | 输出枚举 name | 当前类型 |
| C2 | 类型特性 Write_EnumUsingToString | 输出 toString() 结果 | 同上 |
| C3 | 类型特性 Write_EnumShapeAsObject | 如果有字段?输出 json object 风格 | 同上 |
| D1 | 类型字段 添加 @ONodeAttr 注解 | 输出字段值 | 当前类型 |
| E1 | 类型 自定义编解码 | 输出定制值 | 当前类型 |
| F1 | 值字段特性 Write_EnumUsingName | 输出枚举 name | 当前字段 |
| F2 | 值字段特性 Write_EnumUsingToString | 输出 toString() 结果 | 同上 |
| F3 | 值字段特性 Write_EnumShapeAsObject | 如果有字段?输出 json object 风格 | 同上 |
其中:类型特性和值字段特性,通过注解 @ONodeAttr(features=...) 附加特性。
- 主要的解码控制方式有:
| 方式 | 描述 | 编码(序列化)效果 | 影响范围 |
|---|---|---|---|
| X1 | 默认 | 可接收枚举 ordinal 或 name | 执行相关的所有枚举 |
| Y1 | 类型字段 添加 @ONodeAttr 注解 | 可接收注解字段对应的值 | 当前类型 |
| Z1 | 类型静态方法 添加 @ONodeCreator 注解 | 可接收注解方法参数对应的值 | 当前类型 |
演示素材
@Getter
public class User {
private final String name;
private final int age;
private final Gender gender;
public User(String name, int age, Gender gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
}
@Getter
public enum Gender {
UNKNOWN(10, "未知的性别"), MALE(11, "男"), FEMALE(12, "女"), UNSTATED(19, "未说明的性别");
private final int code;
private final String name;
Gender(int code, String name) {
this.code = code;
this.name = name;
}
@Override
public String toString() {
return name;
}
public static Gender fromCode(Integer code) {
for (Gender gender : Gender.values()) {
if (gender.code == code) {
return gender;
}
}
return UNKNOWN;
}
}
1、编码(序列化) - 方式A:默认
默认输出 ordinal 值
@Test
public void case11() {
User user = new User("solon", 22, Gender.MALE);
String json = ONode.serialize(user);
System.out.println(json);
Assertions.assertEquals("{\"name\":\"solon\",\"age\":22,\"gender\":1}", json);
}
2、编码(序列化) - 方式B:选项特性
选项特性是指:序列化时添加特性,或通过 Options 添加特性,对本次序列化进行控制。
- 使用 Write_EnumUsingName 特性
@Test
public void case21() {
User user = new User("solon", 22, Gender.MALE);
String json = ONode.serialize(user, Feature.Write_EnumUsingName);
System.out.println(json);
Assertions.assertEquals("{\"name\":\"solon\",\"age\":22,\"gender\":\"MALE\"}", json);
}
- 使用 Write_EnumUsingToString 特性
@Test
public void case22() {
User user = new User("solon", 22, Gender.MALE);
String json = ONode.serialize(user, Feature.Write_EnumUsingToString);
System.out.println(json);
Assertions.assertEquals("{\"name\":\"solon\",\"age\":22,\"gender\":\"男\"}", json);
}
- 使用 Write_EnumShapeAsObject 特性(输出枚举的所有字段)
@Test
public void case23() {
User user = new User("solon", 22, Gender.MALE);
String json = ONode.serialize(user, Feature.Write_EnumShapeAsObject);
System.out.println(json);
Assertions.assertEquals("{\"name\":\"solon\",\"age\":22,\"gender\":{\"code\":11,\"name\":\"男\"}}", json);
}
3、编码(序列化) - 方式C:类型特性(v4.0.11 后支持)
类型特性是指,为枚举类型添加 @ONodeAttr 注解,并附加特性。
@ONodeAttr(features=Feature.Write_EnumUsingName)
public static enum Gender {...}
@Test
public void case31() {
User user = new User("solon", 22, Gender.MALE);
String json = ONode.serialize(user);
System.out.println(json);
Assertions.assertEquals("{\"name\":\"solon\",\"age\":22,\"gender\":\"MALE\"}", json);
}
其它特性演示,略过。
4、编码(序列化) - 方式D:类型字段添加注解(优先级第二高)
类型字段添加注解,是指在枚举类型的字段上添加注解,以此字段值代表此类型输出。
public static enum Gender {
UNKNOWN(10, "未知的性别"), MALE(11, "男"), FEMALE(12, "女"), UNSTATED(19, "未说明的性别");
@ONodeAttr
private final int code;
private final String name;
Gender(int code, String name) {
this.code = code;
this.name = name;
}
}
//本例把 `code` 的值作为此枚举类型输出。
@Test
public void case41() {
User user = new User("solon", 22, Gender.MALE);
String json = ONode.serialize(user);
System.out.println(json);
Assertions.assertEquals("{\"name\":\"solon\",\"age\":22,\"gender\":11}", json);
}
5、编码(序列化) - 方式E:类型自定义编解码(优先级最高)
类型自定义编解码,是指通过 Options 添加特定类型的编解码器(优先级最高)。
@Test
public void case51() {
User user = new User("solon", 22, Gender.MALE);
//模拟 Feature.Write_EnumShapeAsObject 效果
Options options = Options.of().addEncoder(Gender.class, (ctx, value, target) -> {
return target.set("code", value.getCode()).set("name", value.getName());
});
String json = ONode.serialize(user, options);
System.out.println(json);
Assertions.assertEquals("{\"name\":\"solon\",\"age\":22,\"gender\":{\"code\":11,\"name\":\"男\"}}", json);
}
6、编码(序列化) - 方式F:值字段特性
值字段特性,是指在用到它的字段,通过注解附加特性。
public class User {
private final String name;
private final int age;
@ONodeAttr(features=Feature.Write_EnumUsingName)
private final Gender gender;
public User(String name, int age, Gender gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
}
@Test
public void case61() {
User user = new User("solon", 22, Gender.MALE);
String json = ONode.serialize(user, options);
System.out.println(json);
Assertions.assertEquals("{\"name\":\"solon\",\"age\":22,\"gender\":\"MALE\"}", json);
}
7、解码(反序列化) - 方式X:默认
默认状态下,支持 ordinal 或 name 输入
Assertions.assertEquals(Gender.MALE, ONode.deserialize("1", Gender.class));
Assertions.assertEquals(Gender.MALE, ONode.deserialize("\"MALE\"", Gender.class));
8、解码(反序列化) - 方式Y:类型字段 添加 @ONodeAttr 注解
此方式与 方式D1 对应。
@Getter
public static enum Gender {
UNKNOWN(10, "未知的性别"), MALE(11, "男"), FEMALE(12, "女"), UNSTATED(19, "未说明的性别");
@ONodeAttr
private final int code;
private final String name;
Gender(int code, String name) {
this.code = code;
this.name = name;
}
}
要求输入值与注解的字段对象
Assertions.assertEquals(Gender2.MALE, ONode.deserialize("11", Gender.class));
9、解码(反序列化) - 方式Z:类型静态方法 添加 @ONodeCreator 注解
使用 @ONodeCreator 时,要求必须是:静态方法,且只有一个参数。
@Getter
public static enum Gender {
UNKNOWN(10, "未知的性别"), MALE(11, "男"), FEMALE(12, "女"), UNSTATED(19, "未说明的性别");
private final int code;
private final String name;
Gender(int code, String name) {
this.code = code;
this.name = name;
}
@ONodeCreator
public static Gender fromCode(Integer code) {
for (Gender gender : Gender.values()) {
if (gender.code == code) {
return gender;
}
}
return UNKNOWN;
}
}
可以是值(或对象属性)与参数对应上
//值对上
Assertions.assertEquals(Gender2.MALE, ONode.deserialize("11", Gender.class));
//或者对象的同名属性对上
Assertions.assertEquals(Gender2.MALE, ONode.deserialize("{\"code\":11,\"name\":\"男\"}", Gender.class));