自定义 数据模型
本教程中先前的 示例 显示了一些简单的 CodeGen 自定义。现在,您已经了解了 CodeGen 如何处理带有默认设置的 HR-XML TimeCard 模式,我们接下来将研究一些更强大的自定义。
自定义数据模型
CodeGen 使用默认设置生成的数据模型代码有一些弱点。首先,模式类型名称全都以 Type 为结尾,并且这种情况延续到对应的生成的类名上,导致名称过长。通过模式名称空间生成的包名 org.hrxml.ns 是合理的,但是如果包名可以表明该数据模型专门用于 TimeCard 文档,那么效果会更好。
清单 11 显示了生成的数据模型类的另外一个缺点,其中 java.math.BigInteger 用于表示 xs:integer 类型。这是使用标准 Java 类时 xs:integer 的最精确表示,但是与简单的 int 原语或 java.lang.Integer 对象类型相比,BigInteger 并不好用。糟糕的是,即使使用 xs:int 会更恰当,人们也通常使用 xs:integer 类型编写模式,因此开发人员可能会在生成的代码中遇到 BigInteger 值。本例就是这种情况:GenderCode 允许的实际值全都是个位数(如清单底部的原始模式片段所示)。
清单 11. xs:integer 生成示例
/**
* Schema fragment(s) for this class:
* <pre>
* <xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:integer"
* name="GenderCode"/>
* </pre>
*/
public class GenderCode
{
private BigInteger genderCode;
/**
* Get the 'GenderCode' element value.
*
* @return value
*/
public BigInteger getGenderCode() {
return genderCode;
}
/**
* Set the 'GenderCode' element value.
*
* @param genderCode
*/
public void setGenderCode(BigInteger genderCode) {
this.genderCode = genderCode;
}
}
<xsd:simpleType name="GenderCodeType">
<xsd:annotation>
<xsd:documentation>Must conform to ISO 5218 - Representation of Human Sexes
(0 - Not Known; 1 - Male; 2 - Female; 9 - Not specified)</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:integer">
<xsd:pattern value="[0129]"/>
</xsd:restriction>
</xsd:simpleType>
|
清单 12 显示了可以改进生成数据模型的这些缺点的自定义。package="org.hrxml.timecard" 属性将提供用于生成的类的 Java 包。type-substitutions="xs:integer xs:int" 属性将定义 CodeGen 所应用的模式类型置换,在本例中使用 xs:int 类型替换模式中引用的 xs:integer。通过向列表中添加更多类型名称,使用空格分隔每对置换以及其中的类名,您可以定义多对置换。
嵌套的 name-converter 元素将确定如何处理被转换为 Java 名称的 XML 名称。在本例中,strip-suffixes="Type" 属性将告诉 CodeGen 只要 Type 出现在名称末尾就删除它。您可以用一张用空格分隔的列表来提供要通过此属性删除的多个备选内容。您也可以使用 strip-prefixes 属性删除名称中不必要的前导文本,以及其他几种形式的自定义。如果您需要在名称转换中执行一些特殊操作,甚至可以用您自己的实现来替换默认的名称转换类。有关这些 name-converter 选项的完整信息,请参阅 JiBX CodeGen 文档。
最后,嵌套的 class-decorator 元素将向代码生成序列中添加一个修饰符(decorator)。在本例中,修饰符是 CodeGen 发行版中提供的预定义内容,它将添加用于集合值的有用的支持方法。在 CodeGen 构造数据模型类的源代码时,它将按顺序调用所有已配置的代码生成修饰符,并且这些修饰符可以进行修改或者添加到 CodeGen 生成的字段、方法和类构造中。使用 Eclipse AST 实现,把所有这些构造作为抽象语法树(Abstract Syntax Tree,AST)组件传递给修饰符。提供的修饰符(包括在这里用于添加方法的 org.jibx.schema.codegen.extend.CollectionMethodsDecorator 修饰符,以及用于向数据模型类中添加 java.io.Serializable 接口和可选的版本 id 的 org.jibx.schema.codegen.extend.SerializableDecorator)演示了如何结合使用 Eclipse AST 以扩展 CodeGen,因此这些类的源代码是编写您自己的修饰符的最佳起点。
清单 12. TimeCard 自定义示例
<schema-set xmlns:xs="http://www.w3.org/2001/XMLSchema" package="org.hrxml.timecard"
type-substitutions="xs:integer xs:int">
<name-converter strip-suffixes="Type"/>
<class-decorator class="org.jibx.schema.codegen.extend.CollectionMethodsDecorator"/>
</schema-set> |
您可以使用 custgen1 Ant 目标尝试执行清单 12 中的自定义,也可以使用 custom1 目标运行完整的生成、编译、绑定及测试操作。清单 13 显示了应用自定义的结果。TimeCardType 类名已经改为 TimeCard,并且除了 List get 和 set 方法之外,现在还添加了 size、add、indexed get 和 clear 方法。在 GenderCode 类中,BigInteger 引用已经被替换为一个简单的 int 原语类型。
清单 13. 自定义的数据模型
/**
* Schema fragment(s) for this class:
* <pre>
* ...
* </pre>
*/
public class TimeCard
{
...
private List<ReportedTime> reportedTimeList = new ArrayList<ReportedTime>();
...
/**
* Get the list of 'ReportedTime' element items.
*
* @return list
*/
public List<ReportedTime> getReportedTimes() {
return reportedTimeList;
}
/**
* Set the list of 'ReportedTime' element items.
*
* @param list
*/
public void setReportedTimes(List<ReportedTime> list) {
reportedTimeList = list;
}
/**
* Get the number of 'ReportedTime' element items.
* @return count
*/
public int sizeReportedTime() {
return reportedTimeList.size();
}
/**
* Add a 'ReportedTime' element item.
* @param item
*/
public void addReportedTime(ReportedTime item) {
reportedTimeList.add(item);
}
/**
* Get 'ReportedTime' element item by position.
* @return item
* @param index
*/
public ReportedTime getReportedTime(int index) {
return reportedTimeList.get(index);
}
/**
* Remove all 'ReportedTime' element items.
*/
public void clearReportedTime() {
reportedTimeList.clear();
}
...
}
/**
* Schema fragment(s) for this class:
* <pre>
* <xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:int"
* name="GenderCode"/>
* </pre>
*/
public class GenderCode
{
private int genderCode;
/**
* Get the 'GenderCode' element value.
*
* @return value
*/
public int getGenderCode() {
return genderCode;
}
/**
* Set the 'GenderCode' element value.
*
* @param genderCode
*/
public void setGenderCode(int genderCode) {
this.genderCode = genderCode;
}
} |

 |

|
清除不使用的定义
在使用初始简单模式的第一个自定义示例中,您看到了通过使用 generate-all="false" 禁止生成每个全局定义,并使用 includes 列表强制生成特定定义,从而控制生成的数据模型中包括的类型定义。清单 14 显示了添加了这些属性的 TimeCard 模式的修改后的自定义,只包含要包括到生成的数据模型中的 TimeCard 元素(当然,还包含 TimeCard 表示所使用的一切内容)。
清单 14. 只包含 TimeCard 组件的自定义
<schema-set xmlns:xs="http://www.w3.org/2001/XMLSchema" package="org.hrxml.timecard"
type-substitutions="xs:integer xs:int" generate-all="false">
<name-converter strip-suffixes="Type"/>
<class-decorator class="org.jibx.schema.codegen.extend.CollectionMethodsDecorator"/>
<schema name="TimeCard.xsd" includes="TimeCard"/>
</schema-set> |
您可以使用 custgen2 Ant 目标尝试用 CodeGen 使用此自定义,或者使用 custom2 目标运行完整的生成、编译、绑定及测试。此更改将把数据模型中顶级类的数目从 15 个减少到 10 个 — 这是简化数据模型的好开端。
|