Wednesday, August 29, 2012

Keeping "DRY" with Classtemplater

Since I have been starting with REST jax-rs and tests I always had to repeat coding DAOs and Tests. This was extremely unproductive. I have been looking in to Spring Roo and some Eclipse plugins.

Spring Roo was too large and complex and I would have had to re-create the whole project according to the Spring Roo and Maven guidelines. Also I didn't know if GWTP is supported. I didn't want to learn yet another Framework and start from scratch again even if Spring Roo looks very promising and seems to support the creation of GWT. But I just found it to be to complicated and less flexible as I wanted it to be. 

All the other Eclipse Plugins I have been looking at also didn't support all features that I wanted until I stumbled over a plugin called Classtemplater.

Classtemplater is using Apache Velocity which is a scripting language to generate customized configuration files. I have already worked with Velocity and got interested. And..... it is extremely easy and yet f*ing brilliant. Basically the whole code for your DAOs, Tests and and other Classes that rely on to the Entity Class (or any other class but the entity class is the most convenient one) can be generated with Velocity templates.

If you want to get started read the following documentation:
In Classtemplater you define a template that you create from a class. In my example I want to create a CardResourceTests.class based on the Card.class (the entity class that contains all the getter and setter methods and attributes). So you create the Card.class first. Then you create the template called for example resourceTestsCRUD.vm which you put in to a folder in the root of your project. Mine is called "templates".

Once you install the Eclipse Plugin (over Help -> Install New Software -> you can right click on to the entity class (in my example Card.class), choose "classtemplator" and click on to "Generate". This will open a menu where you can choose the corresponding .vm template (in my example resourceTestsCRUD.vm).

Classtemplater specific Velocity variables
Print Methods
If you want to get all the methods from a class you are using the .vm template with you can do following:
#foreach( $method in $class.methods )
${} - ${method.returnType}
This will print the method name and the return type of all methods.  
Print attributes
#foreach( $attr in $attrs )
${} - ${attr.type}

This will print all the attributes and types of the attributes.

This is actually all you need. The rest is done with Velocity.

In my example we'll be creating a Card.class entity with some attributes. We will use this entity class together with a resourceTestsCrud.vm Velocity template to create the code of the CardResourceTests.class.

import java.util.Date;

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import javax.xml.bind.annotation.XmlRootElement;

public class Card {
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    @Extenstion(vendorName="datanucleus",  key="gae.encoded-pk", value="true")
    private String key;
    private String name;
    private Date creationDate;    
    private Date modificationDate;
    public Card() {
    public Card(String name)
        this.setCreationDate(new Date());
        this.setModificationDate(new Date());

    public Long getKey() {
        return key;

    public void setKey(Long key) {
        this.key = key;

    public String getName() {
        return name;

    public void setName(String name) { = name;

    public Date getCreationDate() {
        return creationDate;

    public void setCreationDate(Date creationDate) {
        this.creationDate = creationDate;

    public Date getModificationDate() {
        return modificationDate;

    public void setModificationDate(Date modificationDate) {
        this.modificationDate = modificationDate;

package ${package};

public class ${classname}ResourceTests {
    public void testCreate() throws Exception {
        Client client = Client.create();
        ${classname} ${classname.toLowerCase()} = new ${classname}();
#foreach($attr in $attrs)   
#if(${} != "key" && ${} != "creationDate" && ${} != "modificationDate")
        ${classname.toLowerCase()}.set${,1).toUpperCase()}${} = setme(${attr.type});

        WebResource ${classname.toLowerCase()}Resource = client.resource("http://localhost:8888/api/${classname.toLowerCase()}");
        ClientResponse response = ${classname.toLowerCase()}Resource.type(MediaType.APPLICATION_JSON)
            .post(ClientResponse.class, ${classname.toLowerCase()});
        ${classname} ${classname.toLowerCase()}Returned = (${classname})respone.getEntity(${classname}.class);
        assertEquals("Status", response.getStatus(), 200);
#foreach($attr in $attrs)   
#if(${} != "key" && ${} != "creationDate" && ${} != "modificationDate")
        assertEquals("${}", ${classname.toLowerCase()}.get${,1).toUpperCase()}${}(), ${classname.toLowerCase()}Returned.get${,1).toUpperCase()}${}());

Now we can right click on to the Card.class -> Choose "classtemplator" -> "Generate" and then choose the "resourceTestsCRUD.vm" template.

The code that appears in the preview that now could be saved as "CardResourceTests.class" looks as following:

public class CardResourceTests {
    public void testCreate() throws Exception {
        Client client = Client.create();
        Card card = new Card();
        card.setName = setme(String);

        WebResource cardResource = client.resource("http://localhost:8888/api/card");
        ClientResponse response = cardResource.type(MediaType.APPLICATION_JSON)
            .post(ClientResponse.class, card);
        Card cardReturned = (Card)respone.getEntity(Card.class);
        assertEquals("Status", response.getStatus(), 200);
        assertEquals("name", card.getName(), cardReturned.getName());

No comments:

Post a Comment