Sunday, June 3, 2012

Daogen a Generator for JPA Dao Implementations

Recently I created a small library to generate Java JPA Dao's from Dao interface type annotated with query string. There are no runtime dependencies other the javax.persistence. Compile-time dependencies are freemarker and jalopy.
One of the drawbacks of using Named Queries in JPA is that you have to attach the query definitions either as annotation to an Entity class or put them manually in separate orm mapping files (XML). Daogen lets you attach query string as annotation to a method in your Dao interface type like this:
@DaoTypepublic interface CustomerDao {        
   @JpaNamedQuery(query = "select c from Customer c where name = :name")    
   List<Customer> findByName(String name);    

   @JpaNamedQuery(query = "select c from Customer c where name = :name
        and c.creationDate < :date", throwException = false)    
   Customer findByUniqueNameAndBeforeDate(String name, @JpaTemporal(TemporalType.DATE)Date date);    
   
   @JpaNamedQuery(query = "select c from Customer c where name = :name", throwException = true)    
   Customer findByUniqueNameMandatory(String name);    
   
   @JpaNamedQuery(query = "select o from Order o where o.customer.id = :id")    
   List<Order> findOrdersByCustomerId(Long id);    
}
Daogen will create Dao implementations for all Dao interface types, in this case CustomerDaoImpl. Method parameters are matched against query parameter names. If you don't want named queries you can use dynamic queries by using @JpaQuery instead of @JpaNamedQuery. Furthermore it generates one queries-orm.xml file for all named queries.
@Generated(value="Generated by nl.koelec.daogen.gen.DaoProcessor", date = "Mon May 28 21:43:32 CEST 2012")
public class CustomerDaoImpl extends AbstractDao implements CustomerDao {    
   private final EntityManager entityManager;    

   public CustomerDaoImpl(EntityManager entityManager) {        
       this.entityManager = entityManager;    
   }    

   @Override        
   protected EntityManager getEntitymanager() {
       return entityManager;        
   }
    
   @Override        
   public List findByName(String name) {
      Query query = getEntitymanager().createNamedQuery("CustomerDao.findByName"); 
      setParam("name", name, null, query);            
      return query.getResultList();        
   }
   ...
}

queries-orm.xml:

<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" 
    http://java.sun.com/xml/ns/persistence/orm 
    http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"version="1.0">
<!-- @Generated(value="Generated by nl.koelec.daogen.gen.DaoProcessor",
date = "Mon May 28 21:43:32 CEST 2012") -->
<named-query name="CustomerDao.findByName"> <query><![CDATA[ select c from Customer c where name = :name ]]></query></named-query>
<named-query name="CustomerDao.findByUniqueNameAndBeforeDate"> <query><![CDATA[ select c from Customer c where name = :name and c.creationDate < :date ]]></query></named-query>
...
</entity-mappings>

The queries-orm file is referenced from persistence.xml like so:
<persistence-unit name="testPU" transaction-type="RESOURCE_LOCAL">
   <provider>org.hibernate.ejb.HibernatePersistence</provider>
   <mapping-file>queries-orm.xml</mapping-file>
   ...

GITHUB

The code is in github and can be build with gradle
There are three gradle projects: daogen-core, dao-gen-processor and daogen-sample, each containing just a couple of java class files and some freemarker template files (part of daogen-processor).At runtime you will only need daogen-core. The daogen-processor jar contains the AnnotationProcessor used to generate the files at compile time.
You can use the prebuild jar files from the dist folder right away. Or you can build the projects yourself and go from there. The gradlew.bat file in the base folder lets you build daogen from source, whithout installing anything in advance with the following invocation: gradlew.bat build
After this you can take a look at the generated code and the test code in daogen-sample.

Using daogen in your own project.

Maven

put this plugin config in your pom file.
<build>   
   <plugins>      
      <plugin>         
         <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
              <version>2.3.2</version>              
              <configuration>                 
                 <source>1.6</source>                 
                 <target>1.6</target>                 
                 <generatedSourcesDirectory>generated-sources/src/main/java</generatedSourcesDirectory><annotationProcessors>
              <annotationProcessor>nl.koelec.daogen.gen.DaoProcessor</annotationProcessor>  
              </annotationProcessors>              
        </configuration>      
      </plugin>   
   </plugins>
</build>
Of course you also need the daogen-core and daogen-processor.jar as dependencies in your pom file.

Gradle

Look at gradle.build file in daogen-sample project.

Configuration

If you want you can override the used freemarker templates to change or add behaviour.Without supplying options to the DaoProcessor it will use the default templates packaged with the daogen-processor jar file.The following DaoProcessor options are supported:
  • templatedir folder where to look for override templates
  • ormtemplate queries orm template file name
  • daotemplate dao implementation template file name
  • daofactorytemplate dao factory implementation template file name
  • idaofactorytemplate dao factory interface template file name

Note

Don't forget to mark your Dao interface type with @DaoType at the class level.

No comments: