【问题标题】:xs:int unmarshalled to null for decimal valuesxs:int 对于十进制值解组为 null
【发布时间】:2013-02-06 23:51:18
【问题描述】:

我遇到了一个与基于 JAX-WS 的 WebService 中的解组过程相关的问题。在 WSDL 文件中有一个元素定义为

    <element name="quantity" nillable="true" type="int" />

在相关的JAVA类中定义为:

   @XmlElement(name = "Quantity", required = true, type = Integer.class, nillable = true)
   protected Integer quantity;

当此元素的 XML 值是十进制数 (3.4) 的表示形式时,该元素将被解组为空整数。不会生成 SOAPFault,并且无法在 WebService 中区分十进制值和空值。 这可能是 JAXB 实现中的缺陷还是我做错了什么?

【问题讨论】:

    标签: jaxb jax-ws


    【解决方案1】:

    这可能是 JAXB 实现中的缺陷还是我正在做某事 错了吗?

    这不是JAXB (JSR-222) 实现中的缺陷。这是将 JAX-WS 配置为使用 JAXB 的结果。下面我用一个例子来演示。

    下面是一个域对象,其字段与您问题中的字段相匹配。我已经从@XmlElement 注释中删除了type=Integer.class,因为它是多余的。

    import javax.xml.bind.annotation.*;
    
    @XmlRootElement
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Root {
    
        @XmlElement(name = "Quantity", required = true, nillable = true)
        protected Integer quantity;
    
    }
    

    演示

    JAXB 提供了在Unmarshaller 上设置ValidationEventHandler 的功能,让您可以控制如何处理解组错误。

    import java.io.StringReader;
    import javax.xml.bind.*;
    
    public class Demo {
    
        public static void main(String[] args) throws Exception {
            JAXBContext jc = JAXBContext.newInstance(Root.class);
    
            Unmarshaller unmarshaller = jc.createUnmarshaller();
            unmarshaller.setEventHandler(new ValidationEventHandler() {
    
                @Override
                public boolean handleEvent(ValidationEvent event) {
                    System.out.println(event.getMessage());
                    return true;
                }
            });
    
            StringReader xml = new StringReader("<root><Quantity>3.4</Quantity></root>");
            Root root = (Root) unmarshaller.unmarshal(xml);
    
            Marshaller marshaller = jc.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.marshal(root, System.out);
        }
    
    }
    

    输出

    在专家组中,我们认为无效元素数据很常见,并且每次遇到这种情况时 JAXB 都不应失败,但您可以看到引发了 ValidationEvent

    Not a number: 3.4
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <root>
        <Quantity xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
    </root>
    

    更新演示

    如果我们更新ValidationEventHandler 以表明我们不希望在引发ValidationEvent 时继续unmarshal,我们可以进行以下更改。

            @Override
            public boolean handleEvent(ValidationEvent event) {
                System.out.println(event.getMessage());
                return false;
            }
    

    更新输出

    现在出现以下输出。

    Not a number: 3.4
    Exception in thread "main" javax.xml.bind.UnmarshalException: Not a number: 3.4
     - with linked exception:
    [java.lang.NumberFormatException: Not a number: 3.4]
        at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:647)
        at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleError(UnmarshallingContext.java:676)
        at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleError(UnmarshallingContext.java:672)
        at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.handleParseConversionException(Loader.java:256)
        at com.sun.xml.internal.bind.v2.runtime.unmarshaller.LeafPropertyLoader.text(LeafPropertyLoader.java:54)
        at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.text(UnmarshallingContext.java:499)
        at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.processText(SAXConnector.java:166)
        at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.endElement(SAXConnector.java:139)
        at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(AbstractSAXParser.java:606)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(XMLDocumentFragmentScannerImpl.java:1742)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2900)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:607)
        at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:116)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:489)
        at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:835)
        at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:764)
        at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:123)
        at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1210)
        at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:568)
        at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:203)
        at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:175)
        at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:157)
        at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:214)
        at forum14741140.Demo.main(Demo.java:22)
    Caused by: java.lang.NumberFormatException: Not a number: 3.4
        at com.sun.xml.internal.bind.DatatypeConverterImpl._parseInt(DatatypeConverterImpl.java:101)
        at com.sun.xml.internal.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl$17.parse(RuntimeBuiltinLeafInfoImpl.java:713)
        at com.sun.xml.internal.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl$17.parse(RuntimeBuiltinLeafInfoImpl.java:711)
        at com.sun.xml.internal.bind.v2.runtime.reflect.TransducedAccessor$CompositeTransducedAccessorImpl.parse(TransducedAccessor.java:232)
        at com.sun.xml.internal.bind.v2.runtime.unmarshaller.LeafPropertyLoader.text(LeafPropertyLoader.java:50)
        ... 19 more
    

    【讨论】:

    • 非常感谢@Blaise Doughan。我理解给出的示例,但我仍在处理将我的 WebService 配置为使用自定义 ValidationEventHandler 的问题。解组器在我的源代码之外创建,当然我不能调用 unmarshaller.setEventHandler。
    【解决方案2】:

    我回答了这个问题:https://stackoverflow.com/a/30617814/3632201

    上周我一直在努力解决这个问题,最后我找到了一个可行的解决方案。诀窍是 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);
      }
    

    【讨论】:

      猜你喜欢
      • 2014-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多