Coverage Report - org.kuali.rice.devtools.generators.ImmutableJaxbGenerator
 
Classes in this File Line Coverage Branch Coverage Complexity
ImmutableJaxbGenerator
0%
0/15
0%
0/8
2.609
ImmutableJaxbGenerator$1
N/A
N/A
2.609
ImmutableJaxbGenerator$FieldModel
0%
0/5
N/A
2.609
ImmutableJaxbGenerator$Generator
0%
0/202
0%
0/54
2.609
 
 1  
 /*
 2  
  * Copyright 2011 The Kuali Foundation
 3  
  *
 4  
  * Licensed under the Educational Community License, Version 1.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  * http://www.opensource.org/licenses/ecl1.php
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.kuali.rice.devtools.generators;
 17  
 
 18  
 import com.sun.codemodel.ClassType;
 19  
 import com.sun.codemodel.JAnnotationArrayMember;
 20  
 import com.sun.codemodel.JAnnotationUse;
 21  
 import com.sun.codemodel.JArray;
 22  
 import com.sun.codemodel.JBlock;
 23  
 import com.sun.codemodel.JClass;
 24  
 import com.sun.codemodel.JCodeModel;
 25  
 import com.sun.codemodel.JConditional;
 26  
 import com.sun.codemodel.JDefinedClass;
 27  
 import com.sun.codemodel.JDocComment;
 28  
 import com.sun.codemodel.JExpr;
 29  
 import com.sun.codemodel.JFieldRef;
 30  
 import com.sun.codemodel.JFieldVar;
 31  
 import com.sun.codemodel.JInvocation;
 32  
 import com.sun.codemodel.JMethod;
 33  
 import com.sun.codemodel.JMod;
 34  
 import com.sun.codemodel.JType;
 35  
 import com.sun.codemodel.JVar;
 36  
 import com.sun.codemodel.writer.SingleStreamCodeWriter;
 37  
 import org.apache.commons.lang.builder.EqualsBuilder;
 38  
 import org.apache.commons.lang.builder.HashCodeBuilder;
 39  
 import org.apache.commons.lang.builder.ToStringBuilder;
 40  
 import org.kuali.rice.core.api.CoreConstants;
 41  
 import org.kuali.rice.core.api.mo.ModelBuilder;
 42  
 import org.kuali.rice.core.api.mo.ModelObjectComplete;
 43  
 
 44  
 import javax.xml.bind.annotation.XmlAccessType;
 45  
 import javax.xml.bind.annotation.XmlAccessorType;
 46  
 import javax.xml.bind.annotation.XmlAnyElement;
 47  
 import javax.xml.bind.annotation.XmlElement;
 48  
 import javax.xml.bind.annotation.XmlRootElement;
 49  
 import javax.xml.bind.annotation.XmlType;
 50  
 import java.io.ByteArrayOutputStream;
 51  
 import java.io.Serializable;
 52  
 import java.lang.reflect.Method;
 53  
 import java.util.ArrayList;
 54  
 import java.util.List;
 55  
 
 56  
 /**
 57  
  * This is a description of what this class does - ewestfal don't forget to fill this in. 
 58  
  * 
 59  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 60  
  *
 61  
  */
 62  0
 public class ImmutableJaxbGenerator {
 63  
 
 64  
         public static void main(String[] args) throws Exception {
 65  
                 
 66  0
                 if (args.length > 2 || args.length < 1) {
 67  0
                         System.err.println("There should be two arguments defined as follows:\n" + 
 68  
                                         "     1. Fully qualified class name of a 'contract' interface\n" + 
 69  
                                         "     2. [Optional] Fully qualified class name of the class to generate.  If not specified, will use the name of the contract interface class and remove \"Contract\" from the end of it.\n");
 70  0
                         System.exit(1);
 71  
                 }
 72  
                 
 73  
                 // argument one should be a fully qualified class name of a "contract" interface
 74  0
                 String contractInterfaceName = args[0];
 75  
                 
 76  0
                 String className = null;
 77  
                 // argument two should be the fully qualified class name of the class to generate
 78  0
                 if (args.length == 2) {
 79  0
                         className = args[1];
 80  
                 } else {
 81  0
                         if (!contractInterfaceName.endsWith("Contract")) {
 82  0
                                 throw new IllegalArgumentException("If not explicitly specifying target classname, then contract class name must end with 'Contract'");
 83  
                         }
 84  0
                         className = contractInterfaceName.substring(0, contractInterfaceName.lastIndexOf("Contract"));
 85  
                 }
 86  
                 
 87  0
                 Generator generator = new Generator(contractInterfaceName, className);
 88  0
                 generator.generate();
 89  0
         }
 90  
         
 91  
         public static class Generator {
 92  
                 
 93  
                 private final String contractInterfaceName;
 94  
                 private final String className;
 95  
                 private final JCodeModel codeModel;
 96  
                 
 97  0
                 public Generator(String contractInterfaceName, String className) {
 98  0
                         this.contractInterfaceName = contractInterfaceName;
 99  0
                         this.className = className;
 100  0
                         this.codeModel = new JCodeModel();
 101  0
                 }
 102  
                 
 103  
                 public void generate() throws Exception {
 104  0
                         byte[] javaCode = generateJava();
 105  0
                         System.out.println(new String(javaCode));
 106  0
                 }
 107  
                 
 108  
                 private byte[] generateJava() throws Exception {
 109  
                         
 110  0
                         JDefinedClass classModel = codeModel._class(JMod.PUBLIC | JMod.FINAL, className, ClassType.CLASS);
 111  0
                         Class<?> contractInterface = Class.forName(contractInterfaceName);
 112  0
                         classModel._implements(contractInterface);
 113  0
                         classModel._implements(ModelObjectComplete.class);
 114  
                         
 115  0
                         List<FieldModel> fields = determineFields(contractInterface);
 116  
                         
 117  0
                         renderConstantsClass(classModel);
 118  0
                         renderElementsClass(classModel, fields);
 119  0
                         renderClassLevelAnnotations(classModel, fields);
 120  0
                         renderFields(classModel, fields);
 121  0
                         renderFutureElementsField(classModel);                        
 122  0
                         renderPrivateJaxbConstructor(classModel, fields);
 123  0
                         renderBuilderConstructor(classModel, fields);
 124  0
                         renderGetters(classModel, fields);
 125  0
                         renderBuilderClass(classModel, fields, contractInterface);
 126  0
                         renderStandardObjectMethods(classModel);
 127  
                         
 128  0
                         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
 129  0
                         codeModel.build(new SingleStreamCodeWriter(outputStream));
 130  0
                         return outputStream.toByteArray();
 131  
                         
 132  
                 }
 133  
                 
 134  
                 private List<FieldModel> determineFields(Class<?> contractInterface) throws Exception {
 135  0
                         List<FieldModel> fieldModels = new ArrayList<FieldModel>();
 136  
                         
 137  0
                         Method[] methods = contractInterface.getMethods();
 138  0
                         for (Method method : methods) {
 139  0
                                 String methodName = method.getName();
 140  0
                                 String fieldName = null;
 141  0
                                 if (method.getReturnType() != Void.class && method.getParameterTypes().length == 0) {
 142  0
                                         if (methodName.startsWith("get")) {
 143  0
                                                 fieldName = Util.toLowerCaseFirstLetter(methodName.substring(3));
 144  0
                                         } else if (methodName.startsWith("is")) {
 145  0
                                                 fieldName = Util.toLowerCaseFirstLetter(methodName.substring(2));
 146  
                                         } else {
 147  
                                                 continue;
 148  
                                         }
 149  0
                                         fieldModels.add(new FieldModel(fieldName, method.getReturnType()));
 150  
                                 }
 151  
                         }
 152  
                         
 153  0
                         return fieldModels;
 154  
                 }
 155  
                 
 156  
                 private void renderConstantsClass(JDefinedClass classModel) throws Exception {
 157  
                         
 158  
                         // define constants class
 159  0
                         JDefinedClass constantsClass = classModel._class(JMod.STATIC, Util.CONSTANTS_CLASS_NAME);
 160  
                         
 161  
                         // generate the javadoc on the top of the Constants class
 162  0
                         JDocComment javadoc = constantsClass.javadoc();
 163  0
                         javadoc.append(Util.CONSTANTS_CLASS_JAVADOC);
 164  
                         
 165  
                         // render root element name
 166  0
                         JFieldVar rootElementField = constantsClass.field(JMod.FINAL | JMod.STATIC, String.class, Util.ROOT_ELEMENT_NAME_FIELD);
 167  0
                         rootElementField.init(JExpr.lit(Util.toLowerCaseFirstLetter(classModel.name())));
 168  
                         
 169  
                         // render type name
 170  0
                         JFieldVar typeNameField = constantsClass.field(JMod.FINAL | JMod.STATIC, String.class, Util.TYPE_NAME_FIELD);
 171  0
                         typeNameField.init(JExpr.lit(classModel.name() + Util.TYPE_NAME_SUFFIX));
 172  
                         
 173  
                         // hash code excludes array
 174  0
                         JFieldVar hashCodeExcludesField = constantsClass.field(JMod.FINAL | JMod.STATIC, String[].class, Util.HASH_CODE_EQUALS_EXCLUDE_FIELD);
 175  0
                         JArray excludeArray = JExpr.newArray(codeModel.ref(String.class));
 176  0
                         JClass coreConstants = codeModel.ref(CoreConstants.class);
 177  0
                         JFieldRef futureElementsRef = coreConstants.staticRef(Util.COMMON_ELEMENTS_CLASS).ref(Util.FUTURE_ELEMENTS_FIELD);
 178  0
                         excludeArray.add(futureElementsRef);
 179  0
                         hashCodeExcludesField.init(excludeArray);
 180  
                         
 181  0
                 }
 182  
                 
 183  
                 private void renderElementsClass(JDefinedClass classModel, List<FieldModel> fields) throws Exception {
 184  
                         
 185  
                         // define constants class
 186  0
                         JDefinedClass elementsClass = classModel._class(JMod.STATIC, Util.ELEMENTS_CLASS_NAME);
 187  
                         
 188  
                         // generate the javadoc on the top of the Elements class
 189  0
                         JDocComment javadoc = elementsClass.javadoc();
 190  0
                         javadoc.append(Util.ELEMENTS_CLASS_JAVADOC);
 191  
                         
 192  
                         // go through each field and create a corresponding constant
 193  0
                         for (FieldModel fieldModel : fields) {
 194  0
                                 if (Util.isCommonElement(fieldModel.fieldName)) {
 195  0
                                         continue;
 196  
                                 }
 197  0
                                 JFieldVar elementFieldVar = elementsClass.field(JMod.FINAL | JMod.STATIC, String.class, Util.toConstantsVariable(fieldModel.fieldName));
 198  0
                                 elementFieldVar.init(JExpr.lit(fieldModel.fieldName));
 199  0
                         }
 200  0
                 }
 201  
                 
 202  
                 private void renderClassLevelAnnotations(JDefinedClass classModel, List<FieldModel> fields) throws Exception {
 203  0
                         JFieldRef constantsClass = classModel.staticRef(Util.CONSTANTS_CLASS_NAME);
 204  0
                         JFieldRef elementsClass = classModel.staticRef(Util.ELEMENTS_CLASS_NAME);
 205  0
                         JClass coreConstants = codeModel.ref(CoreConstants.class);
 206  0
                         JFieldRef commonElementsRef = coreConstants.staticRef("CommonElements");
 207  
                         
 208  
                         // XmlRootElement
 209  0
                         JAnnotationUse rootElementAnnotation = classModel.annotate(XmlRootElement.class);
 210  0
                         rootElementAnnotation.param("name", constantsClass.ref(Util.ROOT_ELEMENT_NAME_FIELD));
 211  
                         
 212  
                         // XmlAccessorType
 213  0
                         JAnnotationUse xmlAccessorTypeAnnotation = classModel.annotate(XmlAccessorType.class);
 214  0
                         xmlAccessorTypeAnnotation.param("value", XmlAccessType.NONE);
 215  
                         
 216  
                         // XmlType
 217  0
                         JAnnotationUse xmlTypeAnnotation = classModel.annotate(XmlType.class);
 218  0
                         xmlTypeAnnotation.param("name", constantsClass.ref(Util.TYPE_NAME_FIELD));
 219  0
                         JAnnotationArrayMember propOrderMember = xmlTypeAnnotation.paramArray("propOrder");
 220  0
                         for (FieldModel field : fields) {
 221  0
                                 if (Util.isCommonElement(field.fieldName)) {
 222  0
                                         propOrderMember.param(commonElementsRef.ref(Util.toConstantsVariable(field.fieldName)));
 223  
                                 } else {
 224  0
                                         propOrderMember.param(elementsClass.ref(Util.toConstantsVariable(field.fieldName)));
 225  
                                 }
 226  
                         }
 227  0
                         propOrderMember.param(commonElementsRef.ref("FUTURE_ELEMENTS"));
 228  0
                 }
 229  
                 
 230  
                 private void renderFields(JDefinedClass classModel, List<FieldModel> fields) {
 231  0
                         for (FieldModel fieldModel : fields) {
 232  0
                                 renderField(classModel, fieldModel);
 233  
                         }
 234  0
                 }
 235  
                 
 236  
                 private void renderField(JDefinedClass classModel, FieldModel fieldModel) {
 237  0
                         JFieldVar field = classModel.field(JMod.PRIVATE | JMod.FINAL, fieldModel.fieldType, fieldModel.fieldName);
 238  0
                         JAnnotationUse annotation = field.annotate(XmlElement.class);
 239  0
                         if (Util.isCommonElement(fieldModel.fieldName)) {
 240  0
                                 JClass coreConstants = codeModel.ref(CoreConstants.class);
 241  0
                                 JFieldRef commonElementsRef = coreConstants.staticRef("CommonElements");
 242  0
                                 annotation.param("name", commonElementsRef.ref(Util.toConstantsVariable(fieldModel.fieldName)));
 243  0
                         } else {
 244  0
                                 JClass elementsClass = codeModel.ref(Util.ELEMENTS_CLASS_NAME);
 245  0
                                 JFieldRef fieldXmlNameRef = elementsClass.staticRef(Util.toConstantsVariable(fieldModel.fieldName));
 246  0
                                 annotation.param("name", fieldXmlNameRef);
 247  
                         }
 248  0
                         annotation.param("required", false);
 249  0
                 }
 250  
                 
 251  
                 private void renderFutureElementsField(JDefinedClass classModel) throws Exception {
 252  0
                         JType collectionType = codeModel.parseType("java.util.Collection<org.w3c.dom.Element>");
 253  0
                         JFieldVar field = classModel.field(JMod.PRIVATE | JMod.FINAL, collectionType, "_futureElements");
 254  0
                         field.init(JExpr._null());
 255  0
                         JAnnotationUse annotation = field.annotate(SuppressWarnings.class);
 256  0
                         annotation.param("value", "unused");
 257  0
                         field.annotate(XmlAnyElement.class);
 258  0
                 }
 259  
                 
 260  
                 private void renderPrivateJaxbConstructor(JDefinedClass classModel, List<FieldModel> fields) {
 261  0
                         JMethod method = classModel.constructor(JMod.PRIVATE);
 262  0
                         JBlock body = method.body();
 263  0
                         for (FieldModel fieldModel : fields) {
 264  0
                                 body.directStatement("this." + fieldModel.fieldName + " = " + getInitString(fieldModel.fieldType) + ";");
 265  
                         }
 266  0
                         method.javadoc().add("Private constructor used only by JAXB.");
 267  0
                 }
 268  
 
 269  
         private String getInitString(Class<?> clazz) {
 270  0
             if (clazz == Boolean.TYPE) {
 271  0
                 return "false";
 272  0
             } else if (clazz == Character.TYPE) {
 273  0
                 return "'\\\\u0000'";
 274  0
             } else if (clazz == Long.TYPE) {
 275  0
                 return "0L";
 276  0
             } else if (clazz == Float.TYPE) {
 277  0
                 return "0.0F";
 278  0
             } else if (clazz == Double.TYPE) {
 279  0
                 return "0.0D";
 280  0
             } else if (clazz == Byte.TYPE || clazz == Short.TYPE || clazz == Integer.TYPE) {
 281  0
                 return "0";
 282  
             } else {
 283  0
                 return "null";
 284  
             }
 285  
         }
 286  
                 
 287  
                 private void renderBuilderConstructor(JDefinedClass classModel, List<FieldModel> fields) {
 288  0
                         JMethod method = classModel.constructor(JMod.PRIVATE);
 289  0
                         method.param(codeModel.ref("Builder"), "builder");
 290  0
                         JBlock body = method.body();
 291  0
                         for (FieldModel fieldModel : fields) {
 292  0
                                 body.directStatement("this." + fieldModel.fieldName + " = builder." + Util.generateGetter(fieldModel.fieldName, isBoolean(fieldModel.fieldType)) + ";");
 293  
                         }
 294  0
                 }
 295  
                 
 296  
                 private void renderGetters(JDefinedClass classModel, List<FieldModel> fields) {
 297  0
             for (FieldModel fieldModel : fields) {
 298  0
                 JMethod getterMethod = classModel.method(JMod.PUBLIC, fieldModel.fieldType, Util.generateGetterName(fieldModel.fieldName, isBoolean(fieldModel.fieldType)));
 299  0
                                 JBlock methodBody = getterMethod.body();
 300  0
                                 methodBody.directStatement("return this." + fieldModel.fieldName + ";");
 301  0
                                 getterMethod.annotate(Override.class);
 302  0
                         }
 303  0
                 }
 304  
 
 305  
         private boolean isBoolean(Class<?> clazz) {
 306  0
             return clazz == Boolean.TYPE || clazz == Boolean.class;
 307  
         }
 308  
                 
 309  
                 private void renderBuilderClass(JDefinedClass classModel, List<FieldModel> fields, Class<?> contractInterface) throws Exception {
 310  
                         
 311  
                         // define constants class
 312  0
                         JDefinedClass builderClass = classModel._class(JMod.PUBLIC | JMod.STATIC | JMod.FINAL, Util.BUILDER_CLASS_NAME);
 313  
                         
 314  
                         // create a literal version of the Builder class so that the code generator won't pre-pend Builder class references with outermost class
 315  0
                         JClass literalBuilderClass = codeModel.ref("Builder");
 316  
                         
 317  
                         // generate the javadoc on the top of the Elements class
 318  0
                         JDocComment javadoc = builderClass.javadoc();
 319  0
                         javadoc.append(Util.generateBuilderJavadoc(classModel.name(), contractInterface.getSimpleName()));
 320  
                         
 321  0
                         builderClass._implements(contractInterface);
 322  0
                         builderClass._implements(ModelBuilder.class);
 323  0
                         builderClass._implements(Serializable.class);
 324  
                         
 325  
                         // render the builder fields
 326  0
                         for (FieldModel fieldModel : fields) {
 327  0
                                 builderClass.field(JMod.PRIVATE, fieldModel.fieldType, fieldModel.fieldName);
 328  
                         }
 329  
                         
 330  
                         // render default empty constructor for builder
 331  0
                         JMethod constructor = builderClass.constructor(JMod.PRIVATE);
 332  0
                         constructor.body().directStatement("// TODO modify this constructor as needed to pass any required values and invoke the appropriate 'setter' methods");
 333  
                 
 334  0
                         renderBuilderDefaultCreate(builderClass, literalBuilderClass);
 335  0
                         renderBuilderCreateContract(builderClass, literalBuilderClass, fields, contractInterface);
 336  0
                         renderBuild(builderClass);
 337  0
                         renderGetters(builderClass, fields);
 338  0
                         renderSetters(builderClass, fields);
 339  0
                 }
 340  
                 
 341  
                 private void renderBuilderDefaultCreate(JDefinedClass builderClass, JClass literalBuilderClass) {
 342  0
                         JMethod createMethod = builderClass.method(JMod.PUBLIC | JMod.STATIC, literalBuilderClass, "create");
 343  0
                         JBlock createMethodBody = createMethod.body();
 344  0
                         createMethodBody.directStatement("// TODO modify as needed to pass any required values and add them to the signature of the 'create' method");
 345  0
                         createMethodBody.directStatement("return new Builder();");
 346  0
                 }
 347  
                 
 348  
                 private void renderBuilderCreateContract(JDefinedClass builderClass, JClass literalBuilderClass, List<FieldModel> fields, Class<?> contractInterface) {
 349  0
                         JMethod createContractMethod = builderClass.method(JMod.PUBLIC | JMod.STATIC, literalBuilderClass, "create");
 350  0
                         JVar contractParam = createContractMethod.param(contractInterface, "contract");
 351  0
                         JBlock body = createContractMethod.body();
 352  0
                         JConditional nullContractCheck = body._if(contractParam.eq(JExpr._null()));
 353  0
                         nullContractCheck._then().directStatement("throw new IllegalArgumentException(\"contract was null\");");
 354  0
                         body.directStatement("// TODO if create() is modified to accept required parameters, this will need to be modified");
 355  0
                         body.directStatement("Builder builder = create();");
 356  0
                         for (FieldModel fieldModel : fields) {
 357  0
                                 String fieldName = fieldModel.fieldName;
 358  0
                                 body.directStatement("builder." + Util.generateSetter(fieldName, "contract." + Util.generateGetter(fieldName, isBoolean(fieldModel.fieldType))) + ";");
 359  0
                         }
 360  0
                         body.directStatement("return builder;");
 361  0
                 }
 362  
                 
 363  
                 private void renderBuild(JDefinedClass builderClass) {
 364  0
                         JMethod buildMethod = builderClass.method(JMod.PUBLIC, builderClass.outer(), "build");
 365  0
                         buildMethod.body().directStatement("return new " + builderClass.outer().name() + "(this);");
 366  0
                 }
 367  
                 
 368  
                 private void renderSetters(JDefinedClass builderClass, List<FieldModel> fields) {
 369  0
                         for (FieldModel fieldModel : fields) {
 370  0
                                 String fieldName = fieldModel.fieldName;
 371  0
                                 JMethod setterMethod = builderClass.method(JMod.PUBLIC, codeModel.VOID, Util.generateSetterName(fieldName));
 372  0
                                 setterMethod.param(fieldModel.fieldType, fieldName);
 373  0
                                 setterMethod.body().directStatement("// TODO add validation of input value if required and throw IllegalArgumentException if needed");
 374  0
                                 setterMethod.body().directStatement("this." + fieldName + " = " + fieldName + ";");
 375  0
                         }
 376  0
                 }
 377  
                 
 378  
                 /**
 379  
                  * Generates standard hashCode, equals, and toString methods
 380  
                  */
 381  
                 private void renderStandardObjectMethods(JDefinedClass classModel) {
 382  
                         
 383  0
                         JClass constantsClass = codeModel.ref(Util.CONSTANTS_CLASS_NAME);
 384  0
                         JFieldRef hashCodeEqualsExcludes = constantsClass.staticRef(Util.HASH_CODE_EQUALS_EXCLUDE_FIELD);
 385  
                         
 386  
                         // hashCode
 387  0
                         JMethod hashCodeMethod = classModel.method(JMod.PUBLIC, codeModel.INT, "hashCode");
 388  0
                         JInvocation hcInvoke = codeModel.ref(HashCodeBuilder.class).staticInvoke("reflectionHashCode");
 389  0
                         hcInvoke.arg(JExpr._this());
 390  0
                         hcInvoke.arg(hashCodeEqualsExcludes);
 391  0
                         hashCodeMethod.body()._return(hcInvoke);
 392  0
                         hashCodeMethod.annotate(Override.class);
 393  
                         
 394  
                         // equals
 395  0
                         JMethod equalsMethod = classModel.method(JMod.PUBLIC, codeModel.BOOLEAN, "equals");
 396  0
                         JVar objectParam = equalsMethod.param(Object.class, "object");
 397  0
                         JInvocation equalsInvoke = codeModel.ref(EqualsBuilder.class).staticInvoke("reflectionEquals");
 398  0
                         equalsInvoke.arg(objectParam);
 399  0
                         equalsInvoke.arg(JExpr._this());
 400  0
                         equalsInvoke.arg(hashCodeEqualsExcludes);
 401  0
                         equalsMethod.body()._return(equalsInvoke);
 402  0
                         equalsMethod.annotate(Override.class);
 403  
                         
 404  
                         // toString
 405  0
                         JMethod toStringMethod = classModel.method(JMod.PUBLIC, String.class, "toString");
 406  0
                         JInvocation toStringInvoke = codeModel.ref(ToStringBuilder.class).staticInvoke("reflectionToString");
 407  0
                         toStringInvoke.arg(JExpr._this());
 408  0
                         toStringMethod.body()._return(toStringInvoke);
 409  0
                         toStringMethod.annotate(Override.class);
 410  
                         
 411  
                         
 412  0
                 }
 413  
                                 
 414  
         }
 415  
         
 416  0
         private static class FieldModel {
 417  
                 
 418  
                 private final String fieldName;
 419  
                 private final Class<?> fieldType;
 420  
                 
 421  0
                 private FieldModel(String fieldName, Class<?> fieldType) {
 422  0
                         this.fieldName = fieldName;
 423  0
                         this.fieldType = fieldType;
 424  0
                 }
 425  
                                 
 426  
         }
 427  
         
 428  
 }