使用 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
。
下面代码的作用如下:
- 调用
testMime()
,它创建一个 quoted-printable
部分,然后正确显示它(最高位设置字符使用以 =
开头的序列转义);
- 调用
stockQuoteTest
,它只是获取一个新的 Web 服务入口点 - 它不需要实际调用 Web 服务;
- 再次调用
testMime()
,创建了quoted-printable
部分,但是显示不正确,没有转义字符; system.out.Println
然后(可以预见地)将它们替换为 ?
.
我使用了多个 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 默认文件编码;显然这可能会产生其他后果
这让我困惑了好几个小时,似乎不太可能,但请多多包涵;我相信我有证据。
我已将其简化为最小测试用例(如下)。要测试代码,您需要使用 EmailTest.java
(如下),然后导入 SOAP 服务。为此,我使用了:
wsimport -d bin -s src -keep -extension 'http://www.webservicex.net/stockquote.asmx?wsdl'
为方便起见,我还将代码放在 github here 上,因此您可以简单地克隆它并 运行 它;这已经执行了 wsimport
。
下面代码的作用如下:
- 调用
testMime()
,它创建一个quoted-printable
部分,然后正确显示它(最高位设置字符使用以=
开头的序列转义); - 调用
stockQuoteTest
,它只是获取一个新的 Web 服务入口点 - 它不需要实际调用 Web 服务; - 再次调用
testMime()
,创建了quoted-printable
部分,但是显示不正确,没有转义字符;system.out.Println
然后(可以预见地)将它们替换为?
.
我使用了多个 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 默认文件编码;显然这可能会产生其他后果