A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

   在上一篇章的基础前提条件下,我们将进入第二阶段的学习,使用Castor进行编组和解组。首先从一些简单的对象类开始,比如代表人、唱片、图书或者某种其他具体对象的类。然后可以阅读本文中关于映射的内容,从而增加一些更复杂的类。
  Castor 最基本的操作是取一个 Java 类然后将类的实例编组成 XML。可以把类本身作为顶层容器元素。比如 Book 类很可能在 XML 文档中得到一个名为 “book” 的根元素。类的每个属性也表示在 XML 文档中。因此值为 “Power Play” 的 title 属性将生成这样的 XML<title>Power Play</title>
这样一来,很容易由此推出一个简单 Java 类所生成的 XML 文档的其余部分。
编组类的实例
开始编组代码之前有几点需要注意。第一,只能编组类的实例而不能编组类本身。类是一种结构,等同于 XML 约束模型,如 DTD XML Schema。类本身没有数据,仅仅定义了所存储的数据的结构和访问方法。
实例化类(或者通过工厂以及其他实例生成机制获得)将赋予它具体的形式。然后用实际数据填充实例的字段。实例是惟一的,它和同一类的实例具有相同的结构,但数据是不同的。图 1 直观地说明了这种关系。
1. 类提供结构,实例即数据

因而编组的只能是实例。后面将看到如何使用约束模型和映射文件改变 XML 的结构。但是现在要做的是让 XML 结构(元素和属性)和 Java 结构(属性)匹配。
(一)基本的编组
下面是本文中将使用的一个简单的 Book
public class Book {
private String isbn;
private String title;
private String authorName;
public Book(String isbn, String title, String authorName) {
this.isbn = isbn;
this.title = title;
this.authorName = authorName;
}
...set/get方法省略...
编译上述代码将得到 Book.class 文件。这个类非常简单,只有三个属性:ISBN、标题和作者姓名(这里有些问题,暂时先不管)。仅仅这一个文件还不够,Castor 还需要几行代码将 Book 类的实例转化成 XML 文档。
下面的程序创建了一个新的 Book 实例并使用 Castor 转化成 XML
(二)Book 编组器类
public class BookMarshaller {
public static void main(String[] args) {
Book book = new Book("9780312347482", "Power Play", "Joseph Finder");
FileWriter writer = new FileWriter("book.xml");
Marshaller.marshal(book, writer);
}
}
运行该程序。将得到一个新文件 book.xml。打开该文件将看到如下所示的内容:
<?xml version="1.0" encoding="UTF-8"?>
<book><author-name>Joseph Finder</author-name>
<isbn>9780312347482</isbn><title>Power Play</title></book>
(三)更复杂的类型
存储多个作者的 Book
public class Book {
private String isbn;
private String title;
private List authorNames;
public Book(String isbn, String title, List authorNames) {
this.isbn = isbn;
this.title = title;
this.authorNames = authorNames;
}
public Book(String isbn, String title, String authorName) {
this.isbn = isbn;
this.title = title;
this.authorNames = new LinkedList();
authorNames.add(authorName);
}
...set/get方法省略...
}
修改 BookMarshaller 类如下:
public class BookMarshaller {
public static void main(String[] args) {
Book book = new Book("9780312347482", "Power Play", "Joseph Finder");
FileWriter writer = new FileWriter("book.xml");
Marshaller.marshal(book, writer);
List book2Authors = new ArrayList();
book2Authors.add("Douglas Preston");
book2Authors.add("Lincoln Child");
Book book2 = new Book("9780446618502", "The Book of the Dead",
book2Authors);
writer = new FileWriter("book2.xml");
Marshaller.marshal(book2, writer);
}
}
打开 book2.xml 看看 Castor 如何处理集合:
带有收集器的 XML 结果
  <?xml version="1.0" encoding="UTF-8"?>
<book><isbn>9780446618502</isbn><title>The Book of the Dead</title>
<author-names xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="java:java.lang.String">Douglas Preston</author-names>
<author-names xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="java:java.lang.String">Lincoln Child</author-names>
</book>
        显 然,Castor 处理作者姓名列表没有问题。更重要的是,Castor 不仅为作者名称创建了一个 blanket 容器,这个框架实际上看到了列表的内部,并认识到内容是字符串(要记住,这不是参数化列表,Castor 必须自己确定列表成员的类型)。因此 XML 进行了一些非常具体的类型化工作。这是个不错的特性,尤其是如果需要将 XML 转化回 Java 代码之前进行一些处理的话。
(四)添加自定义类
存储字符串作者姓名肯定最终会出现重复的数据(多数作者写了不只一本书)。
public class Author {
private String firstName, lastName;
private int totalSales;
public Author(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
...set/get方法省略...
public void addToSales(int additionalSales) {
this.totalSales += additionalSales;
}
}
(五)使用自定义作者类的 Book
public class Book {
private String isbn;
private String title;
private List authors;
public Book(String isbn, String title, List authors) {
this.isbn = isbn;
this.title = title;
this.authors = authors;
}
public Book(String isbn, String title, Author author) {
this.isbn = isbn;
this.title = title;
this.authors = new LinkedList();
authors.add(author);
}
...set/get方法省略...
public void addAuthor(Author author) {
authors.add(author);
}
}
(六)增加了作者信息的 BookMarshaller
public class BookMarshaller {
public static void main(String[] args) {
Author finder = new Author("Joseph", "Finder");
Book book = new Book("9780312347482", "Power Play", finder);
FileWriter writer = new FileWriter("book.xml");
Marshaller.marshal(book, writer);
List book2Authors = new ArrayList();
book2Authors.add(new Author("Douglas", "Preston"));
book2Authors.add(new Author("Lincoln", "Child"));
Book book2 = new Book("9780446618502", "The Book of the Dead",
book2Authors);
writer = new FileWriter("book2.xml");
Marshaller.marshal(book2, writer);
}
}
编译然后运行编组器。看看两个结果文件,这里仅列出 book2.xml,因为这个文件更有趣一点。
包括作者和图书信息的 XML 结果
<?xml version="1.0" encoding="UTF-8"?>
<book><authors xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
total-sales="0" xsi:type="java:ibm.xml.castor.Author"><last-name>Preston</last-name>
<first-name>Douglas</first-name></authors><authors
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" total-sales="0"
xsi:type="java:ibm.xml.castor.Author"><last-name>Child</last-name>
<first-name>Lincoln</first-name></authors><isbn>9780446618502</isbn>
<title>The Book of the Dead</title></book>
Castor 同样能办到。它说明了如何同时编组 Book Author 类(再看看 authors 列表)。Castor 甚至为 Author 增加了 totalSales 属性,可以试试看结果如何。

进行解组
解组非常简单。有了 XML 文档,并保证具有和数据匹配的 Java 类之后,剩下的工作交给 Castor 就行了。我们来解组前面生成的两个 XML 文档
  清单 12. 解组图书
public static void main(String[] args) {
   FileReader reader = new FileReader("book.xml");
   Book book = (Book)Unmarshaller.unmarshal(Book.class, reader);
   System.out.println("Book ISBN: " + book.getIsbn());
   System.out.println("Book Title: " + book.getTitle());
   List authors = book.getAuthors();
   for (Iterator i = authors.iterator(); i.hasNext(); ) {
      Author author = (Author)i.next();
      System.out.println("Author: " + author.getFirstName() + " " +
      author.getLastName());
   }
   reader = new FileReader("book2.xml");
   book = (Book)Unmarshaller.unmarshal(Book.class, reader);
   System.out.println("Book ISBN: " + book.getIsbn());
   System.out.println("Book Title: " + book.getTitle());
   authors = book.getAuthors();
   for (Iterator i = authors.iterator(); i.hasNext(); ) {
      Author author = (Author)i.next();
      System.out.println("Author: " + author.getFirstName() + " " +
      author.getLastName());
   }
}
(一)Castor 要求使用无参数的构造器
Castor 主要通过反射和调用 Class.forName(类名).newInstance() 这样的方法进行解组,因而 Castor 不需要了解很多就能实例化类。但是,它还要求类必须能通过不带参数的构造器实例化。
好消息是 Book 和 Author 类只需简单修改就能避免这些错误。只需要为两个类增加不带参数的构造器,public Book() { } 和 public Author() { }。重新编译并运行代码。
有了无参数的构造器,不仅仅是 Castor,任何 类或者程序都能创建类的新实例。对于图书和作者来说,可以创建没有 ISBN、标题和作者的图书,或者没有姓和名的作者 — 这肯定会造成问题。如果 Castor 没有更先进的特性,这种缺陷就不可避免,因此必须非常注意类的使用。还必须考虑为任何可能造成 NullPointerException 错误的数据类型设置具体的值(字符串可以设为空串或者默认值,对象必须初始化等等)。
  还记得 吗?Castor 使用反射机制。恰恰因为只有对象提供无参数构造器的时候它才能创建对象,因为没有 setFieldName() 方法就无法设置字段的值。因此需要为 Book 和 Author 类增加一些方法。下面是需要添加的方法:
  setIsbn(String isbn)(Book 类)
  setFirstName(String firstName)(Author 类)
  setLastName(String lastName)(Author 类)
增加上述方法之后重新编译就行了。
(三)成功解组
  再次尝试运行解组器,将得到如下所示的结果:
增加作者和 ISBN setter 方法后的解组结果
[bmclaugh:~/Documents/developerworks/castor-2] java ibm.xml.castor.BookUnmarshaller
Book ISBN: 9780312347482
Book Title: Power Pla
Author: Joseph Finder
Book ISBN: 9780446618502
Book Title: The Book of the Dead
Author: Douglas Preston
Author: Lincoln Child
前面我曾提到解组非常简单。但是这和上面的情况不符,解组不是需要对类作很多修改吗?
实际上的确很简单。修改都是在您的类中,而和 Castor 解组过程无关。Castor 用起来非常简单,只要类的结构符合 Castor 的要求 — 每个类都要有无参数构造器,每个字段都要有 get/set 方法。
结束语
  到目前为止还没有提到的 Castor 的一大特性是映射文件。我们是直接从 Java 代码翻译成 XML。但是有几个假定:
  需要把 Java 类中的所有字段持久到 XML。
  需要在 XML 中保留类名和字段名。
  有一个类模型和需要反序列化的 XML 文档中的数据匹配。
  对于企业级编程,这些假定都有可能不成立。如果将字段名和类名存储到 XML 文档中被认为是一种安全风险,可能会过多泄露应用程序的结构,该怎么办?如果交给您一个 XML 文档需要转化成 Java 代码,但希望使用不同的方法名称和字段名称,怎么办?如果只需要少数类属性存储到 XML 中,怎么办?

  所有这些问题的答案都是一 个:Castor 提供了进一步控制 Java 代码和 XML 之间映射关系的方式。下一篇章将详细介绍映射。现在,不要只考虑编组和解组,还要花时间想想为了让 Castor 正常工作所作的那些修改意味着什么。在思考的同时,不要忘记看看下一篇章。到时候再见。

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马