[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的測試
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 ...
而這造成的維護問題, 還在思考中