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

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

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


person Steve Ferguson    schedule 22.09.2011    source источник
comment
Добавлю, что это система Solaris 10. Вот моя версия JRE: [/usr/jdk/instances/jdk1.6.0]: java -version java version 1.6.0_24 Java(TM) SE Runtime Environment (сборка 1.6.0_24-b07) Java HotSpot(TM) Server VM (сборка 19.1-b02, смешанный режим)   -  person Steve Ferguson    schedule 23.09.2011


Ответы (7)


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

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

person Jaden Gu    schedule 08.03.2012
comment
Это также исправлено в моей среде разработки под eclipse/linux/open-jdk6. - person рüффп; 07.06.2012
comment
Я предпочитаю это решение изменению пути к классу загрузки, потому что изменение пути к классу загрузки не всегда возможно, например: Java Web Start (JNLP). - person gb96; 15.05.2013
comment
Спасибо, это сработало и в Linux/Tomat6/jdk6. - person Blitz; 16.12.2013

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

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, и попробовать более «настоящий» тест из этого простого тестового примера.

person Steve Ferguson    schedule 23.09.2011
comment
Дополнительная информация: после того, как я добавил -Xbootclasspath/p:${com.sun.aas.installRoot}/modules/javax.mail.jar к параметрам JVM в своем домене Glassfish и обновил файл $AS_INSTALL/glassfish/domains/{domain}/config/logging.properties информацией, указанной выше, я периодически получаю уведомления по электронной почте, содержащие все события журнала в состоянии WARNING и выше. - person Steve Ferguson; 23.09.2011

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

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

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

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

person Taavi Ilves    schedule 07.08.2012
comment
Спасибо за контекст, так как URL сейчас кажется мертвым. - person Taavi Ilves; 20.06.2019

Хотя я хотел бы узнать больше о деталях, почему это проблема, и что эта опция -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 (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. Flush or close the MailHandler before the cleaner runs.
  2. Flush all handlers before the cleaner runs (I.E. web app undeploy). You have to synchronize on the LogManager and collect all handlers from each logger. Flush all of the handlers outside of the synchronized block.
  3. Extend the MailHandler and override close to set and restore the context class loader if the context class loader is null.
  4. Install a new LogManager and override reset to set and restore the context class loader if the context class loader is null.
  5. Install a subject formatter to set the context class loader if the cleaner is running.
  6. Set the push level to ALL or set the capacity to 1 so an email is sent for every log record and get spammed.
  7. Run on a Java version with patched with RFE JDK-8025251.

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

person jmehrens    schedule 28.05.2013

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

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

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

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

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

person R-JANA    schedule 05.09.2012

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

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

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

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

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

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

person Jeff C.    schedule 26.09.2013

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