最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

FastJson實(shí)現(xiàn)駝峰下劃線相互轉(zhuǎn)換方法詳解

 更新時(shí)間:2023年01月18日 17:08:17   作者:氵奄不死的魚  
這篇文章主要介紹了使用FastJson進(jìn)行駝峰下劃線相互轉(zhuǎn)換寫法及誤區(qū),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧

PropertyNamingStrategy

有四種序列化方式。

CamelCase策略,Java對(duì)象屬性:personId,序列化后屬性:persionId – 實(shí)際只改了首字母 大寫變小寫

PascalCase策略,Java對(duì)象屬性:personId,序列化后屬性:PersonId – 實(shí)際只改了首字母 小寫變大寫

SnakeCase策略,Java對(duì)象屬性:personId,序列化后屬性:person_id --大寫字母前加下劃線

KebabCase策略,Java對(duì)象屬性:personId,序列化后屬性:person-id -大寫字母前加減號(hào)

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;
        }
    }

發(fā)揮作用的是translate方法

指定序列化格式

了解了PropertyNamingStrategy后,看其是怎么發(fā)揮作用的,

閱讀源碼發(fā)現(xiàn)在buildBeanInfo時(shí)(注意是將bean轉(zhuǎn)為json時(shí)構(gòu)建json信息時(shí),如果是map,JSONObject不會(huì)有這個(gè)轉(zhuǎn)換)

    if(propertyNamingStrategy != null && !fieldAnnotationAndNameExists){
                    propertyName = propertyNamingStrategy.translate(propertyName);
                }

這里分別調(diào)用PropertyNamingStrategy對(duì)應(yīng)的方法處理

常見誤區(qū)

那么也就是說通過PropertyNamingStrategy的方式設(shè)置輸出格式,只對(duì)javaBean有效,并且,至于轉(zhuǎn)換結(jié)果,需要根據(jù)PropertyNamingStrategy#translate方法的內(nèi)容具體分析

如果javaBean中的字段是用下劃線間隔的,那么指定CamelCase進(jìn)行序列化,也是無法轉(zhuǎn)成駝峰的!

例如

        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”},因?yàn)閳?zhí)行 PropertyNamingStrategy#translate的CamelCase,僅僅只是,判斷如果首字母大寫轉(zhuǎn)成小寫。并不能完成,下劃線到駝峰的轉(zhuǎn)換

 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反序列化時(shí),是能自動(dòng)下劃線轉(zhuǎn)駝峰的。這點(diǎn)是很方便的。,在反序列化時(shí)無論采用那種形式都能匹配成功并設(shè)置值

        String str = "{'user_name':123}";
        User user = JSON.parseObject(str, User.class);
        System.out.println(user);

輸出{userName=‘123’}

fastjson智能匹配處理過程

fastjson在進(jìn)行反序列化的時(shí)候,對(duì)每一個(gè)json字段的key值解析時(shí),會(huì)調(diào)用

com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer#parseField

這個(gè)方法

以上面的例子為例,通過debug打個(gè)斷點(diǎn)看一下解析user_id時(shí)的處理邏輯。

此時(shí)這個(gè)方法中的key為user_id,object為要反序列化的結(jié)果對(duì)象,這個(gè)例子中就是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 {
            //進(jìn)行智能匹配
            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;
                }
                //獲取出反序列化目標(biāo)對(duì)象的字段名稱hashcode值,并進(jìn)行排序
                Arrays.sort(hashArray);
                this.smartMatchHashArray = hashArray;
            }
            // smartMatchHashArrayMapping
            long smartKeyHash = TypeUtils.fnv1a_64_lower(key);
            //進(jìn)行二分查找,判斷是否找到
            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去掉后再次進(jìn)行匹配
                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中之所以能做到下劃線自動(dòng)轉(zhuǎn)駝峰,主要還是因?yàn)樵谶M(jìn)行字段對(duì)比時(shí),使用了fnv1a_64_lower和fnv1a_64_extract方法進(jìn)行了處理。

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);
            //去掉下劃線和減號(hào)
            if (ch == '_' || ch == '-') {
                continue;
            }
            //大寫轉(zhuǎn)小寫
            if (ch >= 'A' && ch <= 'Z') {
                ch = (char) (ch + 32);
            }
            hashCode ^= ch;
            hashCode *= fnv1a_64_magic_prime;
        }
        return hashCode;
    }

從源碼可以看出,fnv1a_64_extract方法主要做了這個(gè)事:

去掉下劃線、減號(hào),并大寫轉(zhuǎn)小寫

總結(jié)

fastjson中字段智能匹配的原理是在字段匹配時(shí),使用了TypeUtils.fnv1a_64_lower方法對(duì)字段進(jìn)行全體轉(zhuǎn)小寫處理。

之后再用TypeUtils.fnv1a_64_extract方法對(duì)json字段進(jìn)行去掉"_“和”-"符號(hào),再全體轉(zhuǎn)小寫處理。

如果上面的操作仍然沒有匹配成功,會(huì)再進(jìn)行一次去掉json字段中的is再次進(jìn)行匹配。

如果上面的操作仍然沒有匹配成功,會(huì)再進(jìn)行一次去掉json字段中的is再次進(jìn)行匹配。

關(guān)閉智能匹配的情況

智能匹配時(shí)默認(rèn)開啟的,需要手動(dòng)關(guān)閉,看這個(gè)例子

 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’}

那么這種情況如何完成下劃線到駝峰的轉(zhuǎn)換

那么就需要使用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);

那么此時(shí)PropertyNamingStrategy.SnakeCase又是如何發(fā)揮作用的?

斷點(diǎn)PropertyNamingStrategy#translate方法

發(fā)現(xiàn)在構(gòu)建JavaBeanDeserializer時(shí)

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));

會(huì)根據(jù)配置對(duì)propertyName進(jìn)行translate。轉(zhuǎn)換成對(duì)應(yīng)格式的屬性名稱

常見誤區(qū):

與序列化誤區(qū)相同,如果是map,JSONObject不會(huì)有這個(gè)轉(zhuǎn)換,并且轉(zhuǎn)換結(jié)果需要參照translate方方法邏輯來看

值的注意的是,JSONObject的toJavaObject方法,智能匹配會(huì)生效??梢苑判牡眠M(jìn)行下劃線和駝峰得互相轉(zhuǎn)換

        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);

到此這篇關(guān)于FastJson實(shí)現(xiàn)駝峰下劃線相互轉(zhuǎn)換方法詳解的文章就介紹到這了,更多相關(guān)FastJson駝峰下劃線相互轉(zhuǎn)換內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中定時(shí)任務(wù)的全方位場(chǎng)景實(shí)現(xiàn)思路分析

    Java中定時(shí)任務(wù)的全方位場(chǎng)景實(shí)現(xiàn)思路分析

    在開發(fā)過程中,根據(jù)需求和業(yè)務(wù)的不同經(jīng)常會(huì)有很多場(chǎng)景需要用到不同特性的定時(shí)任務(wù),本文將針對(duì)這些場(chǎng)景,提供不同的一個(gè)實(shí)現(xiàn)思路,感興趣的小伙伴快跟隨小編一起學(xué)習(xí)一下吧
    2023-12-12
  • Spring Boot2.x如何自定義Endpoint

    Spring Boot2.x如何自定義Endpoint

    這篇文章主要介紹了Spring Boot2.x如何自定義Endpoint,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • 從零開始使用IDEA創(chuàng)建SpringBoot項(xiàng)目(圖文)

    從零開始使用IDEA創(chuàng)建SpringBoot項(xiàng)目(圖文)

    這篇文章主要介紹了從零開始使用IDEA創(chuàng)建SpringBoot項(xiàng)目(圖文),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-05-05
  • Java 實(shí)現(xiàn)多線程的幾種方式匯總

    Java 實(shí)現(xiàn)多線程的幾種方式匯總

    JAVA多線程實(shí)現(xiàn)方式主要有三種:繼承Thread類、實(shí)現(xiàn)Runnable接口、使用ExecutorService、Callable、Future實(shí)現(xiàn)有返回結(jié)果的多線程。其中前兩種方式線程執(zhí)行完后都沒有返回值,只有最后一種是帶返回值的。
    2016-03-03
  • Java實(shí)現(xiàn)黃金分割法的示例代碼

    Java實(shí)現(xiàn)黃金分割法的示例代碼

    黃金分割法是一種區(qū)間收縮方法。所謂區(qū)間收縮方法,指的是將含有最優(yōu)解的區(qū)間逐步縮小,直至區(qū)間長度為零的方法。本文將用Java實(shí)現(xiàn)這一算法,需要的可以參考一下
    2022-03-03
  • 徹底理解Java中的ThreadLocal

    徹底理解Java中的ThreadLocal

     ThreadLocal翻譯成中文比較準(zhǔn)確的叫法應(yīng)該是:線程局部變量。使用這個(gè)工具類可以很簡(jiǎn)潔地編寫出優(yōu)美的多線程程序。 接下來通過本文給大家介紹Java中的ThreadLocal,需要的朋友可以參考下
    2017-03-03
  • 簡(jiǎn)單了解Java創(chuàng)建線程兩種方法

    簡(jiǎn)單了解Java創(chuàng)建線程兩種方法

    這篇文章主要介紹了簡(jiǎn)單了解Java創(chuàng)建線程兩種方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • 詳解SpringBoot中@NotNull,@NotBlank注解使用

    詳解SpringBoot中@NotNull,@NotBlank注解使用

    這篇文章主要為大家詳細(xì)介紹了Spring?Boot中集成Validation與@NotNull,@NotBlank等注解的簡(jiǎn)單使用,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-08-08
  • RabbitMQ 如何解決消息冪等性的問題

    RabbitMQ 如何解決消息冪等性的問題

    這篇文章主要介紹了RabbitMQ 如何解決消息冪等性的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • 基于dubbo中Listener的實(shí)現(xiàn)方法

    基于dubbo中Listener的實(shí)現(xiàn)方法

    下面小編就為大家?guī)硪黄赿ubbo中Listener的實(shí)現(xiàn)方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-08-08

最新評(píng)論

巫溪县| 开平市| 固原市| 西青区| 福清市| 高要市| 靖边县| 新龙县| 青州市| 丹东市| 昌吉市| 澄城县| 泉州市| 中卫市| 衡阳县| 襄樊市| 阜南县| 霍山县| 玛曲县| 宕昌县| 金川县| 灌云县| 曲水县| 沅陵县| 启东市| 宝鸡市| 宜州市| 琼中| 台湾省| 汕头市| 万载县| 瑞丽市| 石棉县| 乌审旗| 无棣县| 定襄县| 平度市| 营山县| 陈巴尔虎旗| 缙云县| 黄冈市|