使用fastjson提供的接口实现自定义的编解码器
FastJson中文 API
在項目開發中經常會遇到一些業務需要對某些數據進行特殊的定制化處理,fastjson為我們提供了接口可以用于實現自定義的編解碼器來完成我們的業務要求。
ObjectSerializer和ObjectDeserializer分別是fastjson的編碼器和解碼器接口。
ObjectDeserializer接口源碼:
/*** <p>Interface representing a custom deserializer for Json. You should write a custom* deserializer, if you are not happy with the default deserialization done by Gson. You will* also need to register this deserializer through* {@link ParserConfig#putDeserializer(Type, ObjectDeserializer)}.</p>* <pre>* public static enum OrderActionEnum {* FAIL(1), SUCC(0);* * private int code;* * OrderActionEnum(int code){* this.code = code;* }* }* * public static class OrderActionEnumDeser implements ObjectDeserializer {* * public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {* Integer intValue = parser.parseObject(int.class);* if (intValue == 1) {* return (T) OrderActionEnum.FAIL;* } else if (intValue == 0) {* return (T) OrderActionEnum.SUCC;* }* throw new IllegalStateException();* }* * * public int getFastMatchToken() {* return JSONToken.LITERAL_INT;* }* }* </pre>* * <p>You will also need to register {@code OrderActionEnumDeser} to ParserConfig:</p>* <pre>* ParserConfig.getGlobalInstance().putDeserializer(OrderActionEnum.class, new OrderActionEnumDeser());* </pre>*/ public interface ObjectDeserializer {/*** fastjson invokes this call-back method during deserialization when it encounters a field of the* specified type.* <p>In the implementation of this call-back method, you should consider invoking* {@link JSON#parseObject(String, Type, Feature[])} method to create objects* for any non-trivial field of the returned object. ** @param parser context DefaultJSONParser being deserialized* @param type The type of the Object to deserialize to* @param fieldName parent object field name* @return a deserialized object of the specified type which is a subclass of {@code T}*/<T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName);int getFastMatchToken(); }ObjectSerializer接口源碼:
/*** Interface representing a custom serializer for fastjson. You should write a custom serializer, if* you are not happy with the default serialization done by fastjson. You will also need to register* this serializer through {@link com.alibaba.fastjson.serializer.SerializeConfig#put(Type, ObjectSerializer)}.** <pre>* public static class Result {* public ResultCode code;* }* * public static enum ResultCode {* LOGIN_FAILURE(8), INVALID_ARGUMENT(0), SIGN_ERROR(17);* public final int value;* ResultCode(int value){* this.value = value;* }* }* * public static class ResultCodeSerilaizer implements ObjectSerializer {* public void write(JSONSerializer serializer, * Object object, * Object fieldName, * Type fieldType,* int features) throws IOException {* serializer.write(((ResultCode) object).value);* }* }* * SerializeConfig.getGlobalInstance().put(ResultCode.class, new ResultCodeSerilaizer());* * Result result = new Result();* result.code = ResultCode.SIGN_ERROR;* String json = JSON.toJSONString(result, config); // {"code":17}* Assert.assertEquals("{\"code\":17}", json);* </pre>* @author wenshao[szujobs@hotmail.com]*/ public interface ObjectSerializer {/*** fastjson invokes this call-back method during serialization when it encounters a field of the* specified type.* @param serializer * @param object src the object that needs to be converted to Json.* @param fieldName parent object field name* @param fieldType parent object field type* @param features parent object field serializer features* @throws IOException*/void write(JSONSerializer serializer, //Object object, //Object fieldName, //Type fieldType, //int features) throws IOException; }自定義編解碼器實例
1、通過實現ObjectSerializer接口來自定義枚舉對象的序列化實現
/*** 自定義枚舉對象的序列化實現:在接口返回數據時,將枚舉字段轉換成map格式的數據,例如{"value":1,"label":"測試"}* @author: liumengbing* @date: 2019/05/28 15:26*/ @Component public class EnumsSerializer implements ObjectSerializer {@Overridepublic void write(JSONSerializer serializer, Object object, Object o1, Type type, int i) throws IOException {if (object == null) {serializer.out.writeNull();} else {BaseEnum baseEnum = (BaseEnum) object;serializer.write(new EnumsEntity(baseEnum.getValue(), baseEnum.getLabel()));}}class EnumsEntity{private Integer value;private String label;public EnumsEntity(){}public EnumsEntity(Integer value, String label) {this.value = value;this.label = label;}public Integer getValue() {return value;}public void setValue(Integer value) {this.value = value;}public String getLabel() {return label;}public void setLabel(String label) {this.label = label;}}}2、通過實現ObjectDeserializer接口來自定義枚舉對象的反序列化實現
/*** 自定義枚舉對象的反序列化實現:接口獲取枚舉的value值時,將其反序列化成枚舉對象* @author: liumengbing* @date: 2019/05/28 15:26**/ public class EnumDeserializer implements ObjectDeserializer{@Overridepublic <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {JSONLexer lexer = parser.lexer;Integer value = null;Object parse = parser.parse();if (parse == null)return null;String s = parse.toString();if (Pattern.matches("\\d+", s)){value = (int)parse;} else {if (s.startsWith("{")){JSONObject jo = (JSONObject) parse;value = jo.getIntValue("value");}}if (value == null)return null;if (value < -999999)return null;Class<T> clazz = (Class<T>)type;T[] enumConstants = clazz.getEnumConstants();return (T) BaseEnum.valueOfEnum1(enumConstants, value);}@Overridepublic int getFastMatchToken() {return 0;} }3、通過實現ObjectDeserializer接口來自定義數字對象的反序列化
/*** 自定義數字對象的反序列化實現:接口在接收數字參數時,將數字轉換成BigDecimal* @author: liumengbing* @date: 2019/05/28 15:26**/ public class BigDecimalDeserializer implements ObjectDeserializer{@Overridepublic <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {Object parse = parser.parse();if (parse == null)return (T)(new BigDecimal(0));String s = parse.toString();if ("".equals(s))return (T)(new BigDecimal(0));if (Pattern.matches("(\\d|\\.)+", s))return (T)(new BigDecimal(s));else {throw new IllegalArgumentException();}}@Overridepublic int getFastMatchToken() {return 0;} }枚舉基類:
package com.example.springboottest;import org.springframework.util.ReflectionUtils;import java.lang.reflect.Field;/*** 枚舉基類接口* @author: liumengbing* @date: 2019/04/10 10:40**/ public interface BaseEnum {String DEFAULT_VALUE_NAME = "value";String DEFAULT_LABEL_NAME = "label";default Integer getValue() {Field field = ReflectionUtils.findField(this.getClass(), DEFAULT_VALUE_NAME);if (field == null)return null;try {field.setAccessible(true);return Integer.parseInt(field.get(this).toString());} catch (IllegalAccessException e) {throw new RuntimeException(e);}}default String getLabel() {Field field = ReflectionUtils.findField(this.getClass(), DEFAULT_LABEL_NAME);if (field == null)return null;try {field.setAccessible(true);return field.get(this).toString();} catch (IllegalAccessException e) {throw new RuntimeException(e);}}static <T extends Enum<T>> T valueOfEnum(Class<T> enumClass, Integer value) {if (value == null)throw new IllegalArgumentException("DisplayedEnum value should not be null");if (enumClass.isAssignableFrom(BaseEnum.class))throw new IllegalArgumentException("illegal DisplayedEnum type");T[] enums = enumClass.getEnumConstants();for (T t: enums) {BaseEnum displayedEnum = (BaseEnum)t;if (displayedEnum.getValue().equals(value))return (T) displayedEnum;}throw new IllegalArgumentException("cannot parse integer: " + value + " to " + enumClass.getName());}static <T> T valueOfEnum1(T[] enums, Integer value) {for (T t: enums) {BaseEnum displayedEnum = (BaseEnum)t;if (displayedEnum.getValue().equals(value))return (T) displayedEnum;}throw new IllegalArgumentException("cannot parse integer: " + value + " to " );} }實現了自定義的編解碼器之后就該考慮如何使用了,上面我們提到過,實現自定義的編解碼器的目的是完成業務要求中對一些數據的定制化處理,這些數據可能是單獨一個屬性字段,也可能是某種類,那么針對不同的情況,自定義編解碼器有兩種使用方式:
1、通過 @JsonField的serializeUsing和deserializeUsing屬性指定編解碼過程中使用的編解碼器來對類的某個屬性進行定制序列化
public class TestEnum {@JSONField(serializeUsing = EnumsSerializer.class)public Enum status; }public class TestBigDecimalSerializer {@JSONField(serializeUsing = BigDecimalSerializerSerializer.class)public BigDecimal money; }2、通過SerializeConfig來配置某一個類的序列化
private static SerializeConfig mapping = new SerializeConfig(); private static String dateFormat; static { dateFormat = "yyyy-MM-dd HH:mm:ss"; mapping.put(Date.class, new SimpleDateFormatSerializer(dateFormat)); }3、結合之前的文章還有一種用法-通過添加配置類來注入Bean(使用HttpMessageConverter來實現HTTP的序列化和反序列化)
import com.alibaba.fastjson.serializer.SerializerFeature; import com.alibaba.fastjson.support.config.FastJsonConfig; import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;import java.math.BigDecimal; import java.util.ArrayList; import java.util.List;/*** @author: liumengbing* @date: 2019/04/09 17:35**/ @Configuration//將一個物理類變成一個配置文件 public class MassageConverConfiguration {@Autowiredprivate BigDecimalSerializer bigDecimalSerializer;@Beanpublic HttpMessageConverters fastJsonHttpMessageConverters() {//1.構建了一個HttpMessageConverter FastJson 消息轉換器FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();//2.定義一個配置,設置編碼方式,和格式化的形式FastJsonConfig fastJsonConfig = new FastJsonConfig();//3.設置成了PrettyFormat格式fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);//使用SerializeConfig配置自定義編解碼器fastJsonConfig.getSerializeConfig().put(BigDecimal.class,bigDecimalSerializer);//4.處理中文亂碼問題List<MediaType> fastMediaTypes = new ArrayList<>();fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);fastConverter.setSupportedMediaTypes(fastMediaTypes);//5.將fastJsonConfig加到消息轉換器中fastConverter.setFastJsonConfig(fastJsonConfig);return new HttpMessageConverters(fastConverter);}} 超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生總結
以上是生活随笔為你收集整理的使用fastjson提供的接口实现自定义的编解码器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用HttpMessageConvert
- 下一篇: Springboot对web应用的统一异