Levi9 Tech Blog



Tuesday, January 29, 2008

Lightweight Code Generator

For the Ministries projects for Ordina there was a need to write the Java code based on database schema. Websites of the Ministries are based on Hippo CMS, Cocoon, Java and JPOX (a JDO implementation) for persistance layer. Large amount of data is periodically exported on one system and imported to our system.
The majority of the application was generated with ddl2hbm (database to Hibernate mapping) tool but lot of changes on Hibernate 2 tools code was needed.

Hibernate tools also enable generating hibernate mapping from Java class (class2hbm) and vice versa (hbm2java). Since the tool is in Java (no templating supported) it was quite hard to make the changes to meet specific needs.
Based on idea that Hibernate mapping “look a like” XML (extended with several attributes or tags) is used the idea for lightweight code generation tool arrose. The tool should be easily extensible and template based. This is the reason why Jakarta Velocity is used as a simple, yet very effective template engine.
Code generator enables easy code generation based on simple model and easy to write templates. It enables code generation for Java, .NET, PHP, … basically everything that is object oriented.
Based on input model (similar to Hibernate mapping) and Velocity template(s) result is generated in the output directory.

Input model:
<?xml version="1.0" encoding="UTF-8"?>
<hibernate-mapping>
<class name="nl.levi9.cmt.woonfonds.Complaint">
<id name="id" type="int">
<generator class="identity">
</id>
<property type="String" name="title" name="Title" null="true">
<property type="String" name="email" name="E-mail" null="true">
<property type="int" name="visible" name="Visible" null="true">
</class>
</hibernate-mapping>

Template:
## Bean.vm
#parse( "Macros.vmm" )
#copyright()
package ${class.Package};

import nl.levi9.cmt.entity.GenericBean;
import nl.levi9.cmt.exception.AuthorizationException;
import nl.levi9.cmt.security.Security;
import nl.levi9.cmt.security.SecurityFactory;
import nl.levi9.cmt.util.logging.LogManager;
import nl.levi9.cmt.util.logging.LoggerInterface;
import nl.levi9.cmt.navigation.Project;

/**
* ${class.Name} bean
#vas()
$class.Access class ${class.Name} extends GenericBean {

/** Logger */
private static LoggerInterface logger = LogManager.getLogger(${class.Name}.class);
// Fields
#foreach($att in $class.Attributes)
#set ($access = $att.Access)
$att.Access ${att.Type} ${att.Name} = ${utility.defaultValue(${att.Type}, ${att.defaultValue})};
#end
$access Project project = null;

// Set methods
#foreach($att in $class.Attributes)
public void ${att.setterSignature()}(${att.Type} ${att.Name}) { this.${att.Name} = ${att.Name}; }
#end
public void setProject(Project project) { this.project = project; }

// Get methods
#foreach($att in $class.Attributes)
public ${att.Type} ${att.getterSignature()}() { return this.${att.Name}; }
#end
public Project getProject() { return this.project; }

// Copy method
public ${class.Name} copy() {
${class.Name} cc = new ${class.Name}();
#foreach($att in $class.Attributes)
cc.${att.setterSignature()}(this.${att.Name});
#end
cc.setProject(this.project);
Security sec = null;
try {
sec = SecurityFactory.createSecurity(
SecurityFactory.${class.Name.toUpperCase()}, null, cc);
} catch (AuthorizationException e) {
logger.warn(e);
}
cc.setSecurity(sec);
return cc;
}
}

Generated source:
/*
* Copyright (c) 2007 Levi9. All Rights Reserved.
*/
package nl.levi9.cmt.woonfonds;

import nl.levi9.cmt.entity.GenericBean;
import nl.levi9.cmt.exception.AuthorizationException;
import nl.levi9.cmt.security.Security;
import nl.levi9.cmt.security.SecurityFactory;
import nl.levi9.cmt.util.logging.LogManager;
import nl.levi9.cmt.util.logging.LoggerInterface;
import nl.levi9.cmt.navigation.Project;

/**
* Complaint bean
* @version 3.0
* @author cosmos@mailinglists.levi9.com
* @since 09-10-2007
*/
public class Complaint extends GenericBean {

/** Logger */
private static LoggerInterface logger = LogManager.getLogger(Complaint.class);
// Fields
protected int id = 0;
protected String title = "";
protected String email = "";
protected int visible = 0;
protected Project project = null;

// Set methods
public void setId(int id) { this.id = id; }
public void setTitle(String title) { this.title = title; }
public void setEmail(String email) { this.email = email; }
public void setVisible(int visible) { this.visible = visible; }
public void setProject(Project project) { this.project = project; }

// Get methods
public int getId() { return this.id; }
public String getTitle() { return this.title; }
public String getEmail() { return this.email; }
public int getVisible() { return this.visible; }
public Project getProject() { return this.project; }

// Copy method
public Complaint copy() {
Complaint cc = new Complaint();
cc.setId(this.id);
cc.setTitle(this.title);
cc.setEmail(this.email);
cc.setVisible(this.visible);
cc.setProject(this.project);
Security sec = null;
try {
sec = SecurityFactory.createSecurity(
SecurityFactory.COMPLAINT, null, cc);
} catch (AuthorizationException e) {
logger.warn(e);
}
cc.setSecurity(sec);
return cc;
}

}

Further reading:
http://today.java.net/pub/a/today/2004/05/12/generation1.html
http://www.onjava.com/pub/a/onjava/2004/05/05/cg-vel1.html
http://www.codegeneration.net/
http://jakarta.apache.org/velocity/
http://www.andromda.org/
http://xdoclet.sourceforge.net/xdoclet/index.html
http://www.codesmithtools.com/


posted by Damir Solajic
 

0 Comments:


Post a Comment
+ Blog Home
 

Links

Get the RSS Feed
Levi9 Global Sourcing

Previous Posts

Views on a new technologyOnce in a while – it can ...
Tomorrow it happens: Progress Software is hosting ...

Archives

September 2006
November 2006
January 2008

Powered by Blogger
Levi9 Global Sourcing | Jan van Goyenkade 8 | 1075 HP Amsterdam | The Netherlands | +31(0)206701947 | info@levi9.com
Copyright © Levi9 | www.levi9.com | www.levi9.de