Ошибка класса 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

Я даже получаю дубликат вышеупомянутого для типа text / 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

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

Спасибо Стив

7 ответов

Решение

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

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, и попробовать более "реальный" тест из этого простого теста.

Добавьте их, прежде чем отправить сообщение:

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, и она работает.

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

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

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

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

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

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

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 завершает работу shutdown hook (JDK6+), контекстный загрузчик классов вынужден загружать загрузчик классов, который не может найти 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.

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

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

  1. Промойте или закройте MailHandler до запуска очистителя.
  2. Очистите все обработчики перед запуском очистителя (IE веб-приложение отменено). Вы должны синхронизироваться в LogManager и собрать все обработчики из каждого регистратора. Очистите все обработчики вне синхронизированного блока.
  3. Расширьте MailHandler и переопределите значение close для установки и восстановления загрузчика класса контекста, если загрузчик класса контекста имеет значение null.
  4. Установите новый LogManager и переопределите reset установить и восстановить загрузчик класса контекста, если загрузчик класса контекста равен нулю.
  5. Установите предметный форматер, чтобы установить загрузчик класса контекста, если уборщик работает.
  6. Установите уровень нажатия на ALL или установите емкость 1, чтобы электронное письмо отправлялось для каждой записи журнала и получало спам.
  7. Запустите версию Java с исправлением с помощью RFE JDK-8025251.

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

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

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

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

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

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

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

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

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

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

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

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

Для всех, имеющих это сообщение об ошибке выше, оказалось, что в моем случае данные аутентификации были пустыми, это было связано с тем, что я отключил аутентификацию почтового сервера, мне больше не требовалось имя пользователя и пароль, но пустые значения были как-то проанализированы и создал отсутствующую ошибку аутентификации, которая не была хорошо уловлена в Почте 1.4.0, обновление до Почты 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=""/> -->
  ...
Другие вопросы по тегам