我需要复制由 Oracle 生成并部署在 Oracle 上的旧 Web 服务。新服务将用 Java 编写并部署在 Tomcat 上。原始服务的所有功能必须完全相同,这意味着我无法更改 wsdl 或响应对象的格式。
我正在使用 cxf 和 wsdl2java 来生成存根的类和服务。我的问题是原始 wsdl 使用了“any”元素,并且响应中有不寻常的 xml 代码填充到该元素中。我似乎无法重现与原始服务相同的响应。
wsdl 中的请求和响应类型定义:
<complexType name="getNewServiceXML">
<sequence>
<element name="pNum" nillable="true" type="decimal" />
</sequence>
</complexType>
<complexType name="getNewServiceXMLResponse">
<sequence>
<element name="result" nillable="true">
<complexType>
<sequence>
<any />
</sequence>
</complexType>
</element>
</sequence>
</complexType>
CXF 生成 GetNewServiceXMLResponse 类,在该类中是 Result 类。在结果中可以找到任何字段。
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "getNewServiceXMLResponse", propOrder = {
"result"
})
public class GetNewServiceXMLResponse {
@XmlElement(required = true, nillable = true)
protected GetNewServiceXMLResponse.Result result;
...
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"any"
})
public static class Result {
@XmlAnyElement(lax = true)
protected Object any;
...
这是预期的响应格式:
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns0="http://dev.mycompany.com/NewService.wsdl/types/">
<env:Body>
<ns0:getNewServiceXMLResponseElement>
<ns0:result>
<result>
<ROWSET>
<ROW num="0">
<FIELD1>3649648</FIELD1>
<FIELD2>WEEK</FIELD2>
<FIELD3>TTN476273</FIELD3>
</ROW>
<ROW num="1">
<FIELD1>3649650</FIELD1>
<FIELD2>WEEK</FIELD2>
<FIELD3>TTN476273</FIELD3>
</ROW>
<ROW num="2">
<FIELD1>540969</FIELD1>
<FIELD2>DAY</FIELD2>
<FIELD3>null</FIELD3>
</ROW>
</ROWSET>
</result>
</ns0:result>
</ns0:getNewServiceXMLResponseElement>
</env:Body>
我被 ROW num="X" 标签挂断了。我以前在 SOAP 服务中没有看到过这种情况。因此,我尝试手动创建 ROWSET xml 并将其放入字符串中。然后将字符串通过 any 元素传回。为了让它工作,我将它包装在一个 JAXBElement 中,以便它可以成功解组。
List<Object> dataRecords = manager.getDataRecords(request.getPNum());
GetNewServiceXMLResponse response = new GetNewServiceXMLResponse();
String str = manager.convertDataToString(dataRecords);
JAXBElement<String> obj = new JAXBElement<String>(new QName("result"), String.class, str);
result.setAny(obj);
response.setResult(result);
现在这种方法的问题是字符串被编码(因为它是一个字符串......),你最终得到的是< blah blah >
etc 而不是漂亮的 xml。
<getNewServiceXMLResponseElement xmlns="http://dev.mycompany.com/NewService.wsdl/types/">
<result>
<result xmlns:ns2="http://dev.mycompany.com/NewService.wsdl/types/" xmlns=""><ROWSET>..snip..</ROWSET></result>
</result>
</getNewServiceXMLResponseElement>
所以接下来我尝试创建一个文档(如其他帖子所建议)
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new InputSource(new StringReader(str)));
JAXBElement<Document> obj = new JAXBElement<Document>(new QName("result"),Document.class,document);
这给我一个错误:
WARNING: Interceptor has thrown exception, unwinding now
org.apache.cxf.interceptor.Fault: Marshalling Error: org.w3c.dom.Document is not known to this context
at org.apache.cxf.jaxb.JAXBEncoderDecoder.marshall(JAXBEncoderDecoder.java:159)
at org.apache.cxf.jaxb.io.DataWriterImpl.write(DataWriterImpl.java:169)
at org.apache.cxf.interceptor.AbstractOutDatabindingInterceptor.writeParts(AbstractOutDatabindingInterceptor.java:105)
at org.apache.cxf.interceptor.BareOutInterceptor.handleMessage(BareOutInterceptor.java:68)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:236)
at org.apache.cxf.interceptor.OutgoingChainInterceptor.handleMessage(OutgoingChainInterceptor.java:74)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:236)
at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:104)
at org.apache.cxf.transport.servlet.ServletDestination.invoke(ServletDestination.java:99)
at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:452)
at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:196)
at org.apache.cxf.transport.servlet.AbstractCXFServlet.invoke(AbstractCXFServlet.java:220)
at org.apache.cxf.transport.servlet.AbstractCXFServlet.doPost(AbstractCXFServlet.java:153)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
at org.apache.cxf.transport.servlet.AbstractCXFServlet.service(AbstractCXFServlet.java:211)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at com.googlecode.psiprobe.Tomcat70AgentValve.invoke(Tomcat70AgentValve.java:38)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.ajp.AjpProcessor.process(AjpProcessor.java:200)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:585)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
Caused by: javax.xml.bind.MarshalException
- with linked exception:
[javax.xml.bind.JAXBException: org.w3c.dom.Document is not known to this context]
at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:318)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:244)
at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:75)
at org.apache.cxf.jaxb.JAXBEncoderDecoder.writeObject(JAXBEncoderDecoder.java:444)
at org.apache.cxf.jaxb.JAXBEncoderDecoder.marshall(JAXBEncoderDecoder.java:138)
... 31 more
Caused by: javax.xml.bind.JAXBException: org.w3c.dom.Document is not known to this context
at com.sun.xml.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.java:246)
at com.sun.xml.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.java:261)
at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl$1.serializeBody(ElementBeanInfoImpl.java:144)
at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl$1.serializeBody(ElementBeanInfoImpl.java:189)
at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeBody(ElementBeanInfoImpl.java:315)
at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeRoot(ElementBeanInfoImpl.java:322)
at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeRoot(ElementBeanInfoImpl.java:72)
at com.sun.xml.bind.v2.runtime.property.SingleReferenceNodeProperty.serializeBody(SingleReferenceNodeProperty.java:111)
at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:332)
at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:699)
at com.sun.xml.bind.v2.runtime.property.SingleElementNodeProperty.serializeBody(SingleElementNodeProperty.java:152)
at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:332)
at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:699)
at com.sun.xml.bind.v2.runtime.property.SingleElementNodeProperty.serializeBody(SingleElementNodeProperty.java:152)
at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl$1.serializeBody(ElementBeanInfoImpl.java:157)
at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl$1.serializeBody(ElementBeanInfoImpl.java:189)
at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeBody(ElementBeanInfoImpl.java:315)
at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeRoot(ElementBeanInfoImpl.java:322)
at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeRoot(ElementBeanInfoImpl.java:72)
at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:494)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:315)
... 35 more
Caused by: javax.xml.bind.JAXBException: org.w3c.dom.Document is not known to this context
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getBeanInfo(JAXBContextImpl.java:621)
at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl$1.serializeBody(ElementBeanInfoImpl.java:141)
... 53 more
怎么办?我是否走错了路,试图将 XML 作为其他内容(如字符串)发送?有没有办法更好地复制 ROW num="X" 行为?如果无法更改 wsdl(以及因此的基础对象),我还没有找到答案。
附加信息:Tomcat 7、Java 1.6