带附件的Java邮件:javax.mail.Multipart上的ClassCastException

时间:2011-01-04 13:38:11

标签: java javamail

我使用以下代码从邮件中下载附件,但它在Multipart声明中提供了ClassCastException

  

线程“main”中的异常java.lang.ClassCastException:com.sun.mail.imap.IMAPInputStream无法强制转换为javax.mail.Multipart       在ReadAttachment.main(ReadAttachment.java:52)

如何处理IMAPInputStream?

Message messages[] = inbox.getMessages();

for (int j = 0; j < messages.length; j++) {

   String mailType = messages[j].getContentType();

   System.out.println("-- Message " + (j + 1) + " --");

   System.out.println("SentDate : " + messages[j].getSentDate());
   System.out.println("From : " + messages[j].getFrom()[0]);
   System.out.println("Subject : " + messages[j].getSubject());             
   System.out.println("Type :" + messages[j].getContentType()); 
   System.out.println("Attachment :" + messages[j].getFileName());  

   Multipart mp = (Multipart) messages[j].getContent();
   ..

   System.out.println();
}

6 个答案:

答案 0 :(得分:5)

我遇到了与JavaMail 1.5.1和OSGi相同的问题。使用msg.getContent()总是在从OSGi包中调用时返回一个InputStream,而当从一个简单的Java测试程序调用时它可以正常工作。

设置默认的CommandMap对我来说不起作用,但我在这里找到了一个解决方案:

https://www.java.net/node/705585

ClassLoader tcl = Thread.currentThread().getContextClassLoader();
try {
    Thread.currentThread().setContextClassLoader(javax.mail.Session.class.getClassLoader());
    // now call JavaMail API
    // ...
} finally {
    Thread.currentThread().setContextClassLoader(tcl);
}

答案 1 :(得分:4)

getContent方法将内容作为Java对象返回,其类型当然取决于内容本身。

  

为“text / plain”返回的对象   content通常是一个String对象   返回的对象为“multipart”   内容始终是Multipart   子类。
  对于内容类型   DataHandler系统未知,   输入流作为返回   内容。

见到Java Apache Cocoon source code *

Object objRef = msg.getContent();
if (!(objRef instanceof Multipart)) {
   String message = "This Message is not a multipart message!";
   getLogger().warn(message);
   return;
}
Multipart multipart = (Multipart) objRef;

*我不承担可能滥用 instanceof

的责任

答案 2 :(得分:3)

行。我认为这里真正的问题是,虽然你应该检查你正在回来的对象类型......它仍然可能是IMAPInputStream,但它不应该是。

我已经坚持了两天以上。

基本问题通常是Java Mail API做了一些非常愚蠢的事情,它试图读取一个名为mailcap的文件,如果已经切换了类加载器,那么这个文件并不总是可用。这在我的情况下特别棘手,因为我正在处理OSGi包,并且似乎没有直接控制我正在使用哪个加载器....但我离题了。

我发现'修复'......也许是在筛选Java Mail API的源代码之后作为最后的手段进行修复。

        // Set up our Mailcap entries.  This will allow the JAF
    // to locate our viewers.
    File capfile = new File("/path/to/mailcap");
    if (!capfile.isFile()) {
    System.out.println(
        "Cannot locate the \"simple.mailcap\" file.");
    System.exit(1);
    }

    CommandMap.setDefaultCommandMap( new MailcapCommandMap(
    new FileInputStream(capfile)));

我已经谷歌搜索了几天,发现了几十个有同样问题和各种类路径,线程,类加载器建议的人。但这是唯一对我有用的东西,它相对简单。因此将这个发布到似乎是最接近的相关问题并且有一些动力。呼。

答案 3 :(得分:3)

我已通过添加以下代码行修复了此错误。 MailCap有问题,javamail找不到multipart / mixed部分的处理程序,所以需要添加这个位。这解决了我的问题。希望它可以帮助那些人。

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);

干杯!

答案 4 :(得分:2)

是的,因为您假设getContent()返回实现Multipart的内容,而在这种情况下它不会(IMAPInputStream扩展InputStream)。

您的代码需要考虑到这种可能性。

答案 5 :(得分:2)

getContent返回的对象取决于消息类型。如果消息类型是 multipart ,它将只是Multipart。您可以执行if检查以查看MIME类型...

if(messages[j].getContentType().equals("multipart")) {
  //Do your cast and stuff
} else {
  //This message isn't a multipart message, maybe just skip it.
}

当然,这涉及使用魔术字符串。更复杂的解决方案是查看DataHandler API并在消息上使用getDataHandler()方法。不幸的是,我对该API了解不多。