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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4594206/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 07:07:47  来源:igfitidea点击:

Java mail with attachment: ClassCastException on javax.mail.Multipart

javajavamail

提问by Karthick Ramu

I use the following code to download the attachment from the mail but it gives the ClassCastExceptionon the Multipart declaration:

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

Exception in thread "main" java.lang.ClassCastException: com.sun.mail.imap.IMAPInputStream cannot be cast to javax.mail.Multipart at ReadAttachment.main(ReadAttachment.java:52)

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

How do I handle IMAPInputStream?

我如何处理 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();
}

回答by kahlk

I had the same problem with the JavaMail 1.5.1 and OSGi. Using msg.getContent() always returned an InputStream when called from an OSGi bundle while it works perfectly when called from a simple Java test program.

我在 JavaMail 1.5.1 和 OSGi 上遇到了同样的问题。当从 OSGi 包调用时,使用 msg.getContent() 总是返回一个 InputStream,而当从简单的 Java 测试程序调用时它工作得很好。

Setting the default CommandMap didn't work for me, but I found a solution here:

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

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

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

回答by systempuntoout

The getContentmethod returns the content as a Java object and its type is of course dependent on the content itself.

所述的getContent方法返回的内容以Java对象,其类型是当然依赖于内容本身的。

The object returned for "text/plain" content is usually a String object.
The object returned for a "multipart" content is always a Multipart subclass.
For content-types that are unknown to the DataHandler system, an input stream is returned as the content.

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

Seen on the Java Apache Cocoon source code*:

在 Java Apache Cocoon源代码上看到的*

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;

* I don't take the responsability for the possible misuse of instanceof

*我不承担可能滥用instanceof的责任

回答by Brendan

OK. I think the real problem here is that although you should be checking for the object type you're getting back....it still might be IMAPInputStream when it should not be.

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

I have been hammering on this for over two days.

我已经为此苦苦思索了两天多了。

The underlying problem is often that the Java Mail API does something very dumb, it tries to read in a file called mailcap which isn't always available if the class loader has been switched. This is particularly tricky in my case because I'm dealing with OSGi bundles and don't seem to have direct control over which loader I'm using....but I digress.

潜在的问题通常是 Java Mail API 做了一些非常愚蠢的事情,它尝试读取名为 mailcap 的文件,如果类加载器已切换,则该文件并不总是可用。这在我的情况下特别棘手,因为我正在处理 OSGi 包并且似乎无法直接控制我正在使用的加载程序......但我离题了。

I found 'a fix'...perhaps THE FIX after sifting through the source code of the Java Mail API as a last resort.

我找到了'一个修复'......也许是在筛选 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)));

I've been Googling for days and found dozens of people with the same problem and various classpath, thread, classloader suggestions. But this is the only thing that worked for me and it's relatively simple. Hence posting this to what seems to be the closest related issue with some momentum. PHEW.

我已经用谷歌搜索了好几天,发现有很多人有同样的问题和各种类路径、线程、类加载器的建议。但这是唯一对我有用的方法,而且相对简单。因此,将其发布到似乎是最相关的具有某种势头的问题上。呼。

回答by jagmohan

I have fixed this error by adding following lines of code. There is something wrong with MailCap, javamail can not find a handler for the multipart/mixed part, so this bit needs to be added. This resolved my problem. Hope it helps someone out there.

我通过添加以下代码行修复了这个错误。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);

Cheers!

干杯!

回答by skaffman

Yes, because you're assuming that getContent()returns something that implements Multipart, and in this case it does not (IMAPInputStreamextends InputStream).

是的,因为您假设getContent()返回的东西实现了Multipart,而在这种情况下它没有(IMAPInputStream扩展InputStream)。

Your code needs to account for this possibility.

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

回答by Pace

The object returned by getContentdepends on the message type. It will only be Multipart if the message type is multipart. You could do an if check to look at the MIME type...

返回的对象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.
}

Of course that involves the use of magic strings. A more sophisticated solution would be to look into the DataHandler API and use the getDataHandler()method on the message. Unfortunately I don't know much about that API.

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