首先明确项目采用中采用的是什么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; } }