Вложение JAXB2 Mtom нарушено спецификацией

Я использую JAXB2 для выполнения OXM в Spring-WS. Указанный мной XSD требует, чтобы к сообщению мыла был прикреплен большой XML-файл, поэтому я использую MTOM для передачи файла и включил MTOM на моем JAXB2Marshaller.

Когда JAXB2 упорядочивает вложение MTOM, которое имеет ожидаемый тип mime text / xml, он доставляет этот элемент как объект 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.'

Это вызвано отметкой порядка байтов перед закодированным текстом в файле, хотя эта спецификация не требуется в файле с кодировкой UTF-8, она разрешена стандартом Unicode, Java не поддерживает спецификации в кодировке UTF-8. потоки.

Я могу решить эту проблему, отправив файл без спецификации, но на самом деле это невозможно, так как это вызовет проблемы с большинством продуктов Microsoft, которые вставляют спецификацию.

Существует множество обходных путей для отказа Sun / Oracle исправить эту проблему с помощью Streams, но все они требуют, чтобы вы имели доступ к Stream, исходный объект, предоставляемый JAXB2, не имеет InputStream, у него есть только объект Reader. Есть ли у меня способ решить эту проблему, либо обернув объект Sources Reader читателем, который знает, как игнорировать спецификацию в кодировке UTF-8, либо изменить способ, которым JAXB2 считывает вложение в источник, чтобы он мог игнорировать спецификация в кодировке UTF-8.

Заранее спасибо, Крейг


person Craig Warren    schedule 13.01.2011    source источник


Ответы (1)


Уловка состоит в том, чтобы «пометить» Читателя. Если ваш ридер не поддерживает маркировку, вы можете обернуть его в BufferedReader, который:

ВАРИАНТ №1 - Проверить наличие спецификации и удалить ее

Я считаю, что мой исходный код неправильно записывал спецификацию. Исходный код ниже имеет больше смысла:

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

}
person bdoughan    schedule 18.01.2011
comment
Использование десятичных чисел вместо шестнадцатеричных для ваших символьных констант - это неприглядно. - person dkarp; 18.01.2011
comment
Спасибо за попытку blaise. К сожалению, я уже пробовал это, и это не работает, читатель, который содержится в моем источнике, не реализует метку. - person Craig Warren; 18.01.2011
comment
Здесь на помощь приходит BufferedReader. Вы можете обернуть свой Reader BufferedReader, чтобы получить эту возможность: download.oracle.com/javase/6/docs/api/java/io/ - person bdoughan; 18.01.2011
comment
Спасибо за помощь, Блейз, я пробовал что-то подобное в прошлом, но безуспешно, но я попробовал. К сожалению, я продолжаю получать java.io.IOException: базовый поток ввода вернул нулевые байты. Это происходит только при наличии бомбы, при вызове сброса все в порядке. - person Craig Warren; 19.01.2011
comment
Можете ли вы предоставить подробную информацию об обходном пути стриана? Может быть, это что-то повлияет на читателей. - person bdoughan; 19.01.2011
comment
Вот где проблема упоминается в Sun / Oracle, и они указывают на обходной путь, но также отмечают, что они не исправят ошибку. bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058 - person Craig Warren; 19.01.2011
comment
К сожалению, кто-то также упоминает unicodeInputStream по этому адресу, ссылка на который содержится в отчете об ошибке koti.mbnet. fi / akini / java / unicodereader - person Craig Warren; 19.01.2011
comment
Я только что реализовал ваш демонстрационный код, чтобы проверить его, и он работает, пока вы не установите начало файла на 0xEFBBBF вместо 0xFEFF. По-прежнему возникают ошибки с: Ошибка, сообщенная синтаксическим анализатором XML: Содержимое не разрешено в прологе. - person Craig Warren; 19.01.2011
comment
Я разместил новый код. Думаю, раньше я неправильно писал спецификацию. - person bdoughan; 20.01.2011