fastjson深度源码解析- 序列化(三) - 序列化字段属性键值对

x33g5p2x  于2021-12-25 转载在 其他  
字(4.9k)|赞(0)|评价(0)|浏览(578)

SerializeWriter成员函数

序列化字段名称

  1. public void writeFieldName(String key, boolean checkSpecial) {
  2. if (key == null) {
  3. /** 如果字段key为null, 输出 "null:" */
  4. write("null:");
  5. return;
  6. }
  7. if (useSingleQuotes) {
  8. if (quoteFieldNames) {
  9. /** 使用单引号并且在字段后面加':'输出 标准的json key*/
  10. writeStringWithSingleQuote(key);
  11. write(':');
  12. } else {
  13. /** 输出key,如果有特殊字符会自动添加单引号 */
  14. writeKeyWithSingleQuoteIfHasSpecial(key);
  15. }
  16. } else {
  17. if (quoteFieldNames) {
  18. /** 使用双引号输出json key 并添加 : */
  19. writeStringWithDoubleQuote(key, ':');
  20. } else {
  21. boolean hashSpecial = key.length() == 0;
  22. for (int i = 0; i < key.length(); ++i) {
  23. char ch = key.charAt(i);
  24. boolean special = (ch < 64 && (sepcialBits & (1L << ch)) != 0) || ch == '\\';
  25. if (special) {
  26. hashSpecial = true;
  27. break;
  28. }
  29. }
  30. if (hashSpecial) {
  31. /** 如果包含特殊字符,会进行特殊字符转换输出,eg: 使用转换后的native编码输出 */
  32. writeStringWithDoubleQuote(key, ':');
  33. } else {
  34. /** 输出字段不加引号 */
  35. write(key);
  36. write(':');
  37. }
  38. }
  39. }
  40. }

序列化字段名称方法writeFieldName主要的任务:

  1. 完成字段特殊字符的转译
  2. 添加字段的引号

处理输出key的特殊字符方法writeStringWithDoubleQuote前面已经分析过了,序列化字段名称是否需要添加引号和特殊字符处理参考writeKeyWithSingleQuoteIfHasSpecial

  1. private void writeKeyWithSingleQuoteIfHasSpecial(String text) {
  2. final byte[] specicalFlags_singleQuotes = IOUtils.specicalFlags_singleQuotes;
  3. int len = text.length();
  4. int newcount = count + len + 1;
  5. if (newcount > buf.length) {
  6. if (writer != null) {
  7. if (len == 0) {
  8. /** 如果字段为null, 输出空白字符('':)作为key */
  9. write('\'');
  10. write('\'');
  11. write(':');
  12. return;
  13. }
  14. boolean hasSpecial = false;
  15. for (int i = 0; i < len; ++i) {
  16. char ch = text.charAt(i);
  17. if (ch < specicalFlags_singleQuotes.length && specicalFlags_singleQuotes[ch] != 0) {
  18. hasSpecial = true;
  19. break;
  20. }
  21. }
  22. /** 如果有特殊字符,给字段key添加单引号 */
  23. if (hasSpecial) {
  24. write('\'');
  25. }
  26. for (int i = 0; i < len; ++i) {
  27. char ch = text.charAt(i);
  28. if (ch < specicalFlags_singleQuotes.length && specicalFlags_singleQuotes[ch] != 0) {
  29. /** 如果输出key中包含特殊字符,添加转译字符并将特殊字符替换成普通字符 */
  30. write('\\');
  31. write(replaceChars[(int) ch]);
  32. } else {
  33. write(ch);
  34. }
  35. }
  36. /** 如果有特殊字符,给字段key添加单引号 */
  37. if (hasSpecial) {
  38. write('\'');
  39. }
  40. write(':');
  41. return;
  42. }
  43. /** 输出器writer为null触发扩容,扩容到为原有buf容量1.5倍+1, copy原有buf的字符*/
  44. expandCapacity(newcount);
  45. }
  46. if (len == 0) {
  47. int newCount = count + 3;
  48. if (newCount > buf.length) {
  49. expandCapacity(count + 3);
  50. }
  51. buf[count++] = '\'';
  52. buf[count++] = '\'';
  53. buf[count++] = ':';
  54. return;
  55. }
  56. int start = count;
  57. int end = start + len;
  58. /** buffer能够容纳字符串,直接拷贝text到buf缓冲数组 */
  59. text.getChars(0, len, buf, start);
  60. count = newcount;
  61. boolean hasSpecial = false;
  62. for (int i = start; i < end; ++i) {
  63. char ch = buf[i];
  64. if (ch < specicalFlags_singleQuotes.length && specicalFlags_singleQuotes[ch] != 0) {
  65. if (!hasSpecial) {
  66. newcount += 3;
  67. if (newcount > buf.length) {
  68. expandCapacity(newcount);
  69. }
  70. count = newcount;
  71. /** 将字符后移两位,插入字符'\ 并替换特殊字符为普通字符 */
  72. System.arraycopy(buf, i + 1, buf, i + 3, end - i - 1);
  73. /** 将字符后移一位 */
  74. System.arraycopy(buf, 0, buf, 1, i);
  75. buf[start] = '\'';
  76. buf[++i] = '\\';
  77. buf[++i] = replaceChars[(int) ch];
  78. end += 2;
  79. buf[count - 2] = '\'';
  80. hasSpecial = true;
  81. } else {
  82. newcount++;
  83. if (newcount > buf.length) {
  84. expandCapacity(newcount);
  85. }
  86. count = newcount;
  87. /** 包含特殊字符,将字符后移一位,插入转译字符\ 并替换特殊字符为普通字符 */
  88. System.arraycopy(buf, i + 1, buf, i + 2, end - i);
  89. buf[i] = '\\';
  90. buf[++i] = replaceChars[(int) ch];
  91. end++;
  92. }
  93. }
  94. }
  95. buf[newcount - 1] = ':';
  96. }

序列化Boolean类型字段键值对

  1. public void writeFieldValue(char seperator, String name, boolean value) {
  2. if (!quoteFieldNames) {
  3. /** 如果不需要输出双引号,则一次输出字段分隔符,字段名字,字段值 */
  4. write(seperator);
  5. writeFieldName(name);
  6. write(value);
  7. return;
  8. }
  9. /** true 占用4位, false 占用5位 */
  10. int intSize = value ? 4 : 5;
  11. int nameLen = name.length();
  12. /** 输出总长度, 中间的4 代表 key 和 value 总共占用4个引号 */
  13. int newcount = count + nameLen + 4 + intSize;
  14. if (newcount > buf.length) {
  15. if (writer != null) {
  16. /** 依次输出字段分隔符,字段:字段值 */
  17. write(seperator);
  18. writeString(name);
  19. write(':');
  20. write(value);
  21. return;
  22. }
  23. /** 输出器writer为null触发扩容,扩容到为原有buf容量1.5倍+1, copy原有buf的字符*/
  24. expandCapacity(newcount);
  25. }
  26. int start = count;
  27. count = newcount;
  28. /** 输出字段分隔符,一般是, */
  29. buf[start] = seperator;
  30. int nameEnd = start + nameLen + 1;
  31. /** 输出字段属性分隔符,一般是单引号或双引号 */
  32. buf[start + 1] = keySeperator;
  33. /** 输出字段名称 */
  34. name.getChars(0, nameLen, buf, start + 2);
  35. /** 字段名称添加分隔符,一般是单引号或双引号 */
  36. buf[nameEnd + 1] = keySeperator;
  37. /** 输出boolean类型字符串值 */
  38. if (value) {
  39. System.arraycopy(":true".toCharArray(), 0, buf, nameEnd + 2, 5);
  40. } else {
  41. System.arraycopy(":false".toCharArray(), 0, buf, nameEnd + 2, 6);
  42. }
  43. }

序列化boolean类型的键值对属性,因为不涉及特殊字符,主要就是把原型序列化为字面量值。

序列化Int类型字段键值对

  1. public void writeFieldValue(char seperator, String name, int value) {
  2. if (value == Integer.MIN_VALUE || !quoteFieldNames) {
  3. /** 如果是整数最小值或不需要输出双引号,则一次输出字段分隔符,字段名字,字段值 */
  4. write(seperator);
  5. writeFieldName(name);
  6. writeInt(value);
  7. return;
  8. }
  9. /** 根据数字判断占用的位数,负数会多一位用于存储字符`-` */
  10. int intSize = (value < 0) ? IOUtils.stringSize(-value) + 1 : IOUtils.stringSize(value);
  11. int nameLen = name.length();
  12. int newcount = count + nameLen + 4 + intSize;
  13. if (newcount > buf.length) {
  14. if (writer != null) {
  15. write(seperator);
  16. writeFieldName(name);
  17. writeInt(value);
  18. return;
  19. }
  20. /** 扩容到为原有buf容量1.5倍+1, copy原有buf的字符*/
  21. expandCapacity(newcount);
  22. }
  23. int start = count;
  24. count = newcount;
  25. /** 输出字段分隔符,一般是, */
  26. buf[start] = seperator;
  27. int nameEnd = start + nameLen + 1;
  28. /** 输出字段属性分隔符,一般是单引号或双引号 */
  29. buf[start + 1] = keySeperator;
  30. /** 输出字段名称 */
  31. name.getChars(0, nameLen, buf, start + 2);
  32. buf[nameEnd + 1] = keySeperator;
  33. buf[nameEnd + 2] = ':';
  34. /** 输出整数值,对整数转化成单字符 */
  35. IOUtils.getChars(value, count, buf);
  36. }

序列化int类型的键值对属性,因为不涉及特殊字符,主要就是把原型序列化为字面量值。截止到现在,已经把核心SerializWriter类讲完了,剩余字段键值对极其类似writeFieldValue boolean和int等,因此无需冗余分析。因为序列化真正开始之前,这个类极其基础并且非常重要,因此花的时间较多。

相关文章