2

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 クラスがあります。any フィールドは 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);

現在、そのアプローチの問題は、文字列がエンコードされ(文字列であるため...)&lt; blah blah &gt;、きれいなxmlではなくetcになってしまうことです。

<getNewServiceXMLResponseElement xmlns="http://dev.mycompany.com/NewService.wsdl/types/">
  <result>
    <result xmlns:ns2="http://dev.mycompany.com/NewService.wsdl/types/" xmlns="">&lt;ROWSET&gt;..snip..&lt;/ROWSET&gt;</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

4

1 に答える 1

1

他の誰かが私と同様の問題を抱えている場合に備えて、ここに私が思いついた解決策があります. きれいではありませんが、機能します。

元のサービスのエンドポイントとまったく同じように見えるリクエスト マッピングを使用して、基本的な Spring MVC Web アプリケーションを作成しました。コントローラー クラスで、入力を解析し、データベースから結果レコードを取得してから、データから xml 文字列を手動で作成します。

@RequestMapping(value = "/getNewService", method = RequestMethod.POST)
public ModelAndView getNewServicePost() {
    StringWriter writer = new StringWriter();
    try {
        IOUtils.copy(request.getInputStream(), writer, "UTF-8");
    } catch (Exception e) {
        e.printStackTrace();
    }
    String theString = writer.toString();
    int pNum = XMLUtil.extractNum(theString);
    List<Object> results = XMLDaoLayer.getResults(pNum);
    String message = XMLUtil.convertListToResponse(results);
    return new ModelAndView("response","message",message);
}

response.jsp ページは次のようになります。

<%@ page contentType="text/xml" %>${message}

SoapUI は、「エンドポイント」にアクセスして結果を表示するのに問題はなく、基本的に違いがわかりませんでした。

明らかに、これはベスト プラクティスの例ではありません。サービスのインターフェースは何年も変更されておらず、プロセス全体が完全に置き換えられるまでは何も変更されないため、実際の Web サービスを設計することのすべての利点/利点などはそれほど重要ではありません。私たちはそれが機能することを望んでいました。

于 2013-09-02T03:38:33.410 に答える