【问题标题】:Duplicate Tag accepted by JAXBJAXB 接受的重复标签
【发布时间】:2020-04-22 17:03:53
【问题描述】:

在我们的应用程序中,用户正在发送如下 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 并使用第二个 MessageHeader 对象填充对象。请注意 MessageHeader 不是 List 类型。 有没有办法阻止 JAXB 像这样运行,它应该抛出 ParsingException。由于某种原因,我们不能在解析之前使用 xml 的模式验证。但是有什么方法可以指示 JAXB 解析器检查目标类型是否为列表并抛出错误。

非常感谢。

【问题讨论】:

    标签: java xml xsd jaxb unmarshalling


    【解决方案1】:

    JAXB 是一种为 XML Schema 模型生成 Java 类的技术。因此,JAXB 执行的任何验证都将使用 XML 模式验证。

    有没有办法阻止 JAXB 像这样运行它应该抛出 ParsingException

    没有。除非您在 JAXB 解组器中启用模式验证。

    由于某种原因,我们无法在解析之前对 xml 进行架构验证。

    您应该提供原因,或者不提及。这是一个非常奇怪的规则,因为 JAXB 是一种 XML Schema 技术,而 Java 本身就支持 XSD 验证。

    请注意 MessageHeader 不是 List 类型。

    List 类型适用于简单 类型。 MessageHeader 基于复杂类型。

    我建议您忽略“无模式验证”的规则。在 MessageHeader 上设置 maxOccurs=1 并在 JAXB 解组器上启用模式验证。

    【讨论】:

      【解决方案2】:

      正如已经指出的,要走的路是使用模式验证。生成一个模式并在 MessageHeader 上设置 maxOccurs="1"。您可以使用以下方式设置架构:

      unmarshaller.setSchema(schema);
      

      如果由于某种奇怪的原因您绝对不能使用架构验证,您可以在使用 Unmarshaller.Listener 的实现处理重复的 MessageHeader 时做一个丑陋的 hack 来抛出异常

      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;
              }
          }
      });
      

      虽然这应该可行,但我坚持认为您应该重新考虑架构验证。

      还请注意,解组器会默默地忽略某些事件,例如遇到未映射的 en 元素时。那不是您的情况,因为您的用例中没有映射问题,但是,例如,如果您收到消息:

      <Decl>
        <MessageHeader>
           <A>Info1</A>
           <C>Info3</C>
        </MessageHeader>
      </Decl>
      

      使用元素 &lt;C&gt; 而不是 &lt;B&gt;,您最终会得到值 A = Info1 和 B = null,因为 JAXB 会默默地忽略元素 &lt;C&gt;

      您可以捕获这些事件并抛出异常,将ValidationEventHandler 设置为返回false

      unmarshaller.setEventHandler(new ValidationEventHandler() {
          @Override
          public boolean handleEvent(ValidationEvent event) {
              // log event ....
              return false;
          }
      });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-27
        • 1970-01-01
        相关资源
        最近更新 更多