Return to Snippet

Revision: 10018
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