WebService对象可空的困惑,关于nillable和minOccurs
术语约定 1、首先来看minOccurs和Nillable的定义 <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的规则 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类的三个属性是一样的,加入这三个参数的目的是进行对比测试。 <?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、得出结论?? 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类的三个属性是一样的,加入这三个参数的目的是进行对比测试。 <?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、得出结论 <?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对应的是引用类型 [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; } } } 分析: 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 得出结论 总结: <?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,javax.xml.namespace.QName _xmlType) {
return
new org.apache.axis.encoding.ser.BeanDeserializer(
_javaType,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 得出结论: (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |