我如何在jaxb中解体并享受架构验证而无需使用显式架构文件

2022-09-04 02:54:47

我正在使用 jaxb 进行应用程序配置

我觉得我正在做一些非常歪曲的事情,我正在寻找一种不需要实际文件或此事务的方法。

正如您在代码 I 中看到的:

1.从我的JaxbContext(实际上从我的类注释)创建一个模式到文件中 2.设置这个模式文件,以便在我取消marshal时允许真正的验证

JAXBContext context = JAXBContext.newInstance(clazz);
Schema mySchema = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(schemaFile);
jaxbContext.generateSchema(new MySchemaOutputResolver()); // ultimately creates schemaFile   
Unmarshaller u = m_context.createUnmarshaller();
u.setSchema(mySchema);
u.unmarshal(...);

你们中是否有人知道如何验证 jaxb 而无需创建位于计算机中的模式文件?

我是否需要创建一个用于验证的模式,当我通过JaxbContect.generateSchema获得它时,它看起来是多余的?

你是怎么做到的?


答案 1

关于上面的 ekeren 解决方案,在单个线程中使用 PipedOutputStream/PipedInputStream 不是一个好主意,以免缓冲区溢出并导致死锁。ByteArrayOutputStream/ByteArrayInputStream 可以工作,但是如果您的 JAXB 类生成多个模式(在不同的命名空间中),则需要多个 StreamSource。

我最终得到了这个:

JAXBContext jc = JAXBContext.newInstance(Something.class);
final List<ByteArrayOutputStream> outs = new ArrayList<ByteArrayOutputStream>();
jc.generateSchema(new SchemaOutputResolver(){
    @Override
    public Result createOutput(String namespaceUri, String suggestedFileName) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        outs.add(out);
        StreamResult streamResult = new StreamResult(out);
        streamResult.setSystemId("");
        return streamResult;
    }});
StreamSource[] sources = new StreamSource[outs.size()];
for (int i=0; i<outs.size(); i++) {
    ByteArrayOutputStream out = outs.get(i);
    // to examine schema: System.out.append(new String(out.toByteArray()));
    sources[i] = new StreamSource(new ByteArrayInputStream(out.toByteArray()),"");
}
SchemaFactory sf = SchemaFactory.newInstance( XMLConstants.W3C_XML_SCHEMA_NS_URI );
m.setSchema(sf.newSchema(sources));
m.marshal(docs, new DefaultHandler());  // performs the schema validation

答案 2

我遇到了确切的问题,并在Apache Axis 2源代码中找到了解决方案:

protected List<DOMResult> generateJaxbSchemas(JAXBContext context) throws IOException {
    final List<DOMResult> results = new ArrayList<DOMResult>();
    context.generateSchema(new SchemaOutputResolver() {
        @Override
        public Result createOutput(String ns, String file) throws IOException {
            DOMResult result = new DOMResult();
            result.setSystemId(file);
            results.add(result);
            return result;
        }
     });
    return results;
}

在获取表示架构的 DOMResult 列表后,您需要先将它们转换为 DOMSource 对象,然后才能将它们馈送到架构生成器中。第二步可能如下所示:

Unmarshaller u = myJAXBContext.createUnmarshaller();
List<DOMSource> dsList = new ArrayList<DOMSource>();   
for(DOMResult domresult : myDomList){
    dsList.add(new DOMSource(domresult.getNode()));
}
String schemaLang = "http://www.w3.org/2001/XMLSchema";
SchemaFactory sFactory = SchemaFactory.newInstance(schemaLang);
Schema schema = sFactory.newSchema((DOMSource[]) dsList.toArray(new DOMSource[0]));
u.setSchema(schema);            

推荐