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

前端之家收集整理的这篇文章主要介绍了43. fastjson处理下划线和驼峰问题的方法和源码分析前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

一. 前言

在开发过程中经常遇到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;
}

猜你在找的Json相关文章