赞
踩
开局一吐槽,Fastjson的文档,比Jackson还差。Jackson只是位置不明确,如果安下心来看看,还是能够理清楚的。而Fastjson是位置不明确,如果安下心来看看,还会发现,它的文档零零散散,中英文混杂,找不准主线在哪儿。我记得知乎上有个问题,fastjson这么快老外为啥还是热衷 jackson?,就这文档,让老外用个啥。
不过看还是要看的,毕竟它是目前主流序列化框架之一。老样子,我们还是从基本使用方法和原理分析两部分着手。
Fastjson仅仅针对json,尚不支持其它任何格式,也没有看到谁为它进行格式扩展。因为这并不是它的目的,库如其名,它是为了更快地序列化Json而存在。因此,使用上来,会简单许多。具体分为几个部分
fun testBase() {
data class Resource(
var id: String,
var type: Type
)
val jsonString = JSON.toJSONString(Resource("1", Type.RECORD))
println(jsonString)
val resource = JSON.parseObject(jsonString, Resource::class.java)
println(resource)
}
序列化:JSON.toJSONString(对象)
反序列化:JSON.parseObject(jsonString, 对象class)
注意
默认情况下,是根据getter和setter方法取得和设置字段的,如果没有,将得不到输出
也可以基于属性获取和设置字段,考虑下面的例子
fun testBasedOnFields() { data class Resource( private var id: String, private var type: Type ) // 设置基于字段的序列化 val serializeConfig = SerializeConfig(true) // 设置基于字段反序列化 val parserConfig = ParserConfig(true) val jsonString = JSON.toJSONString(Resource("1", Type.RECORD), serializeConfig) println(jsonString) val resource = JSON.parseObject<Resource>(jsonString, Resource::class.java, parserConfig) println(resource) }
注解方面它采取了另一种思路,它只有两个注解,但将功能放在注解的属性中
// 一个简单的修改属性名字献给大家
fun testAnnotations() {
@JSONType(alphabetic = false, ignores = ["id"])
data class Resource(
val id: String,
@JSONField(name = "resourceType")
val type: Type,
val updatedTime: Date
)
println(JSON.toJSONString(Resource("1", Type.RECORD, Date()), SerializerFeature.PrettyFormat))
}
仔细想想,从注解能力上来说,还是有所差别的
不多解释,传统技能:为LocalDateTime自定义序列化器
fun testCustomSerializer() { data class Resource( val id: String, val type: Type, val updatedTime: LocalDateTime ) class LocalDateTimeSerializer : ObjectSerializer { override fun write( serializer: JSONSerializer, `object`: Any?, fieldName: Any?, fieldType: java.lang.reflect.Type?, features: Int ) { val out = serializer.out if (`object` == null) { out.writeNull() } else { out.writeLong((`object` as LocalDateTime).toInstant(ZoneOffset.UTC).toEpochMilli()) } } } SerializeConfig.globalInstance.put(LocalDateTime::class.java, LocalDateTimeSerializer()) println(JSON.toJSONString(Resource("1", Type.RECORD, LocalDateTime.now()))) }
不过这序列化器注册的方式嘛,是不是不大友好呀。要么全局注册,要么序列化时传参进去,并不能持有多套配置JSON对象。
过滤器是Fastjson比较独有的概念,也比较好理解:在序列化的多个阶段提供给用户参与调整的机会。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BadIHUdQ-1635758649921)(https://gdz.oss-cn-shenzhen.aliyuncs.com/local/image-20211015152451901.png)]
具体怎么用,只能靠猜,源码也没有注释,文档也不好找,需要的时候再去找吧。这里就展示怎么注册:把所有名称都设置为大写
fun testCustomFilter() { data class Resource( val id: String, val type: Type, val updatedTime: LocalDateTime ) class IdFilter : NameFilter { override fun process(`object`: Any?, name: String, value: Any): String? { return name.uppercase(Locale.getDefault()) } } SerializeConfig.globalInstance.addFilter(Resource::class.java, IdFilter()) println(JSON.toJSONString(Resource("1", Type.RECORD, LocalDateTime.now()))) }
没错,它也有树模型,只是功能没那么强大而已,它也只有两个对象
fun testTreeModel() {
val resource = JSONObject()
.fluentPut("ID", 1)
.fluentPut(
"data", JSONArray()
.fluentAdd(
JSONObject()
.fluentPut("images", "[]")
)
)
println(JSON.toJSONString(resource, SerializerFeature.PrettyFormat, SerializerFeature.SortField))
}
输出如下,这里可以看到一个问题:Fastjson默认序列化后所有的字段都是排序的,这就很不好。
{
"data":[
{
"images":"[]"
}
],
"ID":1
}
其它功能,主要就是在Feature中指定的内容了,基本都是置顶序列化和反序列化时遵循的特性。
// 序列化相关的功能 public enum SerializerFeature { // 字段名用引号引起来 QuoteFieldNames, // 使用单引号 UseSingleQuotes, WriteMapNullValue, // 枚举调用toString()输出 WriteEnumUsingToString, // 枚举调用name()输出 WriteEnumUsingName, // 日期使用ISO8601格式 UseISO8601DateFormat, // 列表的null输出为[] WriteNullListAsEmpty, // 字符串的null输出为空串 WriteNullStringAsEmpty, // 数字的null输出为0 WriteNullNumberAsZero, // 布尔的null输出为false WriteNullBooleanAsFalse, // 忽略被transient标记的字段 SkipTransientField, // 为字段排序 SortField, // 格式化输出 PrettyFormat, // 输出结果添加类名,可用来实现多态 WriteClassName, // 关闭循环引用检测 DisableCircularReferenceDetect, // 将斜线当做特殊符号 WriteSlashAsSpecial, // 浏览器兼容 BrowserCompatible, // Date使用日期格式输出 WriteDateUseDateFormat, // 不写根类的名字 NotWriteRootClassName, // 将java bean的字段以数组的形式输出,而不是对象 BeanToArray, // 将非字符串的key当做字符串输出 WriteNonStringKeyAsString, // 不为没有值的属性写默认值 NotWriteDefaultValue, // 浏览器安全 BrowserSecure, // 忽略没有幕后字段的getter IgnoreNonFieldGetter, // 将非字符串的值当做字符串输出 WriteNonStringValueAsString, // getter报错时忽略 IgnoreErrorGetter, // 将bigdecimal当做字符串输出 WriteBigDecimalAsPlain, // map输出时也要将字段排序 MapSortField; } // 反序列化相关的功能 public enum Feature { // 读取完后自动关闭读取源 AutoCloseSource, // 允许注释出现 AllowComment, // 允许未被引号包含的字段名 AllowUnQuotedFieldNames, // 允许单引号 AllowSingleQuotes, // 字段名intern化,主要用于节省空间 InternFieldNames, // 允许ISO8601格式的日期格式 AllowISO8601DateFormat, // 允许任意数量的逗号间隔 AllowArbitraryCommas, // 数字使用BigDecinal接收 UseBigDecimal, // 字段不匹配时忽略,不报错 IgnoreNotMatch, // 启用有序字段的匹配算法,会更快 SortFeidFastMatch, // 不启用ASM DisableASM, // 关闭循环引用的检测 DisableCircularReferenceDetect, // 字符串类型的字段初始化为空串 InitStringFieldAsEmpty, // 支持将数组转换为bean SupportArrayToBean, // 字段排序 OrderedField, // 关闭特殊字符检测 DisableSpecialKeyDetect, // 使用对象数组 UseObjectArray, // 支持非public的字段写入 SupportNonPublicField, // 忽略autotype,即多态的功能 IgnoreAutoType, // disable field smart match, improve performance in some scenarios. DisableFieldSmartMatch, // 开启自动类型转换 SupportAutoType, // 非字符串的key转化为string NonStringKeyAsString, // 使用自定义的Map的反序列化器 CustomMapDeserializer, // 枚举不匹配时报错 ErrorOnEnumNotMatch, // 安全模式 SafeMode, // 字符串字段去除两头空字符 TrimStringFieldValue }
看了kotlinx.serialization、Jackson,再看Fastjson,发现它们的组成基本一致,无非三个部分,可能根据情况其命名和具体实现方式会有所不同。这部分没啥新意,自己追一下方法就OK了。
Fastjson的特点在于快,为什么这么快呢?据说是算法,作者自己的博客——Fastjson技术内幕有所描述,归结起来大概就是
所以Fastjson的原理,重点是算法,而不在结构上。而这些算法,是不是有点奇技淫巧了
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。