关键词:
PropertyNamingStrategy
有四种序列化方式。
CamelCase策略,Java对象属性:personId,序列化后属性:persionId – 实际只改了首字母 大写变小写
PascalCase策略,Java对象属性:personId,序列化后属性:PersonId – 实际只改了首字母 小写变大写
SnakeCase策略,Java对象属性:personId,序列化后属性:person_id --大写字母前加下划线
KebabCase策略,Java对象属性:personId,序列化后属性:person-id -大写字母前加减号
public enum PropertyNamingStrategy
CamelCase, //驼峰
PascalCase, //
SnakeCase, //大写字母前加下划线
KebabCase;
public String translate(String propertyName)
switch (this)
case SnakeCase:
StringBuilder buf = new StringBuilder();
for (int i = 0; i < propertyName.length(); ++i)
char ch = propertyName.charAt(i);
if (ch >= 'A' && ch <= 'Z')
char ch_ucase = (char) (ch + 32);
if (i > 0)
buf.append('_');
buf.append(ch_ucase);
else
buf.append(ch);
return buf.toString();
case KebabCase:
StringBuilder buf = new StringBuilder();
for (int i = 0; i < propertyName.length(); ++i)
char ch = propertyName.charAt(i);
if (ch >= 'A' && ch <= 'Z')
char ch_ucase = (char) (ch + 32);
if (i > 0)
buf.append('-');
buf.append(ch_ucase);
else
buf.append(ch);
return buf.toString();
case PascalCase:
char ch = propertyName.charAt(0);
if (ch >= 'a' && ch <= 'z')
char[] chars = propertyName.toCharArray();
chars[0] -= 32;
return new String(chars);
return propertyName;
case CamelCase:
char ch = propertyName.charAt(0);
if (ch >= 'A' && ch <= 'Z')
char[] chars = propertyName.toCharArray();
chars[0] += 32;
return new String(chars);
return propertyName;
default:
return propertyName;
发挥作用的是translate方法
指定序列化格式
了解了PropertyNamingStrategy后,看其是怎么发挥作用的,
阅读源码发现在buildBeanInfo时(注意是将bean转为json时构建json信息时,如果是map,JSONObject不会有这个转换)
if(propertyNamingStrategy != null && !fieldAnnotationAndNameExists)
propertyName = propertyNamingStrategy.translate(propertyName);
这里分别调用PropertyNamingStrategy对应的方法处理
常见误区
那么也就是说通过PropertyNamingStrategy的方式设置输出格式,只对javaBean有效,并且,至于转换结果,需要根据PropertyNamingStrategy#translate方法的内容具体分析
如果javaBean中的字段是用下划线间隔的,那么指定CamelCase进行序列化,也是无法转成驼峰的!
例如
Student student = new Student();
student.setTest_name("test");
SerializeConfig serializeConfig = new SerializeConfig();
serializeConfig.setPropertyNamingStrategy(PropertyNamingStrategy.CamelCase);
System.out.println(JSON.toJSONString(student,serializeConfig));
输出test_name":“test”,因为执行 PropertyNamingStrategy#translate的CamelCase,仅仅只是,判断如果首字母大写转成小写。并不能完成,下划线到驼峰的转换
case CamelCase:
char ch = propertyName.charAt(0);
if (ch >= 'A' && ch <= 'Z')
char[] chars = propertyName.toCharArray();
chars[0] += 32;
return new String(chars);
return propertyName;
指定反序列化格式
智能匹配功能
fastjson反序列化时,是能自动下划线转驼峰的。这点是很方便的。,在反序列化时无论采用那种形式都能匹配成功并设置值
String str = "'user_name':123";
User user = JSON.parseObject(str, User.class);
System.out.println(user);
输出userName=‘123’
fastjson智能匹配处理过程
fastjson在进行反序列化的时候,对每一个json字段的key值解析时,会调用
com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer#parseField
这个方法
以上面的例子为例,通过debug打个断点看一下解析user_id时的处理逻辑。
此时这个方法中的key为user_id,object为要反序列化的结果对象,这个例子中就是FastJsonTestMain.UserInfo
public boolean parseField(DefaultJSONParser parser, String key, Object object, Type objectType,
Map<String, Object> fieldValues, int[] setFlags)
JSONLexer lexer = parser.lexer; // xxx
//是否禁用智能匹配;
final int disableFieldSmartMatchMask = Feature.DisableFieldSmartMatch.mask;
final int initStringFieldAsEmpty = Feature.InitStringFieldAsEmpty.mask;
FieldDeserializer fieldDeserializer;
if (lexer.isEnabled(disableFieldSmartMatchMask) || (this.beanInfo.parserFeatures & disableFieldSmartMatchMask) != 0)
fieldDeserializer = getFieldDeserializer(key);
else if (lexer.isEnabled(initStringFieldAsEmpty) || (this.beanInfo.parserFeatures & initStringFieldAsEmpty) != 0)
fieldDeserializer = smartMatch(key);
else
//进行智能匹配
fieldDeserializer = smartMatch(key, setFlags);
***此处省略N多行***
再看下核心的代码,智能匹配smartMatch
public FieldDeserializer smartMatch(String key, int[] setFlags)
if (key == null)
return null;
FieldDeserializer fieldDeserializer = getFieldDeserializer(key, setFlags);
if (fieldDeserializer == null)
if (this.smartMatchHashArray == null)
long[] hashArray = new long[sortedFieldDeserializers.length];
for (int i = 0; i < sortedFieldDeserializers.length; i++)
//java字段的nameHashCode,源码见下方
hashArray[i] = sortedFieldDeserializers[i].fieldInfo.nameHashCode;
//获取出反序列化目标对象的字段名称hashcode值,并进行排序
Arrays.sort(hashArray);
this.smartMatchHashArray = hashArray;
// smartMatchHashArrayMapping
long smartKeyHash = TypeUtils.fnv1a_64_lower(key);
//进行二分查找,判断是否找到
int pos = Arrays.binarySearch(smartMatchHashArray, smartKeyHash);
if (pos < 0)
//原始字段没有匹配到,用fnv1a_64_extract处理一下再次匹配
long smartKeyHash1 = TypeUtils.fnv1a_64_extract(key);
pos = Arrays.binarySearch(smartMatchHashArray, smartKeyHash1);
boolean is = false;
if (pos < 0 && (is = key.startsWith("is")))
//上面的操作后仍然没有匹配到,把is去掉后再次进行匹配
smartKeyHash = TypeUtils.fnv1a_64_extract(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, sortedFieldDeserializers[i].fieldInfo.nameHashCode);
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;
通过上面的smartMatch方法可以看出,fastjson中之所以能做到下划线自动转驼峰,主要还是因为在进行字段对比时,使用了fnv1a_64_lower和fnv1a_64_extract方法进行了处理。
fnv1a_64_extract方法源码:
public static long fnv1a_64_extract(String key)
long hashCode = fnv1a_64_magic_hashcode;
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 *= fnv1a_64_magic_prime;
return hashCode;
从源码可以看出,fnv1a_64_extract方法主要做了这个事:
去掉下划线、减号,并大写转小写
总结
fastjson中字段智能匹配的原理是在字段匹配时,使用了TypeUtils.fnv1a_64_lower方法对字段进行全体转小写处理。
之后再用TypeUtils.fnv1a_64_extract方法对json字段进行去掉"_“和”-"符号,再全体转小写处理。
如果上面的操作仍然没有匹配成功,会再进行一次去掉json字段中的is再次进行匹配。
如果上面的操作仍然没有匹配成功,会再进行一次去掉json字段中的is再次进行匹配。
关闭智能匹配的情况
智能匹配时默认开启的,需要手动关闭,看这个例子
String str = "'user_name':123";
ParserConfig parserConfig = new ParserConfig();
parserConfig.propertyNamingStrategy = PropertyNamingStrategy.SnakeCase;
User user = JSON.parseObject(str, User.class, parserConfig,Feature.DisableFieldSmartMatch);
System.out.println(user);
输出userName=‘null’
那么这种情况如何完成下划线到驼峰的转换
那么就需要使用parseConfig了
String str = "'user_name':123";
ParserConfig parserConfig = new ParserConfig();
parserConfig.propertyNamingStrategy = PropertyNamingStrategy.SnakeCase;
User user = JSON.parseObject(str, User.class,parserConfig,Feature.DisableFieldSmartMatch);
System.out.println(user);
那么此时PropertyNamingStrategy.SnakeCase又是如何发挥作用的?
断点PropertyNamingStrategy#translate方法
发现在构建JavaBeanDeserializer时
public JavaBeanDeserializer(ParserConfig config, Class<?> clazz, Type type)
this(config //
, JavaBeanInfo.build(clazz, type, config.propertyNamingStrategy, config.fieldBased, config.compatibleWithJavaBean, config.isJacksonCompatible())
);
if (propertyNamingStrategy != null)
propertyName = propertyNamingStrategy.translate(propertyName);
add(fieldList, new FieldInfo(propertyName, method, field, clazz, type, ordinal, serialzeFeatures, parserFeatures,
annotation, fieldAnnotation, null, genericInfo));
会根据配置对propertyName进行translate。转换成对应格式的属性名称
常见误区:
与序列化误区相同,如果是map,JSONObject不会有这个转换,并且转换结果需要参照translate方方法逻辑来看
值的注意的是,JSONObject的toJavaObject方法,智能匹配会生效。可以放心得进行下划线和驼峰得互相转换
String str = "'user_name':123";
JSONObject object = (JSONObject) JSON.parse(str);
System.out.println(object);
User user = object.toJavaObject(User.class);
System.out.println(user);
java实现驼峰和下划线相互转换(代码片段)
...录一波,工作使用到直接copy。/****<p>*将驼峰转为下划线*</p>*@paramstr*@returnjava.lang.String*@authorcomapss*@date2022/5/90:01*@since1.0.0**/publicstaticStringhumpToUnderline(Stringstr)Patterncompile=Pattern.compile("[A-Z]");Matcher... 查看详情
将驼峰写法的单词转换为下划线分割的单词
直接上代码:时间复杂度为O(1)的算法1publicstaticStringconvert(StringhumpWords){2//初始化过滤的字符start3char[]fiterCharArray="abcdefghigklmnopqrstuvwxyz.0123456789".toCharArray();4Arrays.sort(fiterCharArray);5//初始化过滤的字符end67 查看详情
java将json中key值下划线转为驼峰格式(代码片段)
...时会遇到json不是严格按照驼峰命名,需要将其中带有下划线的字段进行格式化转换为驼峰命名。如果是对JSON格式里的返回字段清楚的情况下,可以进行逐层解析转换。但是,效率比较低,而且JSON里可能会循环嵌... 查看详情
如何在 REST API 中使用下划线将驼峰大小写转换为小写?
】如何在RESTAPI中使用下划线将驼峰大小写转换为小写?【英文标题】:HowtoconvertcamelcasetolowercasewithunderscoresinaRESTAPI?【发布时间】:2021-04-2702:54:24【问题描述】:我正在使用Quarkus和MicroprofileOpenAPI来映射RESTAPI中的实体。我可以通... 查看详情
java/spring/jackson驼峰-下划线字段转换
java下划线与驼峰命名互转-学不死的程序员-博客园方式一:下划线与驼峰命名转换:publicclassToolprivatestaticPatternlinePattern=Pattern.compile("_(\\\\whttps://www.cnblogs.com/zhuhui-site/p/10090880.htmlSpringBoot统一设置Json数据返回风格ÿ... 查看详情
idea插件系列(48):camelbar插件——下划线转驼峰命名
1.插件介绍camelBar插件。可以将下划线命名转换成驼峰命名。如例:user_name->userNameuser-name->userName2.安装方式第一种方式,是在IDEA上搜索插件进行安装,会适配当前IDEA的版本。 第二种安装方式是使用离线插件进行... 查看详情
javascript下划线转换成驼峰命名
letfirstChange=first.replace(/_(\\w)/g,function(all,letter)returnletter.toUpperCase();); 查看详情
python基础汇总
变量的命名规则:1、变量名由数字、字母和下划线组成名?2、变量名不能以数字开头3、禁止使用python中的关键字4、不能使用中文和拼音5、变量名要区分大小写6、变量名要有意义7、推荐写法:1、驼峰体:a:大驼峰eg:AgeOfOldboy=56b:... 查看详情
jackson常用注解,比如忽略某些属性,驼峰和下划线互转
一般情况下使用JSON只使用了java对象与字符串的转换,但是,开发APP时候,我们经常使用实体类来做转换;这样,就需要用到注解;Jackson默认是针对get方法来生成JSON字符串的,可以使用注解来做一些特殊用途;常见的使用如下... 查看详情
驼峰命名法
...。基本概念有些程序员喜欢全部小写,有些程序员喜欢用下划线,所以如果要写一个myname的变量,他们常用的写法会有myname、my_ 查看详情
csharp简单的c#扩展方法,将驼峰大小写字符串转换为下划线表示法而不使用任何正则表达式(代码片段)
notepad++,vim驼峰命名与下划线的互相转换(代码片段)
...替换为第一组和第二组的大写点击全部替换成功。驼峰转下划线查找目标:([a-z])([A-Z])查找“小写大写”的组合,括号用来分组替换为:1_l2替换为第一组加下滑线加第二组,第二组小写l是小写的L点击全部替换ctrl+shift+u小写... 查看详情
awk/sed 脚本将文件从驼峰式转换为下划线
】awk/sed脚本将文件从驼峰式转换为下划线【英文标题】:Awk/sedscripttoconvertafilefromcamelCasetounderscores【发布时间】:2015-05-0123:02:31【问题描述】:我想将项目中的多个文件从camelCase转换为underscore_case。我想要一个只需要文件名的在... 查看详情
使用fastjson进行转换
packagejunit.test;importjava.util.ArrayList;importjava.util.HashMap;importjava.util.List;importjava.util.Map;importcom.alibaba.fastjson.JSON;importcom.alibaba.fastjson.TypeReference;/**这里将json的转化和解析都放 查看详情
object转换成map(支持驼峰,下划线)(代码片段)
一.Object转换成Map,支持下划线转换成map importcom.google.common.base.CaseFormat;importcom.google.common.base.Converter;classUtilsprivatestaticConverter<String,String>converter=CaseFormat.LOWER_CAMEL.converterTo(CaseFormat.UPPER_UNDERSCORE);//Object转换为Map(实体对... 查看详情
将circe中json对象的所有键从“下划线”转换为“驼峰式”
】将circe中json对象的所有键从“下划线”转换为“驼峰式”【英文标题】:Transformallkeysfrom`underscore`to`camelcase`ofjsonobjectsincirce【发布时间】:2016-10-0117:16:21【问题描述】:原产地"first_name":"foo","last_name":"bar","parent":"first_name":"baz","l... 查看详情
驼峰法和下划线命名法的互相转换
主要是接口入参太多,python和java的命名不同,做个转换 #coding:utf8importreclassStrTransverter(object):p=re.compile(r‘([a-z]|d)([A-Z])‘)p2=re.compile(r‘(_w)‘)def__init__(self,raw_str):self.raw_str=raw_strdefhump2unde 查看详情
java驼峰命名转下划线命名(能正确处理连续http等大写)(代码片段)
文章目录【1】功能(驼峰转下划线)【2】测试用例【3】如果使用有Bug,欢迎评论区留言【1】功能(驼峰转下划线)只遍历输入字符串一遍能够处理处理连续的大写字母如HTTP首字母可大写可小写/***双指针法*l... 查看详情