Revision: 10018
Initial Code
Initial URL
Initial Description
Initial Title
Initial Tags
Initial Language
at December 3, 2008 11:38 by theobriscoe
Initial Code
#! /usr/bin/env groovy
import groovy.text.*
import groovy.text.GStringTemplateEngine
import java.lang.reflect.Field
/**
* @author Theo Briscoe
* @modified by Arsalan S.
* @modified by Dan Walker
*/
class GroovyFileReader {
static String IDL_PROJECT_SRC_LOCATION = "C:/Projects/IDL/src/java"
static String IDL_PROJECT_CLASS_LOCATION = "C:/Projects/IDL/build/classes"
// static String IDL_PROJECT_SRC_EXCLUDED = "Stub,Helper,Holder,Operations,Interface"
//Compile and run from ant
//Evaluate command line arguments
//Build list of java classes
//foreach java class
//load the class definitions
//Use reflection to get list of fields
//build the utility class
//Place generated clsses in the correct directory
//Identify enumerations
def subClasses = []
def subClassesCopy= []
def directList = ["SegmentDetailInfo"]
def openMethodList = ["com.aaa.travel.idl.Segment"]
def importArray = []
String getFields(java.lang.String className){
def stringFields = []
def numericFields=[]
def booleanFields = [] // boolean
def customFields = []
def stringArrayFields = []
def enumFields = [] //enum fields inside the object
def numericArrayFields=[]
def booleanArrayFields = []
def customArrayFields = []
def enumArrayFields = []
//1. Load class definition & get all the public fields
java.lang.Class c = Class.forName(className)
println "Class " + c.getName()
java.lang.reflect.Field[] fields = c.getFields()
//2. Identify fields and store them in arrays
fields.each { field ->
print "Type name is "+field.getType().getName()+" -- "
//print " "
println "Field name is "+ field.getName()
def type = field.getType()
def typeName = type.getName()
switch (type) {
case type.isArray():
// Again check for int and boolean arrays
// if (field.getType().getName().contains("java.lang.String")){
// stringArrayFields.add(field)
// }
int startIndex = typeName.indexOf("com.")
Class actualClass = null
// Dividing the arrays in two categories
if (startIndex > 0) {
// category 1: custom classes like com.aaa.*
typeName = typeName.substring(startIndex,typeName.length()-1)
System.out.println("Real type is " + typeName)
def lastIndex = typeName.lastIndexOf(".")
// def a
actualClass = Class.forName(typeName)
if(Helper.isCorbaEnum(actualClass)){
// Array of enum type
enumFields.add(field)
} else {
customFields.add(field)
if(!openMethodList.contains(typeName)) {
subClasses.add(typeName)
}
}
} else {
Class classType = field.getType()
System.out.println("Real type is "+classType.getComponentType())
actualClass = classType.getComponentType()
if (actualClass == String) {
stringArrayFields.add(field)
}
if (actualClass == int || actualClass == double){
numericArrayFields.add(field)
} else if (actualClass == boolean) {
booleanArrayFields.add(field)
}
}
// println "field name is "+ field.getType().getComponentType()
break
case String:
stringFields.add(field)
break
case [int, short, double, float]:
numericFields.add(field)
break
case boolean:
booleanFields.add(field)
break
default:
println "Class before isCorbaEnum = " + field.getName()
print "Type name is "+field.getType().getName()+" -- "
//print " "
println "Field name is "+ field.getName()
if (isCorbaEnum(field.getType())) {
println "\t--this is an enum field"
enumFields.add(field)
} else { //user defined types may need additional checks
customFields.add(field)
if(!openMethodList.contains(field.getType().getName())) {
subClasses.add(field.getType().getName())
}
}
}
}
//Build strings
def varsList = ''
stringFields.each {
varsList += buildGeneralMerge(it.getName(),"String") + "\n\t\t"
}
numericFields.each {
varsList += buildNumericMerge(it.getName()) + "\n\t\t"
}
numericArrayFields.each {
def str = buildGeneralMerge(it.getName(),"Numeric") + "\n\t\t"
// println str
varsList += str
}
booleanFields.each {
varsList += buildBooleanMerge(it.getName()) + "\n\t\t"
}
booleanArrayFields.each {
varsList += buildGeneralMerge(it.getName(),"Boolean") + "\n\t\t"
}
enumFields.each {
varsList += buildEnumMerge(it.getName()) + "\n\t\t"
}
customFields.each {
def customTypeName = ""
if (it.getType().isArray()){
customTypeName = it.getType().getName().substring(0,it.getType().getName().length()-1)
} else {
customTypeName = it.getType().getName()
}
println "Custom type name is " + customTypeName
varsList += buildUserDefinedMerge(it.getName(),customTypeName) + "\n\t\t"
}
String onlyClassName = getOnlyClassName(className)
String fullMethod = buildMethod(onlyClassName, varsList) + "\t\t"
return fullMethod
}
String getOnlyClassName(String input){
int index = input.lastIndexOf(".")
return input.substring(index+1, input.length())
}
boolean isCorbaEnum(Class c){
try {
return c.getDeclaredFields().find { field ->
field.getName().equalsIgnoreCase("__value")
}
} catch(Exception e) {
e.printStackTrace()
// no need to define the result as it is already false
}
return result
}
String buildBooleanMerge(String field){
return "updated.${field} = (newOne.${field} != false) ? newOne.${field} : original.${field};"
}
String buildEnumMerge(String field){
return "updated.${field} = original.${field};"
}
String buildEnumArrayMerge(Field[] enumClass){
}
String buildNumericMerge(String field){
return "updated.${field} = (newOne.${field} > 0) ? newOne.${field} : original.${field};"
}
String buildUserDefinedMerge(String name,String fullTypeName){
String type = getOnlyClassName(fullTypeName)
Writable outputText = null
def substitutionValues = ['name':name, 'type':type]
def templateText = ""
// checking if the current custom class is in directList - a list of classes that require no merging
// for (String value: directList){
// if (type.equ)
// }
if (directList.contains(type)){
templateText = "updated.${name} = original.${name};"
if(!importArray.contains(fullTypeName)) importArray.add(fullTypeName)
}else{
templateText = "updated.${name} = merge${type}(original.${name},newOne.${name});"
}
def templateEngine = new SimpleTemplateEngine()
def template = templateEngine.createTemplate(templateText)
return template.make(substitutionValues)
}
String buildStringMerge(String field){
def substitutionValues = ['field':field]
def templateText = "updated.${field}=mergeString(original.${field},newOne.${field});"
def templateEngine = new SimpleTemplateEngine()
def template = templateEngine.createTemplate(templateText)
return template.make(substitutionValues)
}
String buildGeneralMerge(String field,String typeName){
def substitutionValues = ['field':field, 'typeName':typeName]
def templateText = "updated.${field}=merge${typeName}(original.${field},newOne.${field});"
def templateEngine = new SimpleTemplateEngine()
def template = templateEngine.createTemplate(templateText)
return template.make(substitutionValues)
}
String buildMethod(String className, String methods){
def f = new File('C:/projects/GroovyMergeClassGenerator/src/gv/method.template')
def templateEngine = new GStringTemplateEngine()
//def templateEngine = new SimpleTemplateEngine()
// def stringMethods1 = buildStringMerge("type")
// def stringMethods2 = buildStringMerge("address1")
def substitutionValues = ['className':className, 'methods':methods ]
return templateEngine.createTemplate(f).make(substitutionValues).toString()
// def opFile = new File("C:/projects/GroovyClassGenerator/outputFiles/MergeUtil.java")
// opFile.write(template.toString())
//println template.toString()
}
String recursiveSubClassCall(String finalStr){
subClassesCopy = subClasses.clone()
subClasses = []
subClassesCopy.each { str ->
// println "subClass Array: entry is "+str
def classAdded = false
importArray.find { addedClass ->
// println "\t addedClass value is "+ addedClass
if (addedClass.equalsIgnoreCase(str)){
// do nothing as that custom class has already been taken care of
// println "\t addedClass matched with subClass"
classAdded = true
}
classAdded
}
if(!classAdded){
finalStr+=getFields(str)
importArray.add(str)
}
}
return finalStr
}
/**
* main method to generate the MergeUtil class using templates
* @author Arsalan S.
*
*/
boolean buildFile(List classes, String fileName){
def finalStr = ""
openMethodList.each {
importArray.add(it)
}
classes.each {
finalStr += getFields(it)
importArray.add(it)
}
// Adding the merge methods for custom sub classes if any of them is being used by main classes
// Keep it recursive till no more customSubClasses left, in other words generate all subclasses merge methods
while (subClasses.size() > 0){
finalStr = recursiveSubClassCall(finalStr)
}
// generating string for imports
def importString = ""
final String IMPORTSTR = "import "
importArray.each {
importString+=(IMPORTSTR + it + ";\n")
}
// ---------------------------------------------------------
def f = new File('C:/projects/GroovyMergeClassGenerator/src/gv/util.template')
def templateEngine = new GStringTemplateEngine()
def substitutionVal = ['allImports':importString,'allMethods':finalStr]
def output = templateEngine.createTemplate(f).make(substitutionVal)
def opFile = new File(fileName)
opFile.write(output.toString())
}
}
Initial URL
Initial Description
Initial Title
Creating Java ClassesDynamically
Initial Tags
Initial Language
Groovy