FastJson中文 API
在项目开发中经常会遇到一些业务需要对某些数据进行特殊的定制化处理,fastjson为我们提供了接口可以用于实现自定义的编解码器来完成我们的业务要求。
ObjectSerializer和ObjectDeserializer分别是fastjson的编码器和解码器接口。
ObjectDeserializer接口源码:
/**
* 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)}.
*
* 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;
* }
* }
*
*
* You will also need to register {@code OrderActionEnumDeser} to ParserConfig:
*
* ParserConfig.getGlobalInstance().putDeserializer(OrderActionEnum.class, new OrderActionEnumDeser());
*
*/
public interface ObjectDeserializer {
/**
* fastjson invokes this call-back method during deserialization when it encounters a field of the
* specified type.
* 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 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)}.
*
*
* 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);
*
* @author wenshao[[email protected]]
*/
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 {
@Override
public 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{
@Override
public 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 clazz = (Class)type;
T[] enumConstants = clazz.getEnumConstants();
return (T) BaseEnum.valueOfEnum1(enumConstants, value);
}
@Override
public int getFastMatchToken() {
return 0;
}
}
3、通过实现ObjectDeserializer接口来自定义数字对象的反序列化
/**
* 自定义数字对象的反序列化实现:接口在接收数字参数时,将数字转换成BigDecimal
* @author: liumengbing
* @date: 2019/05/28 15:26
**/
public class BigDecimalDeserializer implements ObjectDeserializer{
@Override
public 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();
}
}
@Override
public 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 valueOfEnum(Class 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 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 {
@Autowired
private BigDecimalSerializer bigDecimalSerializer;
@Bean
public 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 fastMediaTypes = new ArrayList<>();
fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
fastConverter.setSupportedMediaTypes(fastMediaTypes);
//5.将fastJsonConfig加到消息转换器中
fastConverter.setFastJsonConfig(fastJsonConfig);
return new HttpMessageConverters(fastConverter);
}
}