java8:处理默认方法

时间:2014-07-20 13:00:04

标签: java java-8 secret-key default-method

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

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已经。

问题在于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会误导,因为除了合法的破坏调用之外,没有尝试过有效地破坏密钥,这不是更好吗{{3}本来会更合适,你会马上知道发生了什么)

  • 我的方法是(类型检查/演员/召唤)

    if(Destroyable.class.isInstance(key))
        ((Destroyable)key).destroy();
    

    确定是否破坏?什么是另类?

  • 这是一种误解还是只是忘记在ScretKeySpec添加有意义的实施?

2 个答案:

答案 0 :(得分:7)

  

这是一种误解还是只是忘记在SecretKeySpec中添加有意义的实现?

他们没有忘记。 SecretKeySpec确实需要一个实现,但它还没有完成。请参阅错误JDK-8008795。对不起,修复后没有ETA。

理想情况下,在添加默认方法并将接口改装到现有类时,会添加destroy的有效实现,但这可能不会发生,可能是因为调度。

您引用的教程中的“二进制兼容性”概念是一个相当严格的定义,它是Java Language Specification, chapter 13使用的定义。基本上它是关于库类的有效转换,它们在运行时不会导致类加载或链接错误,当与针对这些库类的旧版本编译的类相结合时。这与源不兼容性形成对比,后者导致编译时错误和行为不兼容,这通常会导致系统运行时行为发生不必要的变化。比如抛出之前没有抛出的异常。

这不是为了尽量减少您的代码被破坏的事实。它仍然是不兼容的。 (对不起。)

作为一种解决方法,您可以添加instanceof PrivateKey || instanceof SecretKey(因为这些显然是缺少destroy实现的类)并且让测试断言它们会抛出DestroyFailedException,否则如果instanceof Destroyable 1}}执行测试中的其余逻辑。当这些实例在Java的某些未来版本中获得合理的destroy实现时,测试将再次失败;这将是一个信号,可以将测试更改回所有Destroyables上的destroy。 (另一种方法可能是完全忽略这些类,但是有效的代码路径最终可能会在很长一段时间内被忽略。)

答案 1 :(得分:5)

我只是推测,但我认为在destroy的默认实现中抛出异常的想法是提醒您敏感数据没有被销毁。如果默认实现为空,并且没有实现覆盖默认实现,则可能会错误地认为敏感数据已被破坏。

我认为你应该抓住DestroyFailedException异常,无论它是从默认实现还是从实际实现抛出,因为它警告你没有任何东西被破坏,你应该决定如何处理这个情况。

{7}和Java 8之间没有改变的destroy方法的合同(除了关于默认实现的评论之外)说 - Sensitive information associated with this Object is destroyed or cleared. Subsequent calls to certain methods on this Object will result in an IllegalStateException being thrown.

和:

  

抛出:
     DestroyFailedException - 如果destroy操作失败。

如果destroy失败,对此Object的某些方法的后续调用将导致IllegalStateException被抛出。如果被破坏,那仍然是真的,因此默认实现(什么都不做)会抛出DestroyFailedException

相关问题