使用 Java SOAP 服务会破坏 javax.mail 引用的可打印邮件封装

Using a Java SOAP service breaks javax.mail's quoted printable mail encapsulation

这让我困惑了好几个小时,似乎不太可能,但请多多包涵;我相信我有证据。

我已将其简化为最小测试用例(如下)。要测试代码,您需要使用 EmailTest.java(如下),然后导入 SOAP 服务。为此,我使用了:

wsimport -d bin -s src -keep -extension 'http://www.webservicex.net/stockquote.asmx?wsdl'

为方便起见,我还将代码放在 github here 上,因此您可以简单地克隆它并 运行 它;这已经执行了 wsimport

下面代码的作用如下:

我使用了多个 SOAP 库,所有这些库都做同样的事情 - 我选择了一个简单的演示库来演示。实际上没有必要调用 SOAP 端点。对 getPort 的调用(在 getStockQuoteSoap12 中)似乎是问题所在。

到目前为止,我的调试已确定我知道的默认 Java 编码中的 none 已经更改,问题似乎是在第二次调用 quoted-printable编码器永远不会被调用。这似乎是因为 part.dh.dataContentHandler 在有效时设置为 ObjectDataContentHandler 类型,在无效时设置为 StringDataContentHandler 类型。

关于这里发生的事情或如何解决它的任何想法?

我正在使用 javax.mail 1.5.2(最新的,但旧版本是一样的)- 和

$ java -version
java version "1.6.0_65"
Java(TM) SE Runtime Environment (build 1.6.0_65-b14-462-11M4609)
Java HotSpot(TM) 64-Bit Server VM (build 20.65-b04-462, mixed mode)

这是EmailTest.java

package emailtest;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.mail.MessagingException;
import javax.mail.internet.MimeBodyPart;

// use any SOAP service. This one was generated using
//   wsimport -d bin -s src -keep -extension http://www.webservicex.net/stockquote.asmx?wsdl
import net.webservicex.StockQuote;
import net.webservicex.StockQuoteSoap;

public class Emailtest {

    public static void stockQuoteTest() {
        StockQuote stockService = new StockQuote();
        StockQuoteSoap s = stockService.getStockQuoteSoap12();
        // We don't actually need to call SOAP to demonstrate the problem
        // System.out.println("quote is "+s.getQuote("GOOG"));
    }

    public static void testMime() throws MessagingException {
        String msg = "\u0287x\u01DD\u0287 u\u028Dop \u01DDp\u1D09sdn";

        MimeBodyPart messageBodyPart = new MimeBodyPart();
        messageBodyPart.setText("" + msg, "utf-8");
        messageBodyPart.setHeader("Content-Type", "text/plain; charset=\"utf-8\"");
        messageBodyPart.setHeader("Content-Transfer-Encoding", "quoted-printable");

        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try {
            messageBodyPart.writeTo(os);
            String aString = new String(os.toByteArray(),"UTF-8");
            System.out.println(aString);
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("");
    }

    public static void main(String args[]) {
        try {
            System.out.println("Before call to SOAP:");
            testMime();

            stockQuoteTest();

            System.out.println("After call to SOAP:");
            testMime();
        } catch (MessagingException e) {
            e.printStackTrace();
        }
    }
}

这是输出:

Before call to SOAP:
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable

=CA=87x=C7=9D=CA=87 u=CA=8Dop =C7=9Dp=E1=B4=89sdn

After call to SOAP:
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable

?x?? u?op ?p?sdn

哦,以防万一,编码后的文本是:

ʇxǝʇ uʍop ǝpᴉsdn

您可以看到 quoted-printable 在哪里无法工作(第二次调用),使用普通字母创建的 'upside down' 字母会显示出来。调查显示它根本没有做 quoted-printable

更新

这似乎是 a bug in jax-ws 并且可以说是 javax.mail 中的一个错误,因为它依赖于恰好在 JAF 而不是它自己的 text/plain 处理程序。任何解决方法的想法? (使用 Java 7,据称在 jax-ws 中固定的位置不是一个选项)

我相信这是因为 JAX-WS 中的 this bug(据称已在 Java 7 中修复)。

JAX-WS 使用 JAF 为类型 text/plain 引入了 DataHandler,它不遵守字符集(即 text/plain; charset="utf-8")。当 JAX-WS class加载时,使用它而不是 javax.mail 中的 text/plain 处理程序。然后使用 java 平台默认编码,而不是指定的编码。

两种可能的解决方法是:

  • 升级到 Java 7(专门针对 JAX-WS)

  • 在命令行上使用 -Dfile.encoding=UTF-8 启动应用程序以设置 Java 默认文件编码;显然这可能会产生其他后果