0x03. The setValue() method in AbstractInputCheckedMapDecorator

0 20
0x00. PrefaceCC chain 1 has been analyzed by many predecessors. At the beginning...

0x00. Preface

CC chain 1 has been analyzed by many predecessors. At the beginning, it was good, but later, I always felt confused. What I learned from various materials was also a little bit of understanding. There are many questions that may be quite difficult for me or similar friends who have a weak foundation in Java. Fortunately, I record some points of doubt in addition to the regular chain analysis, for the reference of new partners to follow. Therefore, this article is suitable for friends who are just starting to analyze CC chain 1. If there are any mistakes, please also point them out by the big guys, and I am very grateful.

0x01. Complete exp

It feels very unattractive to paste code directly, so I have uploaded the picture. Everyone can also get the exp from other master's articles.
image.png

0x02. hashmap.put("value",....)

Why call hashmap.put()

0x03. The setValue() method in AbstractInputCheckedMapDecorator

Because the chain is handled during deserialization from the readObject method of AnnotationInvocationHandler, the purpose is to call the memberValue.setValue() method within the readObject method. However, this method is in a for-each loop, and when we obtain the AnnotationInvocationHandler object through reflection, we need to pass a map value to the constructor. This map corresponds to the memberValues within the for loop body. If memberValues is empty, the for loop becomes empty and will directly jump out of the loop body without executing the code inside. Therefore, in order to enter the for loop, there must be values in the map, so we need to call hashmap.put() to put data into it.
image.png

2. Why must the first position of hashmap.put() be the value?

Because after we pass the map, the for loop in the body will obtain the memberType of name through the statement Class<?> memberType = memberTypes.get(name);, we mentioned that during the reflection of AnnotationInvocationHandler, the second parameter is map, and the first parameter is set to Target.class annotation. This is because the Target.class annotation contains the value key, so it can make memberType not empty, thereby satisfying the condition memberType != null. Of course, as long as the annotation provided is not empty, you can set other annotations, such as Repeatable.class,Retention.class, etc.
image.png
Therefore, the memberTypes provided earlier contains the content of the annotation's value
image.png
So, when executing Class<?> memberType = memberTypes.get(name);, this name is derived from the first line String name = memberValue.getKey();, and it can be seen that name comes from the memberValues we provide, and we obtain the map's key value through memberValue.getKey(). Therefore, the second statement will not cause memberType to be null when executing .get(name), thus entering the if loop.
image.png

0x03. The setValue() method in AbstractInputCheckedMapDecorator

Forgive the newbies, when analyzing other articles, it is really hard to understand why, when looking for the checkSetValue method of TransformedMap, it goes to the setValue method of AbstractInputCheckedMapDecorator. After asking AI and analyzing the inheritance relationship, I found the following points:

1. TransformedMap does not have the setValue() method.

The type of memberValue is determined by memberValues, and the corresponding memberValues we pass in is TransformedMap. However, there is no setValue method in the TransformedMap class, so at this time, we will follow the chain to find this method in the parent class of TransformedMap. And TransformedMap inherits from AbstractInputCheckedMapDecorator (this is the key point).
image.png

The following code exists in the AbstractInputCheckedMapDecorator class:
image.png
image.png
image.png

The code in these three figures can be understood as rewriting the logic of the for-each function (we don't delve into the specifics, just understand that it has changed the underlying logic code of the following for loop), and I can know from the arrow that the map is generated through the MapEntry class, and when we look at the MapEntry class, we will find that there is a setValue function, which is one link mentioned in the chain.
image.png

So when we are in a for loop in AnnotationInvocationHandler, memberValue will execute the setValue in MapEntry due to the rewritten loop in the parent class AbstractInputCheckedMapDecorator of TransformedMap.

2. How is the parent controllable as the desired Map type when setValue is called?

Similarly, through the above analysis, we can find that TransformedMap goes to the parent class AbstractInputCheckedMapDecorator to find setValue because it cannot find setValue. So when we are in a loop, inside the entrySet() function, the this value is passed to the EntrySet constructor method, where this refers to TransformedMap, and the parent in the EntrySet constructor method refers to the TransformedMap represented by this. Therefore, when we finally set the value, it is done through TransformedMap.
image.png

You can see the changes in parent and this by debugging.
image.png
image.png
image.png
image.png


This is the confusion I encountered in CC chain 1. If fellow friends have any doubts, please leave a comment for discussion. If seniors find any errors, please correct them, and I will be very grateful.

你可能想看:
最后修改时间:
admin
上一篇 2025年03月25日 04:02
下一篇 2025年03月25日 04:25

评论已关闭