在我们的应用程序中,用户正在发送一个XML,如下图所示。
<Decl>
<MessageHeader>
<A>Info</A>
<B>Info2</B>
</MessageHeader>
</Decl>
我们使用JABX unmarshller来填充java对象,但问题是当用户发送消息时,客户要求产生错误,如下图所示。
<Decl>
<MessageHeader>
<A>Info</A>
<B>Info2</B>
</MessageHeader>
<MessageHeader>
<A>Info3</A>
<B>Info4</B>
</MessageHeader>
</Decl>
JAXB成功地解开了xml的marshling,并用第二个MessageHeader对象填充了对象。请注意MessageHeader不是List类型。由于某些原因,我们不能在解析前使用xml的schema验证,但是有什么办法可以让JAXB停止这样的行为,并且抛出ParingException。但有什么办法可以让JAXB解析器检查目标类型是否为list,并抛出错误。
先谢谢你了。
JAXB是一种为XML Schema模型生成Java类的技术,因此,JAXB执行的任何验证都将使用XML Schema验证。因此,JAXB执行的任何验证都会使用XML Schema验证。
有什么办法可以阻止JAXB这样的行为,它应该抛出ParsingException。
不,除非您在JAXB unmarshaller中启用模式验证。
由于某些原因,我们不能在解析前使用xml的模式验证。
你应该提供原因,或者不提。这是一个非常奇怪的规则,因为JAXB是一种XML Schema技术,而Java对XSD验证有本地支持。
请注意MessageHeader不是List类型。
列表类型是用于 简单的 类型。MessageHeader是基于一个复杂的类型。
我建议你忽略 "没有schema validation "的规则。在MessageHeader上设置maxOccurs=1,并在JAXB unmarshaller上启用schema validation。
正如已经指出的,方法是使用模式验证。生成一个模式并在MessageHeader上设置maxOccurs="1"。你可以用模式设置。
unmarshaller.setSchema(schema);
如果因为一些奇怪的原因你绝对不能使用模式验证 你可以做一个丑陋的黑客,当一个重复的MessageHeader被处理的时候,你可以用 Unmarshaller.Listener
unmarshaller.setListener(new Unmarshaller.Listener() {
boolean messageHeaderAlreadyPresent = false;
@Override
public void beforeUnmarshal(Object target, Object parent) {
// When <Decl> is encountered, set to false
if (target instanceof Decl) {
messageHeaderAlreadyPresent = false;
} else if (target instanceof MessageHeader) {
if (messageHeaderAlreadyPresent) {
throw new RuntimeException("duplicate MessageHeader");
}
messageHeaderAlreadyPresent = true;
}
}
});
虽然这应该是可行的,但我坚持认为你应该重新考虑模式验证。
另外,请注意,unmarshaller会默默地忽略一些事件,例如当遇到没有映射的en元素时。这不是你的情况,因为在你的用例中不存在映射问题,但是,举例来说,如果你收到消息。
<Decl>
<MessageHeader>
<A>Info1</A>
<C>Info3</C>
</MessageHeader>
</Decl>
与元素 <C>
而不是 <B>
,您将以A=Info1和B=null的值结束,因为JAXB会默默地忽略元素 <C>
.
你可以捕获这些事件并抛出一个异常,设置一个 ValidationEventHandler
返回 false
unmarshaller.setEventHandler(new ValidationEventHandler() {
@Override
public boolean handleEvent(ValidationEvent event) {
// log event ....
return false;
}
});