Do not repeat dao!

Source: Internet
Author: User
Tags aop introductions
 

Build generic type-safe DAO

using Hibernate and Spring AOP
Document Options

send this page as an e-mail message


Expand Tomcat Application

Download IBM Open source Java application Server was CE new version V1.1


Level: Intermediate

Per Mellqvist (per@mellqvist.name), System architect, freelance writer

June 05, 2006 because of the adoption of the Java™5 generics, the idea of implementing the generic type security Data Access Object (DAO) becomes practical. In this article, the system architect per mellqvist shows a generic DAO implementation class based on Hibernate. Then show how to use the Spring AOP introductions to add a type-safe interface to a class to facilitate query execution.

For most developers, writing almost the same code for each DAO in the system has become a habit so far. While everyone has labeled this repetition "code taste," Most of us have learned to endure it. There is actually a solution. You can use many ORM tools to avoid code duplication. For example, using Hibernate, you can simply use session operations directly for all persistent domain objects. The disadvantage of this approach is the loss of type safety.

Why do you provide a type-safe interface for data access code. I would argue that when used with modern IDE tools, it reduces programming errors and increases productivity. First, the type-safe interface clearly indicates which domain objects have the available persistent storage. Second, it eliminates the need for error-prone type casts (which is a more common problem in query operations than in CRUD). Finally, it leverages most of the automatic completion features that are available today for most Ides. Using AutoComplete is a quick way to remember what queries can be used for specific domain classes.

In this article, I'll show you how to avoid repeatedly repeating DAO code, while still preserving the benefits of a type-safe interface. In fact, all you need to write for each new DAO is just the Hibernate mapping file, the unformatted old Java interface, and the 10 lines in the Spring configuration file.

DAO implementation

DAO patterns should be familiar to any enterprise Java developer. But the implementation of the pattern is different, so let's clarify the assumption behind the DAO implementation provided in this article: all database accesses in the system are made through DAO to implement encapsulation. Each DAO instance is responsible for one primary domain object or entity. If a domain object has an independent life cycle, it should have its own DAO. DAO is responsible for creating, reading (by primary key), updating, and deleting domain objects (creations, reads, updates, and Deletions,crud). DAO allows queries to be based on criteria other than primary key. I call this the Finder method or the finder. The return value of the Finder is typically a collection of domain objects that DAO is responsible for. DAO is not responsible for handling transactions, sessions, or connections. These are not handled by DAO to achieve flexibility.




Back to the top of the page


Generic DAO interface

The generic DAO is based on its CRUD operations. The following interface defines the method for the generic DAO:
Listing 1. Generic DAO interface

Public interface Genericdao <t, PK extends serializable> {/** Persist the Newinstance

    object into Database */
     PK Create (T newinstance);

    /** Retrieve An object this is previously persisted to the database using
     * The   indicated ID as primary key
     * /
    T read (PK ID);

    /** Save changes made to a persistent object.  *
    /void update (T transientobject);

    /** Remove An object from persistent storage in the database *
    /void Delete (T persistentobject);
}


implementing Interfaces

Using Hibernate to implement the interface in Listing 1 is simple, as shown in Listing 2. It simply calls the underlying Hibernate method and adds coercion type conversions. Spring is responsible for session and transaction management. (I assume, of course, that these functions have been set appropriately, but the topic is described in detail in the Hibernate and Springt manuals.) )
Listing 2. The first generic DAO implementation

public class Genericdaohibernateimpl <t, PK extends serializable>
    implements Genericdao<t, Pk>, Finderexecutor {
    private class<t> type;

    Public Genericdaohibernateimpl (class<t> type) {
        this.type = type;
    }

    Public PK Create (T-O) {return
        (PK) getsession (). Save (O);
    }

    Public T-read (PK ID) {return
        (T) getsession (). Get (type, id)
    ;

    public void update (T o) {
        getsession (). Update (o);
    }

    public void Delete (T o) {
        getsession (). Delete (o);

    Not showing implementations of getsession () and Setsessionfactory ()
            }

Spring Configuration

Finally, in the Spring configuration, I created an instance of Genericdaohibernateimpl. You must tell Genericdaohibernateimpl which domain class The constructor DAO instance will be responsible for. Only in this way can Hibernate know the type of object managed by DAO at run time. In Listing 3, I passed the domain class person from the sample application to the constructor and set the previously configured Hibernate session factory to the parameters of the instantiated DAO:
Listing 3. Configuring DAO

<bean id= "Persondao" class= "Genericdao.impl.GenericDaoHibernateImpl" >
        <constructor-arg>
            < value>genericdaotest.domain.person</value>
        </constructor-arg>
        <property name= " Sessionfactory ">
            <ref bean=" sessionfactory "/>
        </property>
</bean>
        





Back to the top of the page


Available generic DAO

I haven't finished yet, but what I have done is really ready for use. In Listing 4, you can see an example of using the generic DAO intact:
Listing 4. Using DAO

public void Somemethodcreatingaperson () {
    ...
    Genericdao DAO = (Genericdao)
     Beanfactory.getbean ("Persondao");//This should normally is injected person

    p = new Person ("per", "n");
    Dao.create (P);
}
        

Now, I have a generic DAO that can perform type-safe CRUD operations. It would be reasonable to have subclasses genericdaohibernateimpl the ability to add queries to each domain object. Because the purpose of this article is to show how to implement a query without writing explicit Java code for each query, I will use the other two tools to introduce the query into DAO, the Spring AOP and Hibernate named queries.




Back to the top of the page


Spring AOP Introductions

You can use the introductions in Spring AOP to add functionality to existing objects by wrapping them in the broker, defining the interfaces that should be implemented, and assigning all previously unsupported methods to a single handler. In my DAO implementation, I use introductions to add many finder methods to an existing generic DAO class. Because the Finder method is specific to each domain object, it is applied to the typed interface of the generic DAO.

The Spring configuration is shown in Listing 5:
Listing 5. Spring Configuration for Finderintroductionadvisor

<bean id= "Finderintroductionadvisor" class= "Genericdao.impl.FinderIntroductionAdvisor"/> <bean id=

" Abstractdaotarget "
        class=" Genericdao.impl.GenericDaoHibernateImpl "abstract=" true ">
        <property Name = "Sessionfactory" >
            <ref bean= "sessionfactory"/>
        </property>
</bean>

< Bean id= "Abstractdao"
        class= "Org.springframework.aop.framework.ProxyFactoryBean" abstract= "true" >
        <property name= "Interceptornames" >
            <list>
                <value>finderintroductionadvisor</ value>
            </list>
        </property>
</bean>
        

In the configuration file in Listing 5, I have defined three Spring beans. The first bean is finderintroductionadvisor, which handles all the methods that are introduced to DAO, which are not available in the Genericdaohibernateimpl class. I'll introduce the Advisor bean in more detail later.

The second bean is "abstract." In Spring, this means that the bean can be reused in other bean definitions, but not instantiated. In addition to the abstract attributes, the bean definition indicates only the instance I want to genericdaohibernateimpl and the reference to sessionfactory that the instance requires. Note that the Genericdaohibernateimpl class defines only one constructor that takes the domain class as its parameters. Because the bean definition is abstract, I can reuse the definition countless times in the future and set the constructor parameters to the appropriate domain class.

Finally, the third and most interesting bean wraps the Genericdaohibernateimpl vanilla instance in the broker, giving it the ability to execute the Finder method. The bean definition is also abstract and does not specify an interface that you want to introduce to the vanilla DAO. The interface is different for each specific instance. Note that the entire configuration shown in Listing 5 is defined only once.




Back to the top of the page


Extended Genericdao

Of course, each DAO's interface is based on the Genericdao interface. I just need to adapt the interface to a particular domain class and extend the interface to include the Finder method. In Listing 6, you can see examples of GENERICDAO interfaces that are extended for specific purposes:
Listing 6. Persondao Interface

Public interface Persondao extends Genericdao<person, long> {list<person>
    findbyname (String name);



Obviously, the method defined in Listing 6 is designed to find person by name. The required Java implementation code is all generic code and does not require any updates when adding more DAO.

Configure Persondao

Because the Spring configuration relies on a previously defined "abstract" bean, it becomes fairly concise. I need to indicate which domain class The DAO is responsible for and tell Springs which interface the DAO should implement (some methods are used directly, and some methods are used by using introductions). Listing 7 shows the Spring configuration file for Persondao:
Listing 7. Spring Configuration for Persondao

<bean id= "Persondao" parent= "Abstractdao" >
    <property name= "proxyinterfaces" >
        <value> genericdaotest.dao.persondao</value>
    </property>
    <property name= "target" >
        < Bean parent= "Abstractdaotarget" >
            <constructor-arg>
                <value>genericdaotest.domain.person </value>
            </constructor-arg>
        </bean>
    </property>
</bean>
        

In Listing 8, you can see this updated DAO version is used:
listing 8. Using type-safe interfaces

public void Somemethodcreatingaperson () {
    ...
    Persondao DAO = (Persondao)
     Beanfactory.getbean ("Persondao");//This should normally is injected person

    p = new P Erson ("per",);
    Dao.create (p);

    list<person> result = Dao.findbyname ("per"); Runtime Exception
}
        

Although the code in Listing 8 is the correct way to use type-safe Persondao interfaces, the DAO implementation is not complete. Calling Findbyname () can cause a Run-time exception. The problem is that I haven't implemented the query necessary to invoke Findbyname (). All that remains to be done is to specify the query. To correct the problem, I used the Hibernate named query.




Back to the top of the page


Hibernate named query

With Hibernate, you can define HQL queries and name them in the Hibernate mapping file (hbm.xml). You can use the query in Java code later by simply referencing the given name. One of the advantages of this approach is the ability to optimize queries at deployment time without having to change the code. As you'll see, another advantage is that you can implement the "complete" DAO without writing any new Java implementation code. Listing 9 is an example of a mapping file with a named query:
Listing 9. mapping file with named query


Listing 9 defines the Hibernate mapping for the domain class person, which has two properties: Name and weight. A person is a simple POJO with the above attributes. The file also contains a query that finds all instances of person in the database, where "name" equals the supplied parameter. Hibernate does not provide any real namespace functionality for named queries. For discussion purposes, I prefix all query names with the short (unqualified) name of the domain class. In the real world, it might be a better idea to use a full class name that includes a package name.




Back to the top of the page


Step-by-Step Overview

You have seen all the steps necessary to create and configure a new DAO for any domain object. The three simple steps are to define an interface that extends Genericdao and contains any finder methods that are required. Adds a named query for each finder to the Hbm.xml mapping file for the domain object. Adds a 10-line Spring configuration file for DAO.

View the code that executes the Finder method, which was written only once. ) to end my discussion.




Back to the top of the page


Reusable DAO Classes

The Spring advisor and interceptor used are simple, and in fact their job is to refer back to Genericdaohibernateimplclass. All calls with the method name beginning with "find" are passed to DAO and a single method Executefinder ().
listing 10. The realization of Finderintroductionadvisor

public class Finderintroductionadvisor extends {
    Public Finderintroductionadvisor () {Super (New Finderintroductioninterceptor ()); } public class Finderintroductioninterceptor implements Introductioninterceptor {public Object invoke (METHODINVOC ation methodinvocation) throws Throwable {Finderexecutor Genericdao = (finderexecutor) methodinvocation.getthis (

        );
        String methodname = Methodinvocation.getmethod (). GetName ();
            if (Methodname.startswith ("find")) {object[] arguments = methodinvocation.getarguments ();
        Return Genericdao.executefinder (Methodinvocation.getmethod (), arguments);
        else {return methodinvocation.proceed (); } public boolean implementsinterface (Class intf) {return intf.isinterface () && finderexecutor.
    Class.isassignablefrom (intf); }
}

Executefinder () method

The only thing missing from the implementation of listing 10 is the Executefinder () implementation. The code looks at the names of the classes and methods that are invoked, and uses the conventions on the configuration to match them with the names of the Hibernate queries. You can also use Findernamingstrategy to support methods for other named queries. The default implementation looks for a query called "Classname.methodname," where ClassName is a short name with no package. Listing 11 completes the generic type-safe DAO implementation:
implementation of the list of Executefinder ()

Public list<t> Executefinder (method, final object[] Queryargs) {
     final String queryname = Querynamefromm Ethod (method);
     Final Query namedquery = GetSession (). Getnamedquery (queryname);
     string[] namedparameters = Namedquery.getnamedparameters ();
     for (int i = 0; i < queryargs.length i++) {
             Object arg = queryargs[i];
             Type Argtype =  namedquery.setparameter (i, arg);
      }
      Return (list<t>) namedquery.list ();
 }

 Public String Querynamefrommethod (method Findermethod) {return
     type.getsimplename () + "." + Findermethod.getname ( );
 }


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.