当前位置:   article > 正文

com.alibaba.fastjson 序列化 反序列_bigdecimalcodec

bigdecimalcodec

                                  fastjson  序列化 反序列

目录

                                  fastjson  序列化 反序列

在这里插入图片描述

序列化

SerializeWriter成员变量

一 SerializeWriter成员函数

1 序列化整形数字

2 序列化长整形数字

3 序列化浮点类型数字

4 序列化枚举类型

5 序列化单字符

6 序列化Null

7 序列化Boolean

8 序列化16进制字节数组

9 序列化byte字节数组

10 序列化字符串

11 序列化字符数组

12 序列化列表字符串

13 序列化包含特殊字符字符串

14 序列化字段名称

15 序列化Boolean类型字段键值对

16 序列化Int类型字段键值对

二 JSON成员函数

概要

JSON成员函数

序列化回调接口

序列化回调接口实现分析

内部注册的序列化

1 BooleanCodec序列化

2 CharacterCodec序列化

3 IntegerCodec序列化

4 LongCodec序列化

5 FloatCodec序列化

6 BigDecimalCodec序列化

7 BigIntegerCodec序列化

8 StringCodec序列化

9 PrimitiveArraySerializer序列化

10 ObjectArrayCodec序列化

11 MiscCodec序列化

12 AppendableSerializer序列化

13 ToStringSerializer序列化

14 AtomicCodec序列化

15 ReferenceCodec序列化

16 CollectionCodec序列化

 特定序列化实现解析

 1 MapSerializer序列化

2 ListSerializer序列化

3 DateCodec序列化

4 JavaBeanSerializer序列化

反序列化

反序列化回调接口实现分析

内部注册的反序列化

1 BooleanCodec反序列化

2 CharacterCodec反序列化

3 IntegerCodec反序列化

4 LongCodec反序列化

5 FloatCodec反序列化

6  BigDecimalCodec反序列化

 7 StringCodec反序列化

8 ObjectArrayCodec反序列化

9 JavaBeanDeserializer反序列化


序列化

fastjson核心功能包括序列化和反序列化,序列化的含义是将java对象转换成跨语言的json字符串。我认为从这里作为分析入口相对比较简单,

SerializeWriter成员变量

com.alibaba.fastjson.serializer.SerializeWriter类非常重要,序列化输出都是通过转换底层操作,重要字段如下:

  1. /** 字符类型buffer */
  2. private final static ThreadLocal<char[]> bufLocal = new ThreadLocal<char[]>();
  3. /** 字节类型buffer */
  4. private final static ThreadLocal<byte[]> bytesBufLocal = new ThreadLocal<byte[]>();
  5. /** 存储序列化结果buffer */
  6. protected char buf[];
  7. /** buffer中包含的字符数 */
  8. protected int count;
  9. /** 序列化的特性,比如写枚举按照名字还是枚举值 */
  10. protected int features;
  11. /** 序列化输出器 */
  12. private final Writer writer;
  13. /** 是否使用单引号输出json */
  14. protected boolean useSingleQuotes;
  15. /** 输出字段是否追加 "和:字符 */
  16. protected boolean quoteFieldNames;
  17. /** 是否对字段排序 */
  18. protected boolean sortField;
  19. /** 禁用字段循环引用探测 */
  20. protected boolean disableCircularReferenceDetect;
  21. protected boolean beanToArray;
  22. /** 按照toString方式获取对象字面值 */
  23. protected boolean writeNonStringValueAsString;
  24. /** 如果字段默认值不输出,比如原型int,默认值0不输出 */
  25. protected boolean notWriteDefaultValue;
  26. /** 序列化枚举时使用枚举name */
  27. protected boolean writeEnumUsingName;
  28. /** 序列化枚举时使用枚举toString值 */
  29. protected boolean writeEnumUsingToString;
  30. protected boolean writeDirect;
  31. /** key分隔符,默认单引号是',双引号是" */
  32. protected char keySeperator;
  33. protected int maxBufSize = -1;
  34. protected boolean browserSecure;
  35. protected long sepcialBits;

一 SerializeWriter成员函数

1 序列化整形数字

  1. public void writeInt(int i) {
  2. /** 如果是整数最小值,调用字符串函数输出到缓冲区*/
  3. if (i == Integer.MIN_VALUE) {
  4. write("-2147483648");
  5. return;
  6. }
  7. /** 根据数字判断占用的位数,负数会多一位用于存储字符`-` */
  8. int size = (i < 0) ? IOUtils.stringSize(-i) + 1 : IOUtils.stringSize(i);
  9. int newcount = count + size;
  10. /** 如果当前存储空间不够 */
  11. if (newcount > buf.length) {
  12. if (writer == null) {
  13. /** 扩容到为原有buf容量1.5+1, copy原有buf的字符*/
  14. expandCapacity(newcount);
  15. } else {
  16. char[] chars = new char[size];
  17. /** 将整数i转换成单字符并存储到chars数组 */
  18. IOUtils.getChars(i, size, chars);
  19. /** 将chars字符数组内容写到buffer中*/
  20. write(chars, 0, chars.length);
  21. return;
  22. }
  23. }
  24. /** 如果buffer空间够,直接将字符写到buffer中 */
  25. IOUtils.getChars(i, newcount, buf);
  26. /** 重新计数buffer中字符数 */
  27. count = newcount;
  28. }

其中值得提一下的是IOUtils.getChars,里面利用了Integer.getChars(int i, int index, char[] buf),主要的思想是整数超过65536 进行除以100, 循环取出数字后两位,依次将个位和十位转换为单字符,如果整数小于等于65536,进行除以10,取出个位数字并转换单字符,getCharts中 q = (i * 52429) >>> (16+3),可以理解为 (i乘以0.1), 但是精度更高。


2 序列化长整形数字

  1. public void writeLong(long i) {
  2. boolean needQuotationMark = isEnabled(SerializerFeature.BrowserCompatible) //
  3. && (!isEnabled(SerializerFeature.WriteClassName)) //
  4. && (i > 9007199254740991L || i < -9007199254740991L);
  5. if (i == Long.MIN_VALUE) {
  6. if (needQuotationMark) write("\"-9223372036854775808\"");
  7. /** 如果是长整数最小值,调用字符串函数输出到缓冲区*/
  8. else write("-9223372036854775808");
  9. return;
  10. }
  11. /** 根据数字判断占用的位数,负数会多一位用于存储字符`-` */
  12. int size = (i < 0) ? IOUtils.stringSize(-i) + 1 : IOUtils.stringSize(i);
  13. int newcount = count + size;
  14. if (needQuotationMark) newcount += 2;
  15. /** 如果当前存储空间不够 */
  16. if (newcount > buf.length) {
  17. if (writer == null) {
  18. /** 扩容到为原有buf容量1.5+1, copy原有buf的字符*/
  19. expandCapacity(newcount);
  20. } else {
  21. char[] chars = new char[size];
  22. /** 将长整数i转换成单字符并存储到chars数组 */
  23. IOUtils.getChars(i, size, chars);
  24. if (needQuotationMark) {
  25. write('"');
  26. write(chars, 0, chars.length);
  27. write('"');
  28. } else {
  29. write(chars, 0, chars.length);
  30. }
  31. return;
  32. }
  33. }
  34. /** 添加引号 */
  35. if (needQuotationMark) {
  36. buf[count] = '"';
  37. IOUtils.getChars(i, newcount - 1, buf);
  38. buf[newcount - 1] = '"';
  39. } else {
  40. IOUtils.getChars(i, newcount, buf);
  41. }
  42. count = newcount;
  43. }

序列化长整型和整型非常类似,增加了双引号判断,采用用了和Integer转换为单字符同样的技巧。

 

3 序列化浮点类型数字

  1. public void writeDouble(double doubleValue, boolean checkWriteClassName) {
  2. /** 如果doubleValue不合法或者是无穷数,调用writeNull */
  3. if (Double.isNaN(doubleValue)
  4. || Double.isInfinite(doubleValue)) {
  5. writeNull();
  6. } else {
  7. /** 将高精度double转换为字符串 */
  8. String doubleText = Double.toString(doubleValue);
  9. /** 启动WriteNullNumberAsZero特性,会将结尾.0去除 */
  10. if (isEnabled(SerializerFeature.WriteNullNumberAsZero) && doubleText.endsWith(".0")) {
  11. doubleText = doubleText.substring(0, doubleText.length() - 2);
  12. }
  13. /** 调用字符串输出方法 */
  14. write(doubleText);
  15. /** 如果开启序列化WriteClassName特性,输出Double类型 */
  16. if (checkWriteClassName && isEnabled(SerializerFeature.WriteClassName)) {
  17. write('D');
  18. }
  19. }
  20. }
  21. public void writeFloat(float value, boolean checkWriteClassName) {
  22. /** 如果value不合法或者是无穷数,调用writeNull */
  23. if (Float.isNaN(value) //
  24. || Float.isInfinite(value)) {
  25. writeNull();
  26. } else {
  27. /** 将高精度float转换为字符串 */
  28. String floatText= Float.toString(value);
  29. /** 启动WriteNullNumberAsZero特性,会将结尾.0去除 */
  30. if (isEnabled(SerializerFeature.WriteNullNumberAsZero) && floatText.endsWith(".0")) {
  31. floatText = floatText.substring(0, floatText.length() - 2);
  32. }
  33. write(floatText);
  34. /** 如果开启序列化WriteClassName特性,输出float类型 */
  35. if (checkWriteClassName && isEnabled(SerializerFeature.WriteClassName)) {
  36. write('F');
  37. }
  38. }
  39. }

序列化浮点类型的基本思路是先转换为字符串,然后在输出到输出流中。

 

4 序列化枚举类型

  1. public void writeEnum(Enum<?> value) {
  2. if (value == null) {
  3. /** 如果枚举value为空,调用writeNull输出 */
  4. writeNull();
  5. return;
  6. }
  7. String strVal = null;
  8. /** 如果开启序列化输出枚举名字作为属性值 */
  9. if (writeEnumUsingName && !writeEnumUsingToString) {
  10. strVal = value.name();
  11. } else if (writeEnumUsingToString) {
  12. /** 采用枚举默认toString方法作为属性值 */
  13. strVal = value.toString();;
  14. }
  15. if (strVal != null) {
  16. /** 如果开启引号特性,输出json包含引号的字符串 */
  17. char quote = isEnabled(SerializerFeature.UseSingleQuotes) ? '\'' : '"';
  18. write(quote);
  19. write(strVal);
  20. write(quote);
  21. } else {
  22. /** 输出枚举所在的索引号 */
  23. writeInt(value.ordinal());
  24. }
  25. }

5 序列化单字符

  1. public void write(int c) {
  2. int newcount = count + 1;
  3. /** 如果当前存储空间不够 */
  4. if (newcount > buf.length) {
  5. if (writer == null) {
  6. expandCapacity(newcount);
  7. } else {
  8. /** 强制流输出并刷新缓冲区 */
  9. flush();
  10. newcount = 1;
  11. }
  12. }
  13. /** 存储单字符到buffer并更新计数 */
  14. buf[count] = (char) c;
  15. count = newcount;
  16. }

6 序列化Null

  1. public void writeNull() {
  2. /** 调用输出字符串null */
  3. write("null");
  4. }

7 序列化Boolean

  1. public void write(boolean value) {
  2. if (value) {
  3. /** 输出true字符串 */
  4. write("true");
  5. } else {
  6. /** 输出false字符串 */
  7. write("false");
  8. }
  9. }

8 序列化16进制字节数组

  1. public void writeHex(byte[] bytes) {
  2. /** 计算总共字符长度, 乘以2 代表一个字符要占用2字节, 3代表要添加 x 和 前后添加' */
  3. int newcount = count + bytes.length * 2 + 3;
  4. if (newcount > buf.length) {
  5. if (writer != null) {
  6. char[] chars = new char[bytes.length + 3];
  7. int pos = 0;
  8. chars[pos++] = 'x';
  9. chars[pos++] = '\'';
  10. for (int i = 0; i < bytes.length; ++i) {
  11. byte b = bytes[i];
  12. int a = b & 0xFF;
  13. /** 取字节的高四位 1111 0000*/
  14. int b0 = a >> 4;
  15. /** 取字节的低四位 0000 1111*/
  16. int b1 = a & 0xf;
  17. /** 索引低索引存储字节高位
  18. * 如果4位表示的数字是 0~9, 转换为ascii的 0~9
  19. * 如果4位表示的不是数字, 转换为16进制ascii码字符
  20. */
  21. chars[pos++] = (char) (b0 + (b0 < 10 ? 48 : 55));
  22. chars[pos++] = (char) (b1 + (b1 < 10 ? 48 : 55));
  23. }
  24. chars[pos++] = '\'';
  25. try {
  26. writer.write(chars);
  27. } catch (IOException ex) {
  28. throw new JSONException("writeBytes error.", ex);
  29. }
  30. return;
  31. }
  32. /** buffer容量不够并且输出器为空,触发扩容 */
  33. expandCapacity(newcount);
  34. }
  35. buf[count++] = 'x';
  36. buf[count++] = '\'';
  37. for (int i = 0; i < bytes.length; ++i) {
  38. byte b = bytes[i];
  39. int a = b & 0xFF;
  40. /** 取字节的高四位 */
  41. int b0 = a >> 4;
  42. /** 取字节的低四位 */
  43. int b1 = a & 0xf;
  44. /** 索引低索引存储字节高位
  45. * 如果4位表示的数字是 0~9, 转换为ascii的 0~9
  46. * 如果4位表示的不是数字, 转换为16进制ascii码字符
  47. */
  48. buf[count++] = (char) (b0 + (b0 < 10 ? 48 : 55));
  49. buf[count++] = (char) (b1 + (b1 < 10 ? 48 : 55));
  50. }
  51. buf[count++] = '\'';
  52. }

writeHex 这个序列化方法主要对16进制的自己转换为占用2个ascii码字符,添加单引号和x前缀。

9 序列化byte字节数组

  1. public void writeByteArray(byte[] bytes) {
  2. if (isEnabled(SerializerFeature.WriteClassName.mask)) {
  3. /** 如果开启序列化特性WriteClassName,直接写16进制字符 */
  4. writeHex(bytes);
  5. return;
  6. }
  7. int bytesLen = bytes.length;
  8. final char quote = useSingleQuotes ? '\'' : '"';
  9. if (bytesLen == 0) {
  10. String emptyString = useSingleQuotes ? "''" : "\"\"";
  11. /** 如果字节数组长度为0,输出空白字符 */
  12. write(emptyString);
  13. return;
  14. }
  15. final char[] CA = IOUtils.CA;
  16. /** 验证长度是24bit位整数倍 */
  17. int eLen = (bytesLen / 3) * 3;
  18. /** base64 编码字符长度
  19. *
  20. * base64 :
  21. * 第一步,将每三个字节作为一组,一共是24个二进制位。
  22. * 第二步,将这24个二进制位分为四组,每个组有6个二进制位。
  23. * 第三步,在每组前面加两个00,扩展成32个二进制位,即四个字节。
  24. * 第四步,根据下表,得到扩展后的每个字节的对应符号,这就是Base64的编码值。
  25. *
  26. * ref: http://www.ruanyifeng.com/blog/2008/06/base64.html
  27. */
  28. int charsLen = ((bytesLen - 1) / 3 + 1) << 2;
  29. // char[] chars = new char[charsLen];
  30. int offset = count;
  31. int newcount = count + charsLen + 2;
  32. if (newcount > buf.length) {
  33. if (writer != null) {
  34. write(quote);
  35. for (int s = 0; s < eLen;) {
  36. /** 三个字节为一组, 扩展为四个字节 */
  37. int i = (bytes[s++] & 0xff) << 16 | (bytes[s++] & 0xff) << 8 | (bytes[s++] & 0xff);
  38. write(CA[(i >>> 18) & 0x3f]);
  39. write(CA[(i >>> 12) & 0x3f]);
  40. write(CA[(i >>> 6) & 0x3f]);
  41. /** 填充00 */
  42. write(CA[i & 0x3f]);
  43. }
  44. /** 对齐并编码剩余不足3个字节为一组的数据 */
  45. // Pad and encode last bits if source isn't even 24 bits.
  46. int left = bytesLen - eLen; // 0 - 2.
  47. if (left > 0) {
  48. /**
  49. * a) 1个字节的情况:
  50. * 将这1字节8位二进制,每6位分成2组,最后一组除了前面加00,后面加上0000,
  51. * 这样得到 两位的Base64编码, 在末尾补上2个"="号
  52. *
  53. * b) 2个字节的情况:
  54. * 将这2字节的一共16个二进制位,每6位分成3组,最后一组除了前面加00,后面也要加00,
  55. * 这样得到 3位的Base64编码, 在末尾补上"="号
  56. *
  57. *
  58. * 如果只有1个字节,按照前面规则a)
  59. * 第1组是6位,第2组后面4个0, 因此应该左移 10 = 6 + 4
  60. *
  61. * 如果只有2个字节,按照前面规则b)
  62. * 第1个字节左移 10 位 加上 第2个字节左移 2 位补0即可
  63. */
  64. int i = ((bytes[eLen] & 0xff) << 10) | (left == 2 ? ((bytes[bytesLen - 1] & 0xff) << 2) : 0);
  65. /** 扩展为四个字节 */
  66. write(CA[i >> 12]);
  67. write(CA[(i >>> 6) & 0x3f]);
  68. write(left == 2 ? CA[i & 0x3f] : '=');
  69. write('=');
  70. }
  71. write(quote);
  72. return;
  73. }
  74. expandCapacity(newcount);
  75. }
  76. count = newcount;
  77. buf[offset++] = quote;
  78. // Encode even 24-bits
  79. for (int s = 0, d = offset; s < eLen;) {
  80. /** 三个字节为一组, 扩展为四个字节 */
  81. int i = (bytes[s++] & 0xff) << 16 | (bytes[s++] & 0xff) << 8 | (bytes[s++] & 0xff);
  82. // Encode the int into four chars
  83. buf[d++] = CA[(i >>> 18) & 0x3f];
  84. buf[d++] = CA[(i >>> 12) & 0x3f];
  85. buf[d++] = CA[(i >>> 6) & 0x3f];
  86. /** 填充00 */
  87. buf[d++] = CA[i & 0x3f];
  88. }
  89. /** 对齐并编码剩余不足3个字节为一组的数据 */
  90. int left = bytesLen - eLen; // 0 - 2.
  91. if (left > 0) {
  92. // Prepare the int
  93. int i = ((bytes[eLen] & 0xff) << 10) | (left == 2 ? ((bytes[bytesLen - 1] & 0xff) << 2) : 0);
  94. /** 扩展为四个字节 */
  95. buf[newcount - 5] = CA[i >> 12];
  96. buf[newcount - 4] = CA[(i >>> 6) & 0x3f];
  97. buf[newcount - 3] = left == 2 ? CA[i & 0x3f] : '=';
  98. buf[newcount - 2] = '=';
  99. }
  100. buf[newcount - 1] = quote;
  101. }

writeByteArray序列化字节数组实际上就是做了base64编码转换,代码添加了详尽的注释帮助理解。

10 序列化字符串

  1. public void write(String str, int off, int len) {
  2. /** 计算总共字符串长度 */
  3. int newcount = count + len;
  4. /** 如果当前存储空间不够 */
  5. if (newcount > buf.length) {
  6. if (writer == null) {
  7. expandCapacity(newcount);
  8. } else {
  9. /**
  10. * 如果字符串str超过缓冲区大小, 进行循环拷贝
  11. */
  12. do {
  13. /** 计算当前buffer剩余容纳字符数 */
  14. int rest = buf.length - count;
  15. /** 将字符串str[off, off + rest) 拷贝到buf[count, ...]中*/
  16. str.getChars(off, off + rest, buf, count);
  17. count = buf.length;
  18. /** 强制刷新输出流,会重置count = 0 */
  19. flush();
  20. /** 计算剩余需要拷贝的字符数量 */
  21. len -= rest;
  22. /** 剩余要拷贝字符在str中偏移量(索引) */
  23. off += rest;
  24. } while (len > buf.length);
  25. newcount = len;
  26. }
  27. }
  28. /** 存储空间充足,直接将str[off, off + len) 拷贝到buf[count, ...]中*/
  29. str.getChars(off, off + len, buf, count);
  30. count = newcount;
  31. }

序列化字符串write(string),最终都会转化为上面形式write(string, 0, string.length)

11 序列化字符数组

  1. public void write(char c[], int off, int len) {
  2. if (off < 0 //
  3. || off > c.length //
  4. || len < 0 //
  5. || off + len > c.length //
  6. || off + len < 0) {
  7. throw new IndexOutOfBoundsException();
  8. } else if (len == 0) {
  9. return;
  10. }
  11. /** 计算总共字符串长度 */
  12. int newcount = count + len;
  13. /** 如果当前存储空间不够 */
  14. if (newcount > buf.length) {
  15. if (writer == null) {
  16. expandCapacity(newcount);
  17. } else {
  18. /**
  19. * 如果字符数组c超过缓冲区大小, 进行循环拷贝
  20. */
  21. do {
  22. /** 计算当前buffer剩余容纳字符数 */
  23. int rest = buf.length - count;
  24. /** c[off, off + rest) 拷贝到buf[count, ...]中*/
  25. System.arraycopy(c, off, buf, count, rest);
  26. count = buf.length;
  27. /** 强制刷新输出流,会重置count = 0 */
  28. flush();
  29. /** 计算剩余需要拷贝的字符数量 */
  30. len -= rest;
  31. /** 剩余要拷贝字符在c中偏移量(索引) */
  32. off += rest;
  33. } while (len > buf.length);
  34. newcount = len;
  35. }
  36. }
  37. System.arraycopy(c, off, buf, count, len);
  38. count = newcount;
  39. }

12 序列化列表字符串

  1. public void write(char c[], int off, int len) {
  2. if (off < 0 //
  3. || off > c.length //
  4. || len < 0 //
  5. || off + len > c.length //
  6. || off + len < 0) {
  7. throw new IndexOutOfBoundsException();
  8. } else if (len == 0) {
  9. return;
  10. }
  11. /** 计算总共字符串长度 */
  12. int newcount = count + len;
  13. /** 如果当前存储空间不够 */
  14. if (newcount > buf.length) {
  15. if (writer == null) {
  16. expandCapacity(newcount);
  17. } else {
  18. /**
  19. * 如果字符数组c超过缓冲区大小, 进行循环拷贝
  20. */
  21. do {
  22. /** 计算当前buffer剩余容纳字符数 */
  23. int rest = buf.length - count;
  24. /** c[off, off + rest) 拷贝到buf[count, ...]中*/
  25. System.arraycopy(c, off, buf, count, rest);
  26. count = buf.length;
  27. /** 强制刷新输出流,会重置count = 0 */
  28. flush();
  29. /** 计算剩余需要拷贝的字符数量 */
  30. len -= rest;
  31. /** 剩余要拷贝字符在c中偏移量(索引) */
  32. off += rest;
  33. } while (len > buf.length);
  34. newcount = len;
  35. }
  36. }
  37. System.arraycopy(c, off, buf, count, len);
  38. count = newcount;
  39. }

序列化字符串会转化成[“element”, "element", ...]格式。如果列表字符串中包含特殊字符,调用特化版本writeStringWithDoubleQuote(text, (char) 0)

13 序列化包含特殊字符字符串

  1. public void write(char c[], int off, int len) {
  2. if (off < 0 //
  3. || off > c.length //
  4. || len < 0 //
  5. || off + len > c.length //
  6. || off + len < 0) {
  7. throw new IndexOutOfBoundsException();
  8. } else if (len == 0) {
  9. return;
  10. }
  11. /** 计算总共字符串长度 */
  12. int newcount = count + len;
  13. /** 如果当前存储空间不够 */
  14. if (newcount > buf.length) {
  15. if (writer == null) {
  16. expandCapacity(newcount);
  17. } else {
  18. /**
  19. * 如果字符数组c超过缓冲区大小, 进行循环拷贝
  20. */
  21. do {
  22. /** 计算当前buffer剩余容纳字符数 */
  23. int rest = buf.length - count;
  24. /** c[off, off + rest) 拷贝到buf[count, ...]中*/
  25. System.arraycopy(c, off, buf, count, rest);
  26. count = buf.length;
  27. /** 强制刷新输出流,会重置count = 0 */
  28. flush();
  29. /** 计算剩余需要拷贝的字符数量 */
  30. len -= rest;
  31. /** 剩余要拷贝字符在c中偏移量(索引) */
  32. off += rest;
  33. } while (len > buf.length);
  34. newcount = len;
  35. }
  36. }
  37. System.arraycopy(c, off, buf, count, len);
  38. count = newcount;
  39. }

writeStringWithDoubleQuote方法实现实在是太长了,这个方法主要做了以下几件事情:

1  如果开启序列化BrowserCompatible特性,执行ascii转换成native编码,节省空间。
2   如果输出器writer不为空,会自动触发buffer扩容(原有容量1.5倍+1)。
另外一个针对特殊字符的字符串序列化方法writeStringWithDoubleQuote(char[] text, final char seperator),因为和writeStringWithDoubleQuote(String text, final char seperator)版本极其类似,所以不再冗余分析。

序列化字符串的方法包括添加单引号的版本,详细请参考 writeStringWithSingleQuote :

  1. public void write(char c[], int off, int len) {
  2. if (off < 0 //
  3. || off > c.length //
  4. || len < 0 //
  5. || off + len > c.length //
  6. || off + len < 0) {
  7. throw new IndexOutOfBoundsException();
  8. } else if (len == 0) {
  9. return;
  10. }
  11. /** 计算总共字符串长度 */
  12. int newcount = count + len;
  13. /** 如果当前存储空间不够 */
  14. if (newcount > buf.length) {
  15. if (writer == null) {
  16. expandCapacity(newcount);
  17. } else {
  18. /**
  19. * 如果字符数组c超过缓冲区大小, 进行循环拷贝
  20. */
  21. do {
  22. /** 计算当前buffer剩余容纳字符数 */
  23. int rest = buf.length - count;
  24. /** c[off, off + rest) 拷贝到buf[count, ...]中*/
  25. System.arraycopy(c, off, buf, count, rest);
  26. count = buf.length;
  27. /** 强制刷新输出流,会重置count = 0 */
  28. flush();
  29. /** 计算剩余需要拷贝的字符数量 */
  30. len -= rest;
  31. /** 剩余要拷贝字符在c中偏移量(索引) */
  32. off += rest;
  33. } while (len > buf.length);
  34. newcount = len;
  35. }
  36. }
  37. System.arraycopy(c, off, buf, count, len);
  38. count = newcount;
  39. }

writeStringWithSingleQuote这个方法主要做了以下几件事情:

1  针对特殊字符,添加转译字符并且替换特殊字符为普通字符
2   如果输出器writer不为空,会自动触发buffer扩容(原有容量1.5倍+1)。

  另外一个针对特殊字符的字符串序列化方法writeStringWithSingleQuote(char[]),因为和writeStringWithSingleQuote(String)版本极其类似,所以不再冗余分析。

14 序列化字段名称

  1. public void writeFieldName(String key, boolean checkSpecial) {
  2. if (key == null) {
  3. /** 如果字段keynull, 输出 "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. }

15 序列化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 代表 keyvalue 总共占用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类型的键值对属性,因为不涉及特殊字符,主要就是把原型序列化为字面量值。

16 序列化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等,因此无需冗余分析。因为序列化真正开始之前,这个类极其基础并且非常重要,因此花的时间较多。
 

二 JSON成员函数

概要

fastjson序列化主要使用入口就是在JSON.java类中,它提供非常简便和友好的api将java对象转换成json字符串。

JSON成员函数

  1. /**
  2. * 便捷序列化java对象,序列化对象可以包含任意泛型属性字段,但是不适用本身是泛型的对象。
  3. * 默认序列化返回字符串,可以使用writeJSONString(Writer, Object, SerializerFeature[])
  4. * 将序列化字符串输出到指定输出器中
  5. */
  6. public static String toJSONString(Object object) {
  7. /**
  8. * 直接调用重载方法,将指定object序列化成json字符串,忽略序列化filter
  9. */
  10. return toJSONString(object, emptyFilters);
  11. }

使用便捷接口toJSONString方法,可以将任意java对象序列化为json字符串,内部调用toJSONString(Object, SerializeFilter[], SerializerFeature... ) :

  1. public static String toJSONString(Object object, SerializeFilter[] filters, SerializerFeature... features) {
  2. return toJSONString(object, SerializeConfig.globalInstance, filters, null, DEFAULT_GENERATE_FEATURE, features);
  3. }

继续跟踪方法调用到toJSONString(Object, SerializeConfig ,SerializeFilter[], String, int, SerializerFeature... ) :

  1. public static String toJSONString(Object object, /** 序列化对象 */
  2. SerializeConfig config, /** 全局序列化配置 */
  3. SerializeFilter[] filters, /** 序列化拦截器 */
  4. String dateFormat, /** 序列化日期格式 */
  5. int defaultFeatures, /** 默认序列化特性 */
  6. SerializerFeature... features) { /** 自定义序列化特性 */
  7. /** 初始化序列化writer,用features覆盖defaultFeatures配置 */
  8. SerializeWriter out = new SerializeWriter(null, defaultFeatures, features);
  9. try {
  10. /**
  11. * 初始化JSONSerializer,序列化类型由它委托config查找具体
  12. * 序列化处理器处理,序列化结果写入out的buffer中
  13. */
  14. JSONSerializer serializer = new JSONSerializer(out, config);
  15. if (dateFormat != null && dateFormat.length() != 0) {
  16. serializer.setDateFormat(dateFormat);
  17. /** 调用out 重新配置属性 并且打开WriteDateUseDateFormat特性 */
  18. serializer.config(SerializerFeature.WriteDateUseDateFormat, true);
  19. }
  20. if (filters != null) {
  21. for (SerializeFilter filter : filters) {
  22. /** 添加拦截器 */
  23. serializer.addFilter(filter);
  24. }
  25. }
  26. /** 使用序列化实例转换对象,查找具体序列化实例委托给config查找 */
  27. serializer.write(object);
  28. return out.toString();
  29. } finally {
  30. out.close();
  31. }
  32. }

这个序列化方法实际并不是真正执行序列化操作,首先做序列化特性配置,然后追加序列化拦截器,开始执行序列化对象操作委托给了config对象查找。

我们继续进入serializer.write(object) 查看:

  1. public final void write(Object object) {
  2. if (object == null) {
  3. /** 如果对象为空,直接输出 "null" 字符串 */
  4. out.writeNull();
  5. return;
  6. }
  7. Class<?> clazz = object.getClass();
  8. /** 根据对象的Class类型查找具体序列化实例 */
  9. ObjectSerializer writer = getObjectWriter(clazz);
  10. try {
  11. /** 使用具体serializer实例处理对象 */
  12. writer.write(this, object, null, null, 0);
  13. } catch (IOException e) {
  14. throw new JSONException(e.getMessage(), e);
  15. }
  16. }

 

序列化回调接口

ObjectSerializer序列化接口

我们发现真正序列化对象的时候是由具体ObjectSerializer实例完成,我们首先查看一下接口定义:

  1. void write(JSONSerializer serializer, /** json序列化实例 */
  2. Object object, /** 待序列化的对象*/
  3. Object fieldName, /** 待序列化字段*/
  4. Type fieldType, /** 待序列化字段类型 */
  5. int features) throws IOException;

当fastjson序列化特定的字段时会回调这个方法。

我们继续跟踪writer.write(this, object, null, null, 0) :

  1. public final void write(Object object) {
  2. if (object == null) {
  3. /** 如果对象为空,直接输出 "null" 字符串 */
  4. out.writeNull();
  5. return;
  6. }
  7. Class<?> clazz = object.getClass();
  8. /** 根据对象的Class类型查找具体序列化实例 */
  9. ObjectSerializer writer = getObjectWriter(clazz);
  10. try {
  11. /** 使用具体serializer实例处理对象 */
  12. writer.write(this, object, null, null, 0);
  13. } catch (IOException e) {
  14. throw new JSONException(e.getMessage(), e);
  15. }
  16. }

我们发现在方法内部调用getObjectWriter(clazz)根据具体类型查找序列化实例,方法内部只有一行调用 config.getObjectWriter(clazz),让我们更进一步查看委托实现细节com.alibaba.fastjson.serializer.SerializeConfig#getObjectWriter(java.lang.Class<?>):
 

  1. public ObjectSerializer getObjectWriter(Class<?> clazz) {
  2. return getObjectWriter(clazz, true);
  3. }

内部又调用com.alibaba.fastjson.serializer.SerializeConfig#getObjectWriter(java.lang.Class<?>, boolean),这个类实现相对复杂了一些,我会按照代码顺序梳理所有序列化实例的要点 :

  1. private ObjectSerializer getObjectWriter(Class<?> clazz, boolean create) {
  2. /** 首先从内部已经注册查找特定class的序列化实例 */
  3. ObjectSerializer writer = serializers.get(clazz);
  4. if (writer == null) {
  5. try {
  6. final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
  7. /** 使用当前线程类加载器 查找 META-INF/services/AutowiredObjectSerializer.class实现类 */
  8. for (Object o : ServiceLoader.load(AutowiredObjectSerializer.class, classLoader)) {
  9. if (!(o instanceof AutowiredObjectSerializer)) {
  10. continue;
  11. }
  12. AutowiredObjectSerializer autowired = (AutowiredObjectSerializer) o;
  13. for (Type forType : autowired.getAutowiredFor()) {
  14. /** 如果存在,注册到内部serializers缓存中 */
  15. put(forType, autowired);
  16. }
  17. }
  18. } catch (ClassCastException ex) {
  19. // skip
  20. }
  21. /** 尝试在已注册缓存找到特定class的序列化实例 */
  22. writer = serializers.get(clazz);
  23. }
  24. if (writer == null) {
  25. /** 使用加载JSON类的加载器 查找 META-INF/services/AutowiredObjectSerializer.class实现类 */
  26. final ClassLoader classLoader = JSON.class.getClassLoader();
  27. if (classLoader != Thread.currentThread().getContextClassLoader()) {
  28. try {
  29. for (Object o : ServiceLoader.load(AutowiredObjectSerializer.class, classLoader)) {
  30. if (!(o instanceof AutowiredObjectSerializer)) {
  31. continue;
  32. }
  33. AutowiredObjectSerializer autowired = (AutowiredObjectSerializer) o;
  34. for (Type forType : autowired.getAutowiredFor()) {
  35. /** 如果存在,注册到内部serializers缓存中 */
  36. put(forType, autowired);
  37. }
  38. }
  39. } catch (ClassCastException ex) {
  40. // skip
  41. }
  42. /** 尝试在已注册缓存找到特定class的序列化实例 */
  43. writer = serializers.get(clazz);
  44. }
  45. }
  46. if (writer == null) {
  47. String className = clazz.getName();
  48. Class<?> superClass;
  49. if (Map.class.isAssignableFrom(clazz)) {
  50. /** 如果class实现类Map接口,使用MapSerializer序列化 */
  51. put(clazz, writer = MapSerializer.instance);
  52. } else if (List.class.isAssignableFrom(clazz)) {
  53. /** 如果class实现类List接口,使用ListSerializer序列化 */
  54. put(clazz, writer = ListSerializer.instance);
  55. } else if (Collection.class.isAssignableFrom(clazz)) {
  56. /** 如果class实现类Co
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/人工智能uu/article/detail/923002
推荐阅读
相关标签
  

闽ICP备14008679号