映射集合(Mapping collections) 转贴www.blogjava.net/josson/archive/2007/04/20/112295.html 翻译:?zilong3927?原文地址:?http://docs.codehaus.org/display/XFIRE/Mapping+collections 调用?Web Services?时,经常需要返回集合(?collection?)作为结果,或者接受?collection?型的参数。SOAP?本身就支持这一点。 但是这一机制的问题在于,?java?语言的?collections?是无类型的(?untyped?)?.?因此,如果要在?Java 1.4当中支持?collections?,?就需要做一些额外的工作。 Java 5 &?范型(?Generics?) 首先而且是推荐的做法是在?JDK5?当中使用范型(?generics?)。范型能够使你在代码当中为你的collections?指定类型信息,?从而允许?xfire?自动地推导出?collection?类型,生成正确的?wsdl?等等。 下面示例了如何写这样的一个方法: ? ? Java 1.4 &?集合(?Collections?) 有些情况下并不总能够使用范型(?generics?)?.?例如,如果你的部署环境使用?JDK 1.4?,?或者你想暴露一些遗留的服务,而同时又不打算修改任何代码也不打算进行移植。 对于这样的一些情况而言,?你需要生成一个?xml?映射文件,来指定方法和它们对应的集合类型(collection types?)?. 这个?xml?文件的名字必须是?<className>.aegis.xml?,?其中?className?是你的服务(?service?)的接口类(?unqualified class?)的名字。 下面最好通过一个例子来展示这个?xml?文件的格式。?我们想要展现的服务有这样的一个接口?: ? ? 既然代码中的?collections?没有指定类型,?我们剧需要生成一个?xml?文件来指定所需要的类型。?这个文件的路径应该和?MyService1.class?在同一个包(?package?)当中,?并且它的名字应该是MyService1.aegis.xml 对于这个接口来说,一个最简单的映射文件如下?:
<mappings>
????<mapping> ????????<method?name= "getCollection"?> ????????????<return-type?componentType= "java.lang.String"?/> ????????</method> ????????<method?name= "setList"?> ????????????<parameter?index= "1"?componentType= "java.lang.String"?/> ????????</method> ????</mapping> </mappings> 注意这个映射文件确切地指定了所需要的信息,不包含任何冗余。?例如,?getFoo?方法没有被指定,这是由于它没有包含任何?collections?,因此能够在没有任何映射信息的情况下暴露给使用者。 其次,?setCollection?方法没有指定索引为?0?的参数。?这是由于该参数类型为?int?,因此不需要任何映射 如果我们有多个方法,都匹配指定的映射又该怎么办???这种情况下,?映射就对所有匹配的方法均有效。 所以,如果在我们的接口中增加以下的方法: ? ? 那么现在我们的映射定义对于两个?setList?方法都有作用。这种情况下,?我们不必为额外的参数(译者注:此处指?boolean persist?)指定两次映射?.?映射文件就指定了所有那些第二个参数为?List?的方法,并假定?List?中包含的都是?strings?。 如果我们想让那个具有?3?个参数的方法,其中的?list?不包含?Strings?,?而是实际上包含?Dates??这种情况下,?就需要一个更确切的映射来覆盖(?override?)原先那个更一般的,?所以我们的映射文件需要添加下面这个定义?:
????????<method?name=?? "setList"??>
????????????<parameter?index= "1"?componentType= "java.lang.String"?/> ????????????<parameter?index= "2"?class= "boolean"?/> ????????</method> 注意一下类型属性。?现在这个映射将对所有那些第二个参数为?List?,第三个参数为?boolean?型的方法适用。?在我们的接口当中,这个映射唯一地确定了一个特定的方法,使用这个映射就能够解释方法当中的List?参数。 在优先顺序方面,?更确切的映射总是优先于更一般的。 让我们考虑下面这个复杂一些的例子?: ? ? 映射文件的内容为?:
<mappings>
????<mapping> ????????<!--?mapping 1?--> ????????<method?name= "getCollection"?> ????????????<return-type?componentType= "java.lang.Double"?/> ????????</method> ????????<!--?mapping 2?--> ????????<method?name= "getCollection"?> ????????????<return-type?componentType= "java.lang.Float"?/> ????????????<parameter?index= "0"?class= "int"?/> ????????</method> ????????<!--?mapping 3?--> ????????<method?name= "getCollectionForValues"?> ????????????<return-type?componentType= "java.math.BigDecimal"?/> ????????</method> ????????<!--?mapping 4?--> ????????<method?name= "getCollectionForValues"?> ????????????<parameter?index= "0"?class= "java.lang.String"?/> ????????????<parameter?index= "1"?componentType= "java.util.Date"?/> ????????</method> ????????<!--?mapping 5?--> ????????<method?name= "getCollectionForValues"?> ?????????????<return-type?componentType= "java.util.Calendar"?/> ????????????<parameter?index= "0"?class= "int"?/> ????????????<parameter?index= "1"?componentType= "java.lang.Bit"?/> ????????</method> ????</mapping> </mappings> 这个文件的格式是不需要做过多解释的。但有几点还是需要加以说明。 ? 先来看一下第一个映射?(mapping 1)?。?这个映射指定了所有?getCollection?方法所返回的?collections contain?均包含?java.lang.Doubles?。?如果没有指定其他的?getCollection?映射,?那么这个映射将对方法?1,?2?,?3?都适用。 但是,第二个映射更加明确地指定了它所适用的方法。即如果?getCollection?方法的第一个参数是?int?型,那么该方法所返回的?collection?包含的是?Float?型。?由于这条规则更加明确,它将为方法?2?覆盖掉第一个映射,这是满足映射约束标准的。 使用以上的规则,不难推导出方法?4?和方法?5?返回的?collections?结果的组件类型(?component types)。 ?
public????interface??? MyService2
{ ???? Collection getCollection();?//method 1 ???? Collection getCollection(?int?id);?//method 2 ???? Collection getCollection( String id);?//method 3 ???? Collection getCollectionForValues(?int?value , Collection c);?//method 4 ???? Collection getCollectionForValues( String id , Collection c);?//method 5 } ?
void?setList(int?id ,java.util.List,boolean?persist);
?
public?interface?MyService1{
???? String getFoo(); ???? Collection getCollection(); ????void?setList(?int?id , java.util.List); } ?
public??? Collection<?? String??>?getValuesForIds(Collection<?? Integer??>);
|
Collections on Javabeans
对于使用?collections?的?java beans?来说,语法也是类似的。?例如,比方说我们有一个?Company bean?,包含了一个?List?,?其中的对象是?employees:
?
?
除了可以使用?<method> & <parameter>?元素外,?也可以使用?<property>?元素?:
??<mapping>
?????<property?componentType= "org.codehaus.xfire.Employee"?/>
??</mapping>
</mappings>
Handling Maps
Java Maps?并不能很好地映射到?XML Schema (no pun intended)?,因为?XML Schema?中没有?Map?的概念,客户端也是这样,?Maps?被转换成?{key?,?value}?元组的集合。?除了要提供?value?的类型以外,你还必须为?Aegis?提供?key?的类型?:
?
?
映射文件应该像下面这样?:
??<mapping>
????<method?name= "getGiftList"?>
??????<return-type?keyType= "org.codehaus.xfire.NiceChild"?componentType= "org.codehaus.xfire.Present"?>
????</method>
??</mapping>
</mappings>
这将生成下面的类型?:
??<xsd:sequence>
????<xsd:element?name= "entry"?minOccurs= "0"?maxOccurs= "unbounded"?>
??????<xsd:complexType>
????????<xsd:sequence>
??????????<xsd:element?name= "key"?type= "ns1:NiceChild"?minOccurs= "0"?maxOccurs= "1"?/>
??????????<xsd:element?name= "value"?type= "ns1:Present"?minOccurs= "0"?maxOccurs= "1"?/>
????????</xsd:sequence>
??????</xsd:complexType>
????</xsd:element>
??</xsd:sequence>
</xsd:complexType>
Collections of Collections of Collections of....
在某些情况下,你可能想要传递?Collections of Collections?。比方说你有一个返回?List of a List of Doubles?的服务?(?不要问为什么你要做这样一件事情?...):
?
?
要处理这种情况,我们需要引进一个新的?<component>?元素。?下面是一个很好的例子?:
??<mapping>
????<method?name= "getListofListofDoubles"?>
??????<return-type?componentType= "#someDoubles"?/>
????</method>
????<component?name= "someDoubles"?class= "java.util.List"?componentType= "java.lang.Double"?/>
??</mapping>
</mappings>
正像你在这里所看到的,返回类型的?componentType?是一个指向?<component>?的引用,而不是一个类。组件类型?"#someDoubles"?引用到名字为?"someDoubles"?的?<component>?。
Aegis?将会自动给这些?collections?命名为?ArrayOfDouble?和?ArrayOfArrayOfDouble?。?你也可以改变这些名字。?lin