我在基于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)时,该元素将被解组为null整数。不会生成SOAPFault,也无法将十进制值与WebService中的空值区分开来。 这可能是JAXB实施中的缺陷还是我做错了什么?
答案 0 :(得分:3)
它可能是JAXB实现中的缺陷还是我正在做某事 错?
这不是JAXB (JSR-222)实施中的缺陷。这是JAX-WS如何配置为使用JAXB的结果。我将在下面举例说明。
<强>根强>
下面是一个域对象,其字段与您问题中的字段匹配。我已从type=Integer.class
注释中删除@XmlElement
,因为它是多余的。
import javax.xml.bind.annotation.*;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
@XmlElement(name = "Quantity", required = true, nillable = true)
protected Integer quantity;
}
<强>演示强>
JAXB提供了在ValidationEventHandler
上设置Unmarshaller
的功能,让您可以控制如何处理解组错误。
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
表示我们不希望在unmarshal
被提出时继续ValidationEvent
,我们可以进行以下更改。
@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
答案 1 :(得分:0)
我在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类中创建的metodh 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);
}