你问这个问题的“最佳实践”是什么。我将假设您所说的“这个问题”是指第 3 方库升级的问题,特别是这两个问题:
什么时候应该升级?
您应该如何保护自己免受不良升级(例如您的示例中提到的 commons-codec 错误)?
要回答第一个问题,“您应该什么时候升级?”行业中存在许多策略。在大多数商业 Java 世界中,我相信当前的主流做法是“当你准备好升级时应该升级”。换句话说,作为开发人员,您首先需要意识到有一个新版本的库可用(适用于您的每个库!),然后您需要将它集成到您的项目中,并且您是制作最终版本的人基于您自己的测试平台的 go/no-go 决定 --- junit、回归、手动测试等......无论您做什么来确保质量。 Maven 通过使最流行的库的多个版本可用于自动下载到您的构建系统中并默认培养这种“固定”传统来促进这种方法(我称之为版本“固定”)。
但确实存在其他实践,例如,在 Debian Linux 发行版中,理论上可以将大量工作委托给 Debian 软件包维护者。您只需根据 Debian 提供的 4 个级别调整您的舒适度,选择新鲜度而不是风险,反之亦然。 Debian 提供的 4 个级别是:OLDSTABLE、STABLE、TESTING、UNSTABLE。尽管 Unstable 名称如此,但它非常稳定,而且 OLDSTABLE 提供的库与其原始“上游”项目网站上提供的最新最好的版本相比可能已经过时了 3 年之久。
至于第二个问题,如何保护自己,我认为目前业界的“最佳实践”是双重的:根据声誉选择您的库(Apache 的通常相当不错),并等待一段时间再升级,例如,不要总是急于成为最新最好的。也许选择一个已经发布 3 到 6 个月的库的公开版本,希望自最初发布以来所有严重的错误都已被清除和修补。
您可以走得更远,通过编写专门保护您在依赖项中依赖的行为的 JUnit 测试。这样,当您关闭较新版本的库时,您的 JUnit 将立即失败,并警告您该问题。但根据我的经验,我没有看到很多人这样做。而且通常很难意识到您所依赖的精确行为。
而且,顺便说一下,我是 Julius,负责这个错误的人!请接受我对这个问题的歉意。这就是为什么我认为它发生了。我只会为我自己说话。要了解 apache commons-codec 团队中其他人的想法,您必须自己询问他们(例如 ggregory、sebb)。
当我在 1.4 和 1.5 版本中处理 Base64 时,我非常关注 Base64 的主要问题,即将二进制数据编码为低 127 ASCIi,并将其解码回二进制.
所以在我看来(这就是我出错的地方)“aGk=\r\n”和“aGk=”之间的区别并不重要。它们都解码为相同的二进制结果!
但在阅读了您在此处发布的 stackoverflow 帖子后,从更广泛的意义上考虑它,我意识到可能有一个非常流行的用例,我从未考虑过。也就是说,根据数据库中的加密密码表检查密码。在该用例中,您可能会执行以下操作:
// 一种。将用户的密码存储在数据库中
// 使用加密和盐,最后,
// commons-codec-1.4.jar(带有“\r\n”)。
//
// b.每次用户登录时,加密他们的
// 密码使用适当的加密算法,加上盐,
// 最后使用最新版本的 commons-codec.jar 进行 base64 编码,
// 然后检查数据库中的加密密码
// 看是否匹配。
因此,如果 commons-codec.jar 更改其编码行为,即使根据 base64 规范以非物质方式更改,这个用例当然会失败。非常抱歉!
我认为,即使我在本文开头阐明了所有“最佳实践”,但仍有很大可能会被搞砸。 Debian 测试已经包含了 commons-codec-1.5,即有 bug 的版本,修复这个 bug 本质上意味着让那些使用 1.5 版而不是 1.4 版的人搞砸。但我会尝试在 apache 网站上放一些文档来警告人们。感谢您在 stack-overflow 上提到它(我对用例的看法是对的吗?)。
ps。我认为Paul Grime 的解决方案非常简洁,但我怀疑它依赖于在 Jar 的META-INF/MANIFEST.MF 文件中推送版本信息的项目。我认为所有 Apache Java 库都这样做,但其他项目可能不会。不过,这种方法是一种在构建时将自己固定到版本的好方法:与其意识到您依赖“\r\n”并编写防止这种情况发生的 JUnit,您可以编写一个更简单的 JUnit: assertTrue(desiredLibVersion.equals(actualLibVersion)).
(假设运行时库与构建时库相比没有变化!)