首先明确项目采用中采用的是什么jackJson序列化和反序列化的,我们项目中采用的是com.fasterxml.jackson。
枚举实列:
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
@Getter
public enum PersonsTypeEnum implements BaseEnum<Integer> {
UNREALCHINESE(1,"未实名的内地人"),
REALCHINESE(2,"已实名的内地人"),
FOREIGN(3,"外国人"),
SPECIALREGION(4,"特别行政区"),
UNKNOWN(5,"未知");
@JsonValue
private Integer code;
private String msg;
PersonsTypeEnum(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
@Override
public Integer getValue() {
return code;
}
}
由于JsonValue为code,其类型为integer类型。当前端传入1的时候,其映射枚举为REALCHINESE,因为枚举中可以看作一个数组,当为integer的时候,就会根据其下标去取值
com.fasterxml.jackson的枚举的反序列化的源码:解析类:EnumDeserializer
@Override
public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
{
JsonToken curr = p.currentToken();
// 为字符串类型,根据jsonValue注解中的字符串的hash值和key的hash值匹配
//见方法lookup.find(name),当没找到,又会将字符串做一系列转换,如果是数字类字符串直 接取下标
if (curr == JsonToken.VALUE_STRING || curr == JsonToken.FIELD_NAME) {
CompactStringObjectMap lookup = ctxt.isEnabled(DeserializationFeature.READ_ENUMS_USING_TO_STRING)
? _getToStringLookup(ctxt) : _lookupByName;
final String name = p.getText();
Object result = lookup.find(name);
if (result == null) {
return _deserializeAltString(p, ctxt, lookup, name);
}
return result;
}
// 当为数字类型时,默认取intValue,然后取下标值
if (curr == JsonToken.VALUE_NUMBER_INT) {
// ... unless told not to do that
int index = p.getIntValue();
if (ctxt.isEnabled(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS)) {
return ctxt.handleWeirdNumberValue(_enumClass(), index,
"not allowed to deserialize Enum value out of number: disable DeserializationConfig.DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS to allow"
);
}
if (index >= 0 && index < _enumsByIndex.length) {
return _enumsByIndex[index];
}
if ((_enumDefaultValue != null)
&& ctxt.isEnabled(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE)) {
return _enumDefaultValue;
}
if (!ctxt.isEnabled(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)) {
return ctxt.handleWeirdNumberValue(_enumClass(), index,
"index value outside legal index range [0..%s]",
_enumsByIndex.length-1);
}
return null;
}
return _deserializeOther(p, ctxt);
}
综合上述,前端传入数字类型,只会根据其下标去取值,为了与jsonValue中的code映射上需要重写其反序列化,为了不影响其他枚举的映射,因此定义了一个枚举基类。
//指定反序列化类
//由于项目中使用了mybatisPlus,因此基类也继承了IEnum,根据实际情况去掉即可
@JsonDeserialize(using = JackSonIntegerToEnum.class)
public interface BaseEnum<T extends Serializable> extends IEnum {
}
//只有继承BaseEnum类的数字类型才做处理
public class JackSonIntegerToEnum extends JsonDeserializer<BaseEnum> {
@Override
public BaseEnum deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
String currentName = jp.currentName();
Object currentValue = jp.getCurrentValue();
JsonToken curr = jp.currentToken();
Class findPropertyType = null;
if (currentValue instanceof Collection) {
JsonStreamContext parsingContext = jp.getParsingContext();
JsonStreamContext parent = parsingContext.getParent();
Object currentValue3 = parent.getCurrentValue();
String currentName3 = parent.getCurrentName();
try {
Field listField = currentValue3.getClass().getDeclaredField(currentName3);
ParameterizedType listGenericType = (ParameterizedType) listField.getGenericType();
Type listActualTypeArguments = listGenericType.getActualTypeArguments()[0];
findPropertyType = (Class) listActualTypeArguments;
} catch (Exception e) {
e.printStackTrace();
}
} else {
findPropertyType = BeanUtils.findPropertyType(currentName, currentValue.getClass());
}
if (findPropertyType.isEnum()) {
BaseEnum[] baseEnums = (BaseEnum[]) findPropertyType.getEnumConstants();
for (BaseEnum baseEnum : baseEnums) {
//兼容前端传字符串和数字,都映射成对应枚举
if(curr == JsonToken.VALUE_NUMBER_INT && baseEnum.getValue().equals(jp.getIntValue())) {
return baseEnum;
}else if(curr == JsonToken.VALUE_STRING && baseEnum.getValue().toString().equals(jp.getValueAsString())) {
return baseEnum;
}
}
}
return null;
}
}
该博客讨论了如何在使用com.fasterxml.jackson库进行JSON序列化和反序列化时,针对枚举类型的特殊处理。文章指出,当前端传入数字时,Jackson默认根据枚举的下标进行映射,但为了匹配`@JsonValue`中的integer代码,需要重写枚举的反序列化过程。作者提供了一个基类`BaseEnum`和一个自定义反序列化类`JackSonIntegerToEnum`,确保数字类型能正确映射到对应的枚举实例。

4748

被折叠的 条评论
为什么被折叠?



