42. fastjson处理下划线和驼峰问题的方法和源码分析

简介:

一. 前言

在开发过程中经常遇到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是怎么做到的呢?

看了下源代码 

https://github.com/alibaba/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,如需转载请自行联系原作者




相关文章
|
4月前
|
Java 程序员
驼峰命名法在编程中的应用
驼峰命名法在编程中的应用
|
6月前
|
JSON Java fastjson
Java【问题 06】一次解决JSON.toJSONString和@RestController首字母大小写问题(特指属性首字母大写变小写)
Java【问题 06】一次解决JSON.toJSONString和@RestController首字母大小写问题(特指属性首字母大写变小写)
574 0
驼峰下划线互转工具类
驼峰下划线互转工具类
104 0
|
Java
Java实现驼峰、下划线互相转换
Java实现驼峰、下划线互相转换
794 1
|
Java 编译器 API
Java注释和注解的区别
Java注释和注解的区别
165 0
|
JSON JavaScript 数据格式
Js 将JSON内部key值转换大小写和首字母大写
Js 将JSON内部key值转换大小写和首字母大写
393 0
|
自然语言处理 Java Linux
知识分享之Golang——Bleve中的字符过滤器和分词规则
知识分享之Golang篇是我在日常使用Golang时学习到的各种各样的知识的记录,将其整理出来以文章的形式分享给大家,来进行共同学习。欢迎大家进行持续关注。 知识分享系列目前包含Java、Golang、Linux、Docker等等。
212 0
知识分享之Golang——Bleve中的字符过滤器和分词规则
|
Java
|
Java 数据库连接 数据库
map-underscore-to-camel-case驼峰式命名规则配置
mybatis默认是属性名和数据库字段名一一对应的,即 数据库表列:address_book 实体类属性:address_book 在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射 例如:address_book—> addressBook 此属性在 MyBatis 中默认值为 false,在Springboot中,可以通过设置map-underscore-to-camel-case属性为true来开启驼峰功能。 application.yml中:
620 0
|
Java
java中驼峰命名和下划线命名互转方法(代码实现)
1 /** 2 * 将驼峰式命名的字符串转换为下划线大写方式。如果转换前的驼峰式命名的字符串为空,则返回空字符串。 3 * 例如:HelloWorld->HELLO_WORLD 4 * @param name 转换前的驼峰式命名的字符串 5 * @return 转换后下划线大写方...
7769 0