第30期-Jakarta Commons Betwixt

第30期-Jakarta Commons Betwixt


作者:jini         来源:java 公开原始码报
申明:未经作者同意,谢绝转载




Jakarta Commons
#ASF#




ICQ 与 MSN 还有 Yahoo 等等 即时通讯 的战火从未间断, MSN 8 率先启动收费机制, 每个月 9.95 美元, 他列出了 10 个理由. 哇, Microsoft 的绝招就是靠著广大的使用群众, 以免费的手法击败对手, 再来自己订定价格, 真是厉害的商业策略. 这又是另一次的表现了 ^^~


但是, 很早之前, 大家都是使用 icq 的, 为何 msn 加入战局之后, 整个局势都被逆转了, 当 MSN 6 加入了自己可以设定传送的 icon 功能后, 我忽然深深觉得, icq 那个丑陋又难看的笑脸, 应该不会再出现在我眼前了, 那熟悉的 "喔喔.." 也将成为历史.... 整个商业经营的失败, 我觉得最重要的是 ICQ 自己的问题, 如同太平天国, 有极好的时机, 却少了策略. 另外, 我看到国内很多软件公司, 尤其因为达康时代的创意实作迅速窜起, 占领了多数的市场, 但是后来也是因为缺少策略, 失去了一切. 这个大概就是创业唯艰, 守成不易吧.


此外, 我很佩服 BEA 将 Microsoft 的 VB Develope Team 挖来开发 WorkShop, 不同于以往, 我看到了 IDE 原来可以这样做, BEA Weblogic WorkShop 8.1 可以轻易地开发 Portal, 我想, BEA 大概是因为 2002 年业绩被 IBM 微幅领先而不悦吧... 这个策略, 我能够遇见到 BEA 可以站稳这个市场. 而 Sun 呢 ? Project Rave 只闻楼梯响, 却连个屁都还闻不到, 我想他们应该要努力点, 不知道是不是能够如同他们宣称 JSF 可以 Component 化, 制作 WEB 呢 ^^~ , 大厂们, 加油吧 ^^~
之前介绍过 commons-digester , 用来读取 XML 的档案到 JavaBean, 那么, 当你要把 JavaBean 写成 XML, 就要使用 commons-betwixt.


欢迎参观 jini(99% jakarta) 的部落格 -


赞助 -- 如果你觉得这个电子报对你有帮助, 可以汇款赞助, 如果需要刊登广告, 也可联系 !
汇款帐号 : 第一银行 板桥分行 201-10-071238

帐户名称 : 松凌科技股份有限公司

联系电话 : (02)8951-9554 # 121 王先生

联系Email: johnny@softleader.com.tw

本周主题 -- jakarta commons-betwixt
SECTION 01 JavaBean 与 Betwixt 简介

其实, JavaBean 在 Java 初期就已经有的东西, 大家可以下载他的 Specification 1.0.1 查阅, 在标准的 JDK 中, 都会存在着 java.beans.* 这个 package, 而 JavaBean 到底是做些什么呢, 最重要的是, 只要是我们可以重复利用到的组件, 都可以把他做成一颗颗的 JavaBean, 而这次和 betwixt 有关的, 就是 BeanInfo Interface, 可以参阅他的教学文件, 此外, 好的 JavaBean 该如何制作, 可以参考 How to be a Good Bean .


而 Betwixt 就是提供了 XML introspection 的 机制去对应 JavaBeans 到 XML, 他实现出 XMLIntrospector 及 XMLBeanIfno 相似于 jdk 中标准的 Introspector 及 BeanInfo (都在 java.beans.* 之下), 提供了将 beans 转换成 XML 的方法, 可以自动产生 digester 的规则, 也可以根据个人的打字习惯设定不同的 BeanInfo 机制等等. 而 Maven, Scarab, commons-sql 都有采用到 betwixt 这些功能. 相似的项目有 JAXB, Castor, XMLBeans, JiBX 等等, 不过 Betwixt 是其中最简单去操控的, 而且可以与 EJB RemoteInterface 结合. 他算是以 Beans-centric 而 Castor 比较算是 Schema-centric.


目前版本为 1.0 alpha


binary 下载处 http://www.apache.org/dist/jakarta/commons/betwixt/binaries/commons-betwixt-1.0-alpha-1.zip

source 下载处 http://www.apache.org/dist/jakarta/commons/betwixt/source/commons-betwixt-1.0-alpha-1-src.zip


SECTION 02 Beans 和 XML 的对应关系

假设我们有下面这个 CustomerBean, 我们可以用两种 xml 表示方式来代表他存在的数值.
public class CustomerBean {
public String getName();
public Order[] getOrders();
public String[] getEmailAddresses();
}
第一种, 我可以把 name 的值设为 CustomerBean 的属性.
<CustomerBean name='James'>
    <order id='1'>...</order>
    <order id='2'>...</order>
    <emailAddress>jstrachan@apache.org</emailAddress>
</CustomerBean>
第二种, 我也可以把 name 拉出来成为 CustomerBean 的一个节点.
<customer>
    <name>James</name>
    <orders>
        <order id='1'>...</order>
        <order id='2'>...</order>
    </orders>
    <email-addresses>
        <email-address>jstrachan@apache.org</email-address>
    </email-addresses>
</customer>  



SECTION 03 简单的 BeanWriter 范例程序

首先, PersonBean.java 中, 我们就只是单纯的建立一个标准的 JavaBean, 具有一个空的 contructor ( 为了 reflection ), getters 及 setters, 外加一个 toString(), 为了简化范例程序, 我们另外建立了一个可以带入参数的 contructor.
public class PersonBean {
    
    private String name;
    private int age;
    
    /** Need to allow bean to be created via reflection */
    public PersonBean() {}
    
    public PersonBean(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }   
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }
    
    public String toString() {
        return "PersonBean[name='" + name + "',age='" + age + "']";
    }
}
接着, 我们使用 WriteExampleApp 来解释 betwixt 的操作模式, 我们先打印出 xml 的标头, 接着, 设置 beanWriter 的相关属性, 再来建立一个 John Smith 的 PersonBean, 我们只需要使用 beanWriter.write 就可以把 PersonBean 的 XML 数据放到 outputWriter 之中, 而 outputWriter.toString() 就会显示 PersonBean 的 XML 数据.
import java.io.StringWriter;

import org.apache.commons.betwixt.io.BeanWriter;

public class WriteExampleApp {

    /** 
     * Create an example bean and then convert it to xml.
     */
    public static final void main(String [] args) throws Exception {
        
        // Start by preparing the writer
        // We'll write to a string 
        StringWriter outputWriter = new StringWriter(); 
        
        // Betwixt just writes out the bean as a fragment
        // So if we want well-formed xml, we need to add the prolog
        outputWriter.write("<?xml version='1.0' ?>");
        
        // Create a BeanWriter which writes to our prepared stream
        BeanWriter beanWriter = new BeanWriter(outputWriter);
        
        // Configure betwixt
        // For more details see java docs or later in the main documentation
        beanWriter.getXMLIntrospector().setAttributesForPrimitives(false);
        beanWriter.setWriteIDs(false);
        beanWriter.enablePrettyPrint();
        
        // Write example bean as base element 'person'
        beanWriter.write("person", new PersonBean("John Smith", 21));
        
        // Write to System.out
        // (We could have used the empty constructor for BeanWriter 
        // but this way is more instructive)
        System.out.println(outputWriter.toString());
    }
}
执行的结果是
<?xml version='1.0' ?>
<person>
  <age>21</age>
  <name>John Smith</name>
</person>

如果我们将 setAttributesForPrimitives 设为 true,执行的结果是. ( 只要是 primitive 的数值都视为 xml 的属性 )
<?xml version='1.0' ?>
<person age="21" name="John Smith"/>



SECTION 04 简单的 BeanReader 范例程序

我们之前使用 commons-digester, 可以将 xml 数据读入 javabean 之中, 而 betwixt 的 BeanReader 就是靠著 digester 将 xml 数据读入, 不过他多了一个 registerBeanClass 来注册 Bean , 先建立一个 person.xml 文件放到执行目录中.
<?xml version='1.0' ?>
<person>
  <age>30</age>
  <name>Gary Lee</name>
</person>
接着, 我们先设定好 beanReader 的相关属性, 采用 parse 将 XML 数据读取到 beanReader 之中, 再来就是放入 person 这个 bean 之内, 因此, person 将拥有 person.xml 所设定的数值. 最后将使用 PersonBean.toString() 将数据显示出来.
import java.io.*;

import org.apache.commons.betwixt.io.BeanReader;

public class ReadExampleApp {
    
    public static final void main(String args[]) throws Exception{
        
        // Now convert this to a bean using betwixt
        // Create BeanReader
        BeanReader beanReader  = new BeanReader();
       
        // Configure the reader
        // If you're round-tripping, make sure that the configurations are compatible!
        beanReader.getXMLIntrospector().setAttributesForPrimitives(false);
        beanReader.setMatchIDs(false);
        
        // Register beans so that betwixt knows what the xml is to be converted to
        // Since the element mapped to a PersonBean isn't called the same, 
        // need to register the path as well
        beanReader.registerBeanClass("person", PersonBean.class);
        
        // Read Data From person.xml and parse it
        PersonBean person 
            = (PersonBean)beanReader.parse(new File("person.xml"));        
        
        // send bean to system out
        System.out.println(person);
    }
    
}
执行的结果是
PersonBean[name='Gary Lee',age='30']



SECTION 05 strategy 的一些技巧

如果我们直接采用 BeanWriter 印出 TallTreeBean 的 XML 文件, writer.write(new TallTreeBean(15.1f));
public class TallTreeBean {

    private float heightOfTree;
    
    public TallTreeBean(float height) {
        setHeightOfTree(height);
    }
    
    public float getHeightOfTree() {
        return heightOfTree;
    }   
    
    public void setHeightOfTree(float heightOfTree) {
        this.heightOfTree = heightOfTree;
    }
}       
将会产生下面的 xml 数据, 但是我们的 XML 属性习惯不会采用复和字, heightOfTree 我们希望用 height-of-tree 来显示, 此外, TallTreeBean 开头我们通常也是采用小写字元 tallTreeBean 来表示.
<TallTreeBean heightOfTree="15.1"/>
因此我们程序改为
import org.apache.commons.betwixt.io.BeanWriter;
import org.apache.commons.betwixt.strategy.DecapitalizeNameMapper;
import org.apache.commons.betwixt.strategy.HyphenatedNameMapper;

public class NameMapperExampleApp {
    
    public static final void main(String args[]) throws Exception{
        
        // create write and set basic properties
        BeanWriter writer = new BeanWriter();
        writer.getXMLIntrospector().setAttributesForPrimitives(true);
        writer.enablePrettyPrint();
        writer.setWriteIDs(false);
        
        // set a custom name mapper for attributes
        writer.getXMLIntrospector().setAttributeNameMapper(new HyphenatedNameMapper());
        // set a custom name mapper for elements
        writer.getXMLIntrospector().setElementNameMapper(new DecapitalizeNameMapper());
        
        // write out the bean
        writer.write(new TallTreeBean(15.1f));
        System.out.println("");
    }
    
}
HyphenatedNameMapper() 就是将复合字用"-"来切割, DecapitalizeNameMapper() 就是将首字改为小写, 此外 org.apache.commons.betwixt.strategy 下面还有
BadCharacterReplacingNMapper NameMapper implementation that processes a name by replacing or stripping illegal characters before passing result down the chain.
CapitalizeNameMapper A beanmapper which converts a type to start with an uppercase.
ClassNormalizer Class normalization strategy.
ConvertUtilsObjectStringConverter String <-> object conversion strategy that delegates to ConvertUtils.
DecapitalizeNameMapper A name mapper which converts types to a decapitalized String.
DefaultNameMapper A default implementation of the name mapper.
DefaultObjectStringConverter Default string <-> object conversion strategy.
DefaultPluralStemmer A default implementation of the plural name stemmer which tests for some common english plural/singular patterns and then uses a simple starts-with algorithm
HyphenatedNameMapper A name mapper which converts types to a hypenated String.
ListedClassNormalizer ClassNormalizer that uses a list of substitutions.
ObjectStringConverter Strategy class for string <-> object conversions.
大家可以自己尝试一下各种状况,


例如你的 bean 是属于
public class SomeBean {
    public <CollectionType> getFoo*();
    public void addFoo(<SingularType> foo);
}
CollectionType 可能是 array, a Collection, Enumeration, Iterator, Map 等等, 而 SingularType 是属于 Foo 的属性, 就是采用 DefaultPluralStemmer 来处理.


SECTION 06 结论

Betwixt 目前对于 DynaBean 的处理还有一些问题, 不过许多高级的处理, 例如整合 EJB 都有简单的方法处理, 当读取一个复杂的 bean 时, 可以自行定义 *.betwixt 文件, 让程序去正确地读取. 我不在此一一讲述, 有兴趣的可以到 commons-betwixt 的网站中, 查阅 advanced 的技巧.
参考 -- 相关书目或相关文章

  1. jakarta commons
    http://jakarta.apache.org/commons/
  2. jakarta commons-betwixt
    http://jakarta.apache.org/commons/betwixt/
  3. jakarta commons-betwixt api
    http://jakarta.apache.org/commons/betwixt/apidocs/index.html
  4. Oreilly OnJava Using the Jakarta Commons, Part 2
    http://www.onjava.com/pub/a/onjava/2003/07/09/commons.html?page=2


原作者:jini
来 源:java 公开原始码报
共有1265位读者阅读过此文

  • 上篇文章:第29期-Jakarta Commons DBCP
  • 下篇文章:配置 Tomcat 集群
  • posted on 2004-12-23 21:25  笨笨  阅读(3011)  评论(1编辑  收藏  举报

    导航