网易首页 > 网易号 > 正文 申请入驻

一个 List.of 引发的“血案”

0
分享至

导语:本文作者将分享一个使用List.of后掉进的坑以及爬坑的全过程,希望大家能引以为戒同时引起这样的意识:在使用新技术前先搞清楚其实现的原理。

随着卓越工程的推进,很多底层技术的升级迭代被正式投入使用,例如 JDK11 的升级。然而,当我们拥抱变化,欣喜地使用一些新特性或者语法糖的同时,也有可能正在无意识的掉入一些陷阱。

本篇文章,我将分享一个使用List.of后掉进的坑以及爬坑的全过程,希望大家能引以为戒同时引起这样的意识:在使用新技术前先搞清楚其实现的原理。

案发现场

一句话总结:在一次后端发布的变更后,前端解析接口返回的格式失败。

前情提要:

  • 后端 JAVA 应用 JDK 版本11,提供 HSF 服务端接口。

  • 前端通过陆游平台(一个 Node 可视化逻辑编排的平台)配置接口,内部通过 node 泛化调用后端的 HSF 接口,平台解析返回接口结果。


过程回顾:

1.后端发布的变更示意:

// 发布前
public List before(Long id) {
...
if (...) {
return null;
}
...
}

// 发布后
public List after(Long id) {
...
if (...) {
return List.of();
}
...
}

这里的核心变化点就是将默认的返回从 null 改成了 List.of() 。

为什么可以这么改?已知前端对null和空数组[]做了同样的兼容逻辑。

2.前端获取到接口的格式变化:

// 发布前
{
"test": null
}
// 发布后
{
"test": {
"tag": 1
}
}

这个结构的变更直接导致了前端后续的字段结构解析失败,因为理论上 test 字段需要提供一个数组的格式(也可以是null),但是实际变成了一个对象。

所以整个环节中最离奇的是:为什么我的List.of在前端调用返回的接口中变成了一个带有tag字段的对象,它到底经历了怎么样的转换过程?

案情推理

List.of 触发的离奇现象让我不得不重新审视它,一步步看下它的源码实现。

1. 初窥门径:List.of


public interface List extends Collection {
/**
* Returns an unmodifiable list containing zero elements.
*
* See Unmodifiable Lists for details.
*
* @param the {@code List}'s element type
* @return an empty {@code List}
*
* @since 9
*/
static List of() {
return ImmutableCollections.emptyList();
}
}

从官方注释中得到3点结论:

1.这是一个 JDK9 之后的特性;

2.返回的是一个不可修改的数组;

3.底层实现使用的 ImmutableCollections 的 emptyList 方法,而 ImmutableCollections 这个类是一个不可变集合的容器类;

2. 渐入佳境:ImmutableCollections.emptyList


class ImmutableCollections {

static List emptyList() {
return (List) ListN.EMPTY_LIST;
}

static final class ListN extends AbstractImmutableList
implements Serializable {

// EMPTY_LIST may be initialized from the CDS archive.
static @Stable List EMPTY_LIST;

static {
VM.initializeFromArchive(ListN.class);
if (EMPTY_LIST == null) {
EMPTY_LIST = new ListN<>();
}
}
...
}

static abstract class AbstractImmutableList extends AbstractImmutableCollection
implements List, RandomAccess {
...
}
}

到这一步,案件的主人公终于登场了:一个新的类 ListN。但是在这段代码中,还有很多隐藏的细节线索:

1.ListN 是 List 的实现类:ListN 继承了AbstractImmutableList,而 AbstractImmutableList 实际又实现了List;

2.ListN 中的静态变量 EMPTY_LIST 会被初始化为一个空的 ListN 的对象;

3.emptyList 方法中做了 List 类型的强转,但是由于JAVA的类型转换原则,实际仍然返回的是一个ListN对象(这是关键线索之一),通过排查过程中发现的阿尔萨斯监控也可以确认这一点:

3. 直击要害:node的 HSF 解析

陆游平台调取HSF接口走的是node的泛化调用,默认情况下node只能解析一些基础的java类型,例如List和Map。

一个完整的类型映射表可以查看:java-对象与-node-的对应关系以及调用方法

而遇到这次返回的 ListN,可以确定是这种特殊类型在序列化/反序列化的过程中出现了不同的逻辑导致。

4. 真相大白:ListN的序列化


static final class ListN extends AbstractImmutableList
implements Serializable {
@Stable
private final E[] elements;

@SafeVarargs
ListN(E... input) {
// copy and check manually to avoid TOCTOU
@SuppressWarnings("unchecked")
E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input
for (int i = 0; i < input.length; i++) {
tmp[i] = Objects.requireNonNull(input[i]);
}
elements = tmp;
}

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
throw new InvalidObjectException("not serial proxy");
}


ListN实现了自定义的序列化方法 writeReplace 和反序列方法 readObject。readObject直接抛出异常是一个防御性措施,说明该类直接反序列化会报错,来保证自己的不可变性。而 writeReplace 表示在序列化写入的时候替换成另一个对象,在这里返回的是一个内部的序列化代理对象CollSer(关键线索之二)。在实例化这个CollSer对象的时候,传递了2个变量:


  • CollSer.IMM_LIST 静态值 = 1

  • elements 一个空的对象数组 = new Object[0]

final class CollSer implements Serializable {
private static final long serialVersionUID = 6309168927139932177L;

static final int IMM_LIST = 1;
static final int IMM_SET = 2;
static final int IMM_MAP = 3;

private final int tag;

/**
* @serial
* @since 9
*/
private transient Object[] array;

CollSer(int t, Object... a) {
tag = t;
array = a;
}
}

注意这里见到了我们眼熟的 tag 字段,另外一个字段 array 被 transient 标识所以序列化处理过程中会被忽略,这下我们终于知道 tag = 1 是怎么来的了。

结案陈词

综上所述,当后端在HSF接口中使用了 List.of() 做返回,在 node 调用 HSF 序列化获取返回结果时会解析成一个带有tag字段的对象,而不是预期的空数组。这个问题其实想解决很简单,将 List.of() 替换成我们常用的 Lists.newArrayList() 就行,本质上还是对底层实现的不清晰不了解导致了这整个事件。

当然在结尾处,其实还有一个疑点,在 HSF 控制台调试这个接口的时候,我发现它的 json 结构是可以正确解析的:

怀疑可能是序列化类型的问题,hsfops 也是用了泛化调用,序列化类型是 hessian,可能 node 的序列化类型不一样,这个后续研究确定后我再补充一下。

最后的反思与大家共勉:对于新技术(或者新特性)的应用一定要先搞清楚内部的实现细节,不然可能出现使用时的大坑。

↓↓↓ 2023 阿里云金秋云创季 主会场

private Object writeReplace() {
return new CollSer(CollSer.IMM_LIST, elements);
}
}

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
CCTV5+直播,早8点,7万人面前,36岁梅西率阿根廷开启卫冕之路

CCTV5+直播,早8点,7万人面前,36岁梅西率阿根廷开启卫冕之路

侧身凌空斩
2024-06-20 09:21:08
毕业典礼扇老师耳光!身份被扒:家中人脉深厚,黑历史一箩筐

毕业典礼扇老师耳光!身份被扒:家中人脉深厚,黑历史一箩筐

温柔看世界
2024-06-20 11:38:19
给1000万离开中国!美国开出天价年薪,只为挖走中国一普通技校生

给1000万离开中国!美国开出天价年薪,只为挖走中国一普通技校生

贾文彬的史书
2024-06-19 18:57:24
前瞻|普京第五次到访越南,全面战略伙伴或讨论武器及双边支付

前瞻|普京第五次到访越南,全面战略伙伴或讨论武器及双边支付

澎湃新闻
2024-06-20 12:26:32
马云越闹越大了,“换个江湖,后会有期!”马云终于选择了日本!

马云越闹越大了,“换个江湖,后会有期!”马云终于选择了日本!

橘子大娱社
2024-06-19 20:50:02
多省设立“警税合成作战中心”,背后有何考量?如何打消疑虑

多省设立“警税合成作战中心”,背后有何考量?如何打消疑虑

南方都市报
2024-06-20 15:49:09
王思聪终于回复黄一鸣,网友:确实是他的风格

王思聪终于回复黄一鸣,网友:确实是他的风格

菠萝小九
2024-06-18 12:40:43
中央音乐学院教授被爆性侵多名未成年女生,长期嫖娼,搞婚外情

中央音乐学院教授被爆性侵多名未成年女生,长期嫖娼,搞婚外情

180°视角
2024-06-20 13:54:37
中国海警对菲船艇依法登临检查 本报独家获取现场执法图片

中国海警对菲船艇依法登临检查 本报独家获取现场执法图片

环球时报新闻
2024-06-19 16:30:05
31省份公布2023年人口数据,11省份人口正增长

31省份公布2023年人口数据,11省份人口正增长

第一财经资讯
2024-06-19 18:25:18
60岁落马的女干部被“双开”!曾与“老虎”共事

60岁落马的女干部被“双开”!曾与“老虎”共事

上观新闻
2024-06-20 12:02:22
芬兰证实,俄罗斯将芬俄边境俄军的80%抽到俄乌战场,俄损失惨重

芬兰证实,俄罗斯将芬俄边境俄军的80%抽到俄乌战场,俄损失惨重

山河路口
2024-06-19 21:44:14
还是斧头好用,一砸一个洞,菲律宾补给船全军覆没

还是斧头好用,一砸一个洞,菲律宾补给船全军覆没

三叔的装备空间
2024-06-20 11:05:19
中央财大教授对11万人测量研究得出结论:阴茎越短智商越高!

中央财大教授对11万人测量研究得出结论:阴茎越短智商越高!

兵叔评说
2024-06-20 12:04:40
抵制恶意降价销售!曝成都某小区业主提六点诉求:补差价补车位!补偿10年物业费

抵制恶意降价销售!曝成都某小区业主提六点诉求:补差价补车位!补偿10年物业费

可达鸭面面观
2024-06-20 15:59:59
余琦三个问题很严重,警方已经调查,老公身份曝光,结局大快人心

余琦三个问题很严重,警方已经调查,老公身份曝光,结局大快人心

兰子记
2024-06-19 18:42:11
汽车博主爆料:小米直营店汽车销售底薪6000元!锁单交付一台小米SU7提成800元,一线销售赚得盆满钵满

汽车博主爆料:小米直营店汽车销售底薪6000元!锁单交付一台小米SU7提成800元,一线销售赚得盆满钵满

和讯网
2024-06-20 14:17:42
曝蒙古国反华分子big gee来中国开演唱会,歌词:把中国人像猪一样杀

曝蒙古国反华分子big gee来中国开演唱会,歌词:把中国人像猪一样杀

不掉线电波
2024-06-19 16:53:13
有人质疑排名第十二的姜萍,为什么没有人质疑排名第一的韦东奕

有人质疑排名第十二的姜萍,为什么没有人质疑排名第一的韦东奕

王朝风云
2024-06-20 07:08:48
放弃社会主义制度的20多个国家,现在的状况都怎么样了

放弃社会主义制度的20多个国家,现在的状况都怎么样了

云舟史策
2024-06-17 19:30:33
2024-06-20 16:58:44
阿里云云栖号
阿里云云栖号
阿里云官方内容社区!
2943文章数 864关注度
往期回顾 全部

科技要闻

小米SU7流量泼天,富贵却被蔚来接住了

头条要闻

报道称中国或对欧盟乳制品发起反补贴调查 商务部回应

头条要闻

报道称中国或对欧盟乳制品发起反补贴调查 商务部回应

体育要闻

绿军的真老大,开始备战下赛季了

娱乐要闻

叶舒华参加柯震东生日聚会,五毒俱全

财经要闻

日本银行巨头突然爆雷!

汽车要闻

售价11.79-14.39万元 新一代哈弗H6正式上市

态度原创

本地
游戏
手机
旅游
公开课

本地新闻

2024·合肥印象|用崭新视角对话城市发展

《EVE Vanguard》Steam页面 暂不支持中文

手机要闻

喜大泪奔,华为Pura 70系列总算降价,入手国产自主手机不再是梦

旅游要闻

铁路儿童票新规 已有超4900万小旅客免费出行

公开课

近视只是视力差?小心并发症

无障碍浏览 进入关怀版