• wsdl 关于nillable和minOccurs 在.NET和java中的不同


    术语约定
    文章中会反复出现[值类型]、[包装类型]、[普通引用类型]、[元素节点]和[元素取值]的表述
    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

  • 相关阅读:
    vid = two 切开 分开 两个眼睛 还有看的含义 词根
    ACS 构词法 + 44个后缀 记忆方法
    测试打包失败 已解决 分析过程 关键字 Jenkins nexus packagelock.json npm install build
    RBAC 介绍,案例讲解
    为什么Dapr是比SpringCloud和Istio更优雅的微服务框架?
    SmartIDE v0.1.18 已经发布 助力阿里国产IDE OpenSumi 插件安装提速10倍、Dapr和Jupyter支持、CLI k8s支持
    Then Swift 初始化对象语法糖
    javaGUI 最基础的界面 标签、输入框、按钮、事件处理 模板
    2019百度之星第三场 最短路2
    2021百度之星初赛第二场 魔怔
  • 原文地址:https://www.cnblogs.com/itpro/p/5320144.html
Copyright © 2020-2023  润新知