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,如需转载请自行联系原作者




相关文章
|
JSON 算法 安全
不破不立!Fastjson2.0 性能炸裂,为了下一个十年
Alibaba Fastjson: 目前在人类已知范围内,这个星球跑的最快的Java JSON库。在过去的十年里,fastjson v1作为国内github star最多和最受欢迎的json解析库,如今fastjson v2 重磅来袭,性能炸裂。
19706 2
不破不立!Fastjson2.0 性能炸裂,为了下一个十年
|
Linux iOS开发 MacOS
PowerShell命令行输出和添加系统环境变量
主要介绍使用PowerShell命令如何查看、修改和删除系统环境变量,对于需要操作添加PATH环境变量非常实用 。由于 Powershell 的跨平台,其环境变量修改可以在linux、macos...
6091 0
PowerShell命令行输出和添加系统环境变量
|
JSON Java 数据格式
Java将json中key值下划线转为驼峰格式
Java将json中key值下划线转为驼峰格式
2130 1
|
7月前
|
SQL Java 数据库连接
MyBatis-Flex 实战:极简 CRUD + 高性能分页,吊打传统 MyBatis 的新一代持久层框架
MyBatis-Flex作为新一代Java持久层框架,在MyBatis的灵活性和MyBatis-Plus的便捷性之间实现了完美平衡。本文详细介绍了MyBatis-Flex的环境搭建、核心特性和实战应用,包括:1. 5分钟快速初始化项目配置;2. 通过注解实现零XML的CRUD操作;3. 灵活的QueryWrapper动态SQL构建;4. 高效分页查询实现;5. 关联查询解决方案;6. 编程式事务管理。相比MyBatis-Plus,MyBatis-Flex具有更简洁的API、更高的性能和更低的学习成本。
1759 1
|
安全 Java 数据库
SpringSecurity实现多种登录方式,如邮件验证码、电话号码登录
SpringSecurity实现多种登录方式,如邮件验证码、电话号码登录
3319 2
|
SQL
Mybatis-plus 自定义SQL注入器查询@TableLogic 逻辑删除后的数据
Mybatis-plus使用@TableLogic注解进行逻辑删除数据后,在某些场景下,又需要查询该数据时,又不想写SQL。 自定义Mybatis-plus的SQL注入器一劳永逸的解决该问题
1732 0
|
缓存 Java Spring
servlet和SpringBoot两种方式分别获取Cookie和Session方式比较(带源码) —— 图文并茂 两种方式获取Header
文章比较了在Servlet和Spring Boot中获取Cookie、Session和Header的方法,并提供了相应的代码实例,展示了两种方式在实际应用中的异同。
1926 3
servlet和SpringBoot两种方式分别获取Cookie和Session方式比较(带源码) —— 图文并茂 两种方式获取Header
|
监控 NoSQL Java
在Spring Boot中集成Redisson实现延迟队列
在Spring Boot中集成Redisson实现延迟队列
1243 6
|
Prometheus 监控 Cloud Native
springboot配置Prometheus
springboot配置Prometheus