在编写加密实用程序类时,我遇到了以下方法的问题:
public static void destroy(Key key) throws DestroyFailedException {
if(Destroyable.class.isInstance(key)) {
((Destroyable)key).destroy();
}
}
@Test
public void destroySecretKeySpec() {
byte[] rawKey = new byte[32];
new SecureRandom().nextBytes(rawKey);
try {
destroy(new SecretKeySpec(rawKey , "AES"));
} catch(DestroyFailedException e) {
Assert.fail();
}
}
在
javax.crypto.spec.SecretKeySpec
的特定情况下,上述方法在java7
中可以正常工作,因为SecretKeySpec (javadocs 7)不实现Destroyable (javadocs 7)现在使用
java8
将类SecretKeySpec (javadocs 8)设置为Destroyable (javadocs 8),而方法Destroyable#destroy现在是default
,根据此statement可以然后,即使没有更改
ScretKeySpec
类本身,仅更改了SecretKey接口(interface),该代码仍能毫无问题地进行编译。问题在于,在
oracle's jdk8
中,destroy
方法具有以下实现:public default void destroy() throws DestroyFailedException {
throw new DestroyFailedException();
}
这会在运行时导致异常。
因此,二进制兼容性可能尚未破坏,但是现有代码已被破坏。上面的测试通过
java7
通过,但没有通过java8
所以我的问题是:
Method method = key.getClass().getMethod("destroy");
if(! method.isDefault()) {
((Destroyable)key).destroy();
}
它仅对java8有效,而在以后的版本中可能不正确,因为默认方法可能实现了有意义的实现。
if(Destroyable.class.isInstance(key))
((Destroyable)key).destroy();
确定是否要销毁?有什么替代方法?
ScretKeySpec
中添加有意义的实现? 最佳答案
好吧,他们没有忘记。 SecretKeySpec
确实需要实现,但是还没有完成。参见bug JDK-8008795。抱歉,什么时间解决ETA不会。
理想情况下,应在添加默认方法并将接口(interface)改型到现有类时添加destroy
的有效实现,但未实现,可能是因为调度。
在您引用的教程中,“二进制兼容性”的概念是一个非常严格的定义,它是Java Language Specification, chapter 13使用的定义。基本上,这是对库类的有效转换,当与针对这些库类的较早版本编译的类结合使用时,这些转换不会在运行时导致类加载或链接错误。这与源不兼容(后者会导致编译时错误)和行为不兼容(后者通常会导致系统的运行时行为发生不必要的更改)形成鲜明对比。例如抛出之前未抛出的异常。
这并不是要最小化您的代码已损坏的事实。仍然是不兼容的。 (抱歉。)
作为一种解决方法,您可以添加instanceof PrivateKey || instanceof SecretKey
(因为这些显然是缺少destroy
实现的类),并让测试断言它们确实抛出DestroyFailedException
,否则,如果instanceof Destroyable
执行测试中其余逻辑。当这些实例在将来的Java版本中获得合理的destroy
实现时,测试将再次失败。这是将测试更改回对所有Destroyable调用destroy
的信号。 (一种替代方法可能是完全忽略这些类,但是有效的代码路径可能最终会在相当长的一段时间内未被发现。)