索引
1. 示例需求
在运行下文中讲述的示例时,用户需要预先做一些准备工作。用户可以从
castor网站上获取最新1.1.2.1版本包括castor-1.1.2.1.zip和castor-1.1.2.1-examples.zip解压到本地目录,在Eclipse中构建一个Java项目。然后将解压目录中的castor-1.1.2.1.jar,lib目录下的commons-logging-1.1.jar,log4j-1.2.13.jar和xerces-J_1.4.0.jar添加到项目的类路径中。
2. Castor XML映射概念
Castor XML 通过Mapping定义的方式简化了Java类和XML文档之间的绑定。尽管可以使用Castor默认的自省方式编组和解编Java对象,但是对于复杂的映射绑定,Mapping定义提供了更加细致的控制。同时,Mapping文件可以在一定程度上解耦合Java对象模型与XML文档,从而避免各自的变化给对方带来的影响。
2.1概述
Mpping文件本身也以XML文档格式定义。Mapping文档以Java对象模型为视角,用于描述Java对象如何映射为XML文档节点,Java对象中的字段属性如何映射为XML文档节点中的子节点或属性。
如上图所示,在Castor中,一个Java类映射为一个XML节点,Java类中的属性字段映射为XML节点下的子节点或者属性。描述上述映射的Mapping文件如下所示:
<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<
mapping
>
<
description
>
Description of the mapping
</
description
>
<
map-to
xml
="
Person
"/>
<
class
name
="
Person
">
<
field
name
="
name
"
type
="
string
">
<
bind-xml
name
="
name
"
node
="
element
"/>
</
field
>
<
field
name
="
birthday
"
type
="
date
">
<
bind-xml
name
="
birthday
"
node
="
element
"/>
</
field
>
</
class
>
</
mapping
>
2.2编组过程
在Castor中,一个Java类必须映射为一个XML节点。当Castor编组一个Java对象的过程如下:首先,如果存在映射信息,从映射信息中确定该对象所对应的XML节点名称;如果不存在映射信息,则使用对象的类名作为XML节点名。然后,使用映射文件中字段
<
field
>的映射信息确定Java对象中的一个字段属性如何转换为XML文档中的如下几种存在:
Castor遍历整个Java对象,如果发现一个Class类型的属性,则查找Mapping文件中的
<
class
>节点定义。
如果在Mapping文件中找不到一个类的对应信息,默认情况下,Castor会分析这个类的元数据,采用一组默认的规则来定义要编组的字段属性所映射的XML文档元素。默认规则如下:
2.3解编过程
在解编过程中,当Castor查找到一个XML文档节点时,Castor首先查找映射信息来决定如何解编XML文档为Java对象。如果不存在映射信息,Castor会使用XML节点的名称决定如何构建类(Class)实例,例如,如果节点的名称为”test-element”,在Mapping文件不存在时,Castor将构建一个名称为”TestElement”的类。然后,Castor根据映射文件中关于字段属性的映射信息处理该XML文档节点下的内容。
3. 映射文件定义详解
3.1Mapping文件的根节点
如上例XML Mapping
文件所示,Mapping
文件的根节点为
<mapping>。<mapping>节点的Xml Schema定义为:
<
xsd:element
name
="
mapping
">
<
xsd:complexType
>
<
xsd:sequence
>
<
xsd:element
name
="
description
"
type
="
xsd:string
"
minOccurs
="
0
"/>
<
xsd:element
ref
="
include
"
minOccurs
="
0
"
maxOccurs
="
unbounded
"/>
<
xsd:element
ref
="
class
"
minOccurs
="
0
"
maxOccurs
="
unbounded
"/>
<
xsd:element
ref
="
key-generator
"
minOccurs
="
0
"
maxOccurs
="
unbounded
"/>
</
xsd:sequence
>
</
xsd:complexType
>
</
xsd:element
>
<
mapping
>
节点下的节点包括:
-
一个
<
description
>
节点,可选的,用于添加描述信息
-
一个或多个
<
include
>
节点,用于引用其他的映射文件
-
一个或多个
<
class
>
节点,用于描述每一个定义
Mapping
的
Java
类
-
一个或多个
<
key-generator
>
节点,该节点在
Castor JDO
中使用,后续文档将详细解释
Mapping
文件举例如下:
<?xml version="1.0"?> <!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN" "http://castor.org/mapping.dtd"> <mapping> <description>Description of the mapping</description> <include href="other_mapping_file.xml"/> <class name="A"> ......... </class> <class name="B"> ......... </class> </mapping> |
|
<
class
>
节点的
Schema
定义如下:
<
xsd:element
name
="
class
">
<
xsd:complexType
>
<
xsd:sequence
>
<
xsd:element
name
="
description
"
type
="
xsd:string
"
minOccurs
="
0
"/>
<
xsd:element
ref
="
cache-type
"
minOccurs
="
0
"/>
<
xsd:element
ref
="
map-to
"
minOccurs
="
0
"/>
<
xsd:element
ref
="
named-query
"
minOccurs
="
0
"
maxOccurs
="
unbounded
"/>
<
xsd:choice
>
<
xsd:element
ref
="
field
"
minOccurs
="
0
"
maxOccurs
="
unbounded
"/>
<
xsd:element
ref
="
container
"
minOccurs
="
0
"
maxOccurs
="
unbounded
"/>
</
xsd:choice
>
</
xsd:sequence
>
<
xsd:attribute
name
="
name
"
type
="
xsd:ID
"
use
="
required
"/>
<
xsd:attribute
name
="
extends
"
type
="
xsd:IDREF
"
use
="
optional
"/>
<
xsd:attribute
name
="
depends
"
type
="
xsd:IDREF
"
use
="
optional
"/>
<
xsd:attribute
name
="
identity
"
type
="
xsd:NMTOKENS
"
use
="
optional
"/>
<
xsd:attribute
name
="
access
"
use
="
optional
"
default
="
shared
">
<
xsd:simpleType
>
<
xsd:restriction
base
="
xsd:string
">
<
xsd:enumeration
value
="
read-only
"/>
<
xsd:enumeration
value
="
shared
"/>
<
xsd:enumeration
value
="
exclusive
"/>
<
xsd:enumeration
value
="
db-locked
"/>
</
xsd:restriction
>
</
xsd:simpleType
>
</
xsd:attribute
>
<
xsd:attribute
name
="
key-generator
"
type
="
xsd:string
"
use
="
optional
"/>
<
xsd:attribute
name
="
auto-complete
"
type
="
xsd:boolean
"
use
="
optional
"
default
="
false
"/>
<
xsd:attribute
name
="
verify-constructable
"
type
="
xsd:boolean
"
use
="
optional
"
default
="
true
"/>
</
xsd:complexType
>
</
xsd:element
>
<
class
>
节点包含了
Java
类与
XML
文档之间映射的所有信息。其中,详细描述了
Java
类中各个字段属性与
XML
文档元素的映射。
Øname:
映射的Java
类名称,使用类的全名,如”com.acme.MyClass”
。
Øextends:
只有在该类扩展其他类时,使用该参数指定扩展的类。如果被扩展的类未在该Mapping
文件中指定,则不能使用该属性。
Ødepends:
在Castor JDO
中指明类之间的依赖关系,用于表示数据库表中关联表的概念。
Øauto-complete:
如果该属性值为”true”
,则Castor
在处理该类时首先采用自省的方式决定该类的字段属性,然后使用Mapping
文件中对该字段属性的设定覆盖自省方式的操作。auto-complete
属性可以让Castor
的默认自省处理方式与Mapping
定义方式很好的结合,从而降低对包含很多字段的类进行复杂的设定操作。
Øidentity:
在Castor JDO
中使用,用于描述该类实例的主键字段,详细信息参考Castor JDO
部分。
Øaccess:
在Castor JDO
中使用,详细信息参考Castor JDO
部分。
Økey-generator:
在Castor JDO
中使用,详细信息参考Castor JDO
部分。
Ødescription
:可选的属性,用于对该类添加描述性信息
Øcache-type:
只在Castor JDO
中使用,详细信息参考Castor JDO
部分。
Ømap-to:
可选属性,如果XML
中节点名称与类(Class)
名称不同,则使用该节点设定。默认的,Castor
会自动分析XML
节点名称和类名称之间的映射,如对于Java
类”XxxYyy”
,Castor
会自动映射为XML
节点”xxx-yyy”
。如果用户不希望Castor
自动生成该名称,则可以使用<map-to>
节点来指定XML
映射名称。注意:<map-to>
仅用于XML文档中的根节点。
Øfield
:节点下包含 零个或多个<field>节点。每个<field>节点用于描述Java类中的一个字段属性。<class>
<class>
映射举例
package mypackage public class MyClass { public int foo; public String getBar() { ... } public void setBar(String bar) { ... } } |
|
如果用户希望
输出的
XML
文档格式如下:
<data foo-like="12"> <something>...</something> </data> |
|
则用户需要以如下方式设定
Mapping
映射文件:
<mapping> ... <class name="mypackage.MyClass"> <map-to xml="data"/> <field name="foo" direct="true" ...> <bind-xml name="foo-like" node="attribute"/> </field> </field name="bar" ....> <bind-xml name="something" node="element"/> </field> </class> ... </mapping> |
|
<map-to>
节点的Schema
定义如下:
<
xsd:element
name
="
map-to
">
<
xsd:complexType
>
<
xsd:attribute
name
="
table
"
type
="
xsd:NMTOKEN
"
use
="
optional
"/>
<
xsd:attribute
name
="
xml
"
type
="
xsd:string
"
use
="
optional
"/>
<
xsd:attribute
name
="
ns-uri
"
type
="
xsd:string
"
use
="
optional
"/>
<
xsd:attribute
name
="
ns-prefix
"
type
="
xsd:NMTOKEN
"
use
="
optional
"/>
<
xsd:attribute
name
="
element-definition
"
type
="
xsd:boolean
"
use
="
optional
"
default
="
false
"/>
<
xsd:attribute
name
="
ldap-dn
"
type
="
xsd:string
"
use
="
optional
"/>
<
xsd:attribute
name
="
ldap-oc
"
type
="
xsd:string
"
use
="
optional
"/>
</
xsd:complexType
>
</
xsd:element
>
<map-to>
节点用于指定给定Java
类与XML
文档节点的映射。<map-to>
节点只用于XML
文档根节点,如果该节点未在Mapping
文件中设定,则Castor
采用如下处理策略:
Ø在编组过程中,通过Java
类名称命名XML
文档根节点名,如Java
类”XxxYyy”
映射为XML
节点”xxx-yyy”
Ø在解编过程中,通过XML
文档根节点名称确定Java
类名称,如XML
节点”test-element”
映射为Java
类”TestElement”
用户可以在castor.properties
中指定Castor
在Java
类名称与XML
文档节点名之间的转换策略。
<map-to>
节点的属性包括:
Øxml
:类映射的XML节点名称Java
Øns-uri:XML
节点的名称空间URI
Øns-prefix:XML
节点的名称空间前缀
Øelement-definition:True if the descriptor as created from a schema definition that was of type element (as opposed to a <complexType> definition). This only is useful in the context of source code generation
Øldap-dn:
在Castor XML
中不使用该属性
Øldap-oc:
在Castor XML
中不使用该属性
< field>
节点的
Schema
定义如下:
<
xsd:element
name
="
field
">
<
xsd:complexType
>
<
xsd:sequence
>
<
xsd:element
name
="
description
"
type
="
xsd:string
"
minOccurs
="
0
"/>
<
xsd:element
ref
="
sql
"
minOccurs
="
0
"/>
<
xsd:element
ref
="
bind-xml
"
minOccurs
="
0
"/>
<
xsd:element
ref
="
ldap
"
minOccurs
="
0
"/>
</
xsd:sequence
>
<
xsd:attribute
name
="
name
"
type
="
xsd:string
"
use
="
required
"/>
<
xsd:attribute
name
="
type
"
type
="
xsd:string
"
use
="
optional
"/>
<
xsd:attribute
name
="
required
"
type
="
xsd:boolean
"
use
="
optional
"
default
="
false
"/>
<
xsd:attribute
name
="
transient
"
type
="
xsd:boolean
"
use
="
optional
"
default
="
false
"/>
<
xsd:attribute
name
="
direct
"
type
="
xsd:boolean
"
use
="
optional
"
default
="
false
"/>
<
xsd:attribute
name
="
lazy
"
type
="
xsd:boolean
"
use
="
optional
"
default
="
false
"/>
<
xsd:attribute
name
="
container
"
type
="
xsd:boolean
"
use
="
optional
"/>
<
xsd:attribute
name
="
get-method
"
type
="
xsd:string
"
use
="
optional
"/>
<
xsd:attribute
name
="
has-method
"
type
="
xsd:string
"
use
="
optional
"/>
<
xsd:attribute
name
="
set-method
"
type
="
xsd:string
"
use
="
optional
"/>
<
xsd:attribute
name
="
create-method
"
type
="
xsd:string
"
use
="
optional
"/>
<
xsd:attribute
name
="
handler
"
type
="
xsd:string
"
use
="
optional
"/>
<
xsd:attribute
name
="
collection
"
use
="
optional
">
<
xsd:simpleType
>
<
xsd:restriction
base
="
xsd:string
">
<
xsd:enumeration
value
="
array
"/>
<
xsd:enumeration
value
="
vector
"/>
<
xsd:enumeration
value
="
arraylist
"/>
<
xsd:enumeration
value
="
hashtable
"/>
<
xsd:enumeration
value
="
collection
"/>
<
xsd:enumeration
value
="
set
"/>
<
xsd:enumeration
value
="
map
"/>
<
xsd:enumeration
value
="
enumerate
"/>
<
xsd:enumeration
value
="
sortedset
"/>
<
xsd:enumeration
value
="
iterator
"/>
</
xsd:restriction
>
</
xsd:simpleType
>
</
xsd:attribute
>
<
xsd:attribute
name
="
comparator
"
type
="
xsd:string
"
use
="
optional
"/>
<
xsd:attribute
name
="
identity
"
type
="
xsd:boolean
"
use
="
optional
"
default
="
false
"/>
</
xsd:complexType
>
</
xsd:element
>
<field>
节点用于描述如何编组/
解编Java
对象中的字段属性。Castor
可以从<field>
节点描述中的”name”
属性确定Java
字段的名称;可以从<field>
节点描述中的”type”
和”collection”
属性确定Java
字段的类型;可以从<field>
节点描述中的”direct”
,”get-method”
和”set-method”
属性确定Java
字段的访问方法。通过上述信息,Castor
能够操作Java
类中的字段属性。
Castor
通过以下两个规则来判定某一字段的类型签名:
如果
<field>
节点中没有
”collection”
属性,
”type”
属性指定的类型即为该字段的
Java
类型。
”type”
属性值既可以是
Java
对象类型的全限定名
(
包含包名称
)
,也可以是
Castor
定义的一系列简称。
Castor
支持的类型简称列表如下:
简称
|
原始类型
|
Java类型
|
other
|
N
|
java.lang.Object
|
string
|
N
|
java.lang.String
|
integer
|
Y
|
java.lang.Integer
|
long
|
Y
|
java.lang.Long
|
boolean
|
Y
|
java.lang.Boolean
|
double
|
Y
|
java.lang.Double
|
float
|
Y
|
java.lang.Float
|
big-decimal
|
N
|
java.math.BigDecimal
|
byte
|
Y
|
java.lang.byte.Type
|
date
|
N
|
java.util.Date
|
short
|
Y
|
java.lang.short.Type
|
char
|
Y
|
java.lang.Character.Type
|
bytes
|
N
|
bytes[]
|
chars
|
N
|
char[]
|
strings
|
N
|
string[]
|
loacle
|
N
|
java.util.Locale
|
Castor
会自动将XML
文档中的节点内容自动转换为上述Java
对象类型。如果设定了”collection”属性,collection属性值遵从下面的对象对象列表:
简称
|
原始类型
|
Java
类型
|
array
|
<java
类型>[]
|
<java
类型>[]
|
arraylist
|
java.util.List
|
java.util.Arraylist
|
vector
|
java.util.Vector
|
java.util.Vector
|
hashtable
|
java.util.Hashtable
|
java.util.Hashtable
|
collection
|
java.util.Collection
|
java.util.Arraylist
|
set
|
java.util.Set
|
java.util.Hashset
|
map
|
java.util.Map
|
java.util.Hashmap
|
sortedset
|
java.util.SortedSet
|
java.util.TreeSet
|
Collection集合中的对象为Java类型。对于Hashtable和Map类型的对象,Castor同时存储其键和值。对于其映射,可以使用org.exolab.castor.mapping.MapItem类通过顶层(相对于嵌套类映射)类映射定义和嵌套类映射定义来描述。
如果
”direct”
属性设定为true,则在Java类定义中,该字段必须具有如下的声明:
public <type> <name>;
如果
”direct”
属性
设定为
false
或者该属性被忽略,
Castor
会通过该属性的存取方法访问该属性。首先,若设定了
'get-method'
或
'set-method'
,
Castor
会访问如下方法签名:
public <type> <get-method>();
或
public void <set-method>(<type> value);
若没有设定'get-method' 或'set-method'属性,Castor会尝试访问如下签名方法:
public <type> get<capitalized-name>();
或
public void set<capitalized-name>(<type> value);
<capitalized-name>是指Castor检查<name>属性值,将其首字母转换为大写,其他字符保持不变。
在默认情况下,’get-method’属性返回集合字段实例,’set-method’属性设定集合字段实例。特例情况如下表所示:
'get-method'
|
If a 'get-method' is provided for a collection field, Castor - in adition to the default behaviour described above - will deviate from the standard case for the following special prefixes:
public Iterator iterate...();
A 'get-method' starting with the prefix '
iterate
' is treated as Iterator method for the given collection field.
public Enumeration enum...();
A 'get-method' starting with '
enum
' is treated as Enumeration method for the given collection field.
|
'set-method'
|
If 'set-method' is provided for a collection field, Castor - in addition to the default behaviour described above - will accept an 'add' prefix and expect the following signature:
public void add...(<type> value);
This method is called for each collection element while unmarshalling.
|
|
<field>节点可以包含将Java字段映射为XML元素,数据库表列名称等信息。<field>节点可配置的属性如下:
Ø
name: 该属性是必须的,即使在该映射类中没有该字段属性。如果配置了”direct”属性,”name”属性值必须是映射对象中的一个public字段(该字段必须是public,非static和非transient的类型)。如果没有”direct”和”get-/set-method”属性设定,“name”属性值对应的字段通过该值确定其访问方法(采用Java Bean规范)。
Ø
type: 该字段属性的Java类型。Castor使用该信息将XML信息转换为Java对象信息(如将字符串转换为整型),定义该字段访问方法的签名。如果设定了”collection”属性,该属性信息用于指定集合中对象的类型信息。
Ø
required: 在编组和解编过程中,该字段是否可选,默认值为false。
Ø
transient: 如果设定为”true”,该字段在处理过程中将被忽略。
Ø
direct: 如果为true,该字段在Java类定义中必须是public类型。
Ø
collection: 如果该字段存在多个,则Castor使用该属性的设定来处理他们。该类型用于定义对应Java类中集合的类型。
Ø
get-method: 可选配置,”name”属性对应Java类字段的访问方法,具体使用参考前文描述。
Ø
set-method: 可选配置,”name”属性对应Java类字段的访问方法,具体使用参考前文描述。
Ø
create-method: 工厂方法,用于构建FieldHandler实例。
在XML Mapping中,<field>节点的子节点仅包含一个<xml>节点,用于描述如何将该字段属性映射到XML文档元素。
Castor自0.9.5版本以后,支持将一个
<
field>节点映射为该字段所属Java类构造函数的参数,这种机制通过”set-method”属性来实现。如果需要设定一个字段作为该类对象初始化时构造函数的一个参数,可以设定该字段在Mapping文件中
<
field>节点的”set-method”属性为”1%”-“9%”。 ”1%”表示构造函数的第一个参数,依次类推。这种机制举例如下:
假定存在如下所示的Java类Foo,Foo类除了具有一个默认的构造函数外,还有一个具有参数的构造函数。
public class Foo { private int size = 20; public Foo() { } public Foo(int size) { this.size = size; } public int getSize() { return size; } public void setSize(int size) { this.size = size; } } |
|
如果用户希望在实例化Foo类时,调用Foo类具有参数的构造函数而不是默认无参构造函数,则通过设定如下的映射文件实现。
<?xml version="1.0"?> <mapping> <class name="Foo"> <field name="size" get-method="getSize" set-method="%1" type="int"> <bind-xml node="attribute"/> </field> </class> </mapping> |
|
Mapping文件中的setMethod=”1%”的设定,会告诉Castor在实例化Foo类时,使用size属性字段作为构造Foo(int)的参数。
注意:如果设定了 ”set-method”
属性,则”get-method”
属性也必须设定。
<bind-xml>
节点的用于描述Java
字段如何在XML
文档中映射展现。在编组和解编过程中均要使用。
<bind-xml>
节点的Schema
定义如下:
<
xsd:element
name
="
bind-xml
">
<
xsd:complexType
>
<
xsd:sequence
>
<
xsd:element
ref
="
class
"
minOccurs
="
0
"/>
<
xsd:element
name
="
property
"
type
="
propertyType
"
minOccurs
="
0
"
maxOccurs
="
unbounded
"/>
</
xsd:sequence
>
<
xsd:attribute
name
="
name
"
type
="
xsd:QName
"
use
="
optional
">
</
xsd:attribute
>
<
xsd:attribute
name
="
type
"
type
="
xsd:NMTOKEN
"
use
="
optional
"/>
<
xsd:attribute
name
="
auto-naming
"
use
="
optional
">
<
xsd:simpleType
>
<
xsd:restriction
base
="
xsd:string
">
<
xsd:enumeration
value
="
deriveByClass
"/>
<
xsd:enumeration
value
="
deriveByField
"/>
</
xsd:restriction
>
</
xsd:simpleType
>
</
xsd:attribute
>
<
xsd:attribute
name
="
location
"
type
="
xsd:string
"
use
="
optional
">
</
xsd:attribute
>
<
xsd:attribute
name
="
matches
"
type
="
xsd:string
"
use
="
optional
"/>
<
xsd:attribute
name
="
reference
"
type
="
xsd:boolean
"
use
="
optional
"/>
<
xsd:attribute
name
="
node
"
use
="
optional
">
<
xsd:simpleType
>
<
xsd:restriction
base
="
xsd:string
">
<
xsd:enumeration
value
="
attribute
"/>
<
xsd:enumeration
value
="
element
"/>
<
xsd:enumeration
value
="
namespace
"/>
<
xsd:enumeration
value
="
text
"/>
</
xsd:restriction
>
</
xsd:simpleType
>
</
xsd:attribute
>
<
xsd:attribute
name
="
QName-prefix
"
type
="
xsd:NMTOKEN
"
use
="
optional
"/>
<
xsd:attribute
name
="
transient
"
type
="
xsd:boolean
"
use
="
optional
"/>
</
xsd:complexType
>
</
xsd:element
>
Ø
name: XML节点或属性的名称。注意:该属性值必须是QName,可以使用名称空间前缀来表明该节点或属性所属的特定名称空间,该前缀在编组过程中并不保留或使用,只是用来保持文档的格式良好。
Ø
auto-naming: 如果未设定name属性,auto-naming属性用于提示是否Castor自动为该字段构建相应的名称。通常情况下,使用<field>节点中的name属性值作为XML元素的名称。
Ø
type: 该节点在XML文档中的 Schema类型,Castor编组框架使用该属性确定对XML节点的处理方式。如”QName”。
Ø
location: 允许用户设定XML文档中 “间接路经”上的节点作为该Java字段属性的映射(如该字段所属类的XML节点映射为“AAA”,该节点的名称为“TTT”,但不是“AAA节点的子节点”,而是“AAA”节点的子节点“BBB”节点的子节点,则可以使用location属性映射为XML文档中的“AAA/BBB/TTT”。详细信息参看下述
“
Loaction
属性简介”。
Ø
QName-prefix: 如果该字段对应XML文档节点中的一个QName值,则可以使用该属性设定其前缀。详细信息参考“Castor源代码自动生成章节”。
Ø
reference: 在解编该字段时,指明该字段是否看作一个对象引用。
Ø
matches: 允许覆盖节点名称的匹配规则。该属性值是一个标准的正则表达式,用于替代”name”属性。如果值为”*”,则可以匹配任何XML节点名称,但是仅当不存在其他字段与XML节点名称匹配时,使用该匹配。
Ø
node: 表明该字段映射成为XML文档中的属性,节点还是文本元素。默认情况下,原始类型的字段映射成XML属性,其他的映射成为XML节点。
Ø
transient: 如果其值设定为true,则视该节点为临时的,不做处理。默认继承<field>节点中transient属性值。
3.5.2 <bind-xml>中使用嵌套的类映射
Castor
自0.9.5.3
版本开始,<bind-xml>
节点支持嵌套的类映射定义。该功能在某个类映射信息需要在多个地方指定时非常方便,如映射Hashtable/HashMap/Map
等集合类时的情况。具体使用参考下面的例子:
嵌套类举例
|
<bind-xml ...> <class name="org.exolab.castor.mapping.MapItem"> <field name="key" type="java.lang.String"> <bind-xml name="id"/> </field> <field name="value" type="com.acme.Foo"/> </class> </bind-xml> |
|
3.5.3 location属性简介
<bind-xml>
节点中的location
属性允许用户将字段映射为XML
文档中的内嵌节点或者在映射节点封装一个节点。封装节点只出现在XML
文档结构中,与Mapping
文件定义的Java
对象没有直接映射关系。下面仍以Foo
类为例,
public class Foo { private Bar bar = null; public Foo(); public getBar() { return bar; } public void setBar(Bar bar) { this.bar = bar; } } |
|
我们希望将该类映射成为下面所示的XML
文档(注:’abc’
节点并不存在于Foo
或者Bar
类的定义中)
<?xml version="1.0"?> <foo>; <abc> <bar>...</bar> </abc> </foo> |
|
为实现上述映射,我们以如下方式定义Mapping
文件
<?xml version="1.0"?> ... <class name="Foo"> <field name="bar" type="Bar"> <bind-xml name="bar" location="abc"/> </field> </class> ... </mapping> |
|
需要注意的是,“location
”属性的值指定的是封装的节点的名称,如果希望封装多层节点,则节点名称之间使用”/”
分隔,如下例所示:
<bind-xml name="bar" location="abc/xyz" /> |
|
此外,用户还需要注意的是,<bind-xml>
节点中的属性”name”
指定的xml
元素名称并不是“location
”属性中指定的封装节点的一部分。同时,封装节点的父节点总是其所封装字段所在类对象映射的节点。“location
”属性同样可以封装XML
属性元素,如下所示的映射定义:
<bind-xml name="bar" location="abc" node="attribute" /> |
|
生成的XML
文档为:
<?xml version="1.0"?> <foo> <abc bar="..."/>; </foo> |
|
4. 映射文件使用举例
下面我们以一个完整的例子,说明如何使用Castor
的Mapping
映射文件实现Java
类与XML
文档之间的相互转换。
首先,我们定义一个名为”order.xml”
的数据文件,我们用这个XML
文件描述一个订单,该订单中包含这个订单的客户信息,以及客户在此订单中所订购的货物。一个订单中可以存在多个货物。
order.xml
<?xml version="1.0"?>
<
Order
reference
="
12343-AHSHE-314159
">
<
Client
>
<
Name
>
Jean Smith
</
Name
>
<
Address
>
2000, Alameda de las Pulgas, San Mateo, CA 94403
</
Address
>
</
Client
>
<
Item
reference
="
RF-0001
">
<
Description
>
Stuffed Penguin
</
Description
>
<
Quantity
>
10
</
Quantity
>
<
UnitPrice
>
8.95
</
UnitPrice
>
</
Item
>
<
Item
reference
="
RF-0034
">
<
Description
>
Chocolate
</
Description
>
<
Quantity
>
5
</
Quantity
>
<
UnitPrice
>
28.50
</
UnitPrice
>
</
Item
>
<
Item
reference
="
RF-3341
">
<
Description
>
Cookie
</
Description
>
<
Quantity
>
30
</
Quantity
>
<
UnitPrice
>
0.85
</
UnitPrice
>
</Item> |
|
我们要为该订单定义三个Java类,分别描述该订单,订单的客户和货物。
Ø
MyOrder
:代表该订单
Ø
ClientData
:代表订单的客户
Ø
Item
:代表订单中的一项货物
这三个Java类的代码如下所示:
MyOrder.java
|
import
java.util.Vector;
import
java.util.Enumeration;
public
class
MyOrder {
private
String
_ref
;
private
ClientData _client;
private
Vector
_items
;
private
float
_total
;
public
void
setReference(String ref) {
_ref
= ref;
}
public
String getReference() {
return
_ref
;
}
public
void
setClientData(ClientData client) {
_client = client;
}
public
ClientData getClientData() {
return
_client;
}
public
void
setItemsList(Vector items) {
_items
= items;
}
public
Vector getItemsList() {
return
_items
;
}
public
void
setTotal(
float
total) {
_total
= total;
}
public
float
getTotal() {
return
_total
;
}
// Do some processing on the data
public
float
getTotalPrice() {
float
total = 0.0f;
for
(Enumeration e =
_items
.elements(); e.hasMoreElements();) {
Item item = (Item) e.nextElement();
total += item._quantity * item._unitPrice;
}
return
total;
}
}
|
|
ClientData.java
|
public
class
ClientData {
private
String
_name
;
private
String
_address
;
public
void
setName(String name) {
_name
= name;
}
public
String getName() {
return
_name
;
}
public
void
setAddress(String address) {
_address
= address;
}
public
String getAddress() {
return
_address
;
}
}
|
|
Item.java
|
public
class
Item {
public
String
_reference
;
public
int
_quantity
;
public
float
_unitPrice
;
public
String
_description
;
} |
|
现在,我们有了预期的XML文档定义,也有了描述文档的Java类定义。下一步,我们定义XML文档与Java类之间的映射。在下面的mapping.xml文件中,我们定义了三个类MyOrder、ClientData和Item的映射。
mapping.xml
|
<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<
mapping
>
<
class
name
="
MyOrder
">
<
map-to
xml
="
Order
"/>
<
field
name
="
Reference
"
type
="
java.lang.String
">
<
bind-xml
name
="
reference
"
node
="
attribute
"/>
</
field
>
<
field
name
="
Total
"
type
="
float
">
<
bind-xml
name
="
total-price
"
node
="
attribute
"/>
</
field
>
<
field
name
="
ClientData
"
type
="
ClientData
">
<
bind-xml
name
="
Client
"/>
</
field
>
<
field
name
="
ItemsList
"
type
="
Item
"
collection
="
vector
">
<
bind-xml
name
="
Item
"/>
</
field
>
</
class
>
<
class
name
="
ClientData
">
<
field
name
="
Name
"
type
="
java.lang.String
">
<
bind-xml
name
="
Name
"
node
="
element
"/>
</
field
>
<
field
name
="
Address
"
type
="
java.lang.String
">
<
bind-xml
name
="
Address
"
node
="
element
"/>
</
field
>
</
class
>
<
class
name
="
Item
">
<
field
name
="
_reference
"
type
="
java.lang.String
"
direct
="
true
">
<
bind-xml
name
="
reference
"
node
="
attribute
"/>
</
field
>
<
field
name
="
_quantity
"
type
="
integer
"
direct
="
true
">
<
bind-xml
name
="
Quantity
"
node
="
element
"/>
</
field
>
<
field
name
="
_unitPrice
"
type
="
float
"
direct
="
true
">
<
bind-xml
name
="
UnitPrice
"
node
="
element
"/>
</
field
>
<
field
name
="
_description
"
type
="
string
"
direct
="
true
">
<
bind-xml
name
="
Description
"
node
="
element
"/>
</
field
>
</
class
>
</
mapping
>
|
|
具备上述资源后,我们通过下面的Java代码测试Castor通过Mapping映射文件来实现XML文档与Java对象间的相互转换。
main.java
|
import
org.exolab.castor.mapping.Mapping;
import
org.exolab.castor.xml.Unmarshaller;
import
org.exolab.castor.xml.Marshaller;
import
java.io.FileReader;
import
java.io.OutputStreamWriter;
import
org.xml.sax.InputSource;
public
class
Main {
public
static
void
main(String args[]) {
Mapping mapping =
new
Mapping();
try
{
// 1.
从
Mapping.xml
文件中加载映射信息
mapping.loadMapping(
"mapping.xml"
);
// 2.
解编
order.xml
文档,构造
java
对象
Unmarshaller unmar =
new
Unmarshaller(mapping);
MyOrder order = (MyOrder) unmar.unmarshal(
new
InputSource(
new
FileReader(
"order.xml"
)));
// 3.
调用
Java
类
MyOrder
的对象实例方法,修改该对象实例
float
total = order.getTotalPrice();
System.
out
.println(
"Order total price = "
+ total);
order.setTotal(total);
// 4.
将修改后的对象实例重新编组为
XML
文档并输出到控制台
Marshaller marshaller =
new
Marshaller(
new
OutputStreamWriter(
System.
out
));
marshaller.setMapping(mapping);
marshaller.marshal(order);
}
catch
(Exception e) {
System.
out
.println(e);
return
;
}
}
}
|
|
用户可以比较原来的order.xml文档与输出到控制台的XML文档数据的差别,从而体会Castor XML编组框架的功能。