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
廣告 -- 松凌科技 獨家贊助



>>軟體生產力提升計畫 -- 企業包班方案<<



如果你們公司正在想要轉型成為 java 的軟體公司,

或是已經採用 java 卻發現不得其門而入,

甚至工程師一直無法突破瓶頸,

松凌科技技術顧問團隊將帶領你們技術人員在五天的課程中,

了解整個 j2ee 的概觀以及標準的開發流程.



課程名稱: 建立 J2EE 標準的開發流程

課程編號: SLJ-021

課程時數: 40 小時

課程規劃:
  • J2EE 架構與概觀
  • 使用 Struts 建立一套完善的 MVC Framework
  • 建立自己的設計模組 Design Pattern
  • 使用 Hibernate 建立 O/R Mapping 的環境
  • 透過 JSTL 處理頁面端邏輯
  • 實作教育
基本開班人數: 10 人

收費標準: 每人 30,000 元, 超過一人酌收 5,000 元 ( 含稅, 大台北地區外需加上車馬費 )

聯絡電話: (02)8951-9554 # 111 陳先生

聯絡Email: kevin@softleader.com.tw

政府補助: 短中期輔導課程, 可申請軟體策進協會補助約 50% 的教育訓練費用

快速訂閱 -- 覺得好就訂閱吧~~~~
目前訂戶數: ; 目前發報數: ;
欣賞之前發行電子報 ;
投票區 ~ 覺得好就投票吧 !
有夠讚 不錯啦 普普說 蠻爛的 爛到最高點