«BASE64DecoderStream» выдает ошибку для зависимости javax-mail

Недавно я изменил зависимость

<dependency>
    <groupId>javax.mail</groupId>
    <artifactId>mail</artifactId>
    <version>1.4</version>
</dependency>

к

<dependency>
    <groupId>javax.mail</groupId>
    <artifactId>javax.mail-api</artifactId>
    <version>1.6.0</version>
</dependency>

потому что Java 8 не поддерживает версию 1.4, так как использует TLS 1.0.

После изменения зависимости этот код начинает выдавать ошибку. Код ошибки:

if (p.getContentType().contains("image/")) {
    File f = new File("image" + new Date().getTime() + ".jpg");
    DataOutputStream output = new DataOutputStream(
            new BufferedOutputStream(new FileOutputStream(f)));
    
    com.sun.mail.util.BASE64DecoderStream test = (com.sun.mail.util.BASE64DecoderStream) p
            .getContent();
    byte[] buffer = new byte[1024];
    int bytesRead;
    while ((bytesRead = test.read(buffer)) != -1) {
        output.write(buffer, 0, bytesRead);
    }

Ошибка предложения Eclipse:

Multiple markers at this line
    - com.sun.mail.util.BASE64DecoderStream cannot be resolved to a type
    - com.sun.mail.util.BASE64DecoderStream cannot be resolved to a type

FWIW: последние обновления Java 8 (и все 11 выше) по умолчанию не поддерживают TLS1.0, но вы можете снова включить его. Тем не менее, хорошая практика в настоящее время требует, чтобы серверы не позволяли вам подключаться с использованием этого (или SSL3), и хотя не все серверы быстро следуют хорошей практике, некоторые делают это сейчас, а со временем еще больше, поэтому обновление вашего клиента остается хорошей идеей.

dave_thompson_085 02.06.2023 11:28
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
1
63
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ошибка, с которой вы столкнулись, связана с тем, что класс com.sun.mail.util.BASE64DecoderStream недоступен в библиотеке javax.mail версии 1.6.0. Этот класс был частью библиотеки javax.mail версии 1.4, которую вы использовали ранее.

Чтобы решить эту проблему, у вас есть несколько вариантов:

Вернитесь к предыдущей версии (1.4) библиотеки javax.mail. Это можно сделать, отменив изменения, внесенные вами в зависимости Maven или Gradle.

xml
Copy code
<dependency>
    <groupId>javax.mail</groupId>
    <artifactId>mail</artifactId>
    <version>1.4</version>
</dependency>

Обновите свой код, чтобы использовать другой подход для декодирования данных Base64. Вместо использования com.sun.mail.util.BASE64DecoderStream можно использовать класс java.util.Base64, доступный в Java SE 8 и более поздних версиях.

Вот пример того, как вы можете изменить свой код:

java
Copy code
if (p.getContentType().contains("image/")) {
    File f = new File("image" + new Date().getTime() + ".jpg");
    try (OutputStream output = new BufferedOutputStream(new FileOutputStream(f))) {
        String content = (String) p.getContent();
        byte[] data = java.util.Base64.getDecoder().decode(content);
        output.write(data);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Обратите внимание, что этот подход предполагает, что содержимое объекта p представляет собой строку в кодировке Base64. Если это не так, вам может потребоваться изменить код соответствующим образом.

Если вам необходимо продолжить использование библиотеки javax.mail версии 1.6.0, вы можете найти в библиотеке альтернативный класс или метод, обеспечивающий функциональность декодирования Base64. Вы можете просмотреть документацию или выполнить поиск примеров или руководств, относящихся к конкретной версии, которую вы используете.

Класс com.sun.mail.util.BASE64DecoderStream все еще существует в реализации JavaMail/JakartaMail 1.6.x. Проблема в том, что OP объявил неправильную зависимость, API, а не реализацию.

Mark Rotteveel 02.06.2023 09:40

Тем не менее, я думаю, что код будет сильнее для использования java.util.Base64, который также может работать в потоковом режиме.

g00se 02.06.2023 10:29

@ g00se Нет необходимости приводить к BASE64DecoderStream, как это делается здесь. ОП мог бы просто использовать getInputStream и использовать это вместо использования getContent() и привести возвращенный объект. Тот факт, что он может (или не может) использовать BASE64DecoderStream, является деталью реализации.

Mark Rotteveel 02.06.2023 14:18

Да, это правда. Поток мог быть скопирован напрямую. Код требует доработки, в том числе замены устаревших классов API.

g00se 02.06.2023 14:29
Ответ принят как подходящий

Вы используете неправильную зависимость. Вы добавили только JakartaMail API. Вы должны использовать реализацию JakartaMail 1.6.x:

<dependency>
    <groupId>com.sun.mail</groupId>
    <artifactId>jakarta.mail</artifactId>
    <version>1.6.7</version>
</dependency>

Эта зависимость включает com.sun.mail.util.BASE64DecoderStream.

Кстати, вместо того, что вы делаете сейчас (используя getContent() и приводя к классу, специфичному для реализации), вы также можете использовать Part.getInputStream():

try (var in = p.getInputStream()) {
    in.transferTo(output);
}

Кроме того, ваше использование DataOutputStream вызывает подозрения, поскольку вы, похоже, не используете какие-либо конкретные методы DataOutputStream, поэтому прямого использования BufferedOutputStream должно быть достаточно.

спасибо, используя неправильную зависимость, это помогает

Rob 02.06.2023 09:45
if (p.getContentType().contains("image/")) {
    Path imageFile  = Path.of("image" + Instant.now().toEpochMilli() + ".jpg");
    try(OutputStream out = Files.newOutputStream(imageFile)) {
        p.getInputStream().transferTo(out);
    }
}

проиллюстрирует комментарии между мной и @Mark Rotteveel. По сути, то, что Марк уже опубликовал, с дальнейшими корректировками обработки даты и попытки использования ресурсов.

getContent() возвращает Object, поэтому тип значения необходимо проверить и привести, и в зависимости от поставщиков активации Jakarta в пути к классам getContent() может вернуть что-то еще. Вместо этого я рекомендую использовать p.getInputStream().
Mark Rotteveel 12.06.2023 16:11

Ах точно спасибо. Будет корректировать

g00se 12.06.2023 16:19

Другие вопросы по теме