我正在使用JAXB2在Spring-WS中执行OXM.我指定的XSD需要在肥皂消息上附加一个较大的XML文件,因此我正在使用MTOM传输文件,并在JAXB2Marshaller上启用了MTOM.
当JAXB2封送一个具有预期的mime类型的text / xml的MTOM附件时,它将将该元素作为javax.xml.transform.Source对象传递.经过一些搜索,我能够找到如何将Source对象发送到文件中.
final Source source = request.getSource();
StreamSource streamSource = (StreamSource) source;
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
File file = new File ("/tempxmlfile.xml");
try{
transformer.transform(streamSource, new StreamResult(file));
LOG.info("File saved in "+file.getAbsolutePath());
}
catch(Exception ex){
ex.getMessage();
}
我遇到的问题是,当我发送UTF-8编码的文件作为附件时,出现以下错误:
[Fatal Error] :1:1: Content is not allowed in prolog.
ERROR: 'Content is not allowed in prolog.'
这是由文件中编码文本前面的字节顺序标记引起的,尽管在Unicode标准允许的UTF-8编码文件中不需要此BOM,但Java不支持UTF-8编码的BOM流.
我可以通过发送不带BOM的文件来解决此问题,但这实际上并不可行,因为它将导致大多数确实插入BOM的Microsoft产品出现问题.
Sun / Oracle拒绝使用Streams解决此问题有很多解决方法,但是它们都要求您可以访问Stream,JAXB2提供的Source Object没有InputStream,而只有Reader对象.我有办法解决此问题的方法,方法是将Sources Reader对象包装到一个读取器,该读取器知道如何忽略UTF-8编码的BOM,或者更改JAXB2将附件读取到源中的方式,以便它可以忽略以UTF-8编码的BOM.
提前致谢,
克雷格
解决方法:
诀窍是“标记”读者.如果您的阅读器不支持标记,则可以将其包装在BufferedReader中,它可以:
> http://download.oracle.com/javase/6/docs/api/java/io/BufferedReader.html#markSupported%28%29
选项#1-检查BOM并将其删除
我相信我的原始代码编写的BOM错误.下面的源代码更有意义:
import java.io.*;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
public class Demo {
private static char[] UTF32BE = {0x00, 0x00, 0xFE, 0xFF};
private static char[] UTF32LE = {0xFF, 0xFE, 0x00, 0x00};
private static char[] UTF16BE = {0xFE, 0xFF};
private static char[] UTF16LE = {0xFF, 0xFE};
private static char[] UTF8 = {0xEF, 0xBB, 0xBF};
public static void main(String[] args) throws Exception {
// Create an XML document with a BOM
FileOutputStream fos = new FileOutputStream("bom.xml");
writeBOM(fos, UTF16LE);
OutputStreamWriter oswUTF8 = new OutputStreamWriter(fos, "UTF-8");
oswUTF8.write("<root/>");
oswUTF8.close();
// Create a Source based on a Reader to simulate source.getRequest()
StreamSource attachment = new StreamSource(new FileReader(new File("bom.xml")));
// Wrap reader in BufferedReader so it will support marking
Reader reader = new BufferedReader(attachment.getReader());
// Remove the BOM
removeBOM(reader);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
t.transform(new StreamSource(reader), new StreamResult(System.out));
}
private static void writeBOM(OutputStream os, char[] bom) throws Exception {
for(int x=0; x<bom.length; x++) {
os.write((byte) bom[x]);
}
}
private static void removeBOM(Reader reader) throws Exception {
if(removeBOM(reader, UTF32BE)) {
return;
}
if(removeBOM(reader, UTF32LE)) {
return;
}
if(removeBOM(reader, UTF16BE)) {
return;
}
if(removeBOM(reader, UTF16LE)) {
return;
}
if(removeBOM(reader, UTF8)) {
return;
}
}
private static boolean removeBOM(Reader reader, char[] bom) throws Exception {
int bomLength = bom.length;
reader.mark(bomLength);
char[] possibleBOM = new char[bomLength];
reader.read(possibleBOM);
for(int x=0; x<bomLength; x++) {
if(bom[x] != possibleBOM[x]) {
reader.reset();
return false;
}
}
return true;
}
}
选项#2-查找’<'并将读者推进到这一点 阅读直到您点击“<”利用标记/重置:
import java.io.*;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
public class Demo2 {
private static char[] UTF32BE = {0x00, 0x00, 0xFE, 0xFF};
private static char[] UTF32LE = {0xFF, 0xFE, 0x00, 0x00};
private static char[] UTF16BE = {0xFE, 0xFF};
private static char[] UTF16LE = {0xFF, 0xFE};
private static char[] UTF8 = {0xEF, 0xBB, 0xBF};
public static void main(String[] args) throws Exception {
// Create an XML document with a BOM
FileOutputStream fos = new FileOutputStream("bom.xml");
writeBOM(fos, UTF16BE);
OutputStreamWriter oswUTF8 = new OutputStreamWriter(fos, "UTF-8");
oswUTF8.write("<root/>");
oswUTF8.close();
// Create a Source based on a Reader to simulate source.getRequest()
StreamSource attachment = new StreamSource(new FileReader(new File("bom.xml")));
// Wrap reader in BufferedReader so it will support marking
Reader reader = new BufferedReader(attachment.getReader());
// Remove the BOM
removeBOM(reader);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
t.transform(new StreamSource(reader), new StreamResult(System.out));
}
private static void writeBOM(OutputStream os, char[] bom) throws Exception {
for(int x=0; x<bom.length; x++) {
os.write((byte) bom[x]);
}
}
private static Reader removeBOM(Reader reader) throws Exception {
reader.mark(1);
char[] potentialStart = new char[1];
reader.read(potentialStart);
if('<' == potentialStart[0]) {
reader.reset();
return reader;
} else {
return removeBOM(reader);
}
}
}