博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
42. fastjson处理下划线和驼峰问题的方法和源码分析
阅读量:6997 次
发布时间:2019-06-27

本文共 3717 字,大约阅读时间需要 12 分钟。

一. 前言

在开发过程中经常遇到json解析和生成的问题,所以用自己也一直用fastjson来实现这个功能。

但是,最近遇到一个问题: 

  1. json字符串里面的数据很多都是"_"下划线的比如,op_id。

  2. 而在java里面,很多都是驼峰的写法,如opId

那这两种可以匹配然后解析吗?

二. http请求的解决方法

http请求有个@JsonProperty的注解,但是这个注解,fastjson不识别;不过fastjson支持JSONField注解,如下:

1
2
@JSONField
(name=
"sta"
)
private 
String status;

三. 智能匹配

fastjson提供了智能匹配的规则,下面写法会自动映射

op_id->opid->ipId

也就是说就算json字符串是'op_id',那java变量也可以用opid或者opId,然后也可以获取相应的数据。

如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public 
class 
Runme {
    
static 
int 
ONE_DAY_SECONDS = 
24 
60 
60 
1000
;
    
public 
static 
void 
main(String[] args) {
        
String json = 
"{\"op-id\":1000}"
;
        
Mo mo = JSON.parseObject(json, Mo.
class
);
         
        
System.out.println(mo.getOpId());
    
}
     
    
public 
static 
class 
Mo {
        
private 
String opId;
 
        
public 
String getOpId() {
            
return 
opId;
        
}
 
        
public 
void 
setOpId(String opId) {
            
this
.opId = opId;
        
}
    
}
}

四. 原理分析

那fastjson是怎么做到的呢?

看了下源代码 

发现它的逻辑如下:

文件:src/main/java/com/alibaba/fastjson/parser/deserializer/JavaBeanDeserializer.java

方法:  smartMatch(String key, int[] setFlags)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public 
FieldDeserializer smartMatch(String key, 
int
[] setFlags) {
        
if 
(key == 
null
) {
            
return 
null
;
        
}
         
        
FieldDeserializer fieldDeserializer = getFieldDeserializer(key, setFlags);
 
        
if 
(fieldDeserializer == 
null
) {
            
long 
smartKeyHash = TypeUtils.fnv1a_64_lower(key);
            
if 
(
this
.smartMatchHashArray == 
null
) {
                
long
[] hashArray = 
new 
long
[sortedFieldDeserializers.length];
                
for 
(
int 
i = 
0
; i < sortedFieldDeserializers.length; i++) {
                    
hashArray[i] = TypeUtils.fnv1a_64_lower(sortedFieldDeserializers[i].fieldInfo.name);
                
}
                
Arrays.sort(hashArray);
                
this
.smartMatchHashArray = hashArray;
            
}
 
            
// smartMatchHashArrayMapping
            
int 
pos = Arrays.binarySearch(smartMatchHashArray, smartKeyHash);
            
boolean 
is = 
false
;
            
if 
(pos < 
0 
&& (is = key.startsWith(
"is"
))) {
                
smartKeyHash = TypeUtils.fnv1a_64_lower(key.substring(
2
));
                
pos = Arrays.binarySearch(smartMatchHashArray, smartKeyHash);
            
}
 
            
if 
(pos >= 
0
) {
                
if 
(smartMatchHashArrayMapping == 
null
) {
                    
short
[] mapping = 
new 
short
[smartMatchHashArray.length];
                    
Arrays.fill(mapping, (
short
) -
1
);
                    
for 
(
int 
i = 
0
; i < sortedFieldDeserializers.length; i++) {
                        
int 
p = Arrays.binarySearch(smartMatchHashArray
                                
, TypeUtils.fnv1a_64_lower(sortedFieldDeserializers[i].fieldInfo.name));
                        
if 
(p >= 
0
) {
                            
mapping[p] = (
short
) i;
                        
}
                    
}
                    
smartMatchHashArrayMapping = mapping;
                
}
 
                
int 
deserIndex = smartMatchHashArrayMapping[pos];
                
if 
(deserIndex != -
1
) {
                    
if 
(!isSetFlag(deserIndex, setFlags)) {
                        
fieldDeserializer = sortedFieldDeserializers[deserIndex];
                    
}
                
}
            
}
 
            
if 
(fieldDeserializer != 
null
) {
                
FieldInfo fieldInfo = fieldDeserializer.fieldInfo;
                
if 
((fieldInfo.parserFeatures & Feature.DisableFieldSmartMatch.mask) != 
0
) {
                    
return 
null
;
                
}
 
                
Class fieldClass = fieldInfo.fieldClass;
                
if 
(is && (fieldClass != 
boolean
.
class 
&& fieldClass != Boolean.
class
)) {
                    
fieldDeserializer = 
null
;
                
}
            
}
        
}
 
 
        
return 
fieldDeserializer;
    
}

它里面有个重要的地方就是调用TypeUtils.fnv1a_64_lower(String)方法,分别计算传入的key(op_id)和定义的java成员变量opId,然后计算他们是否匹配。

如果匹配的话,就会覆盖。

所以,关键就在于TypeUtils.fnv1a_64_lower(String)方法实现,如下:

这个方法就是如果是'_'或者'-',那么就忽略,也就是如果是op_id,那么就会变成opid。

如果是大写,那么就转换成小写,也就是opId,就会变成opid。

所以op-id或者op_id,都可以匹配opId或者opid

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public 
static 
long 
fnv1a_64_lower(String key){
        
long 
hashCode = 0xcbf29ce484222325L;
        
for
(
int 
i = 
0
; i < key.length(); ++i){
            
char 
ch = key.charAt(i);
            
if
(ch == 
'_' 
|| ch == 
'-'
){
                
continue
;
            
}
            
if
(ch >= 
'A' 
&& ch <= 
'Z'
){
                
ch = (
char
) (ch + 
32
);
            
}
            
hashCode ^= ch;
            
hashCode *= 0x100000001b3L;
        
}
        
return 
hashCode;
    
}

     本文转自rongwei84n 51CTO博客,原文链接:http://blog.51cto.com/483181/1981575,如需转载请自行联系原作者

你可能感兴趣的文章
SAN存储方式之falconstor实施方案(2)
查看>>
Bokeh快速入门(1)
查看>>
读取本机的Java运行环境和相关配置文件的内容
查看>>
Linux系统下的RZSZ(文件传输工具)
查看>>
第5章选择结构程序设计
查看>>
linux 下网络流量监控
查看>>
[CentOS6] Page allcation failure
查看>>
MagicLinux+MySQL5+PHP5+Apache2+phpMyAdmin
查看>>
服务器RAID磁盘坏道修复实战
查看>>
SOAP
查看>>
理解Windows中的路由表和默认网关
查看>>
MalformedInputException处理
查看>>
OPENAPI的测试用例编写方法
查看>>
事件通知(Event Notification)实践
查看>>
java json和object互换
查看>>
脚本语言程序员怎么学习程序设计?
查看>>
帮助电力,轻松实现运维管理
查看>>
网络嗅探软件全接触(2)
查看>>
J0ker的CISSP之路:复习-Information Security Management(4)
查看>>
SCOM 2007 R2监控系统安装部署(三)安装SCOM报表服务器和审计服务器
查看>>