wsdl 關於nillable和minOccurs 在.NET和java中的不同

来源:http://www.cnblogs.com/itpro/archive/2016/03/25/5320144.html
-Advertisement-
Play Games

術語約定文章中會反覆出現[值類型]、[包裝類型]、[普通引用類型]、[元素節點]和[元素取值]的表述1> [值類型]指的是java和.NET中的基本數據類型,如:int;2> [包裝類型]指的是java中的包裝類和.NET中的Nullable<T>類型,如:Integer、int?;3> [普通引用 ...


術語約定
文章中會反覆出現[值類型]、[包裝類型]、[普通引用類型]、[元素節點]和[元素取值]的表述
1> [值類型]指的是java和.NET中的基本數據類型,如:int;
2> [包裝類型]指的是java中的包裝類和.NET中的Nullable<T>類型,如:Integer、int?;
3> [普通引用類型]指的是除包裝類型外的其它引用類型;
4> [元素節點]指的是xml文檔中的一個標簽節點,我們可以說[元素節點]是必輸還是非必輸,如:<Name>lubiao</Name>;
5> [元素取值]指的是xml標簽節點的內容,我們可以說[元素取值]是空還是非空,如:<Name>lubiao</Name>表示元素取值不為空,<Name xsi:nil="true"/>表示元素取值為空;

1、首先來看minOccurs和Nillable的定義
minOccurs
:表示XML文檔中某個[元素節點] 是否可以不出現,預設值為1,表示必須出現
nillable:表示XML文檔中某個[元素取值] 是否可以為空(形如:<name xsi:nil="true" />),預設值為false,表示不能為空
那麼,minOccurs和nillable的組合形式就會有4種,如下:
例一,值類型:

<element name="id1" type="int" minOccurs="0" nillable="true"/>
<element name="id2" type="int" minOccurs="0" nillable="false"/>
<element name="id3" type="int" minOccurs="1" nillable="true"/>
<element name="id4" type="int" minOccurs="1" nillable="false"/>

例二,引用類型:

<element name="name1" type="string" minOccurs="0" nillable="true"/>
<element name="name2" type="string" minOccurs="0" nillable="false"/>
<element name="name3" type="string" minOccurs="1" nillable="true"/>
<element name="name4" type="string" minOccurs="1" nillable="false"/>

2、Java和.NET自動生成WSDL的規則
在實際開發時我們通常的做法是先編寫Server端代碼,然後利用工具自動生成wsdl描述,最後再利用工具讀取wsdl進而生成客戶端程式。那麼用工具生成wsdl和用工具反向生成代理程式的規則是什麼呢?下來對此進行實例分析:
2.1 先看.NET生成wsdl的規則
實驗時所用的開發工具為VS 2010,用vs開發WebService的資料,百度搜索一大推,這裡不贅述。
2.1.1、定義數據實體:Person.cs

public class Person 
{
    public int Id { get; set; } //值類型
    public string Name { get; set; }//普通引用類型
    public int? PhoneNbr { get; set; }//包裝類型
}

2.1.2、定義服務類:WebService.cs

/// <summary>
///WebService 的摘要說明
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WebService : System.Web.Services.WebService {

    public WebService () {
       //如果使用設計的組件,請取消註釋以下行 
        //InitializeComponent(); 
    }

    [WebMethod]
    public string HelloWorld(int id,int? phoneNbr,string name,Person person) {
        return "Hello World";
    }
    
}

helloWorld方法有4個參數,前三個參數和Person類的三個屬性是一樣的,加入這三個參數的目的是進行對比測試。
2.1.3、查看生成的wsdl

<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="http://tempuri.org/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" targetNamespace="http://tempuri.org/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
  <wsdl:types>
    <s:schema elementFormDefault="qualified" targetNamespace="http://tempuri.org/">
      <s:element name="HelloWorld">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="1" maxOccurs="1" name="id" type="s:int" />
            <!--nillable預設為false,minOccurs等於1:即id元素為必輸,且值不能為空-->
            <s:element minOccurs="1" maxOccurs="1" name="phoneNbr" nillable="true" type="s:int" />
            <!--nillable等於true,minOccurs等於1:即phoneNbr元素為必輸,但值可以為空-->
            <s:element minOccurs="0" maxOccurs="1" name="name" type="s:string" />
            <!--nillable預設為false,minOccurs等於0:即name元素為非必輸,但值不能為空-->
            <s:element minOccurs="0" maxOccurs="1" name="person" type="tns:Person" />
            <!--nillable預設為false,minOccurs等於0:即person元素為非必輸,但值不能為空-->
          </s:sequence>
        </s:complexType>
      </s:element>
      <s:complexType name="Person">
        <s:sequence>
          <s:element minOccurs="1" maxOccurs="1" name="Id" type="s:int" />
          <!--nillable預設為false,minOccurs預設為1:即id元素為必輸,且值不能為空-->
          <s:element minOccurs="0" maxOccurs="1" name="Name" type="s:string" />
          <!--nillable預設為false,minOccurs等於0:即Name元素為非必輸,但值不能為空-->
          <s:element minOccurs="1" maxOccurs="1" name="PhoneNbr" nillable="true" type="s:int" />
          <!--nillable預設為false,minOccurs等於1:即PhoneNbr元素為必輸,但值可以為空-->
        </s:sequence>
      </s:complexType>
      <s:element name="HelloWorldResponse">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" name="HelloWorldResult" type="s:string" />
          </s:sequence>
        </s:complexType>
      </s:element>
    </s:schema>
  </wsdl:types>
 </wsdl:definitions>

2.1.4、得出結論  
* id參數和Person.Id屬性都為值類型:[元素節點] 都必輸,[元素取值] 都不能為空
* phoneNbr參數和Person.PhoneNbr屬性都是包裝類型:[元素節點] 都必輸,但[元素取值] 都可以為空;
* name參數和Person.Name屬性都是普通引用類型:[元素節點] 都可以不輸,但[元素取值] 都不能為空;
* person參數是普通引用類型:[元素節點] 可以不輸,但[元素取值] 不能為空。
2.2 再看Java的規則
首先,先熟悉在eclipse中快速開發webservice程式的步驟,參考鏈接:http://www.blogjava.net/parable-myth/archive/2010/08/03/327802.html,此次實驗採用的就是這種快速開發方式(註:不同的框架和工具會可能會有不同的生成規則),所用ecllipse版本為:
    Version: Juno Service Release 1
    Build id: 20121004-1855
2.2.1、定義數據實體:Person.java

package com.lubiao.axis;

public class Person  implements java.io.Serializable {
    private int id;//編號,值類型
    private java.lang.String name;//姓名,普通引用類型
    private Integer phoneNbr;//電話,包裝類型
    
    public int getId() {return id;}
    public void setId(int id) {this.id = id;}
	
    public java.lang.String getName() {return name;}
    public void setName(java.lang.String name) {this.name = name;}

    public Integer getPhoneNbr() {return phoneNbr;}
    public void setPhoneNbr(Integer phoneNbr) {this.phoneNbr = phoneNbr;}
}

2.2.2、定義服務類:WebServiceTest.java

package com.lubiao.axis;

public class WebServiceTest{
	public String helloWorld(int id,Integer phoneNbr,String name,Person person){
		return "Hello World";
	}
}

helloWorld方法有4個參數,前三個參數和Person類的三個屬性是一樣的,加入這三個參數的目的是進行對比測試。
2.2.3、查看生成的Wsdl

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://axis.lubiao.com" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="http://axis.lubiao.com" xmlns:intf="http://axis.lubiao.com" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <!--WSDL created by Apache Axis version: 1.4 Built on Apr 22, 2006 (06:55:48 PDT)-->
  <wsdl:types>
    <schema elementFormDefault="qualified" targetNamespace="http://axis.lubiao.com" xmlns="http://www.w3.org/2001/XMLSchema">
      <element name="helloWorld">
        <complexType>
          <sequence>
            <element name="id" type="xsd:int"/>
            <!--nillable預設為false,minOccurs預設為1:即id元素為必輸,且值不能為空-->
            <element name="phoneNbr" type="xsd:int"/>
            <!--nillable預設為false,minOccurs預設為1:即phoneNbr元素為必輸,且值不能為空-->
            <element name="name" type="xsd:string"/>
            <!--nillable預設為false,minOccurs預設為1:即name元素為必輸,且值不能為空-->
            <element name="person" type="impl:Person"/>
            <!--nillable預設為false,minOccurs預設為1:即person元素為必輸,且值不能為空-->
          </sequence>
        </complexType>
      </element>
      <complexType name="Person">
        <sequence>
          <element name="id" type="xsd:int"/>
          <!--nillable預設為false,minOccurs預設為1:即id元素為必輸,且值不能為空-->
          <element name="name" nillable="true" type="xsd:string"/>
          <!--nillable預設為true,minOccurs預設為1:即name元素為必輸,但值可以為空-->
          <element name="phoneNbr" nillable="true" type="xsd:int"/>
          <!--nillable預設為true,minOccurs預設為1:即phoneNbr元素為必輸,但值可以為空-->
        </sequence>
      </complexType>
      <element name="helloWorldResponse">
        <complexType>
          <sequence>
            <element name="helloWorldReturn" type="xsd:string"/>
          </sequence>
        </complexType>
      </element>
    </schema>
  </wsdl:types>
  <!-- 其它元素省略 -->
</wsdl:definitions>

2.2.4、得出結論
* id參數和Person.id屬性都是值類型:[元素節點] 都必輸,[元素取值] 都不能為空;
* phoneNbr參數和Person.phoneNbr屬性都是包裝類型:[元素節點] 都必輸,但前者[元素取值]不能為空,後者[元素取值]可以為空;
* name參數和Person.name屬性都是普通的引用類型:[元素節點] 都必輸,但前者[元素取值]不能為空,後者[元素取值]可以為空;
* person參數屬於普通引用類型:[元素節點]必輸,且[元素取值]不能為空;
*總結:此框架生成wsdl時認為:
        1、作為方法參數時,不管是值類型、包裝類型還是普通引用類型,[元素節點]都為必輸項,且[元素取值]都不能為空;
        2、作為對象屬性時,不管是值類型、包裝類型還是普通引用類型,[元素節點]都為必輸項,其中值類型的[元素取值]不能為空,但包裝類型和普通引用類型的[元素取值]可以為空。
2.3、Java和.NET的異同
其一,對於值類型:
            Java和.NET都認為值類型不論是作為 [方法參數時] 還是 [對象屬性時] ,[元素節點]都為必輸項,且[元素取值]都不能為空。
             (都合理:這符合值類型的特點,總有一個值)
其二,對於包裝類型:
            作為方法參數時:java和.NET都認為[元素節點]是必輸的,但java認為[元素取值]不能為空,而.NET認為[元素取值]可以為空;
               (.NET合理,Java不合理。java既要求必輸又要求值不能為空,那空對象怎麼傳入?可以通過生成客戶端代理進行驗證(這裡不再演示),對於phoneNbr參數客戶端代碼變成了int類型,而服務端可是Integer類型)
            作為對象屬性時:java和.NET都認為[元素是節點]必輸的,而[元素取值]是可以為空的;
                (都合理。java和.net都要求節點必須出現,然後以nillable=true標識可以傳入空值)
其三,對於普通引用類型:
            作為方法參數時:java和.NET都認為[元素取值]是不能為空的,但Java同時認為[元素節點]是必輸的,而.NET認為[元素節點]是非必輸的;
                (.NET合理,Java不合理。java既要求節點必輸還要求值不能為空,那空對象怎麼傳入?)
            作為對象屬性時:java認為[元素節點]是必輸的、[元素取值]是可空的;.NET認為[元素節點]是非必輸的、[元素取值]是不可空的。
                (都合理。java始終要求必輸,但以nillable=true標識可以傳入空對象;.NET始終要求元素取值不能為空,但以minOccurs=0來標識可以傳入空對象)
總結:
作為參數時,java出現了很多不合理的情況,可能是因為選的這個框架有bug,這裡不再關心,主要看作為對象屬性時的情況。文章最開始的時候說到minOccurs和nillable會有4種組合方式,在上面的實驗中java用到了兩種,而.NET用到了3種,分別為:
Java:[ minOccurs=1,nillable=false ] 和 [ minOccurs=1,nillable=true ],前者對應值類型,後者對應引用類型(包裝類型和普通引用類型),java壓根沒用minOccrs=0
.NET:[ minOccurs=1,nillable=false ]、[ minOccurs=1,nillable=true ] 和[ minOccurs=0,nillable=false],前者對應值類型,再者對應包裝類型,最後對應普通引用類型。
3、Java和.NET由WSDL自動生成代碼的規則
接著上面的實驗結果,先來做最簡單的測試:1、用java的client對接java的service生成代碼;2、用.NET的client對接.NET的Service生成代碼,然後分別觀察Client端自動生成的Person類和Server段的Person是否完全一致。這裡不再演示,只說結論,結論是:生成的Person分別和各自Server端的完全相同。
那如果用[ java對接.NET ] 或者[ 用.NET對接java ],會是什麼結果呢?等一等,這麼問好像有問題,哪有什麼誰對接誰,大家對接的都是wsdl,哪裡知道wsdl後面是什麼平臺!!嗯,那就把minOccurs和nillable的四種組合都列出來,看java和.NET的生成規則分別是什麼樣的,繼續。
3.1 先看.NET的規則
3.1.1 定義WSDL,限於篇幅只列出類型定義部分

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:sys="http://com.lubiao.service/system" targetNamespace="http://com.lubiao.service/system" elementFormDefault="qualified">
  <complexType name="Person">
    <sequence>
      <element name="id1" type="long" minOccurs="0" nillable="true"/>
      <element name="id2" type="long" minOccurs="0" nillable="false"/>
      <element name="id3" type="long" minOccurs="1" nillable="true"/>
      <element name="id4" type="long" minOccurs="1" nillable="false"/>
      <element name="name1" type="string" minOccurs="0" nillable="true"/>
      <element name="name2" type="string" minOccurs="0" nillable="false"/>
      <element name="name3" type="string" minOccurs="1" nillable="true"/>
      <element name="name4" type="string" minOccurs="1" nillable="false"/>
    </sequence>
  </complexType>
  
  <complexType name="PersonResponse">
    <sequence>
      <element name="id" type="string" minOccurs="0"/>
    </sequence>
  </complexType>
  
  <element name="GetPerson" type="sys:Person"></element>
  <element name="GetPersonResponse" type="sys:PersonResponse"></element>
</schema>

id對應的是值類型,name對應的是引用類型
3.1.2 生成數據類

    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.18058")]
    [System.SerializableAttribute()]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://com.csii.bank.core/system")]
    public partial class Person{
                
        private System.Nullable<long> id1Field;
        
        private bool id1FieldSpecified;
        
        private long id2Field;
        
        private bool id2FieldSpecified;
        
        private System.Nullable<long> id3Field;
        
        private long id4Field;
        
        private string name1Field;
        
        private string name2Field;
        
        private string name3Field;
        
        private string name4Field;
                
        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
        public System.Nullable<long> id1 {
            get {
                return this.id1Field;
            }
            set {
                this.id1Field = value;
            }
        }
        
        /// <remarks/>
        [System.Xml.Serialization.XmlIgnoreAttribute()]
        public bool id1Specified {
            get {
                return this.id1FieldSpecified;
            }
            set {
                this.id1FieldSpecified = value;
            }
        }
        
        /// <remarks/>
        public long id2 {
            get {
                return this.id2Field;
            }
            set {
                this.id2Field = value;
            }
        }
        
        /// <remarks/>
        [System.Xml.Serialization.XmlIgnoreAttribute()]
        public bool id2Specified {
            get {
                return this.id2FieldSpecified;
            }
            set {
                this.id2FieldSpecified = value;
            }
        }
        
        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
        public System.Nullable<long> id3 {
            get {
                return this.id3Field;
            }
            set {
                this.id3Field = value;
            }
        }
        
        /// <remarks/>
        public long id4 {
            get {
                return this.id4Field;
            }
            set {
                this.id4Field = value;
            }
        }
        
        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
        public string name1 {
            get {
                return this.name1Field;
            }
            set {
                this.name1Field = value;
            }
        }
        
        /// <remarks/>
        public string name2 {
            get {
                return this.name2Field;
            }
            set {
                this.name2Field = value;
            }
        }
        
        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
        public string name3 {
            get {
                return this.name3Field;
            }
            set {
                this.name3Field = value;
            }
        }
        
        /// <remarks/>
        public string name4 {
            get {
                return this.name4Field;
            }
            set {
                this.name4Field = value;
            }
        }
    }

分析:
id1:可空類型、特性:IsNullable=true、生成了對應的id1Specified
id2:值類型、特性:IsNullable=false、生成了對應的id2Specified
id3:可空類型、特性:IsNullable=true
id4:值類型、特性:IsNullable=false
name1:引用類型、特性:IsNullable=true
name2:引用類型、特性:IsNullable=false
name3:引用類型、特性:IsNullable=true
name4:引用類型、特性:IsNullable=false
3.1.3 查看SOAP報文
將可為null的屬性都置位null,然後查看SOAP報文是什麼樣子的
C#代碼1:

Person p=new Person();
p.id1 = null;
p.id2 = 123;
p.id3 = null;
p.id4 = 456;
p.name1 = null;
p.name2 = null;
p.name3 = null;
p.name4 = null;

C#代碼2:

Person p=new Person();
p.id1 = null;
p.id1Specified = true;
request.id2 = 123;
p.id1Specified = true;
p.id3 = null;
p.id4 = 456;
p.name1 = null;
p.name2 = null;
p.name3 = null;
p.name4 = null;

SOAP報文1:對應C#代碼1,只貼出Person部分:

<Person>
      <id3 xsi:nil="true" />
      <id4>456</id4>
      <name1 xsi:nil="true" />
      <name3 xsi:nil="true" />
</Person>

SOAP報文2:對應C#代碼2,只貼出Person部分:

<Person>
      <id1 xsi:nil="true" />
      <id2>123</id2>
      <id3 xsi:nil="true" />
      <id4>456</id4>
      <name1 xsi:nil="true" />
      <name3 xsi:nil="true" />
</Person>

3.1.4 得出結論
其一:對於值類型和包裝類型

minOccurs="0" 組合nillable="true"時
會生成包裝類型(id1),同時會生成對應的id1Specified屬性,為什麼會生成帶Specified的屬性呢?這是因為minOccurs="0"的緣故,minOccurs=0意味著元素節點可以不出現,那到底是出現呢?還是不出現呢?工具自己沒了主意,所以生成了一個xxxSpecified屬性,該屬性預設值為false,只有給它指定true的時候[元素節點]才會出現到soap報文中。
minOccurs="0"組合nillable="false"時
會生成值類型(id2),同時會生成對應的id2Specified屬性(原因同上)
minOccurs="1" 組合nillable="true"時
會生成包裝(id3),不會生成Specified屬性(因為元素節點必輸)。
minOccurs=“1”組合nillable=“false”時
會生成值類型(id4),不會生成Specified屬性(因為元素節點必輸)。
其二:對於普通引用類型
name1、name3:
只要nillable=true不管minOccurs等於什麼,[null對象]序列化的時候都以[元素取值]為空方式來體現這是一個空對象。
name2、name4:   
只要nillable=false不管minOccurs等於什麼,[null對象]序列化時都以[元素節點]不出現的方式來體現這是一個空對象。(上面實驗時,Server端對soap報文進行了schema驗證,所以name4傳null會報錯的)

總結:
* .NET在wsdl_2_C# 和C#_2_wsdl時的思路其實是一致的,1、生成值類型還是包裝類型先看nillable屬性、然後再看minOccurs屬性來控制是否生成xxxSpecified屬性;2、而生成普通引用類型時只關心nillable屬性,nillable=true就採用nil=true的方式發送null對象,nillabe=false則採用[元素節點]不出現的方式發送null對象,壓根就不關心minOccurs是神馬。
* 前面說到name4=null時,Server端會報錯,所以 對於引用類型:minOccurs=1和nillable=false的組合是沒有意義的,這種組合無法讓空對象傳輸過來
3.2 再看Java的規則

3.2.1 定義WSDL,限於篇幅只列出類型定義部分

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:sys="http://com.lubiao.service/system" targetNamespace="http://com.lubiao.service/system" elementFormDefault="qualified">
  <complexType name="Person">
    <sequence>
      <element name="id1" type="long" minOccurs="0" nillable="true"/>
      <element name="id2" type="long" minOccurs="0" nillable="false"/>
      <element name="id3" type="long" minOccurs="1" nillable="true"/>
      <element name="id4" type="long" minOccurs="1" nillable="false"/>
      <element name="name1" type="string" minOccurs="0" nillable="true"/>
      <element name="name2" type="string" minOccurs="0" nillable="false"/>
      <element name="name3" type="string" minOccurs="1" nillable="true"/>
      <element name="name4" type="string" minOccurs="1" nillable="false"/><!--前面說的這個節點這麼定義沒有意義,為了實驗的嚴謹性,依然保留-->
    </sequence>
  </complexType>
  
  <complexType name="PersonRequest">
    <sequence>
      <element name="person" type="sys:Person"/>
    </sequence>
  </complexType>
  <complexType name="PersonResponse">
    <sequence>
      <element name="id" type="string" minOccurs="0"/>
    </sequence>
  </complexType>
  
  <element name="GetPerson" type="sys:PersonRequest"></element>
  <element name="GetPersonResponse" type="sys:PersonResponse"></element>
</schema>


和.net相比,此處多了一個類型PersonRequest,之所以改成這樣是因為:如果按照net那種方式,生成的java代碼中不會有Person類,因為工具認為id1,id2....是GetPerson的參數。
3.1.2 生成數據類

/**
 * Person.java
 *
 * This file was auto-generated from WSDL
 * by the Apache Axis 1.4 Apr 22, 2006 (06:55:48 PDT) WSDL2Java emitter.
 */

package core.bank.csii.com.system;

public class Person  implements java.io.Serializable {
    private java.lang.Long id1;

    private java.lang.Long id2;

    private java.lang.Long id3;

    private long id4;

    private java.lang.String name1;

    private java.lang.String name2;

    private java.lang.String name3;

    private java.lang.String name4;

    public Person() {
    }

    public Person(
           java.lang.Long id1,
           java.lang.Long id2,
           java.lang.Long id3,
           long id4,
           java.lang.String name1,
           java.lang.String name2,
           java.lang.String name3,
           java.lang.String name4) {
           this.id1 = id1;
           this.id2 = id2;
           this.id3 = id3;
           this.id4 = id4;
           this.name1 = name1;
           this.name2 = name2;
           this.name3 = name3;
           this.name4 = name4;
    }


    /**
     * Gets the id1 value for this Person.
     * 
     * @return id1
     */
    public java.lang.Long getId1() {
        return id1;
    }


    /**
     * Sets the id1 value for this Person.
     * 
     * @param id1
     */
    public void setId1(java.lang.Long id1) {
        this.id1 = id1;
    }


    /**
     * Gets the id2 value for this Person.
     * 
     * @return id2
     */
    public java.lang.Long getId2() {
        return id2;
    }


    /**
     * Sets the id2 value for this Person.
     * 
     * @param id2
     */
    public void setId2(java.lang.Long id2) {
        this.id2 = id2;
    }


    /**
     * Gets the id3 value for this Person.
     * 
     * @return id3
     */
    public java.lang.Long getId3() {
        return id3;
    }


    /**
     * Sets the id3 value for this Person.
     * 
     * @param id3
     */
    public void setId3(java.lang.Long id3) {
        this.id3 = id3;
    }


    /**
     * Gets the id4 value for this Person.
     * 
     * @return id4
     */
    public long getId4() {
        return id4;
    }


    /**
     * Sets the id4 value for this Person.
     * 
     * @param id4
     */
    public void setId4(long id4) {
        this.id4 = id4;
    }


    /**
     * Gets the name1 value for this Person.
     * 
     * @return name1
     */
    public java.lang.String getName1() {
        return name1;
    }


    /**
     * Sets the name1 value for this Person.
     * 
     * @param name1
     */
    public void setName1(java.lang.String name1) {
        this.name1 = name1;
    }


    /**
     * Gets the name2 value for this Person.
     * 
     * @return name2
     */
    public java.lang.String getName2() {
        return name2;
    }


    /**
     * Sets the name2 value for this Person.
     * 
     * @param name2
     */
    public void setName2(java.lang.String name2) {
        this.name2 = name2;
    }


    /**
     * Gets the name3 value for this Person.
     * 
     * @return name3
     */
    public java.lang.String getName3() {
        return name3;
    }


    /**
     * Sets the name3 value for this Person.
     * 
     * @param name3
     */
    public void setName3(java.lang.String name3) {
        this.name3 = name3;
    }


    /**
     * Gets the name4 value for this Person.
     * 
     * @return name4
     */
    public java.lang.String getName4() {
        return name4;
    }


    /**
     * Sets the name4 value for this Person.
     * 
     * @param name4
     */
    public void setName4(java.lang.String name4) {
        this.name4 = name4;
    }

    private java.lang.Object __equalsCalc = null;
    public synchronized boolean equals(java.lang.Object obj) {
        if (!(obj instanceof Person)) return false;
        Person other = (Person) obj;
        if (obj == null) return false;
        if (this == obj) return true;
        if (__equalsCalc != null) {
            return (__equalsCalc == obj);
        }
        __equalsCalc = obj;
        boolean _equals;
        _equals = true && 
            ((this.id1==null && other.getId1()==null) || 
             (this.id1!=null &&
              this.id1.equals(other.getId1()))) &&
            ((this.id2==null && other.getId2()==null) || 
             (this.id2!=null &&
              this.id2.equals(other.getId2()))) &&
            ((this.id3==null && other.getId3()==null) || 
             (this.id3!=null &&
              this.id3.equals(other.getId3()))) &&
            this.id4 == other.getId4() &&
            ((this.name1==null && other.getName1()==null) || 
             (this.name1!=null &&
              this.name1.equals(other.getName1()))) &&
            ((this.name2==null && other.getName2()==null) || 
             (this.name2!=null &&
              this.name2.equals(other.getName2()))) &&
            ((this.name3==null && other.getName3()==null) || 
             (this.name3!=null &&
              this.name3.equals(other.getName3()))) &&
            ((this.name4==null && other.getName4()==null) || 
             (this.name4!=null &&
              this.name4.equals(other.getName4())));
        __equalsCalc = null;
        return _equals;
    }

    private boolean __hashCodeCalc = false;
    public synchronized int hashCode() {
        if (__hashCodeCalc) {
            return 0;
        }
        __hashCodeCalc = true;
        int _hashCode = 1;
        if (getId1() != null) {
            _hashCode += getId1().hashCode();
        }
        if (getId2() != null) {
            _hashCode += getId2().hashCode();
        }
        if (getId3() != null) {
            _hashCode += getId3().hashCode();
        }
        _hashCode += new Long(getId4()).hashCode();
        if (getName1() != null) {
            _hashCode += getName1().hashCode();
        }
        if (getName2() != null) {
            _hashCode += getName2().hashCode();
        }
        if (getName3() != null) {
            _hashCode += getName3().hashCode();
        }
        if (getName4() != null) {
            _hashCode += getName4().hashCode();
        }
        __hashCodeCalc = false;
        return _hashCode;
    }

    // Type metadata
    private static org.apache.axis.description.TypeDesc typeDesc =
        new org.apache.axis.description.TypeDesc(Person.class, true);

    static {
        typeDesc.setXmlType(new javax.xml.namespace.QName("http://com.csii.bank.core/system", "Person"));
        org.apache.axis.description.ElementDesc elemField = new org.apache.axis.description.ElementDesc();
        elemField.setFieldName("id1");
        elemField.setXmlName(new javax.xml.namespace.QName("http://com.csii.bank.core/system", "id1"));
        elemField.setXmlType(new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "long"));
        elemField.setMinOccurs(0);
        elemField.setNillable(true);
        typeDesc.addFieldDesc(elemField);
        elemField = new org.apache.axis.description.ElementDesc();
        elemField.setFieldName("id2");
        elemField.setXmlName(new javax.xml.namespace.QName("http://com.csii.bank.core/system", "id2"));
        elemField.setXmlType(new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "long"));
        elemField.setMinOccurs(0);
        elemField.setNillable(false);
        typeDesc.addFieldDesc(elemField);
        elemField = new org.apache.axis.description.ElementDesc();
        elemField.setFieldName("id3");
        elemField.setXmlName(new javax.xml.namespace.QName("http://com.csii.bank.core/system", "id3"));
        elemField.setXmlType(new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "long"));
        elemField.setNillable(true);
        typeDesc.addFieldDesc(elemField);
        elemField = new org.apache.axis.description.ElementDesc();
        elemField.setFieldName("id4");
        elemField.setXmlName(new javax.xml.namespace.QName("http://com.csii.bank.core/system", "id4"));
        elemField.setXmlType(new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "long"));
        elemField.setNillable(false);
        typeDesc.addFieldDesc(elemField);
        elemField = new org.apache.axis.description.ElementDesc();
        elemField.setFieldName("name1");
        elemField.setXmlName(new javax.xml.namespace.QName("http://com.csii.bank.core/system", "name1"));
        elemField.setXmlType(new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "string"));
        elemField.setMinOccurs(0);
        elemField.setNillable(true);
        typeDesc.addFieldDesc(elemField);
        elemField = new org.apache.axis.description.ElementDesc();
        elemField.setFieldName("name2");
        elemField.setXmlName(new javax.xml.namespace.QName("http://com.csii.bank.core/system", "name2"));
        elemField.setXmlType(new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "string"));
        elemField.setMinOccurs(0);
        elemField.setNillable(false);
        typeDesc.addFieldDesc(elemField);
        elemField = new org.apache.axis.description.ElementDesc();
        elemField.setFieldName("name3");
        elemField.setXmlName(new javax.xml.namespace.QName("http://com.csii.bank.core/system", "name3"));
        elemField.setXmlType(new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "string"));
        elemField.setNillable(true);
        typeDesc.addFieldDesc(elemField);
        elemField = new org.apache.axis.description.ElementDesc();
        elemField.setFieldName("name4");
        elemField.setXmlName(new javax.xml.namespace.QName("http://com.csii.bank.core/system", "name4"));
        elemField.setXmlType(new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "string"));
        elemField.setNillable(false);
        typeDesc.addFieldDesc(elemField);
    }

    /**
     * Return type metadata object
     */
    public static org.apache.axis.description.TypeDesc getTypeDesc() {
        return typeDesc;
    }

    /**
     * Get Custom Serializer
     */
    public static org.apache.axis.encoding.Serializer getSerializer(
           java.lang.String mechType, 
           java.lang.Class _javaType,  
           javax.xml.namespace.QName _xmlType) {
        return 
          new  org.apache.axis.encoding.ser.BeanSerializer(
            _javaType, _xmlType, typeDesc);
    }

    /**
     * Get Custom Deserializer
     */
    public static org.apache.axis.encoding.Deserializer getDeserializer(
           java.lang.String mechType, 
           java.lang.Class _javaType,  
           javax.xml.namespace.QName _xmlType) {
        return 
          new  org.apache.axis.encoding.ser.BeanDeserializer(
            _javaType, _xmlType, typeDesc);
    }

}

java生成的Person類沒有Specified屬性,看來它只支持一種形式,下麵進行驗證
3.2.3查看SOAP報文
java代碼:

Person p=new Person();
p.setId1(null);
p.setId2(null);
p.setId3(null);
p.setId4(0);
p.setName1(null);
p.setName2(null);
p.setName3(null);
p.setName4("123");//.NET實驗時,name4傳的是null;但如果此處賦null,報文還未發出去,客戶端框架就報錯:提示不能為null了。

Soap報文:

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Body>
    <GetSystemStatus xmlns="http://com.csii.bank.core/system">
      <person>
        <id3 xsi:nil="true"/>
        <id4>0</id4>
        <name3 xsi:nil="true"/>
        <name4>123</name4>
      </person>
    </GetSystemStatus>
  </soapenv:Body>
</soapenv:Envelope>

3.2.4 得出結論:
其一:對於值類型和包裝:
  1、除 [ minOccurs=1,nillable=false ] 這一組合除外,生成的都是包裝類型。
  2、當對象屬性為null時,java根據minOccurs構造soap報文,如果minOccurs=0則[元素節點]不出現代表null,如果minOccurs=1用nil=true表示null。
其二:對於普通引用類型
  生成的肯定是引用類型(這是廢話),當對象屬性為null是,構造soap報文的規則和上面的2一樣
4、深入淺出,最後的總結
不管是由代碼生成wsdl,還是由wsdl生成代碼,此實驗中java都比.NET要簡潔,個人比較喜歡java的方式,.NET顯得有點兒啰嗦(它把包裝類型和普通引用類型做了區分),下麵進行最後的總結。
先來總結由代碼生成wsdl
java用到了兩種組合:
   [minOccurs=1、
nillable=false]:只有值類型用這一組合
   [minOccurs=1、
nillable=true]:包裝類型和普通引用類型用這一組合
   註:其實Java用[minOccurs=0 和nillable=false]代表包裝類型和普通引用類型也完全可以,如果是我的話我會用這一組合代替上面的組合,這樣可以節省網路流量
而.NET有3種組合:
   [ minOccurs=1、nillable=false]:只有值類型用這一組合
   [ minOccurs=1、nillable=true ] :包裝類型用這一組合
   [ minOccurs=0、nillable=false]:普通引用類型用這一組合
現在如果要我們自己寫一個生成wsdl的框架,那應該有如下的原則:
   1>  值類型只能用
[minOccurs=1、nillable=false],而包裝類型和普通引用類型不能用這一組合(否則空對象無法表示) 
   
2>  包裝類型可以用[minOccurs=1、nillable=true]和[ minOccurs=0、nillable=false]
  3> 普通引用類型可以用
[minOccurs=1、nillable=true]和[ minOccurs=0、nillable=false]
  
4> 對於包裝類型和普通引用類型不建議用[minOccurs=0、nillable=true],這一組合意義不夠明確,究竟是空報文節點表示null呢?還是nill=true表示null呢?當然如果真這麼用肯定也沒問題,只要序列化工具支持就行。

再來看由wsdl生成代碼
我是很難理解微軟為什麼要把[包裝類型]和[普通引用類型]區別對待,在C#_2_WSDL的時候這麼區別開到還沒什麼,但是當WSDL_2_C#的時候就帶來很大的麻煩。
1、首先來看<element name="long" type="dateTime" minOccurs="0" nillable="false"/>,對這一組合微軟生成的是值類型而不是包裝類型,它認為只有nillable=true才代表包裝類型,可包裝類型和普通引用類型本質上有太大的區別嗎?大家都是引用類型,[minOccurs=1、nillable=true]和[
minOccurs=0、nillable=false]應該都可以被解析為包裝類型才合適。你微軟如果認為nillable=true和包裝類型(微軟的可空類型)聯繫那麼緊密,那這樣的節點<element name="name3" type="string" minOccurs="1" nillable="true"/>最好還是別支持了,但現在普通應用類型你既支持minOccurs=0又支持nillable=true,那包裝類型和普通引用類型分開的必要性究竟是神馬!!!!!!
2、再來看xxxSpecified,前面說到,微軟認為對於像type=int這樣的節點,如果element定義中出現了minOccurs=0,則要生成一個xxxSpecified屬性。這麼搞使用起來簡直太麻煩了——讓程式員指定xxxSepcified為true或false來控制元素節點要不要顯示,這種麻煩還是由於“區別對待”帶來的。微軟只通過nillable判斷是否是包裝類型,對於minOccurs=0的情況它不得不生成一個xxxSpecified。而如果不區別對待的話就簡單多了,只要minOccurs=0和nillable=true隨便哪個出現或同時出現,直接生成包裝類型。

最後來總結序列化
序列化的時候,java和.NET在處理上也不盡相同:
1、java優先考慮minOccurs,如果minOccurs=0,那不管nillable等於神馬,程式中的null以[元素節點]不出現的方式來體現;如果minOccurs=1,則程式中的null以[元素取值]為空的方式來體現;這樣的規則同時適用於值類型、包裝類型和普通引用類型。
2、而.NET則優先考慮nillable,如果nillable=true,那不管minOccurs等於神馬,程式中的null以[元素取值]為空的方式來體現;如果nillable=false,則程式中的null以[元素節點]不出現的方式來體現;這樣的規則同時適用於值類型、包裝類型和普通引用類型。(註:Specified=true的前提下)

 

 

引用地址: http://www.xuebuyuan.com/1925655.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 安裝過程 wget http://www.asty.org/cmatrix/dist/cmatrix-1.2a.tar.gztar xvf cmatrix-1.2a.tar.gzcd cmatrix-1.2ayum install ncurses-devel./configure && make &
  • 所有目錄務必保持具有X許可權!!,否則無法進入該目錄及子目錄,且無法讀取該目錄及子目錄下的文件或子目錄
  • 最近在Linux平臺上配置伺服器部署網站(說多了都是淚!),記個筆記! 一、首先是在centos下安裝mysql (參考博客) mysql yum庫提供了一個簡單的和方便的方法來安裝和更新MySQL相關的軟體包到最新版本。 參考文檔:http://dev.mysql.com/downloads/re
  • 本文將tomcat安裝到了/alidata/server/目錄下,當然也可以安裝到其他目錄。 1. 下載tomcat:#wget http://apache.fayea.com/tomcat/tomcat-7/v7.0.54/bin/apache-tomcat-7.0.54.tar.gz 2. 將t
  • 2016-03-18 17:10:19 張超《Linux內核分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000 我的實驗平臺以及代碼見https://www.shiyanlou.com/courses/reports/986221 實驗
  • 如何查看、備份電腦隱藏的恢復分區 步驟: 1.用管理員身份打開CMD(快捷鍵:1. 同時按 win+x 2. 按 a ),輸入diskpart,回車enter。 (或者 按 win+r 在運行中輸入 diskpart 也行)。 2.輸入 lis dis ,回車。 (lis dis 是 list di
  • 1、安裝全部桌面環境,其實Ubuntu系列桌面實際上有幾種桌面應用程式,包括Ubuntu-desktop、Kubunut-desktop和Xubuntu- desktop。 我們就安裝了Ubuntu-desktop還有Gnome因為安裝桌面相關軟體太多。 命令:#sudo aptitude inst
  • When you try invoke a Java/Axis Web Service from a proxy class generated by Visual Studio 2005 or Visual Studio 2008 you often crash against the ‘retu ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...