JAXB解组在InputStream末尾的SAXParseException中结束

时间:2018-05-04 13:35:41

标签: xml svn xsd jaxb jsch

我正在开发一个简短的应用程序,它应该从SVN存储库中的项目读出一些元数据。

SVN本身提供了一些命令行工具。其中一个工具是" SVN列表"。如果给出选项--xml,list命令可以传递xml。因此,如果您想要汇总或累积一些数据,您可以使用linux(在我们的示例中为OS)命令。但是,如果您希望拥有不同的数据并且存储库变得更大,那么它就会变得过于复杂和缓慢(从我的角度来看)。

我的解决方案使用JSch建立连接并检索给定存储库路径的xml。下一步是将带有JAXB的xml解组到类中,然后遍历对象(理论上)。

所以我有 - xml

 <?xml version="1.0"?>
    <lists>
    <list
       path="<URL>/svn/Repository/<anyProject>/trunk">
    </list>
    </lists>
  • xsd

        

    <xsd:complexType name="listsType">
        <xsd:sequence>
            <xsd:element name="list" type="listType"/>
        </xsd:sequence>
    </xsd:complexType>
    
    <xsd:complexType name="listType">
        <xsd:sequence>
            <xsd:element name="entry" type="entryType" minOccurs="0" maxOccurs="unbounded"/>
        </xsd:sequence>
    <xsd:attribute name="path" type="xsd:string"/>
    </xsd:complexType>
    
    <xsd:complexType name="entryType">
        <xsd:sequence>
            <xsd:element name="name" type="xsd:string"/>
            <xsd:element name="size" type="xsd:integer"  minOccurs="0" maxOccurs="1" />
            <xsd:element name="commit" type="commitType"/>
        </xsd:sequence>
        <xsd:attribute name="kind" type="xsd:string" />
    </xsd:complexType>
    
    <xsd:complexType name="commitType">
        <xsd:sequence>
            <xsd:element name="author" type="xsd:string"/>
            <xsd:element name="date" type="xsd:dateTime"/>          
        </xsd:sequence>
        <xsd:attribute name="revision" type="xsd:long"/>
    </xsd:complexType>  
    

  • 映射的类(指xsd)

但每当我为解组而拍摄时,我都会收到这个例外:

[org.xml.sax.SAXParseException; lineNumber: 6; columnNumber: 9; Content is not allowed in prolog]
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.createUnmarshalException(AbstractUnmarshallerImpl.java:335)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.createUnmarshalException(UnmarshallerImpl.java:563)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:249)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:214)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:157)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:125)
    at my.organisation.repo.util.RepoJaxbUtil.unmarshal(RepoJaxbUtil.java:32)
    at my.organisation.repo.util.RepoJaxbUtil.unmarshal(RepoJaxbUtil.java:25)
    at my.organisation.repo.tool.RepoFull.start(RepoFull.java:114)
    at my.organisation.repo.managing.RepoToolManager.start(RepoToolManager.java:107)
    at my.organisation.repo.managing.RepoToolManager.main(RepoToolManager.java:43)
Caused by: org.xml.sax.SAXParseException; lineNumber: 6; columnNumber: 9; Content ist nicht zulässig in angehängtem Abschnitt.
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:203)
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(ErrorHandlerWrapper.java:177)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:400)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:327)
    at com.sun.org.apache.xerces.internal.impl.XMLScanner.reportFatalError(XMLScanner.java:1472)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$TrailingMiscDriver.next(XMLDocumentScannerImpl.java:1431)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:602)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:505)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:841)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:770)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:643)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:243)
... 8 more

我已经在这里和其他地方进行过很多研究 - 但是从来没有找到关于流程结束的东西(我不天真 - 我知道Streams或Arrays等现在已经结束了流程)

更多细节: 从JSch我收到一个InputStream,它存储在ByteBuffer中:

public ByteBuffer sendCommandForInputStream(String command) {
        try {
            Channel channel = sesConnection.openChannel("exec");
            ((ChannelExec) channel).setCommand(command);
            InputStream commandOutput = channel.getInputStream();
            channel.connect();

            byte[] bytes = IOUtils.toByteArray(commandOutput);

            ByteBuffer result = ByteBuffer.wrap(bytes);
            channel.disconnect();
            return result;
        }
        catch (IOException ioX) {
            logWarning(ioX.getMessage());
            return null;
        }
        catch (JSchException jschX) {
            logWarning(jschX.getMessage());
            return null;
        }
    }

我必须使用缓冲区,因为如果我在打开它后关闭连接,我不是100%,结果是完整的。

unmarshal方法也需要一个InputStream - 所以我必须&#34;转换&#34;回来了。也许这里把bug放在任何地方:

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import org.xml.sax.SAXException;

public class RepoJaxbUtil {
    public static <T> T unmarshal(ByteBuffer xml, Class<T> clss) throws JAXBException, SAXException, UnsupportedEncodingException {
        SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        Schema schema = schemaFactory.newSchema(new File("subversionRepo.xsd"));
        JAXBContext jaxbContext = JAXBContext.newInstance(clss.getPackage().getName());
        InputStream xmlS = newInputStream(xml);
        return unmarshal(jaxbContext, schema, xmlS, clss);
    }

    public static <T> T unmarshal(JAXBContext jaxbContext, Schema schema, InputStream xml, Class<T> clss) throws JAXBException, UnsupportedEncodingException {
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        unmarshaller.setSchema(schema);
        StreamSource xmlSource = new StreamSource(xml);
        return clss.cast(unmarshaller.unmarshal(xmlSource));
    }

    public static InputStream newInputStream(final ByteBuffer buf) {
        return new InputStream() {
            public synchronized int read() throws IOException {
                if (!buf.hasRemaining()) {
                    return -1;
                }
                return buf.get();
            }

            public synchronized int read(byte[] bytes, int off, int len) throws IOException {
                // Read only what's left
                len = Math.min(len, buf.remaining());
                buf.get(bytes, off, len);
                return len;
            }
        };
    }
  }
/*(The transfer to a InputSource does not work => just the line from 6 to 7 and the other way around)*/

有人知道如何解决这个问题吗?

1 个答案:

答案 0 :(得分:0)

所以我在@lexicore之后找到了一个解决方案(谢谢),说明给定的xml无效。

xml本身是正确的,但JSch Handler类中的处理是不正确的。问题放在RepoJaxbUtil类中的方法'newInputStream(final ByteBuffer buf)'中。在输入流的最后一个字符之后,我设置'-1',这导致了无效的xml内容。

我在JSch SSH Handler中更改了返回类型和名称:

     public StringBuffer sendCommandForBuffer(String command) {

        StringBuffer outputBuffer = new StringBuffer();
        try {
            Channel channel = sesConnection.openChannel("exec");
            ((ChannelExec) channel).setCommand(command);
            InputStream commandOutput = channel.getInputStream();
            channel.connect();
            int readByte = commandOutput.read();

            while (readByte != 0xffffffff) {
                outputBuffer.append((char) readByte);                
                readByte = commandOutput.read();
            }

            return outputBuffer;
        }
        catch (IOException ioX) {
            logWarning(ioX.getMessage());
            return null;
        }
        catch (JSchException jschX) {
            logWarning(jschX.getMessage());
            return null;
        }
    }

另一方面,为了简单起见,我回顾了RepoJaxbUtil类并“删除”了线程安全(我很确定这不会导致问题):

public class RepoJaxbUtil {

     public static Object unmarshal(StringBuffer xml, Class clss) throws JAXBException, SAXException, UnsupportedEncodingException {
        SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        Schema schema = schemaFactory.newSchema(new File("subversionRepo.xsd"));
        JAXBContext jaxbContext = JAXBContext.newInstance(clss.getPackage().getName());
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        unmarshaller.setSchema(schema);
        StreamSource source = new StreamSource(new StringReader(xml.toString()));
        return unmarshaller.unmarshal(source);
    }
}

另一个很重要的建议可能是从JAXBElement到业务逻辑类的调用和转换到目标对象类型(可能它不好 - 但它以我的方式工作):

xmlReturn = instance.sendCommandForBuffer(cmd);
                ListsType repoLists;

                try {
                    JAXBElement lt = (JAXBElement) RepoJaxbUtil.unmarshal(xmlReturn, ListsType.class);
                    LOG.info(lt.toString());
                    repoLists = (ListsType) lt.getValue();

                    // any other business logic here

                    LOG.info("entryCount: " + repoLists.getList().getEntryType().size());
                }
                catch (JAXBException e) {
                    LOG.warn("JAXBException occured on project [" + project + "]");
                    e.printStackTrace();
                }
                catch (SAXException e) {
                    LOG.warn("SAXException occured on project [" + project + "]");
                    e.printStackTrace();
                }
                catch (UnsupportedEncodingException e) {
                    LOG.warn("UnsupportedEncodingException occured on project [" + project + "]");
                    e.printStackTrace();
                }