你问这个问题的“最佳实践”是什么。我将假设“这个问题”是指第三方库升级的问题,具体来说,是这两个问题:
何时应升级?
你应该做些什么来保护自己免受不良升级的影响(比如你的例子中提到的commons-codec错误)?
为了回答第一个问题,“你什么时候应该升级?”,工业界存在许多策略。在大多数商业Java世界中,我相信目前的主导做法是“当你准备好时,你应该升级”。换句话说,作为开发人员,您首先需要意识到一个新版本的库可用(对于您的每个库!),然后您需要将其集成到您的项目中,并且您是根据自己的测试平台做出最终的go/no-go决定的人,--- junit,回归,手动测试, 等。。。无论你做什么来确保质量。Maven 通过使大多数流行库的多个版本可供自动下载到您的构建系统中,并通过默许培养这种“固定”传统来促进这种方法(我称之为版本“固定”)。
但是其他实践确实存在,例如,在 Debian Linux 发行版中,理论上可以将大量工作委托给 Debian 软件包维护者。您只需根据 Debian 提供的 4 个级别来调整您的舒适度,选择新颖性而不是风险,反之亦然。Debian 提供的 4 个级别是:OLDSTABLE、STABLE、TEST、UNSTABLE。尽管它的名字叫Unstable,但它非常稳定,OLDSTABLE提供的库,与原始“上游”项目网站上提供的最新和最好的版本相比,可能要过时3年。
至于第二个问题,如何保护自己,我认为目前业界的“最佳实践”是双重的:根据声誉选择你的库(Apache的库通常相当不错),并在升级之前等待一段时间,例如,不要总是急于成为最新和最伟大的。也许选择已经可用3到6个月的库的公开版本,希望自初始版本以来任何关键错误都已被清除和修补。
你可以走得更远,通过编写JUnit测试来专门保护你在依赖项中依赖的行为。这样,当您关闭较新版本的库时,JUnit 将立即失败,并警告您存在问题。但根据我的经验,我没有看到很多人这样做。而且通常很难意识到你所依赖的确切行为。
顺便说一句,我是朱利叶斯,负责这个错误的人!请接受我对这个问题的歉意。这就是我认为它发生的原因。我只为自己说话。要了解apache commons-codec团队中的其他人的想法,您必须自己询问他们(例如,ggregory,sebb)。
当我在1.4和1.5版本中使用Base64时,我非常关注Base64的主要问题,即将二进制数据编码到较低的127 ASCIi中,并将其解码回二进制。
因此,在我看来(这是我出错的地方),“aGk=\r\n”和“aGk=”之间的区别是无关紧要的。它们都解码为相同的二进制结果!
但是,在阅读了您在此处的stackoverflow帖子后,从更广泛的意义上考虑它,我意识到可能有一个非常流行的用例,我从未考虑过。也就是说,根据数据库中的加密密码表进行密码检查。在该用例中,您可以执行以下操作:
// a. store user's password in the database
// using encryption and salt, and finally,
// commons-codec-1.4.jar (with "\r\n").
//
// b. every time the user logs in, encrypt their
// password using appropriate encryption alg., plus salt,
// finally base64 encode using latest version of commons-codec.jar,
// and then check against encrypted password in the database
// to see if it matches.
因此,如果 commons-codec.jar更改其编码行为,即使根据 base64 规范以非实质性方式,此用例当然会失败。我很抱歉!
我认为,即使有我在本文开头阐述的所有“最佳实践”,仍然很有可能搞砸这个。Debian 测试已经包含了 commons-codec-1.5,这个版本有这个 bug,修复这个 bug 本质上意味着把那些使用 1.5 版而不是 1.4 版的人搞砸了。但是我会尝试在apache网站上放一些文档来警告人们。感谢您在堆栈溢出中提到它(我对用例的看法正确吗?
我认为Paul Grime的解决方案非常整洁,但我怀疑它依赖于在Jar文件中推送版本信息的项目。我认为所有的Apache Java库都这样做,但其他项目可能不会。不过,这种方法是在构建时将自己固定在版本上的一种很好的方法:与其意识到您依赖于“\r\n”,并编写了防止这种情况的JUnit,不如编写一个更容易的JUnit:。META-INF/MANIFEST.MF
assertTrue(desiredLibVersion.equals(actualLibVersion))
(这假设运行时库与构建时库相比不会更改!