Tag Archives: javadoc

Use Groovy to recurse folders and create files via template

Via scripting one can create multiple files in a folder hierarchy and customize the file contents based on the folder location. This can be easily done using the Groovy language.

Note: In the past “package.html” files were used, but the latest approach is to create “package-info.java” files. These Java files contain the package Javadoc info, and have other uses. Kind of the return of Java classes as configuration as used in the bad ole complex early EJB days.

In this particular use case, I have a legacy Java project that does not contain package level Javadoc files. There are about a hundred package folders. It would be daunting to create these manually. It is not a mere copy since the package info must contain the specific package declaration: package x.y.z;.

 

In listing 1 below, the processFolders method takes in a closure “createInfo” and a variable length argument of Strings. The strings are to allow creating the files starting at multiple base folders. With the paths.each{} we take each string and create a File object. Now we recurse all folders at this file location. At each folder in the recursion we invoke the closure.

import groovy.io.FileType

def processFolders(createInfo, String... paths) {
    paths.each{
        def base = it
        new File(it).eachFileRecurse(FileType.DIRECTORIES){ file -> 
             def path = file.getPath()
             println "$path"
             createInfo(base, path)                                
        }
   }
}

def templateText = ''' 
/**
 * TODO Summary.
 * <p>
 * TODO Description.
 */
package ${pack};
'''

def template = new groovy.text.SimpleTemplateEngine()
       .createTemplate(templateText)

processFolders({base, p ->
    def pack = (p-base).replace(File.separator, '.')
          .replaceFirst(/^\.+/, '');
    new File(p,"package-info.java").text = template.make(['pack':pack]) 
}, 'src\\main\\java','src\\test\\java')

Listing 1
 

Because we are using variable length arguments, which must be the last parameter in a method, we can’t use the usual Groovy closure idiom, and define it inline (but maybe there is a way?):

processFolders(){
   ... body of closure ...
}

Alternatively, we could have used a named closure instead of inline, as follows:

def proc = {base, p ->
    def pack = (p-base).replace(File.separator, '.').replaceFirst(/^\.+/, '');
    new File(p,"package-info.java").text = template.make(['pack':pack]) 
}

At each folder during recurse, we keep the base folder, then later we subtract the folder paths (yup, Groovy allows String subtraction), and convert the folder path into a package string. Then we resolve the template with the binding containing the package name. The String produced by the template is written to a new file via the file’s ‘text’ property.

The result when run is the creation of package-info.java files at each subfolder, and the package line will be correct. Each file will have two TODO entries for the summary and description. Of course, the same code with minor changes can be used to create package.html files instead. Or just add a switch for ‘old’ or ‘new’ package level info file.

Updates
March 4, 2014: Changed to use eachDirRecurse. Not tested yet.
March 5, 2014: Hmmmm. eachDirRecurse didn’t work.

Environment

  • Groovy Version: 2.2.2 JVM: 1.7.0_25 Vendor: Oracle Corporation OS: Windows 7
  • Eclipse 4.3
  • Groovy-Eclipse Feature: 2.9.0.xx-20140228-1800-e43-SNAPSHOT

Some links

Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License.