Java 如何在不使用显式模式文件的情况下在jaxb中解组并享受模式验证
我将jaxb用于我的应用程序配置 我觉得我在做一些非常不正当的事情,我正在寻找一种不需要实际文件或这笔交易的方法 正如您在代码I中看到的: 1.从我的JaxbContext(实际上是从我的类注释)将模式创建到文件中 2.设置此架构文件,以便在解组时允许真正的验证Java 如何在不使用显式模式文件的情况下在jaxb中解组并享受模式验证,java,xsd,jaxb,Java,Xsd,Jaxb,我将jaxb用于我的应用程序配置 我觉得我在做一些非常不正当的事情,我正在寻找一种不需要实际文件或这笔交易的方法 正如您在代码I中看到的: 1.从我的JaxbContext(实际上是从我的类注释)将模式创建到文件中 2.设置此架构文件,以便在解组时允许真正的验证 JAXBContext context = JAXBContext.newInstance(clazz); Schema mySchema = SchemaFactory.newInstance(XMLConstants.W3C_XML
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获取模式时,它看起来是多余的,我需要创建一个模式进行验证吗
如何做到这一点?我相信您只需要在解组器上设置一个
验证EventHandler
。大概是这样的:
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 = 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);
在您的代码中:
Unmarshaller u = m_context.createUnmarshaller();
u.setEventHandler(new JAXBValidator());
u.unmarshal(...);
关于上面ekeren的解决方案,在单个线程中使用PipedOutputStream/PipedInputStream不是一个好主意,以免缓冲区溢出并导致死锁。ByteArrayOutputStream/ByteArrayInputStream可以工作,但如果您的JAXB类生成多个模式(在不同的名称空间中),则需要多个流源 我的结局是:
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
jaxbcontextjc=JAXBContext.newInstance(Something.class);
最终列表=新的ArrayList();
jc.generateSchema(新的SchemaOutputResolver(){
@凌驾
公共结果createOutput(字符串namespaceUri、字符串suggestedFileName)引发IOException{
ByteArrayOutputStream out=新建ByteArrayOutputStream();
out.添加(out);
StreamResult StreamResult=新的StreamResult(输出);
streamResult.setSystemId(“”);
返回结果;
}});
StreamSource[]sources=新的StreamSource[outs.size()];
对于(int i=0;i我遇到了确切的问题,并在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;
}
protectedlist模式(JAXBContext上下文)引发IOException{
最终列表结果=新建ArrayList();
generateSchema(新的SchemaOutputResolver(){
@凌驾
公共结果createOutput(字符串ns、字符串文件)引发IOException{
DOMResult=新的DOMResult();
result.setSystemId(文件);
结果。添加(结果);
返回结果;
}
});
返回结果;
}
在获得表示模式的DOMResults列表后,您需要将它们转换为DOMSource对象,然后才能将它们提供给模式生成器。第二步可能如下所示:
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 = 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);
Unmarshaller u=myJAXBContext.createUnmarshaller();
List dsList=new ArrayList();
for(DOMResult DOMResult:myDomList){
添加(新的DOMSource(domresult.getNode());
}
字符串schemaLang=”http://www.w3.org/2001/XMLSchema";
SchemaFactory sFactory=SchemaFactory.newInstance(schemaLang);
Schema Schema=sFactory.newSchema((DOMSource[])dsList.toArray(new-DOMSource[0]);
u、 设置模式(模式);
如果您使用jaxb2 maven插件使用maven,maven插件可以帮助您。它在生成资源阶段生成架构。为什么不从类路径资源中读取架构?我不确定我是否理解,您能否详细说明一下?我可以从类路径加载架构文件,但我正在尝试避免创建架构文件,正如您在上面看到的,我正在创建g文件并在一秒钟后使用它,我可以在完成封送处理后实际删除它。我是否遗漏了一些重要信息?感谢您的帮助感谢您的响应,就我所知,在没有架构的情况下进行封送处理时,您实际上没有验证XML。例如@XmlElement(required=true)如果没有模式,则无法验证注释。我错了吗?我假设您首先有一个模式,然后使用xjc从中生成JAXB对象。不是这样吗?即使不是这样,我相信只要所有元素都正确注释,解组器仍然可以验证。不是我从带注释的cla开始ss而不是架构。我可以使用JaxbContext上的generateSchema调用在类外创建架构。问题是,如果我不提供架构解组验证,则验证效果不佳。它会警告意外元素,但不会警告元素重复和所需元素。例如,如果要验证XML,则需要schema。您可以使用JAXB附带的schemagen一次性生成模式,而不是在运行时从上下文生成模式。谢谢Jason,您知道我是否可以生成JAXB可以验证的内存模式…我真的不想创建需要与我的应用程序打包的模式文件,我有一些遗留代码问题。Thanks,我还将我的解决方案更改为byteArrayInputStream,但我不知道有多个schema@seanf.您的解决方案运行良好,但生成结果的顺序与依赖项的顺序不匹配。例如:outs[0]可能依赖于outs[1]。因此,在创建新闻模式(源)时,它失败,因为它找不到使用前定义的必要依赖项。是否有方法确保顺序与依赖项中所需的顺序相同?(即:outs[1]在outs[0]之前生成)?在上查看我关于这个问题的帖子。谢谢。它工作得很好,没有虚假的模式文件、流等。至于为什么我们需要跳过这些晦涩难懂的障碍,让JAXB验证它到底应该做什么——因为它是XML!