[Java]Web Service 運用-POJO 異動

  • 3301
  • 0

[Java]Web Service 運用-POJO 異動

Server 環境:

JDK 1.6.X

Tomcat 7.0.X

CXF 2.4.X

SPRING 3.0.X

 

Client 環境:

SPRING 3.0.X

CXF 2.4.X

client-beans.xml 訂義


        factory-bean="clientFactory" factory-method="create"/>
    
    <bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">      
      <property name="serviceClass" value="my.ws.HelloWorldWS"/>
      <property name="address" value="http://localhost:8080/TWeb/CXFServlet/HelloWorld.ws"/>
    </bean>

client java code, 透過cxf實作的JaxWsProxyFactoryBean, 只要把Interface & Pojo加入專案, 至於呼叫遠端服務及序列化到物件都不用費神.


                new String[] { "my/client/client-beans.xml" });

        HelloWorldWS client = (HelloWorldWS) context.getBean("client");

        String response = client.hello("Joe");
        System.out.println("Response: " + response);

        XBean bean = client.getBean();

        //System.out.println("Response: " + bean.getX() + "," + bean.getS());
        System.out.println("Response: " + bean.getX() );
        
        client.setBean(bean);
        
        System.exit(0);

 

 

需求:

WebService 主要以 POJO 交換資訊, 測試POJO 變動時的影響

 

測試結果如下: 打勾者是完全無影響, 反之可能會發生資料錯誤或抛出異常.

  Java (spring + cxf) .NET add Web reference
增加屬性 v x
變更屬性名稱 x x
變更屬性類別 x x
刪除屬性 x x

 

挑戰 1: POJO 版本變動 Server POJO 無繼承關係

 

POJO


    private String s;
    
    private String x;
    
    private String d;

// getter and setter
}



  <xs:sequence>
    <xs:element minOccurs="0" name="d" type="xs:string"/>
    <xs:element minOccurs="0" name="s" type="xs:string"/>
    <xs:element minOccurs="0" name="x" type="xs:string"/>
  </xs:sequence>
</xs:complexType>

public interface HelloWorldWS {
    String hello(String name);
    
    XBean getBean();
    
    void setBean(XBean bean);
}



1 Server POJO 版本變動, 但Client未變動, 執行client 時

(1) 增加屬性







很棒 未抛出Exception 可正常運作.

 

(2) 變更屬性名稱






鬼魂 getBean() , setBean() 皆發生 org.apache.cxf.interceptor.Fault: Unmarshalling Error: unexpected element (uri:"", local:"dd"). Expected elements are <{}d>,<{}s>,<{}x>

 

(3) 變更屬性類別







很棒 getBean() 未抛出Exception , 可正常運作.

鬼魂 setBean() 如果傳入的不是數值, 會出現 org.apache.cxf.binding.soap.SoapFault: Unmarshalling Error: Not a number: d

(4) 刪除屬性


  <xs:sequence>
    <xs:element minOccurs="0" name="s" type="xs:string"/>
    <xs:element minOccurs="0" name="x" type="xs:string"/>
  </xs:sequence>
</xs:complexType>

很棒 getBean() 未抛出Exception , 回傳null

鬼魂 setBean() 出現 javax.xml.ws.soap.SOAPFaultException: Unmarshalling Error: unexpected element (uri:"", local:"d"). Expected elements are <{}s>,<{}x>

 

挑戰2 再來是.NET add service reference的測試

image


            System.Console.WriteLine("Hello " + myClient.hello("Joe"));

            try
            {
                xBean bean = myClient.getBean();
                this.textBox1.Text += ("Response: " + bean.x + "\r\n");
                this.textBox1.Text += ("Response: " + bean.s + "\r\n");
                this.textBox1.Text += ("Response: " + bean.d + "\r\n");
            }
            catch (Exception ex)
            {
                this.textBox1.Text += ex.ToString() + "\t" + ex.Message + "\r\n" + ex.StackTrace;
            }

            try
            {
                xBean bean = new xBean();
                bean.x = "x";
                bean.s = "s";
                bean.d = "d";
                myClient.setBean(bean);
            }
            catch (Exception ex)
            {
                this.textBox1.Text += ex.ToString() + "\t" + ex.Message + "\r\n" + ex.StackTrace;
            }

(1) 增加屬性

魔鬼 這時候出現一個很妙的現象

1-1 增加屬性 e


<xs:element minOccurs="0" name="d" type="xs:string"/>
<xs:element minOccurs="0" name="e" type="xs:string"/>
<xs:element minOccurs="0" name="s" type="xs:string"/>
<xs:element minOccurs="0" name="x" type="xs:string"/>
</xs:sequence>

結果: 沒有出現exception, 但只有d有值 , 其它都沒值, 應該是因為 e 無法對應後, 後頭的s , x 亦無法對應?!

1-2 增加屬性 x


<xs:element minOccurs="0" name="d" type="xs:string"/>
<xs:element minOccurs="0" name="s" type="xs:string"/>
<xs:element minOccurs="0" name="x" type="xs:string"/>
<xs:element minOccurs="0" name="z" type="xs:string"/>
</xs:sequence>

結果: 沒有出現exception, d , s , x 皆有值.

 

(2) 變更屬性名稱

魔鬼 getBean() 如同上者, 不會出現exception, 依順序只要一滾到無法對應, 後面都無法對應.

鬼魂 setBean() 出現 System.ServiceModel.FaultException: Unmarshalling Error: unexpected element (uri:"", local:"s"). Expected elements are <{}d>,<{}ss>,<{}x>

 

(3) 變更屬性類別

鬼魂 同Java 反應

 

(4) 刪除屬性

鬼魂 同Java 反應

 

 

 

結論:

目前主流的運用web service是用動態的proxy, 但也往往因為實作的不同, 而造成在維護時的議題.

對於service來說, 如果增加一個欄位, 對於.net consummer來說, 就必須重新add service reference,

站在consummer的角度, 當然不希望provider 更改造成其問題, 必然會要求 provider 要通知,

但provider 卻很難掌握有那些使用者, 被通知的consummer皆能如預期上線 ...

最後, 就變成provider 必須不斷的增加pojo , service ...

而這造成的維護問題, 還在思考中 沉思