Jackson虽然使用非常方便,但是在处理Enum类型上,还是有不少坑的,此篇算是做一下总结吧
先上一个例子——两个部门之前接口对接,在传参与返参里涉及到Enum的序列化与反序列化
一个协议端口的Enum
1 | public enum ProbePortEnum { |
第一个需求是把Json串里的字符串解析为Enum
1 | String portStr = "{\"ports\":[\"http\"]}"; |
如果没有意外的话,会报这个错误
Cannot deserialize value of type
ProbePortEnum
from String “http”: value not one of declared Enum instance names: [HTTP, GRPC]
要解决这个问题的话,@JsonValue
就够了
1 |
|
后来在调试的时候,觉得端口号是唯一的,直接用端口号比较好,就把返回的数据改成了下面这种
1 | String portStr = "{\"ports\":[80]}"; |
@JsonValue
只能添加在一个属性上面,这时就要把schema上的@JasonValue
移到port上了
1 |
|
结果却行不通了
Cannot deserialize value of type
ProbePortEnum
from number 80: index value outside legal index range [0..1]
原来是因为类型引起的——在 com.fasterxml.jackson.databind.deser.std.EnumDeserializer#deserialize
可以看到有一个判断,如果是JsonToken.VALUE_NUMBER_INT
就会通过Enum的索引来查找,而ProbePortEnum
的索引只有0和1
解决这个问题有两种方式:
一种方式是把json串里的端口号改成字符串( 😳 具体原因可以去看下EnumDeserializer#deserialize
)
1 | String portStr = "{\"ports\":[\"80\"]}"; |
另一种是使用@JsonCreator
1 |
|
前面一直在讨论是单个值的情况,如果想把两个字段都给反序列化出来
1 | String portStr = "{\"ports\":[{\"port\":80,\"schema\":\"http\"}]}"; |
怎么办呢?只需要在@JsonCreator
注解的方法上再添加上剩余的属性即可
1 |
|
说完了反序列化,那么序列化呢?
1 | DeployDTO deployDTO = DeployDTO.builder().ports(Arrays.asList(ProbePortEnum.HTTP)).build(); |
默认输出的是Enum的字面量
如果只想输出某一个属性的话,还是用@JsonValue
如果想输出全部属性的话,可以换成@JsonFormat
1 | (shape = JsonFormat.Shape.OBJECT) |
OVER~