При написании класса утилиты crypto я столкнулся с проблемой со следующим методом:
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) не реализует Разрушимый (javadocs 7)
Теперь с java8
был создан класс SecretKeySpec (javadocs 8) Разрушимый (javadocs 8) и метод Destroyable # destroy теперь default
, что соответствует этому
Способы по умолчанию позволяют добавлять новые функциональные возможности к интерфейсам ваших библиотек и обеспечивать двоичную совместимость с кодом, написанным для более старых версий этих интерфейсов.
тогда код компилируется без каких-либо проблем, несмотря на то, что сам класс ScretKeySpec
не был изменен, только интерфейс SecretKey был.
Проблема заключается в том, что в oracle 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 и может быть неправильным в будущих выпусках, поскольку метод по умолчанию может получить значимую реализацию.
-
Не было бы лучше оставить этот метод по умолчанию пустым, а не бросать исключение (что ИМО вводит в заблуждение, так как в стороне от законного вызова для уничтожения ничего не было предпринято для эффективного уничтожения ключа, UnsupportedOperationException было бы лучше, и вы сразу узнаете, что происходит)
-
Подходит ли мой подход (тип check/cast/call)
if(Destroyable.class.isInstance(key)) ((Destroyable)key).destroy();
для определения того, нужно ли уничтожать или не ошибаться? Что было бы альтернативой?
-
Является ли это заблуждением или они просто забывают добавить значимую реализацию в
ScretKeySpec
?