我有一个web服务,它从xml文件中获取输入流。现在,我想要验证并使用相同的输入流读取它。我使用标记和重置。
在Glassfish和Websphere上它运行正常。但是当我使用openEJB运行集成测试时,流将在验证后关闭。我可以用一个简单的例子重现它。
我怎样才能更好地实现它?验证器实现始终是相同的。但是每个环境都使用另一种输入流实现。
public class XMLReader {
public static void main(String[] args) {
try {
XMLReader reader = new XMLReader();
InputStream stream = new BufferedInputStream(new FileInputStream(
new File("myXML.xml")));
reader.read(stream);
} catch (Exception e) {
e.printStackTrace();
}
}
public void read(InputStream xmlInputStream) throws SAXException,
IOException {
if (xmlInputStream.markSupported()) {
xmlInputStream.mark(0);
validateXML(xmlInputStream);
xmlInputStream.reset();
readXML(xmlInputStream);
}
}
private void readXML(InputStream xmlInputStream) {
// READ xmInputStream with STAX, JAXB, etc. whatever
}
private void validateXML(InputStream xmlInputStream) throws SAXException,
IOException {
Source schemaFile = new StreamSource(new File("myXSD.xsd"));
Source xmlFile = new StreamSource(xmlInputStream);
SchemaFactory schemaFactory = SchemaFactory
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(schemaFile);
Validator validator = schema.newValidator();
try {
validator.validate(xmlFile);
System.out.println("is valid");
} catch (SAXException e) {
System.out.println("is NOT valid");
System.out.println("Reason: " + e.getLocalizedMessage());
}
}
}
例外:
java.io.IOException: Stream closed
at java.io.BufferedInputStream.getBufIfOpen(BufferedInputStream.java:145)
at java.io.BufferedInputStream.reset(BufferedInputStream.java:414)
at xmltest.XMLReader.read(XMLReader.java:36)
at xmltest.XMLReader.main(XMLReader.java:27)
答案 0 :(得分:4)
不幸的是,XML解析器在读完后关闭了流。我不明白为什么会这样做,我不建议任何人关闭他们不拥有的流。可能有一个原因我无法快速掌握这一点。
无论如何,你可以做的是拥有一个BufferedInputStream,它不会关闭包装的InputSteam:
public static void main(String[] args) {
try (FileInputStream in = new FileInputStream(new File("myXML.xml"))){
XMLReader reader = new XMLReader();
InputStream stream = new BufferedInputStream(in) {
@Override
public void close() throws IOException {
// don't close
}
};
reader.read(stream);
} catch (Exception e) {
e.printStackTrace();
}
}
答案 1 :(得分:0)
这让我想到了一个覆盖SAX实现的东西,它在验证结束时关闭你的输入流。
如果您对validateXML行发表评论,那么一切正常吗?
if (xmlInputStream.markSupported()) {
xmlInputStream.mark(0);
// validateXML(xmlInputStream);
xmlInputStream.reset();
readXML(xmlInputStream);
}
如果是,你是否在openEJB类路径中的某个地方有一个xerces jar,它不是在Glassfish中?
我很确定我过去曾遇到这样的问题,但无法记住确切的问题。
答案 2 :(得分:0)
Marcel Steinbach解决方案的一个小修改:BufferedInputStream将维护一个缓冲区,这对于防止输入流关闭是不必要的。相反,您可以创建一个匿名的InputStream类,它只是将read方法委托给包含XML的可标记输入流。由于InputStream中close方法的默认实现不执行任何操作,因此流将在验证后保持打开状态:
validator.validate(new StreamSource(new InputStream() {
@Override
public int read() throws IOException {
return xmlInputStream.read();
}
}));
答案 3 :(得分:0)
如果您不确定您的输入流是否支持标记,您可以使用以下内容将其有效地复制到缓冲区中可以从中读取XML的缓冲区:
final StringWriter sw = new StringWriter(is.available());
validator.validate(new StreamSource(new InputStream() {
@Override public int read() throws IOException {
int ch = is.read();
sw.write(ch);
return ch;
}
}));
readXML(new ByteArrayInputStream(sw.toString().getBytes()));