注解全名(annotation.name):
HashMap#readObject()调用equals()方法,注意在调用equals方法之前会调用到包装对象hashCode方法,所以需要保证对象调用hashCode不能出现问题
- 类别:common 别名:— 优先级:—
- 作者:—
- 依赖:无(纯 JDK)
- 状态:
@Deprecated(已弃用,见下)
构造一个在 Java 原生反序列化(HashMap/ConcurrentHashMap 的 readObject)过程中,会对两个被包装对象触发 equals() 调用的 Map。属于「原生反序列化 → equals sink」的跳板入口:为那些以 equals() 为触发点的下游 gadget(nextTags=Equals)提供反序列化入口。
- 入口
tags:JavaNativeDeserialize—— 承接 Java 原生反序列化入口,是链的最外层跳板之一。 - 衔接
nextTags:Equals—— 其内层必须是一个「以equals()为触发点」的 gadget,且该 gadget 需产出一对对象Object[2](在 map 中相互equals)。 excludes:无。
public Object getObject(Object obj1, Object obj2) throws Exception {
return PayloadHelper.concurrentmap2equals(obj1, obj2); // 把两对象放入会触发 equals 的 map
}
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
Object[] objects = (Object[]) chain.doCreate(context); // 内层产出一对对象
Object getterObject = context.get(ContextTag.FASTJSON_HANDLE_BYPASS_KEY);
Object resultObject = this.getObject(objects[0], objects[1]);
if (getterObject != null) {
return CommonMethod.listWrap(getterObject, resultObject); // Fastjson 绕过时再包一层 List
}
return resultObject;
}- 内层需产出
Object[2]:chain.doCreate被强转为Object[],取objects[0]/objects[1]交给PayloadHelper.concurrentmap2equals。该 helper 把两个对象填入ConcurrentHashMap/HashMap的桶结构,使得反序列化时因哈希落到同一桶而触发key.equals(otherKey)。 - 注解中的关键坑(务必满足):
HashMap.readObject在把 entry 放回散列表前会先调用键对象的hashCode(),之后同桶冲突时才调用equals()。因此被包装对象的hashCode()必须能正常返回、不得抛异常,否则反序列化在 equals 之前就中断。这也是很多 equals 型链需要精心选择包装对象的原因。 FASTJSON_HANDLE_BYPASS_KEY分支:当上下文标记了 Fastjson 绕过场景时,用CommonMethod.listWrap把一个额外的 getter 对象与结果再包成 List,兼容二次处理。常规链此分支为null,直接返回该 map。
本类无 @Param。行为完全由内层产出的对象对与上下文决定。
- 依赖 JDK 内置
HashMap/ConcurrentHashMap的readObject逻辑,无第三方依赖。 - 已
@Deprecated:该实现被更通用/稳定的 equals 跳板取代(参见 HashMapEquals、HashTableEquals)。在选链时优先使用未弃用的替代品。 - 成功前提:被包装对象的
hashCode()不抛异常,且能命中同桶以触发equals。
自由构件,未直接出现在预设链(usedInChains 为空)。
- 下游(
nextTags=Equals):以equals()为触发点、产出对象对的 gadget(如各类*Equals/XString型 sink)。 - 同族替代:HashMapEquals、HashTableEquals(同为
JavaNativeDeserialize → Equals跳板,未弃用)。