每天学习一点点之从 SonarQube Code Smell 看 Serializable

news2024/10/5 17:21:08

相关文章:

  • 每天学习一点点之从 SonarQube Bug 看对线程中断异常的处理

昨天组内同学在进行代码合并的时候发现了一个 SonarQube 异常:
在这里插入图片描述

其实我之前也遇到过这个异常,但觉得“这种异常很无聊”,毕竟让 Spring Bean 去序列化,这不是扯么,就“偷懒”没有仔细去看。晚上回到家越想越不得劲,毕竟留个未知问题睡觉是很难受的,于是又打开电脑去看了下 Sonar 的描述:

Fields in a “Serializable” class should either be transient or serializable

Fields in a Serializable class must themselves be either Serializable or transient even if the class is never explicitly serialized or deserialized. For instance, under load, most J2EE application frameworks flush objects to disk, and an allegedly Serializable object with non-transient, non-serializable data members could cause program crashes, and open the door to attackers. In general a Serializable class is expected to fulfil its contract and not have an unexpected behaviour when an instance is serialized.

This rule raises an issue on non-Serializable fields, and on collection fields when they are not private (because they could be assigned non-Serializable values externally), and when they are assigned non-Serializable types within the class.

Noncompliant Code Example

public class Address {
  //...
}

public class Person implements Serializable {
  private static final long serialVersionUID = 1905122041950251207L;

  private String name;
  private Address address;  // Noncompliant; Address isn't serializable
}

Compliant Solution

public class Address implements Serializable {
  private static final long serialVersionUID = 2405172041950251807L;
}

public class Person implements Serializable {
  private static final long serialVersionUID = 1905122041950251207L;

  private String name;
  private Address address;
}

Exceptions

The alternative to making all members serializable or transient is to implement special methods which take on the responsibility of properly serializing and de-serializing the object. This rule ignores classes which implement the following methods:

 private void writeObject(java.io.ObjectOutputStream out)
     throws IOException
 private void readObject(java.io.ObjectInputStream in)
     throws IOException, ClassNotFoundException;

See

  • MITRE, CWE-594 - Saving Unserializable Objects to Disk
  • Oracle Java 6, Serializable

可以发现 Sonar 的描述已经说的很清楚了:在一个声明为 Serializable 的类中,所有的字段都应该是 Serializabletransient,即使该类没有被显式地序列化或反序列化。

当一个对象被序列化时,它的所有字段(包括继承的字段)都必须是可以序列化的,也就是说它们必须要么实现了 java.io.Serializable 接口,要么被声明为 transient。这是因为,如果一个对象包含一些不是 Serializable 的字段,那么这些字段在序列化过程中将不会被保存,从而可能导致在反序列化时丢失重要的数据或引发其他问题。为了确保对象在序列化过程中得到完全的描述,并且可以在将来被正确地反序列化,我们需要将所有字段都声明为 Serializable 或者将它们声明为 transient

在这块代码中,也就是说引用 WarehouseService 的类实现了 Serializable,但是 WarehouseService 本身却没有实现 Serializable,这可能会导致序列化问题。

例如,我们有两个类:PersonAddress,其中 Person 实现了 Serializable 接口,而 Address 没有:

class Address {
    int id;
    String street;
    int zip;
}

class Person implements Serializable {
    int id;
    String name;
    Address address;
}

如果我们尝试将一个 Person 对象序列化,就会出现异常,因为 Address 类中的字段不能被序列化:

Person p = new Person();
p.id = 1;
p.name = "John";
p.address = new Address();
// ...
try {
    FileOutputStream fileOut = new FileOutputStream("/tmp/tmp.txt");
    ObjectOutputStream out = new ObjectOutputStream(fileOut);
    out.writeObject(p);
} catch (IOException e) {
}

上述代码会抛出异常:

java.io.NotSerializableException: com.example.Address
	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
	at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)

解决这个问题的一种方法是在 Address 类中添加 implements Serializable 关键字,使其也成为可序列化的:

class Address implements Serializable {
    int id;
    String street;
    int zip;
}

class Person implements Serializable {
    int id;
    String name;
    Address address;
}

另一种方法是将 Address 类中的字段声明为 transient,以防止它们被序列化:

class Address {
    transient int id;
    String street;
    int zip;
}

class Person implements Serializable {
    int id;
    String name;
    Address address;
}

在此示例中,Address 类中的 id 字段将会被忽略,不会出现在序列化的数据中。 需要注意的是,如果一个字段声明为 transient,那么在反序列化时,它的值会被重置为其默认值。因此,如果你希望保留其值,在反序列化时应该手动设置。例如,我们可以在 Person 类中添加一个方法来设置地址的 ID:

public void setAddress(Address address) {
    this.address = address;
    if (address != null) {
        this.address.setId(this.id);
    }
}

另外,你还可以实现 private void writeObject(java.io.ObjectOutputStream out) throws IOExceptionprivate void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException 方法来控制如何序列化和反序列化对象。这两个方法通常被称为定制序列化方法,因为它们让你有机会自定义对象的序列化和反序列化方式。

总之,在设计类的时候,请注意一个关键点,如果你想要让一个类是可序列化的,那么它所有字段都必须是可序列化的。如果有字段不应该是序列化的,那么可以将它们声明为 transient,或者使用定制序列化方法来处理它们。

欢迎关注公众号:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1212218.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

d3dcompiler_43.dll丢失了怎么办,详细解答和d3dcompiler_43.dll修复方法

以下将为您提供几种处理d3dcompiler_43.dll文件丢失的解决措施,这些方法实用有效,可以帮助我们恢复计算机运行。 一.d3dcompiler_43.dll是什么 在我们开始探讨如何修复d3dcompiler_43.dll文件丢失的问题之前,首先需要了解这个文件的作用。该…

如何选择正确的SSL证书?

SSL证书已经成为网站安全管理的重要部分,但是市场上SSL证书种类繁多,很多新手在初次购买时都会感到困惑。下面我们就一起来看看如何快速地选择正确的SSL证书。 第一步:明确SSL证书的主要分类 SSL证书主要有三种类型:单域名证书、…

2023selenium自动化(基础篇)

哈喽大家好,我是静姐,今天来给大家介绍在Python中使用selenium进行自动化操作 定义 Selenium是一个用于Web应用程序测试的自动化测试工具。使用Selenium可以驱动浏览器执行特定的动作,如点击、下拉等操作,还可以获取页面信息,断言页面是否如预期。在工作…

Oracle如何快速删除表中重复的数据

方法一: 在Oracle中,你可以使用DELETE语句结合ROWID和子查询来删除重复的记录。以下是一个示例: DELETE FROM your_table WHERE ROWID NOT IN (SELECT MAX(ROWID)FROM your_tableGROUP BY column1, column2, ... -- 列出用于判断重复的列 )…

【动态规划】买卖股票的最佳时期含冷冻期

文章目录 一、买卖股票的最佳时期含冷冻期动态规划五部曲 一、买卖股票的最佳时期含冷冻期 题目: 买卖股票的最佳时期含冷冻期 动态规划五部曲 1.确定dp的含义 由题意可知,这里有三种状态 1.买入状态:dp[i][0]:表示第i天处于买入状态时的最大利润为dp[…

C# Socket通信从入门到精通(9)——如何设置本机Ip地址

前言: 我们开发好Socket通信程序以后,上机调试的时候,首先要做的就是先设置好电脑的IP,这样才能实现不同的电脑之间的通信,并且电脑1的ip地址和电脑2的Ip地址要同处于一个网段,比如电脑1的Ip地址为192.168…

“程序员们的奔溃瞬间”——分享你最令你哭笑不得的程序员经历

文章目录 每日一句正能量前言编程趣事后记 每日一句正能量 每件事最后都会是好事。如果不是好事,说明还没到最后。 前言 作为程序员,我们时常会遇到各种奇怪的错误和挑战,有时候我们会崩溃,但更多的时候,我们会从中学…

蚂蚁集团首次披露数字科技业务海外发展数据 营收规模同比增长300%

蚂蚁集团资深副总裁、数字科技事业群总裁蒋国飞15日在新加坡金融科技节期间表示,过去一年,蚂蚁数科通过科技产品带来的海外营收规模增长了 300%,其中尤以菲律宾、马来西亚、印度尼西亚等新兴市场国家为主。这是蚂蚁集团首次披露数字科技业务板…

WorkPlus私有化部署的即时通讯软件,企业内部沟通协作的利器

随着企业的成长和信息科技的进步,团队协作变得越来越关键。为了更好地促进团队之间的信息共享和沟通,企业内部对聊天软件的需求也在不断增加。 WorkPlus是一个支持海量用户和高并发的私有化部署即时通讯能力,支持纯内网,内外网混…

2023.11.15使用bootstrap做一个简洁的注册页面

2023.11.15使用bootstrap做一个简洁的注册页面 设置密码必须大于等于6位,并且包含大写字母、小写字母、特殊字符或者数字中的三种。 关注:type"button"和type"submit"之间的区别: type"button"用于普通按钮&…

工作中积累的对K8s的就绪和存活探针的一些认识

首先,我的项目是基于 Spring Boot 2.3.5 的,并依赖 spring-boot-starter-actuator 提供的 endpoints 来实现就绪和存活探针,POM 文件如下图: 下面,再让我们来看下与该项目对应的Deployment的YAML文件,如下…

Multisim数电仿真实验——SOS循环序列信号发生器

目录 一、前言二、设计思路2.1序列信号的实现2.2SOS信号的循环再现 三、最终电路图 一、前言 SOS电路是一种简单而重要的电子电路,用于产生和传输紧急信号。我们将介绍SOS电路的连接思路,包括所需的组件选择以及信号的连接方式。 二、设计思路 2.1序列…

Android 12 客制化修改初探-Launcher/Settings/Bootanimation

Android 12 使用 Material You 打造的全新系统界面,富有表现力、活力和个性。使用重新设计的微件、AppSearch、游戏模式和新的编解码器扩展您的应用。支持隐私信息中心和大致位置等新的保护功能。使用富媒体内容插入功能、更简便的模糊处理功能、经过改进的原生调试…

SDL2 播放音频数据(PCM)

1.简介 这里以常用的视频原始数据PCM数据为例,展示音频的播放。 SDL播放音频的流程如下: 初始化音频子系统:SDL_Init()。设置音频参数:SDL_AudioSpec。设置回调函数:SDL_AudioCallback。打开音频设备:SD…

免费IDEA插件分享:Apipost-Helper

今天给大家推荐一款IDEA插件:Apipost-Helper-2.0,写完代码IDEA内一键生成API文档,无需安装、打开任何其他软件;写完代码IDEA内一键调试,无需安装、打开任何其他软件;生成API目录树,双击即可快速…

使用naive-ui做一个标签页展示列表

目录 零、引言 一、引入所需组件 二、引入数据 三、使用动态样式控制列表条纹 四、全部代码 五、设计思路 5.1组件设计思路 5.2背景颜色控制思路 5.3说明 六。最终效果 零、引言 有时候我们会有很多数据,分成好几类 每一类都需要展示,那么这时…

win10配置单一python版本的sublime运行环境

①新建test.py输入下面代码 import sys print ("Python Version {}".format(str(sys.version).replace(\n, ))) ②Ctrlshiftp选择python ③按下CtrlB

中国唯一!华为入选Gartner®企业低代码应用平台魔力象限

近日,全球咨询机构Gartner发布 《Magic Quadrant™ for Enterprise Low-Code Application Platforms》报告,华为入选该象限,作为中国唯一入选厂商,华为已连续两年入选Gartner企业低代码应用平台魔力象限。 华为云Astro低代码平台采…

二百零三、Flume——Flume实时采集数据频率为1s的高频率Kafka数据直接写入ODS层表的HDFS文件路径下

一、目的 在离线数仓中,需要用Flume去采集Kafka中的数据,然后写入HDFS中。 由于每种数据类型的频率、数据大小、数据规模不同,因此每种数据的采集需要不同的Flume配置文件。玩了几天Flume,感觉Flume的使用难点就是配置文件 二、…