加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

发布时间:2020-12-16 19:44:55 所属栏目:百科 来源:网络整理
导读:一. 前言 在开发过程中经常遇到json解析和生成的问题,所以用自己也一直用fastjson来实现这个功能。 但是,最近遇到一个问题: json字符串里面的数据很多都是"_"下划线的比如,op_id。 而在java里面,很多都是驼峰的写法,如opId 那这两种可以匹配然后解析吗

一. 前言

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

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

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

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

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


二. http请求的解决方法

http请求有个@JsonProperty的注解,但是这个注解,fastjson不识别。


三. 智能匹配

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

op_id->opid->ipId


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

如下:

publicclassRunme{
	staticintONE_DAY_SECONDS=24*60*60*1000;
	publicstaticvoidmain(String[]args){
		Stringjson="{"op-id":1000}";
		Momo=JSON.parSEObject(json,Mo.class);
		
		System.out.println(mo.getOpId());
	}
	
	publicstaticclassMo{
		privateStringopId;

		publicStringgetOpId(){
			returnopId;
		}

		publicvoidsetOpId(StringopId){
			this.opId=opId;
		}
	}
}


四. 原理分析

那fastjson是怎么做到的呢?

看了下源代码

https://github.com/alibaba/fastjson

发现它的逻辑如下:

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

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

publicFieldDeserializersmartMatch(Stringkey,int[]setFlags){
if(key==null){
returnnull;
}

FieldDeserializerfieldDeserializer=getFieldDeserializer(key,setFlags);

if(fieldDeserializer==null){
longsmartKeyHash=TypeUtils.fnv1a_64_lower(key);
if(this.smartMatchHashArray==null){
long[]hashArray=newlong[sortedFieldDeserializers.length];
for(inti=0;i<sortedFieldDeserializers.length;i++){
hashArray[i]=TypeUtils.fnv1a_64_lower(sortedFieldDeserializers[i].fieldInfo.name);
}
Arrays.sort(hashArray);
this.smartMatchHashArray=hashArray;
}

//smartMatchHashArrayMapping
intpos=Arrays.binarySearch(smartMatchHashArray,smartKeyHash);
booleanis=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=newshort[smartMatchHashArray.length];
Arrays.fill(mapping,(short)-1);
for(inti=0;i<sortedFieldDeserializers.length;i++){
intp=Arrays.binarySearch(smartMatchHashArray,TypeUtils.fnv1a_64_lower(sortedFieldDeserializers[i].fieldInfo.name));
if(p>=0){
mapping[p]=(short)i;
}
}
smartMatchHashArrayMapping=mapping;
}

intdeserIndex=smartMatchHashArrayMapping[pos];
if(deserIndex!=-1){
if(!isSetFlag(deserIndex,setFlags)){
fieldDeserializer=sortedFieldDeserializers[deserIndex];
}
}
}

if(fieldDeserializer!=null){
FieldInfofieldInfo=fieldDeserializer.fieldInfo;
if((fieldInfo.parserFeatures&Feature.DisableFieldSmartMatch.mask)!=0){
returnnull;
}

ClassfieldClass=fieldInfo.fieldClass;
if(is&&(fieldClass!=boolean.class&&fieldClass!=Boolean.class)){
fieldDeserializer=null;
}
}
}


returnfieldDeserializer;
}



它里面有个重要的地方就是调用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


publicstaticlongfnv1a_64_lower(Stringkey){
longhashCode=0xcbf29ce484222325L;
for(inti=0;i<key.length();++i){
charch=key.charAt(i);
if(ch=='_'||ch=='-'){
continue;
}
if(ch>='A'&&ch<='Z'){
ch=(char)(ch+32);
}
hashCode^=ch;
hashCode*=0x100000001b3L;
}
returnhashCode;
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读