【问题标题】:How to set custom ValidationEventHandler on JAXB unmarshaller when using annotations使用注释时如何在 JAXB 解组器上设置自定义 ValidationEventHandler
【发布时间】:2014-05-20 04:52:58
【问题描述】:

我们将 JAX-WS 与 JAXB 结合使用来接收和解析 XML Web 服务调用。这都是基于注解的,即我们永远不会在我们的代码中获取 JAXBContext。我需要在 unmarshaller 上设置一个自定义的 ValidationEventHandler,这样如果特定字段的日期格式不被接受,我们就可以捕获错误并在响应中报告一些不错的内容。我们在有问题的字段上有一个 XMLJavaTypeAdapter,它进行解析并引发异常。我看不到如何使用我们拥有的基于注释的配置将 ValidationEventHandler 设置到解组器上。有什么想法吗?

注意:与this comment 相同的问题目前没有答案。

【问题讨论】:

  • @BlaiseDoughan 我希望我能就我们正在尝试的事情是否可能得到您的意见。有什么想法吗?
  • 有人吗?似乎注释中的这些“漏洞”支持某些功能(结合注释的通常很好的方面,它使您远离引导细节)意味着如果您需要,您不能真正使用注释那些功能。我一定是看错了,我敢肯定。
  • 您是否设法获得有关此问题的任何信息?在这里遇到同样的问题。
  • 很遗憾没有。关于这个问题,我在网上搜索了几天。 @BlaiseDoughan 似乎是这方面的大师,但不幸的是我无法得到回应。最后,我们将采用部分(阅读:糟糕)解决方案,其中 XMLJavaTypeAdapter 确实进行解析并在需要的地方抛出异常,这些只是在响应中转换为 SOAP 错误。响应文本确实说“blah 不是有效日期”或其他任何内容,但它不指示哪个字段(如果您有多个相同的数据类型会出现问题),并且它包含丑陋的堆栈跟踪。
  • 好的,非常感谢。如果我更幸运,会在这里添加答案。

标签: java validation jaxb jax-ws unmarshalling


【解决方案1】:

上周我一直在努力解决这个问题,最后我找到了一个可行的解决方案。诀窍是 JAXB 在使用 @XmlRootElement 注释的对象中查找方法 beforeUnmarshal 和 afterUnmarshal。

..
@XmlRootElement(name="MSEPObtenerPolizaFechaDTO")
@XmlAccessorType(XmlAccessType.FIELD)

public class MSEPObtenerPolizaFechaDTO implements Serializable {
..

public void beforeUnmarshal(Unmarshaller unmarshaller, Object parent) throws JAXBException, IOException, SAXException {
        unmarshaller.setSchema(Utils.getSchemaFromContext(this.getClass()));
        unmarshaller.setEventHandler(new CustomEventHandler());
  }

  public void afterUnmarshal(Unmarshaller unmarshaller, Object parent) throws JAXBException {
        unmarshaller.setSchema(null);
        unmarshaller.setEventHandler(null);
  }

使用这个 ValidationEventHandler:

public class CustomEventHandler implements ValidationEventHandler{

      @Override
      public boolean handleEvent(ValidationEvent event) {
            if (event.getSeverity() == event.ERROR ||
                        event.getSeverity() == event.FATAL_ERROR)
            {
                  ValidationEventLocator locator = event.getLocator();
                  throw new RuntimeException(event.getMessage(), event.getLinkedException());
            }
            return true;
      }
}

}

这是在你的 Utility 类中创建的 getSchemaFromContext 方法:

  @SuppressWarnings("unchecked")
  public static Schema getSchemaFromContext(Class clazz) throws JAXBException, IOException, SAXException{
        JAXBContext jc = JAXBContext.newInstance(clazz);
        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);
              sources[i] = new StreamSource(new ByteArrayInputStream(out.toByteArray()), "");
        }
        SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        return sf.newSchema(sources);
  }

【讨论】:

  • 您的解决方案效果很好!我收到错误消息,我也可以对其进行修改,如果可能的话,请您帮助我,由于发生了哪个错误,我该如何获取该字段?我想在错误消息中附加字段名称
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-03
  • 1970-01-01
  • 2012-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-28
相关资源
最近更新 更多