Posted By

theobriscoe on 12/03/08


Tagged


Versions (?)

Creating Java ClassesDynamically


 / Published in: Groovy
 

  1. #! /usr/bin/env groovy
  2.  
  3. import groovy.text.*
  4. import groovy.text.GStringTemplateEngine
  5. import java.lang.reflect.Field
  6.  
  7. /**
  8.  * @author Theo Briscoe
  9.  * @modified by Arsalan S.
  10.  * @modified by Dan Walker
  11.  */
  12. class GroovyFileReader {
  13.  
  14. static String IDL_PROJECT_SRC_LOCATION = "C:/Projects/IDL/src/java"
  15. static String IDL_PROJECT_CLASS_LOCATION = "C:/Projects/IDL/build/classes"
  16. // static String IDL_PROJECT_SRC_EXCLUDED = "Stub,Helper,Holder,Operations,Interface"
  17.  
  18. //Compile and run from ant
  19. //Evaluate command line arguments
  20. //Build list of java classes
  21. //foreach java class
  22. //load the class definitions
  23. //Use reflection to get list of fields
  24. //build the utility class
  25. //Place generated clsses in the correct directory
  26. //Identify enumerations
  27. def subClasses = []
  28. def subClassesCopy= []
  29. def directList = ["SegmentDetailInfo"]
  30. def openMethodList = ["com.aaa.travel.idl.Segment"]
  31. def importArray = []
  32.  
  33. String getFields(java.lang.String className){
  34. def stringFields = []
  35. def numericFields=[]
  36. def booleanFields = [] // boolean
  37. def customFields = []
  38. def stringArrayFields = []
  39. def enumFields = [] //enum fields inside the object
  40. def numericArrayFields=[]
  41. def booleanArrayFields = []
  42. def customArrayFields = []
  43. def enumArrayFields = []
  44.  
  45. //1. Load class definition & get all the public fields
  46. java.lang.Class c = Class.forName(className)
  47. println "Class " + c.getName()
  48. java.lang.reflect.Field[] fields = c.getFields()
  49.  
  50. //2. Identify fields and store them in arrays
  51. fields.each { field ->
  52. print "Type name is "+field.getType().getName()+" -- "
  53. //print " "
  54. println "Field name is "+ field.getName()
  55.  
  56. def type = field.getType()
  57. def typeName = type.getName()
  58.  
  59. switch (type) {
  60. case type.isArray():
  61. // Again check for int and boolean arrays
  62. // if (field.getType().getName().contains("java.lang.String")){
  63. // stringArrayFields.add(field)
  64. // }
  65. int startIndex = typeName.indexOf("com.")
  66. Class actualClass = null
  67.  
  68. // Dividing the arrays in two categories
  69. if (startIndex > 0) {
  70. // category 1: custom classes like com.aaa.*
  71. typeName = typeName.substring(startIndex,typeName.length()-1)
  72. System.out.println("Real type is " + typeName)
  73. def lastIndex = typeName.lastIndexOf(".")
  74. // def a
  75. actualClass = Class.forName(typeName)
  76. if(Helper.isCorbaEnum(actualClass)){
  77. // Array of enum type
  78. enumFields.add(field)
  79. } else {
  80. customFields.add(field)
  81. if(!openMethodList.contains(typeName)) {
  82. subClasses.add(typeName)
  83. }
  84. }
  85. } else {
  86. Class classType = field.getType()
  87. System.out.println("Real type is "+classType.getComponentType())
  88. actualClass = classType.getComponentType()
  89.  
  90. if (actualClass == String) {
  91. stringArrayFields.add(field)
  92. }
  93. if (actualClass == int || actualClass == double){
  94. numericArrayFields.add(field)
  95. } else if (actualClass == boolean) {
  96. booleanArrayFields.add(field)
  97. }
  98. }
  99.  
  100. // println "field name is "+ field.getType().getComponentType()
  101. stringFields.add(field)
  102. numericFields.add(field)
  103. booleanFields.add(field)
  104. println "Class before isCorbaEnum = " + field.getName()
  105. print "Type name is "+field.getType().getName()+" -- "
  106. //print " "
  107. println "Field name is "+ field.getName()
  108. if (isCorbaEnum(field.getType())) {
  109. println "\t--this is an enum field"
  110. enumFields.add(field)
  111.  
  112. } else { //user defined types may need additional checks
  113. customFields.add(field)
  114. if(!openMethodList.contains(field.getType().getName())) {
  115. subClasses.add(field.getType().getName())
  116. }
  117. }
  118. }
  119. }
  120.  
  121. //Build strings
  122. def varsList = ''
  123. stringFields.each {
  124. varsList += buildGeneralMerge(it.getName(),"String") + "\n\t\t"
  125. }
  126. numericFields.each {
  127. varsList += buildNumericMerge(it.getName()) + "\n\t\t"
  128. }
  129. numericArrayFields.each {
  130. def str = buildGeneralMerge(it.getName(),"Numeric") + "\n\t\t"
  131. // println str
  132. varsList += str
  133. }
  134. booleanFields.each {
  135. varsList += buildBooleanMerge(it.getName()) + "\n\t\t"
  136. }
  137. booleanArrayFields.each {
  138. varsList += buildGeneralMerge(it.getName(),"Boolean") + "\n\t\t"
  139. }
  140. enumFields.each {
  141. varsList += buildEnumMerge(it.getName()) + "\n\t\t"
  142. }
  143. customFields.each {
  144. def customTypeName = ""
  145. if (it.getType().isArray()){
  146. customTypeName = it.getType().getName().substring(0,it.getType().getName().length()-1)
  147. } else {
  148. customTypeName = it.getType().getName()
  149. }
  150. println "Custom type name is " + customTypeName
  151. varsList += buildUserDefinedMerge(it.getName(),customTypeName) + "\n\t\t"
  152. }
  153.  
  154. String onlyClassName = getOnlyClassName(className)
  155.  
  156. String fullMethod = buildMethod(onlyClassName, varsList) + "\t\t"
  157.  
  158. return fullMethod
  159. }
  160.  
  161. String getOnlyClassName(String input){
  162. int index = input.lastIndexOf(".")
  163. return input.substring(index+1, input.length())
  164. }
  165.  
  166. boolean isCorbaEnum(Class c){
  167. try {
  168. return c.getDeclaredFields().find { field ->
  169. field.getName().equalsIgnoreCase("__value")
  170. }
  171. e.printStackTrace()
  172. // no need to define the result as it is already false
  173. }
  174. return result
  175. }
  176.  
  177.  
  178. String buildBooleanMerge(String field){
  179. return "updated.${field} = (newOne.${field} != false) ? newOne.${field} : original.${field};"
  180. }
  181.  
  182. String buildEnumMerge(String field){
  183. return "updated.${field} = original.${field};"
  184. }
  185.  
  186. String buildEnumArrayMerge(Field[] enumClass){
  187.  
  188. }
  189.  
  190. String buildNumericMerge(String field){
  191. return "updated.${field} = (newOne.${field} > 0) ? newOne.${field} : original.${field};"
  192. }
  193.  
  194. String buildUserDefinedMerge(String name,String fullTypeName){
  195.  
  196. String type = getOnlyClassName(fullTypeName)
  197. Writable outputText = null
  198. def substitutionValues = ['name':name, 'type':type]
  199. def templateText = ""
  200.  
  201. // checking if the current custom class is in directList - a list of classes that require no merging
  202. // for (String value: directList){
  203. // if (type.equ)
  204. // }
  205.  
  206. if (directList.contains(type)){
  207. templateText = "updated.${name} = original.${name};"
  208. if(!importArray.contains(fullTypeName)) importArray.add(fullTypeName)
  209.  
  210. }else{
  211. templateText = "updated.${name} = merge${type}(original.${name},newOne.${name});"
  212. }
  213.  
  214. def templateEngine = new SimpleTemplateEngine()
  215. def template = templateEngine.createTemplate(templateText)
  216.  
  217. return template.make(substitutionValues)
  218. }
  219.  
  220. String buildStringMerge(String field){
  221.  
  222. def substitutionValues = ['field':field]
  223.  
  224. def templateText = "updated.${field}=mergeString(original.${field},newOne.${field});"
  225.  
  226. def templateEngine = new SimpleTemplateEngine()
  227. def template = templateEngine.createTemplate(templateText)
  228.  
  229. return template.make(substitutionValues)
  230. }
  231.  
  232. String buildGeneralMerge(String field,String typeName){
  233.  
  234. def substitutionValues = ['field':field, 'typeName':typeName]
  235.  
  236. def templateText = "updated.${field}=merge${typeName}(original.${field},newOne.${field});"
  237.  
  238. def templateEngine = new SimpleTemplateEngine()
  239. def template = templateEngine.createTemplate(templateText)
  240.  
  241. return template.make(substitutionValues)
  242. }
  243.  
  244.  
  245.  
  246. String buildMethod(String className, String methods){
  247. def f = new File('C:/projects/GroovyMergeClassGenerator/src/gv/method.template')
  248. def templateEngine = new GStringTemplateEngine()
  249. //def templateEngine = new SimpleTemplateEngine()
  250.  
  251. // def stringMethods1 = buildStringMerge("type")
  252. // def stringMethods2 = buildStringMerge("address1")
  253.  
  254. def substitutionValues = ['className':className, 'methods':methods ]
  255.  
  256. return templateEngine.createTemplate(f).make(substitutionValues).toString()
  257. // def opFile = new File("C:/projects/GroovyClassGenerator/outputFiles/MergeUtil.java")
  258. // opFile.write(template.toString())
  259.  
  260. //println template.toString()
  261. }
  262.  
  263.  
  264. String recursiveSubClassCall(String finalStr){
  265. subClassesCopy = subClasses.clone()
  266. subClasses = []
  267.  
  268. subClassesCopy.each { str ->
  269. // println "subClass Array: entry is "+str
  270. def classAdded = false
  271. importArray.find { addedClass ->
  272. // println "\t addedClass value is "+ addedClass
  273. if (addedClass.equalsIgnoreCase(str)){
  274. // do nothing as that custom class has already been taken care of
  275. // println "\t addedClass matched with subClass"
  276. classAdded = true
  277. }
  278. classAdded
  279. }
  280. if(!classAdded){
  281. finalStr+=getFields(str)
  282. importArray.add(str)
  283. }
  284. }
  285. return finalStr
  286. }
  287.  
  288. /**
  289.  * main method to generate the MergeUtil class using templates
  290.  * @author Arsalan S.
  291.  *
  292.  */
  293. boolean buildFile(List classes, String fileName){
  294. def finalStr = ""
  295. openMethodList.each {
  296. importArray.add(it)
  297. }
  298. classes.each {
  299. finalStr += getFields(it)
  300. importArray.add(it)
  301. }
  302.  
  303. // Adding the merge methods for custom sub classes if any of them is being used by main classes
  304. // Keep it recursive till no more customSubClasses left, in other words generate all subclasses merge methods
  305. while (subClasses.size() > 0){
  306. finalStr = recursiveSubClassCall(finalStr)
  307. }
  308.  
  309. // generating string for imports
  310. def importString = ""
  311. final String IMPORTSTR = "import "
  312. importArray.each {
  313. importString+=(IMPORTSTR + it + ";\n")
  314. }
  315. // ---------------------------------------------------------
  316.  
  317. def f = new File('C:/projects/GroovyMergeClassGenerator/src/gv/util.template')
  318. def templateEngine = new GStringTemplateEngine()
  319. def substitutionVal = ['allImports':importString,'allMethods':finalStr]
  320. def output = templateEngine.createTemplate(f).make(substitutionVal)
  321.  
  322. def opFile = new File(fileName)
  323. opFile.write(output.toString())
  324. }
  325. }

Report this snippet  

You need to login to post a comment.