При написании класса полезности криптографии я столкнулся с проблемой со следующим методом:
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) был сделал удаляемым (javadocs 8) и метод Destroyable#destroy теперь равен default
, что соответствует этому утверждение
Методы по умолчанию позволяют добавлять новые функции в интерфейсы ваших библиотек и обеспечивать двоичную совместимость с кодом, написанным для более старых версий этих интерфейсов.
то код компилируется без проблем несмотря на то, что сам класс 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 вводит в заблуждение, поскольку, кроме законного вызова для уничтожения, ничего не было предпринято для эффективного уничтожения ключа, UnsupportedOperationException подойдет лучше, и вы сразу поймете, что происходит)
Является ли мой подход (проверка типа/приведение/вызов)
if(Destroyable.class.isInstance(key)) ((Destroyable)key).destroy();
для определения, уничтожить или не ошибиться? Что может быть альтернативой?
Это заблуждение или они просто забыли добавить осмысленную реализацию в
ScretKeySpec
?
instanceof
? - person Jeffrey   schedule 20.07.2014isInstance
не является динамическим эквивалентомinstance of
? Но, согласно этому ответу, я думаю, чтоinstance of
должно подойти для моего случая. Спасибо, что указали на это. - person A4L   schedule 20.07.2014isInstance
является динамическим эквивалентомinstanceof
. - person Jeffrey   schedule 20.07.2014