How to Generate Java Code using Apache Velocity Template

In this article, I will show you how to generate a Java source code using the Apache Velocity Template Engine. In this article, we will create source code for User.java class dynamically by specifying fields.
To learn more about Apache Velocity Engine, check out official documentation at http://velocity.apache.org/engine/1.7/developer-guide.html.

1. Create a Simple Maven Project

Create a simple maven project using a Create Simple Maven Project Using Eclipse article.
Add below Velocity Template dependency to your pom.xml file:
<!-- https://mvnrepository.com/artifact/org.apache.velocity/velocity -->
<dependency>
     <groupId>org.apache.velocity</groupId>
     <artifactId>velocity</artifactId>
     <version>1.7</version>
</dependency>

2. Create a Velocity Template - class.vm

  1. Create a vtemplates folder under /resources directory.
  2. Create a template called class.vm file under vtemplates folder add the following code to it:
package ${packagename};

public ${className} implements Serializable {

 /** Serial Version UID. */
 private static final long serialVersionUID = 1L;

#foreach( $property in $properties )
 private $property.fieldType $property.fieldName;
#end 
 
#foreach( $property in $properties )
 public ${property.fieldType} get${property.getGetterAndSetterField()}() {
     return this.${property.fieldName};
 }
 
 public void set${property.getGetterAndSetterField()}(${property.fieldType} ${property.fieldName}) {
     this.${property.fieldName} = ${property.fieldName};
 } 
#end
}

3. Create a Velocity Template Writer

Let's first create Field POJO class:

package net.guides.codegenerator.beans;

public class Field {
    private String fieldName;
    private String fieldType;


    public Field(String fieldName, String fieldType) {
        super();
        this.fieldName = fieldName;
        this.fieldType = fieldType;
    }

    public String getFieldName() {
        return fieldName;
    }
    public void setFieldName(String fieldName) {
        this.fieldName = fieldName;
    }
    public String getFieldType() {
        return fieldType;
    }
    public void setFieldType(String fieldType) {
        this.fieldType = fieldType;
    }
}

Follow the below steps to configure and use the velocity template in an application:
  1. Initialize the Velocity engine
  2. Read the template
  3. Put the data model in a context object
  4. Merge the template with context data and render the view
package net.guides.codegenerator.util;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;

import net.guides.codegenerator.beans.Field;

public class VelocityWriter {
 
    static String modelName = "User";
    static String packageName = "com.companyname.projectname";
 
    public static void main(String[] args) {
        VelocityEngine velocityEngine = new VelocityEngine();
        velocityEngine.init();
      
        Template t = velocityEngine.getTemplate("vtemplates/class.vm");
       
        VelocityContext context = new VelocityContext();
  
        if(packageName != null) {
            context.put("packagename", packageName);
        }
  
        List<Field> properties = new ArrayList<>();
        properties.add(new Field("id", "int"));
        properties.add(new Field("firstName", "String"));
        properties.add(new Field("lastName", "String"));
        properties.add(new Field("dob", "LocalDate"));
        context.put("className", modelName);
        context.put("properties", properties);
  
        StringWriter writer = new StringWriter();
        t.merge( context, writer );
  
        System.out.println(writer.toString());
    }
}

4. Demo

Let's run above class will output:
19:26:28.268 [main] DEBUG org.apache.velocity - CommonsLogLogChute name is 'org.apache.velocity'
19:26:28.271 [main] DEBUG org.apache.velocity - Initializing Velocity, Calling init()...
19:26:28.271 [main] DEBUG org.apache.velocity - Starting Apache Velocity v1.7 (compiled: 2010-11-19 12:14:37)
19:26:28.271 [main] DEBUG org.apache.velocity - Default Properties File: org\apache\velocity\runtime\defaults\velocity.properties
19:26:28.271 [main] DEBUG org.apache.velocity - Trying to use logger class org.apache.velocity.runtime.log.AvalonLogChute
19:26:28.271 [main] DEBUG org.apache.velocity - Target log system for org.apache.velocity.runtime.log.AvalonLogChute is not available (java.lang.NoClassDefFoundError: org/apache/log/format/Formatter).  Falling back to next log system...
19:26:28.271 [main] DEBUG org.apache.velocity - Trying to use logger class org.apache.velocity.runtime.log.Log4JLogChute
19:26:28.271 [main] DEBUG org.apache.velocity - Target log system for org.apache.velocity.runtime.log.Log4JLogChute is not available (java.lang.NoClassDefFoundError: org/apache/log4j/Layout).  Falling back to next log system...
19:26:28.271 [main] DEBUG org.apache.velocity - Trying to use logger class org.apache.velocity.runtime.log.CommonsLogLogChute
19:26:28.271 [main] DEBUG org.apache.velocity - Using logger class org.apache.velocity.runtime.log.CommonsLogLogChute
19:26:28.276 [main] DEBUG org.apache.velocity - ResourceLoader instantiated: org.apache.velocity.runtime.resource.loader.FileResourceLoader
19:26:28.276 [main] DEBUG org.apache.velocity - Do unicode file recognition:  false
19:26:28.276 [main] DEBUG org.apache.velocity - FileResourceLoader : adding path '.'
19:26:28.285 [main] DEBUG org.apache.velocity - ResourceCache: initialized (class org.apache.velocity.runtime.resource.ResourceCacheImpl) with class java.util.Collections$SynchronizedMap cache map.
19:26:28.286 [main] DEBUG org.apache.velocity - Loaded System Directive: org.apache.velocity.runtime.directive.Stop
19:26:28.287 [main] DEBUG org.apache.velocity - Loaded System Directive: org.apache.velocity.runtime.directive.Define
19:26:28.287 [main] DEBUG org.apache.velocity - Loaded System Directive: org.apache.velocity.runtime.directive.Break
19:26:28.288 [main] DEBUG org.apache.velocity - Loaded System Directive: org.apache.velocity.runtime.directive.Evaluate
19:26:28.289 [main] DEBUG org.apache.velocity - Loaded System Directive: org.apache.velocity.runtime.directive.Literal
19:26:28.289 [main] DEBUG org.apache.velocity - Loaded System Directive: org.apache.velocity.runtime.directive.Macro
19:26:28.290 [main] DEBUG org.apache.velocity - Loaded System Directive: org.apache.velocity.runtime.directive.Parse
19:26:28.291 [main] DEBUG org.apache.velocity - Loaded System Directive: org.apache.velocity.runtime.directive.Include
19:26:28.292 [main] DEBUG org.apache.velocity - Loaded System Directive: org.apache.velocity.runtime.directive.Foreach
19:26:28.316 [main] DEBUG org.apache.velocity - Created '20' parsers.
19:26:28.325 [main] DEBUG org.apache.velocity - Velocimacro : "velocimacro.library" is not set.  Trying default library: VM_global_library.vm
19:26:28.325 [main] DEBUG org.apache.velocity - Velocimacro : Default library not found.
19:26:28.325 [main] DEBUG org.apache.velocity - Velocimacro : allowInline = true : VMs can be defined inline in templates
19:26:28.325 [main] DEBUG org.apache.velocity - Velocimacro : allowInlineToOverride = false : VMs defined inline may NOT replace previous VM definitions
19:26:28.325 [main] DEBUG org.apache.velocity - Velocimacro : allowInlineLocal = false : VMs defined inline will be global in scope if allowed.
19:26:28.325 [main] DEBUG org.apache.velocity - Velocimacro : autoload off : VM system will not automatically reload global library macros
19:26:28.348 [main] DEBUG org.apache.velocity - ResourceManager : found vtemplates/class.vm with loader org.apache.velocity.runtime.resource.loader.FileResourceLoader
package com.companyname.projectname;

public User implements Serializable {

 /** Serial Version UID. */
 private static final long serialVersionUID = 1L;

 private int id;
 private String firstName;
 private String lastName;
 private LocalDate dob;
 
 public int getId() {
     return this.id;
 }
 
 public void setId(int id) {
     this.id = id;
 } 
 public String getFirstName() {
     return this.firstName;
 }
 
 public void setFirstName(String firstName) {
     this.firstName = firstName;
 } 
 public String getLastName() {
     return this.lastName;
 }
 
 public void setLastName(String lastName) {
     this.lastName = lastName;
 } 
 public LocalDate getDob() {
     return this.dob;
 }
 
 public void setDob(LocalDate dob) {
     this.dob = dob;
 } 
}

5. Generated Source Code

Note that we have printed User.java class code to console:
package com.companyname.projectname;

public User implements Serializable {

    /** Serial Version UID. */
    private static final long serialVersionUID = 1L;

    private int id;
    private String firstName;
    private String lastName;
    private LocalDate dob;
 
    public int getId() {
         return this.id;
    }
 
    public void setId(int id) {
         this.id = id;
    } 
    public String getFirstName() {
         return this.firstName;
    }
 
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    } 
    public String getLastName() {
        return this.lastName;
    }
 
    public void setLastName(String lastName) {
        this.lastName = lastName;
    } 
    public LocalDate getDob() {
        return this.dob;
    }
 
    public void setDob(LocalDate dob) {
        this.dob = dob;
    } 
}
That's it. You can also write above source code to file. Read more about Velocity template engine at http://velocity.apache.org/engine/1.7/developer-guide.html.

Comments

  1. Definition of net.guides.codegenerator.beans.Field; is missing in the example

    ReplyDelete
  2. It is not replacing values for methods name.

    public void $property.getGetterAndSetterField()(LocalDate dob) {
    this.dob = dob;

    vs

    public void setDob(LocalDate dob) {
    this.dob = dob;

    ReplyDelete
  3. how is it that $property.getGetterAndSetterField() is automatically fetching the fieldName instead of fieldType?
    Is it that the first variable in Field model will be fetched?

    ReplyDelete

Post a Comment

Leave Comment