在编写加密实用程序类时,我遇到了以下方法的问题:

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有效,而在以后的版本中可能不正确,因为默认方法可能实现了有意义的实现。
  • 将此默认方法留空而不是引发异常是否会更好(这是IMO的误导,因为除了试图销毁任何东西的合法调用之外,还没有尝试有效地销毁 key ,因此UnsupportedOperationException会更适合您会立即知道发生了什么事)
  • 是我的处理方式(类型检查/播放/调用)
    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的信号。 (一种替代方法可能是完全忽略这些类,但是有效的代码路径可能最终会在相当长的一段时间内未被发现。)

    10-07 23:42