Main   |   Project Page   |   Download  

                                 Grateful to
SourceForge.net Logo
for hosting this project

Learn Daozero Within 15 Minutes


1. What's Daozero? How it help me?

2. How it works?

3. Changed from a typical iBatis DAO bean to daozero bean

4. A abstract class example

5. Some limitation from current daozero release

6. How to deal with those iBatis features that current daozero doesn't support

7. If it doesn't work well

8. For other features & futher usage

9. Why it's recommended? Compare daozero with code generation tools

10. License

If you have any suggestion or problem, contact me (suntoech@sh163.net)
Or if you're familiar with Chinese, I'm very glad to discuss with you in Chinese Java forum

1. What's daozero? How it help me?

Daozero is a tiny Java Spring bean used to reduce the source of a persistence tier based on Spring's iBatis support, not a wrapper of Spring iBatis support. The usual way to use iBatis in Spring is to write code and invoke the iBatis API explicitly. Dao-zero invokes the iBatis API for the developer automatically, without the need to write implementation code. It will implement DAO interfaces automatically and invoke iBatis SQL mapped statements for you. You can use it to replace your DAO bean directly. The only thing developers will do is to declare a bean whose type is "daozero.ibatis.Dao" in spring config xml, and tell dao-zero bean name of DAO interface. No more need DAO implementation codes.

 

2. How it works?

Dao-zero bean invokes iBatis mapped statement whose name is same as method name of DAO interface( or abstract class). Both count and occurrence index of mapped statement should be keeped same as method arguments for current implementation(If the parameter is one Java bean, we could ignore this convention). It's a factory bean which implements org.springframework.beans.factory.FactoryBean and creates proxy object that implements DAO interface( or abstract class) for those beans need it, which typically are service beans. The proxy object takes repsonsibilities of constructing parameter map from invocation arguments and pass the parameter map to iBatis API, such as queryForObject(), queryForList(), etc. It is smart enough to know what you want is a java.lang.List or a ordinary java bean(POJO). But by current release, it doen't support queryForMap() yet.

Proxy object is created from different way depends on whether or not DAO type required is interface. If it is interface, proxy is created using standard JDK proxy(java.lang.reflect.Proxy), else, created using CGLIB enhancer(net.sf.cglib.proxy.Enhancer). For a CGLIB proxy, it will try to implement all public abstract methods for the abstract DAO class proxied. And, dao-zero provides some additional features, for example, to convert java.util.List returned by iBatis to POJO array or java.util.Iterator.

In fact, I hacked iBatis, have to cast some iBatis interface to its internal implementation class, because I cannot found how to get parameter map's meta data by iBatis's API. (So sorry for the bad smell )

 

3. Changed from a typical iBatis DAO bean to daozero bean

*I assume you have experience on taking Spring's iBatis support as persistence tier solution.

Supposed we have a table named "account":

--HSQLDB SQL
create table account (
    userid varchar(80) not null,
    email varchar(80) not null,
    constraint pk_account primary key (userid)
);
.

Accordingly, an entity class with properties "userId" and "email":

public class Account implements Serializable {
    private String userid;
    private String email;
    public String getUserId() { return this.userid; }
    public void setUserId(String s) { this.userid=s; }
    public String getEmail() { return this.email; }
    public void setEmail(String s) { this.email=s; }
}
.

And the DAO interface is:

public interface AccountDao {
    Account getAccountByUserId(String userId);
    void updateAccount(Account account);
    List getUsernameList();
}
.

For usual way, the iBatis DAO implementation may be:

import org.springframework.org.ibatis.support.SqlMapClientDaoSupport;

public class AccountDaoImpl
extends SqlMapClientDaoSupport
implements AccountDao {
   public Account getAccountByUserIdAndEmail(String userId, String email) {
      Map params = new HashMap();
      params.put( "userId", userId );
      params.put( "email", email );
      return getTemplate().queryForObject( "getAccountByUserIdAndEmail", params );
   }

/* Or, another way of getAccount...
   public Account getAccountByUserIdAndEmail(Account conditions) {
      return getTemplate().queryForObject( "getAccountByUserIdAndEmail", conditions );
   }*/


  public int updateAccount(Account account) {
      return getTemplate().update( "updateAccount", account );
   }

   public List getUsernameList();
      return getTemplate().queryForList( "getUsernameList", null );
   }

And the iBatis SQL mapped statement file is:

<select id="getAccountByUserIdAndEmail" resultClass="Account">
    select * from account where userid=#userId# AND email=#email#
</select>

<select id="getUsernameList" resultClass="java.lang.String">
    select userid from account
</select>

<update id="updateAccount">
    update account set email = #email# where userid=#userId#
</update>

And the Spring bean definition is:

<bean id="accountDao" class="AccountDaoImpl">
     <property name="sqlMapClient" ref="sqlMapClient"/>
</bean>

Now let us see what will happen with daozero: the first thing is to delete that AccountDaoImpl.java, and change Spring bean definition to:

<bean id="accountDao" class="daozero.ibatis.Dao">
     <property name="sqlMapClient" ref="sqlMapClient"/>
    <property name="targetType" value="AccountDao" /> <!-- interface -->
</bean>

As you see, the new way takes a fixed bean class "daozero.ibatis.Dao" as the implementation of "AccountDao", so AccountDaoImpl.java is not needed more.
It's not so complicated as imaginated, isn't it?

4. A abstract class example:

In some cases that you hope daozero not to override all your methods implementation, that means daozero should work with abstract implementation. The solution is to set bean's "targetType" property with an abstract class implemented DAO interface. For above sample, we reserve AccountDaoImpl.java, but maybe insert some additional operation into method "updateAccount(Account)":

public abstract class AccountDaoImpl
extends SqlMapClientDaoSupport
implements AccountDao {
    public abstract int __updateAccount(Account account);
    public int updateAccount(Account account) {
        // Insert additional operation code here
        return __updateAccount(account);
    }
}

The last place we should modifiy is SQL mapped statement's name to let daozero build relation between AccountDaoImpl.__updateAccount() and statement "__updateAccount":

<select id="getAccountByUserIdAndEmail" resultClass="Account">
    select * from account where userid=#userId# AND email=#email#
</select>

<select id="getUsernameList" resultClass="java.lang.String">
    select userid from account
</select>

<update id="__updateAccount">
    update account set email = #email# where userid=#userId#
</update>

5. Some limitation from current daozero release:

  • Methods with same name within one class are not allowed unless they have differenct argument amount.
  • Abstract method matches statement should be public abstract: "protected abstract" is not supported now(will be supported later);
  • iBatis queryForMap() is not supported yet( I'm considering how to make daozero more intellegent to support this feature);
  • Hibernate is not supported yet. Although I have already been working for a hibernate release, and there should be more features available because of hibernate's ORM capabilities, but please wait.
  • 6. How to deal with those iBatis features that current daozero doesn't support

  • For features that iBatis provided but currently not supported by daozero, we could implement them by ourselves in own abstract DAO class and let daozero to finish others for us. Daozero would use CGLIB to create a sub-class inherited from abstract DAO class and override remaining abstract methods automatically. For detail, please see 4. A abstract class example
  • Please tell me features you hope, I'm grateful for your suggestion. I will support them as I can as possible, and provide a temporary solution before available.
  • 7. If it doesn't work well

  • Sure that parameter's occurance in SQL mapped statement XML is same as method arguments' occurance.
  • Check using section 5 with limitations from current release, sure that there're no conflication with them.
  • 8. For other features & futher usage:

    In fact there's other user tips, sucha as:
    (1) Namespace: yes, it supports iBatis's namespace.
    (2) DAO bean property setting is supported too by providing a daozero property named "targetProperties". It is simple and direct, please download and see the Spring-JPetstore-based daozero's sample application for how to using it. And yet, there're almost every thing in \sample\jpetstore\war\WEB-INF\dao-context.xml -- the jpetstore DAO layer's spring xml, you could find other recommended service/dao layer practises in this sample if you compare diffences between springframework's version and this version.
    (3) From version 0.3, iBatis RowHandler supporting is available. The usage is nothing, just define an argument which implements RowHandler, daozero can know who is RowHandler so that transfer it to iBatis for us.
    (4) From version 0.4, both PaginatedList & java.util.List paged are supported by presenting conventions. For PaginatedList, method's last argument should be "int" holding page size. For List paged from iBatis' queryForList( ..., int startRow, int maxRow ), method's last 2 arguments should be "int" holding "startRow" and "maxRow".
    (5) From version 0.4, conversion java.util.List returned from iBatis' queryForList(...) to object array (such as java.lang.String[]) and java.util.Iterator can be found.
    (6) We provide 2 samples: a HelloWorld console application & a JPetstore web application based on springframework's jpetstore sample. They coverage how to use daozero. HelloWorld demostrate basic usage, and jpetstore demostrates more details for actual scenes. Please download source to see detail.

    9. Why it's recommended? Compare daozero with code generation tools

    Code generation, such as Abator, are great ideas, specially on speeding up project build-up. Daozero tries not to replace code generation tools but to take over some fixed or repeated codes from code generation tools and developers. Computer could work better and make less mistakes for fixed or repeated jobs than human beings, it's a better way for code generation tools to generate codes that developers may modify or make improvements, not to generate those fixed or repeated codes dropped into developers' views and give peoples opportunities to make mistakes(although those mistakes may be at low level, unconscious and stupid). Of course, we will improve daozero to take over API invocation as many as possible, as long as it doesn't take complexity as cost. Fortunately, daozero leave freedom for developers to write codes in their own abstract implementation(see 4. A abstract class example). Simple and direct, let us use technologies familied with as before and let daozero to deal with remaining things -- this is philosophy daozero follows.

    10. License:

    Apache License Version 2.0