如何在jaxb中解组并享受模式验证而不使用显式模式文件

时间:2010-04-08 22:06:31

标签: java xsd jaxb

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

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

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

1.从我的JaxbContext(实际上来自我的类​​注释)创建一个模式到一个文件 2.设置此模式文件,以便在我解组时允许进行真正的验证

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获取它时看起来多余?

你是怎么做到的?

4 个答案:

答案 0 :(得分:13)

关于上面的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

答案 1 :(得分: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;
}

并且在获得表示模式的DOMResults列表之后,您需要将它们转换为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);            

答案 2 :(得分:1)

我相信你只需要在你的unmarshaller上设置一个ValidationEventHandler。像这样:

public class JAXBValidator extends ValidationEventCollector {
    @Override
    public boolean handleEvent(ValidationEvent event) {
        if (event.getSeverity() == event.ERROR ||
            event.getSeverity() == event.FATAL_ERROR)
        {
            ValidationEventLocator locator = event.getLocator();
            // change RuntimeException to something more appropriate
            throw new RuntimeException("XML Validation Exception:  " +
                event.getMessage() + " at row: " + locator.getLineNumber() +
                " column: " + locator.getColumnNumber());
        }

        return true;
    }
}

在您的代码中:

Unmarshaller u = m_context.createUnmarshaller();
u.setEventHandler(new JAXBValidator());
u.unmarshal(...);

答案 3 :(得分:0)

如果你使用maven使用jaxb2-maven-plugin可以帮到你。它在生成资源阶段生成模式。