class/code 签名更改时,有没有办法自动重新生成 serialVersionuId?

Is there a way to automatically re-generate serialVersionId when class/code signature changes?

我们有一大堆序列化的 classes 但希望数据库位在 "signature" 时失效,即:class 的字段结构和序列化代码发生变化,

是否有可以为 class 文件生成 "hash" 的实用程序,可以最佳地检测 java.serializable 的序列化结构何时针对 class 发生变化?

确实没有办法 "optimally detect when a serialization structure changes" 有一个相当重要的原因:

序列化破坏了封装。

当您实施 Serializable 时,class 的所有私有和包私有字段和成员都成为 class 导出的 API 的一部分。从 class 发布到野外的那一刻起,其序列化形式(包含其所有实现细节)就是其合约的一部分。更改序列化形式将产生以下两种结果之一:

  • 向后兼容性。因为 Serializable 破坏了封装,所以序列化形式成为其导出 API 的一部分。当实现细节发生变化时,开发人员可以自行决定定制 readObject()writeObject() 方法以继续支持原始序列化形式(即使它会因新实现而改变)。如果 API 很远并且更改序列化形式会破坏 API 的许多客户端,这是可取的。在这种情况下,即使序列化形式会因新实现而改变,serialVersionUID 也需要保持不变才能继续支持原始序列化形式。

  • 强制升级。如果 class 的实现发生变化并且不可能或不可行地支持原始序列化形式,则更改 serialVersionUID 将导致 API 的客户端中断,从而迫使客户端升级以使用新的序列化形式。这在某些情况下可能是可取的(但会迫使客户升级他们的代码)。

值得一提的是,如果您没有在可序列化 class 中显式声明静态最终 serialVersionUID,Java 环境将通过对代码应用复杂的过程自动为您计算一个(考虑到字段和方法签名)。

简而言之,serialVersionUID 应该跟踪使用的序列化形式,而不是实际的 class 实现。如果您希望 serialVersionUID 在 class 实现更改时自动更改,您可以简单地省略 serialVersionUID 的显式声明(但这可能会产生其他负面后果)。更改 serialVersionUID 的决定需要明确做出,具体取决于您希望 API 在实现细节发生变化时的行为方式。