Ошибка класса DCH с помощью JavaMail

Я пытаюсь настроить простой протокол регистрации JavaMail в Java EE 6, используя файлы jar, поставляемые с Glassfish 3.1. Там, кажется, множество вопросов по этому вопросу, но я не нашел ответов, которые помогли еще. Мой тестовый код выглядит следующим образом:

import java.util.logging.Logger;

public class MyClass {
  private static final Logger LOGGER = Logger.getLogger("MyClass");

  public static void main(String[] args) {
    LOGGER.severe("This is a test");
  }
}

Мой файл logging.properties содержит следующее:

com.sun.mail.util.logging.MailHandler.mail.smtp.host={my mail hub FQDN}
com.sun.mail.util.logging.MailHandler.mail.smtp.port=25
com.sun.mail.util.logging.MailHandler.mail.to={me}
com.sun.mail.util.logging.MailHandler.mail.from={support address}
com.sun.mail.util.logging.MailHandler.level=WARNING
com.sun.mail.util.logging.MailHandler.verify=local
com.sun.mail.util.logging.MailHandler.subject=Application Error
com.sun.mail.util.logging.MailHandler.formatter=java.util.logging.SimpleFormatter

Я создаю класс, используя:

javac -cp $AS_INSTALL/glassfish/modules/javax.mail.jar:$AS_INSTALL/install/lib/external/jaxb/activation.jar:. MyClass.java

Затем я запускаю программу, используя:

java -cp $AS_INSTALL/glassfish/modules/javax.mail.jar:$AS_INSTALL/install/lib/external/jaxb/activation.jar:. -Djava.util.logging.config.file=logging.properties MyClass

Это приводит к следующей ошибке:

Sep 22, 2011 4:19:25 PM MyClass main
SEVERE: This is a test
java.util.logging.ErrorManager: 3: SEVERE: no object DCH for MIME type multipart/mixed;
        boundary="----=_Part_1_26867996.1316722766145"
javax.activation.UnsupportedDataTypeException: no object DCH for MIME type multipart/mixed;
        boundary="----=_Part_1_26867996.1316722766145"
        at javax.activation.ObjectDataContentHandler.writeTo(DataHandler.java:877)
        at javax.activation.DataHandler.writeTo(DataHandler.java:302)
        at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1476)
        at javax.mail.internet.MimeMessage.writeTo(MimeMessage.java:1772)
        at javax.mail.internet.MimeMessage.writeTo(MimeMessage.java:1748)
        at com.sun.mail.util.logging.MailHandler.toRawString(MailHandler.java:2196)
        at com.sun.mail.util.logging.MailHandler.send(MailHandler.java:1597)
        at com.sun.mail.util.logging.MailHandler.close(MailHandler.java:552)
        at java.util.logging.LogManager.resetLogger(LogManager.java:693)
        at java.util.logging.LogManager.reset(LogManager.java:676)
        at java.util.logging.LogManager$Cleaner.run(LogManager.java:221)

javax.mail.MessagingException: IOException while sending message;
  nested exception is:
        javax.activation.UnsupportedDataTypeException: no object DCH for MIME type multipart/mixed;
        boundary="----=_Part_1_26867996.1316722766145"
        at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1141)
        at javax.mail.Transport.send0(Transport.java:195)
        at javax.mail.Transport.send(Transport.java:124)
        at com.sun.mail.util.logging.MailHandler.send(MailHandler.java:1594)
        at com.sun.mail.util.logging.MailHandler.close(MailHandler.java:552)
        at java.util.logging.LogManager.resetLogger(LogManager.java:693)
        at java.util.logging.LogManager.reset(LogManager.java:676)
        at java.util.logging.LogManager$Cleaner.run(LogManager.java:221)
Caused by: javax.activation.UnsupportedDataTypeException: no object DCH for MIME type multipart/mixed;
        boundary="----=_Part_1_26867996.1316722766145"
        at javax.activation.ObjectDataContentHandler.writeTo(DataHandler.java:877)
        at javax.activation.DataHandler.writeTo(DataHandler.java:302)
        at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1476)
        at javax.mail.internet.MimeMessage.writeTo(MimeMessage.java:1772)
        at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1099)
        ... 7 more

Я проверил, что файл javax.mail.jar содержит многопроцессорный обработчик:

unzip -l $AS_INSTALL/glassfish/modules/javax.mail.jar | grep multipart
     2617  01-14-2011 15:37   com/sun/mail/handlers/multipart_mixed.class

Я даже запускаю программу с включенной отладкой активации. Это показывает мне следующие связанные части:

parse: multipart/*;;            x-java-content-handler=com.sun.mail.handlers.multipart_mixed; x-java-fallback-entry=true
  Type: multipart/*
    Command: content-handler, Class: com.sun.mail.handlers.multipart_mixed

MailcapCommandMap: createDataContentHandler for multipart/mixed
  search DB #1
  search DB #2
  search fallback DB #1
    got content-handler
      class com.sun.mail.handlers.multipart_mixed
Can't load DCH com.sun.mail.handlers.multipart_mixed; Exception: java.lang.ClassNotFoundException: com/sun/mail/handlers/multipart_mixed

Я даже получаю дубликат выше для текста типа /plain.

MailcapCommandMap: createDataContentHandler for text/plain
  search DB #1
    got content-handler
      class com.sun.mail.handlers.text_plain
Can't load DCH com.sun.mail.handlers.text_plain; Exception: java.lang.ClassNotFoundException: com/sun/mail/handlers/text_plain

Что мне здесь не хватает?

Спасибо, Стив

Ответ 1

Я нашел решение здесь:

http://blog.hpxn.net/2009/12/02/tomcat-java-6-and-javamail-cant-load-dch/

Хотя мне бы хотелось узнать больше о деталях, почему это проблема, и что этот параметр -Xbootclasspath делает для устранения проблемы. Если я запускаю свой класс следующим образом:

java -Djava.util.logging.config.file=logging.properties -Xbootclasspath/p:/app/glassfish-3.1/glassfish/modules/javax.mail.jar MyClass

Он находит необходимые классы, и я получаю свою электронную почту. Теперь мне просто нужно выяснить, как перевести эту конфигурацию на мой сервер Glassfish и попробовать более "настоящий" тест из этого простого тестового примера.

Ответ 2

Добавьте их перед отправкой сообщения:

MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
        mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");
        mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
        mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");
        mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed");
        mc.addMailcap("message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822");
        CommandMap.setDefaultCommandMap(mc);

У меня проблема в приложении для Android, и она работает.

Ответ 3

В моем случае я смог решить это, добавив это перед отправкой():

Thread.currentThread().setContextClassLoader( getClass().getClassLoader() );

Это было предложено в связанном блоге, поэтому, если вы хотите узнать больше деталей, прочитайте его. Спасибо Джерри Гу за ссылку сюда и оригинальный блоггер.

URL: http://blog.hpxn.net/2009/12/02/tomcat-java-6-and-javamail-cant-load-dch/

Ответ 4

Вероятность высокая, если вы работаете на сервере KARAF (OSGI), вышеуказанные предложения будут трудно реализовать, поскольку у Karaf нет класса запуска или пути к загрузке.

Я обнаружил, что конфликт activation.jar создал эту проблему.

{FUSEESB_HOME Or ServiceMIX_HOME}/etc/jre.properties was loading activation.jar .

После комментариев все было гладко.

Пожалуйста, просмотрите ссылку ниже.

Ответ 5

Хотя мне бы хотелось узнать больше о деталях, почему это проблема, и что этот параметр -Xbootclasspath делает для устранения проблемы.

Это связано с деревом classloader. Напомним, что дочерние загрузчики классов могут искать классы в загрузчике родительского класса, но не наоборот. В вашей примерной программе дерево classloader выглядит следующим образом:

Running under JDK6, JDK7, and JDK8
+---Boot ClassLoader--+
| java.util.logging.* |
| javax.activation .* |
+---------------------+
          ^
          |
+-----System ClassLoader------+
| javax.mail.*                |
| com.sun.mail.handlers.*     |
| com.sun.mail.util.logging.* |
+-----------------------------+

Когда запускается трюк LogManager$Cleaner (JDK6 +), загрузчик классов контекста вынужден boot classloader, который не может найти класс com.sun.mail.handlers.text_plain, потому что он находится в дочернем загрузчике классов. Из-за этого изменение MailcapCommandMap для включения имен класса mailcap не устранит проблему. Когда вы используете опцию -Xbootclasspath, вы размещаете все соответствующие классы в загрузчике загрузчика, который отображается на LogManager$Cleaner. Однако, не изменяйте свою систему, чтобы использовать -Xbootclasspath, чтобы исправить эту проблему.

Вместо этого обновите до JavaMail 1.5.3 или более поздней версии, который содержит исправление для Ошибка K6552 | GH133 - Использовать эргономичность загрузчика классов в MailHandler. Если вы хотите обновить модуль JavaMail GlassFish, вы можете заменить glassfish-X.X/glassfish/modules/javax.mail.jar на более новую версию JavaMail.

Недопустимый fix, примененный к JavaMail 1.4.7, заключался в том, чтобы установить загрузчик класса контекста загрузчику классов, загрузив MailHandler во время Закрыть. Предполагается, что загрузчик классов, загрузивший MailHandler, сможет найти код активации.

Если вы не можете перейти на более новую версию JavaMail, вам необходимо применить одно из следующих обходных решений:

  • Перед запуском очистителя закройте или закройте MailHandler.
  • Очистите все обработчики перед запуском пылесоса (развернуть веб-приложение I.E.). Вы должны синхронизировать LogManager и собирать все обработчики из каждого регистратора. Сбросьте все обработчики за пределами синхронизированного блока.
  • Расширьте MailHandler и закройте закрыть, чтобы установить и восстановить загрузчик класса контекста, если загрузчик класса контекста имеет значение NULL.
  • Установите новый LogManager и переопределите reset, чтобы установить и восстановить загрузчик класса контекста, если загрузчик класса контекста имеет значение null.
  • Установите текстовый файл темы, чтобы установить загрузчик контекстного класса, если очиститель запущен.
  • Установите уровень push на ALL или установите емкость 1, чтобы по электронной почте было отправлено письмо для каждой записи журнала и получилось спам.
  • Запуск на версии Java с исправлением с помощью RFE JDK-8025251.

Основная проблема заключается в том, что LogManager$Cleaner заставляет загрузчик контекста иметь значение null, прежде чем он называет close на каждом Handler, зарегистрированном с помощью LogManager. Лучшим выбором для LogManager было бы установить загрузчик классов класса к загрузчику класса обработчика перед вызовом close, после того как все обработчики будут закрыты, установите загрузчик класса контекста равным null. Этого можно было бы обмануть вложенными обработчиками, но, по крайней мере, это устранило бы общий случай. Это было зарегистрировано как RFE JDK-8025251 "Средство очистки LogManager должно использовать обработчик класса обработчика при закрытии".

Ответ 6

Я столкнулся с этой проблемой сегодня, и это связано с загрузчиком класса потоков.

если вы выполните sysout: com.sun.mail.handlers.multipart_mixed.class.getClassLoader()

он может не совпадать с текущим загрузчиком классов потоков: Thread.currentThread(). GetContextClassLoader()

Я смог прийти к такому выводу, добавив следующий аргумент: -Djavax.activation.debug = истина

После добавления этого аргумента я увидел, что он не смог загрузить обработчик содержимого данных (DCH) для multipart_mixed.class.

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

Ответ 7

Для всех, имеющих это сообщение об ошибке выше, оказалось, что в моем случае данные аутентификации были пустыми, это было связано с тем, что я отключил аутентификацию почтового сервера, мне больше не нужны имя пользователя и пароль, но пустые значения были как-то разобрался и создал отсутствующую ошибку аутентификации, которая не была хорошо поймана в Mail 1.4.0, обновление до Mail 1.4.7 и удаление двух параметров-элементов ниже разрешило проблему.

<appender name="ALARM_MAIL" class="my.utils.SMTPAppender">
  <!-- remove this line: <param name="SMTPUsername" value=""/> -->
  <!-- remove this line: <param name="SMTPPassword" value=""/> -->
  ...