2021SC@SDUSC
This article is sent synchronously in the personal blog, and the address is Fast JSON source code analysis - deserialization special (I)
outline
Part I Fast JSON source code analysis -- deserialization (3) This paper describes in detail how fastjson creates a deserialization instance without a deserialization instance class, and how to query all Getter/Setter methods through java.lang.reflect.
This issue is a special edition, which specifically introduces the internal registration of deserialization instances of known type classes in the implementation method of deserialization interface.
Official start
In the previous issue, I mentioned the upper level function of processing different getters / setters, saving information and returning deserialization.
Following the previous issue, I introduced in detail the internal registration of deserialization instances of different types of classes
If the type involved is:
Registered type
fastjson has registered commonly used deserialization implementation schemes internally. The function initDeserialize() code registered according to the source code is as follows:
This part of the code can be completely ignored. You can see the clear corresponding relationship by directly looking at the table I sorted out below (find it one by one by the code)
private void initDeserializers() { deserializers.put(SimpleDateFormat.class, MiscCodec.instance); deserializers.put(Calendar.class, CalendarCodec.instance); deserializers.put(XMLGregorianCalendar.class, CalendarCodec.instance); deserializers.put(JSONObject.class, MapDeserializer.instance); deserializers.put(JSONArray.class, CollectionCodec.instance); deserializers.put(Map.class, MapDeserializer.instance); deserializers.put(HashMap.class, MapDeserializer.instance); deserializers.put(LinkedHashMap.class, MapDeserializer.instance); deserializers.put(TreeMap.class, MapDeserializer.instance); deserializers.put(ConcurrentMap.class, MapDeserializer.instance); deserializers.put(ConcurrentHashMap.class, MapDeserializer.instance); deserializers.put(Collection.class, CollectionCodec.instance); deserializers.put(List.class, CollectionCodec.instance); deserializers.put(ArrayList.class, CollectionCodec.instance); deserializers.put(Object.class, JavaObjectDeserializer.instance); deserializers.put(String.class, StringCodec.instance); deserializers.put(StringBuffer.class, StringCodec.instance); deserializers.put(StringBuilder.class, StringCodec.instance); deserializers.put(char.class, CharacterCodec.instance); deserializers.put(Character.class, CharacterCodec.instance); deserializers.put(byte.class, NumberDeserializer.instance); deserializers.put(Byte.class, NumberDeserializer.instance); deserializers.put(short.class, NumberDeserializer.instance); deserializers.put(Short.class, NumberDeserializer.instance); deserializers.put(int.class, IntegerCodec.instance); deserializers.put(Integer.class, IntegerCodec.instance); deserializers.put(long.class, LongCodec.instance); deserializers.put(Long.class, LongCodec.instance); deserializers.put(BigInteger.class, BigIntegerCodec.instance); deserializers.put(BigDecimal.class, BigDecimalCodec.instance); deserializers.put(float.class, FloatCodec.instance); deserializers.put(Float.class, FloatCodec.instance); deserializers.put(double.class, NumberDeserializer.instance); deserializers.put(Double.class, NumberDeserializer.instance); deserializers.put(boolean.class, BooleanCodec.instance); deserializers.put(Boolean.class, BooleanCodec.instance); deserializers.put(Class.class, MiscCodec.instance); deserializers.put(char[].class, new CharArrayCodec()); deserializers.put(AtomicBoolean.class, BooleanCodec.instance); deserializers.put(AtomicInteger.class, IntegerCodec.instance); deserializers.put(AtomicLong.class, LongCodec.instance); deserializers.put(AtomicReference.class, ReferenceCodec.instance); deserializers.put(WeakReference.class, ReferenceCodec.instance); deserializers.put(SoftReference.class, ReferenceCodec.instance); deserializers.put(UUID.class, MiscCodec.instance); deserializers.put(TimeZone.class, MiscCodec.instance); deserializers.put(Locale.class, MiscCodec.instance); deserializers.put(Currency.class, MiscCodec.instance); deserializers.put(Inet4Address.class, MiscCodec.instance); deserializers.put(Inet6Address.class, MiscCodec.instance); deserializers.put(InetSocketAddress.class, MiscCodec.instance); deserializers.put(File.class, MiscCodec.instance); deserializers.put(URI.class, MiscCodec.instance); deserializers.put(URL.class, MiscCodec.instance); deserializers.put(Pattern.class, MiscCodec.instance); deserializers.put(Charset.class, MiscCodec.instance); deserializers.put(JSONPath.class, MiscCodec.instance); deserializers.put(Number.class, NumberDeserializer.instance); deserializers.put(AtomicIntegerArray.class, AtomicCodec.instance); deserializers.put(AtomicLongArray.class, AtomicCodec.instance); deserializers.put(StackTraceElement.class, StackTraceElementDeserializer.instance); deserializers.put(Serializable.class, JavaObjectDeserializer.instance); deserializers.put(Cloneable.class, JavaObjectDeserializer.instance); deserializers.put(Comparable.class, JavaObjectDeserializer.instance); deserializers.put(Closeable.class, JavaObjectDeserializer.instance); deserializers.put(JSONPObject.class, new JSONPDeserializer()); ModuleUtil.callWhenHasJavaSql(initDeserializersWithJavaSql); }
The following is the corresponding table I sorted according to the above code
Type of registration | Deserialize instance | Whether serialization is supported | Whether deserialization is supported |
---|---|---|---|
SimpleDateFormat | MiscCodec | yes | yes |
Calendar | CalendarCodec | yes | yes |
XMLGregorianCalendar | CalendarCodec | yes | yes |
JSONObject | MapDeserializer | - | yes |
JSONArray | CollectionCodec | yes | yes |
**Map | MapDeserializer | - | yes |
Collection | CollectionCodec | yes | yes |
List | CollectionCodec | yes | yes |
ArrayList | CollectionCodec | yes | yes |
Object | JavaObjectDeserializer | - | yes |
String | StringCodec | yes | yes |
StringBuffer | StringCodec | yes | yes |
StringBuilder | StringCodec | yes | yes |
char/Character | CharacterCodec | yes | yes |
byte/Byte | NumberDeserializer | - | yes |
short/Short | NumberDeserializer | - | yes |
int/Integer | IntegerCodec | yes | yes |
long/Long | LongCodec | yes | yes |
BigInteger | BigIntegerCodec | yes | yes |
BigDecimal | BigDecimalCodec | yes | yes |
float/Float | FloatCodec | yes | yes |
double/Double | NumberDeserializer | - | yes |
boolean/Boolean | BooleanCodec | yes | yes |
Class | MiscCodec | yes | yes |
char[] | CharArrayCodec | - | yes |
Atomic* | *Codec | Attributes with * | |
WeakReference | ReferenceCodec | yes | yes |
SoftReference | ReferenceCodec | yes | yes |
UUID/TimeZone/Locale/Currency | MiscCodec | yes | yes |
Inet4/6/SocketAddress | MiscCodec | yes | yes |
File/URI/URL | MiscCodec | yes | yes |
Pattern/Charset/JSONPath | MiscCodec | yes | yes |
Serializable | JavaObjectDeserializer | - | yes |
Cloneable | JavaObjectDeserializer | - | yes |
Comparable | JavaObjectDeserializer | - | yes |
Closeable | JavaObjectDeserializer | - | yes |
JSONPObject | JSONPDeserializer | - | yes |
By registering different types of serialization / deserialization instances internally, fastjson can find specific deserialization instances at runtime without using the default Java deserialization instance.
From the table I sorted out, we can see three problems:
- Almost all types have existing deserialization instances
- fastjson discards the serialization implementation of some classes, but still retains the deserialization operation of these classes
I speculate that fastjson does not realize serialization. These classes are too complex and have too many internal fields, or these classes do not comply with JavaBean standards and do not have Getter/Setter methods inside
- By looking at the classes containing Codec fields in the deserialization instance, you can find that these classes are serialization instances of corresponding types. Serialized instances in fastjson all implement deserialization at the same time, and there are many types registered internally. If the sender uses fastjson serialization to generate JSONString, when the receiver calls deserialization, it can ensure that "Whoever serializes will also perform deserialization"
This feature not only ensures the stability, but also greatly reduces the coupling between programs, and greatly reduces the cost of programmers maintaining code. If a certain type of deserialization instance is found to have a bug later, you can debug a specific instance without involving any other instance.
In a word, such programming logic ensures the high performance of fastjson and low later maintenance cost of the program.
In the last issue, we saw how to standardize code and improve code readability. In this issue, we can see Alibaba developers' meticulous grasp of program coupling. By traversing and subdividing all common Java classes, the deserialization instance is registered first to improve performance. Because of careful classification, the serialization instance is used to complete the deserialization operation, reduce the coupling degree and improve the stability.
In my opinion, I can't write code with such optimization logic with improved performance and stability at the same time. This shows that we still have a lot to learn in the future, and we still need to improve ourselves slowly
last
The deserialization of fastjson is briefly introduced here. Special one lists in detail all registered deserialization instances (actually serialization instances) within fastjson. In the next step, I will go further and interpret the internal use of token in each deserialization instance (for details of token, please refer to my classmate's article: Fastjson source code analysis - deserialization - Token definition and parsing (1))
In the next issue, the special will continue to analyze the implementation logic of several major deserialization instances (Boolean codec, charactercodec, integercodec, floatcodec, JavaBean deserializer)
Thank you for your reading and guidance!