Как правильно организовать обработку исключение в MVC в Java?

Имеется структура каталогов, разработанная на основе MVC, и имеет вид (другие каталоги исключены для наглядности и понимания сущности происходящего):

model/dao/AccountDao.class
util/AesCrypt.class

Имеется класс AesCrypt, содержащий метод encrypt(String password), который занимается шифрованием и дефишрованием пароля:

public String encrypt(String password) throws CryptException {
        try {
            IvParameterSpec ivParameterSpec = new IvParameterSpec(VECTOR.getBytes(StandardCharsets.UTF_8));
            SecretKeySpec secretKeySpec = new SecretKeySpec(KEY.getBytes(StandardCharsets.UTF_8), "AES");

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);

            return new String(Hex.decodeHex(password.toCharArray()));
        } catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidAlgorithmParameterException | InvalidKeyException | DecoderException e) {
            LOGGER.error("Cant' create a crypt.");
            throw new CryptException("Can't create a crypt.", e);
        }
    }

Как вы можете заметить, внутри имеется обработка возможных исключений.
В классе AccountDao имеется метод create(Account account, String password), который внутри себя занимается шифрованием пароля, переданного в данный метод, для последующего помещения зашифрованного пароля в БД. Внутри данного метода нужно будет вызвать метод шифрования пароля create(Account account, String password) того самого AesCrypt и выглядит это дело так (лишний код заменен на комментарии):

@Override
    public boolean create(Account account, String password) throws DaoException {
        // ... code
        AesCrypt crypt = utilProvider.getAesCrypt();
        
        try {
            // ... code
            String cryptPassword = crypt.encrypt(password);  // тут должна быть обработка исключений

        } catch (SQLException e) {
            LOGGER.error("Couldn't create an account in the database: {}.", account);
            throw new DaoException("Couldn't create an account in the database " + account);
        } 
        
        // ... code
    }

В строке String cryptPassword = crypt.encrypt(password); должна быть обработка исключений.

Вопрос - опять повторно нужно обрабатывать исключения или как правильно организовать код? Получится, что в двух разных классах будет дублирование кода, который обрабатывает исключения.


Ответы (1 шт):

Автор решения: Roman Konoval

В строке String cryptPassword = crypt.encrypt(password); должна быть обработка исключений.

Не обязательно, а в этом случае, скорее всего, не нужна. Обработку исключений нужно делать там, где это имеет смысл, а именно там, где клиент получивший исключение, может что-то осмысленное с ним сделать.

Примеры, когда можно что-то сделать:

  1. ошибка соединения с сетью - можно попробовать опять после паузы
  2. ошибка во входных данных предоставленных пользователем - можно и нужно попросить ввести данные заново

В вашей же ситуации, если функция create(Account account, String password) получит, скажем, NoSuchAlgorithmException, она ничего сделать не может. Это ошибка программиста и нет никакой возможности на этом уровне обработать такие исключения, вызванные ошибкой программиста. Правильное решение это сделать CryptException runtime исключением, и не обрабатывать его в этом месте вообще. В крайнем случае завернуть в DaoException, если у вас по контракту, все исключения из DAO слоя заворачиваются в DAOException.

Обработка этого исключение будет в обобщенном виде на уровне контроллера, там где он ловит все исключения, и в зависимости от типа возвращает соответствующий http status, если это web приложение.

→ Ссылка