View Javadoc
1   package at.rseiler.spbee.core.generator;
2   
3   import at.rseiler.spbee.core.exception.MultipleObjectsReturned;
4   import at.rseiler.spbee.core.exception.ObjectDoesNotExist;
5   import at.rseiler.spbee.core.pojo.*;
6   import at.rseiler.spbee.core.util.CodeModelUtil;
7   import at.rseiler.spbee.core.util.StringUtil;
8   import com.sun.codemodel.*;
9   
10  import javax.annotation.processing.ProcessingEnvironment;
11  import javax.sql.DataSource;
12  import java.io.IOException;
13  import java.util.*;
14  
15  /**
16   * Generator for the DTO classes.
17   *
18   * @author Reinhard Seiler {@literal <rseiler.developer@gmail.com>}
19   */
20  public class DtoGenerator extends AbstractGenerator {
21  
22      private static final String SPRING_ANNOTATION_AUTOWIRED = "org.springframework.beans.factory.annotation.Autowired";
23      private static final String SPRING_ANNOTATION_SERVICE = "org.springframework.stereotype.Service";
24  
25      private final Properties config;
26      private final Map<String, ResultSetClass> resultSetMap;
27  
28      public DtoGenerator(ProcessingEnvironment processingEnv, Properties config, Map<String, ResultSetClass> resultSetMap) {
29          super(processingEnv);
30          this.config = config;
31          this.resultSetMap = resultSetMap;
32      }
33  
34      /**
35       * Generates the DTO classes.
36       *
37       * @param dtoClasses the DTO classes to generate
38       * @throws JClassAlreadyExistsException if a class is defined twice
39       * @throws IOException                  if the generated class can't be written
40       */
41      public void generateDtoClasses(List<DtoClass> dtoClasses) throws JClassAlreadyExistsException, IOException {
42          for (DtoClass dtoClass : dtoClasses) {
43              DtoClassGeneratorInstance dtoClassGeneratorInstance = new DtoClassGeneratorInstance(config, dtoClass, resultSetMap)
44                      .createClass()
45                      .createConstructor()
46                      .addStoredProcedureMethods();
47  
48              generateClass(dtoClassGeneratorInstance.getModel(), dtoClass.getQualifiedClassName());
49          }
50      }
51  
52      /**
53       * Holds all information to generate one specific DTO class and generates the necessary code.
54       */
55      private static class DtoClassGeneratorInstance {
56  
57          private final Properties config;
58          private final DtoClass dtoClass;
59          private final Map<String, ResultSetClass> resultSetMap;
60          private JCodeModel model = new JCodeModel();
61          private JDefinedClass dtoJClass;
62          private JMethod constructor;
63          private JVar dataSource;
64          private Map<String, JFieldVar> spFields = new HashMap<>();
65  
66          public DtoClassGeneratorInstance(Properties config, DtoClass dtoClass, Map<String, ResultSetClass> resultSetMap) {
67              this.config = config;
68              this.dtoClass = dtoClass;
69              this.resultSetMap = resultSetMap;
70          }
71  
72          public JCodeModel getModel() {
73              return model;
74          }
75  
76          /**
77           * Generates:
78           * <pre>
79           * {@literal @Service} public class *DaoImpl extends *Dao
80           * {@literal @Service} public class *DaoImpl implements *Dao
81           * </pre>
82           */
83          private DtoClassGeneratorInstance createClass() throws JClassAlreadyExistsException {
84              JPackage dtoJPackage = model._package(dtoClass.getPackage());
85              dtoJClass = dtoJPackage._class(dtoClass.getSimpleClassName());
86              CodeModelUtil.annotateGenerated(dtoJClass);
87              dtoJClass.annotate(model.directClass(SPRING_ANNOTATION_SERVICE));
88              addSuperClassOrInterface();
89              return this;
90          }
91  
92          /**
93           * Generates:
94           * <pre>
95           * {@literal @Autowired} public * (DataSource dataSource)
96           * </pre>
97           */
98          public DtoClassGeneratorInstance createConstructor() {
99              constructor = dtoJClass.constructor(JMod.PUBLIC);
100             constructor.annotate(model.directClass(SPRING_ANNOTATION_AUTOWIRED));
101             dataSource = constructor.param(DataSource.class, "dataSource");
102 
103             if (dtoClass.hasDataSourceConstructor()) {
104                 constructor.body().add(JExpr.invoke("super").arg(dataSource));
105             }
106 
107             return this;
108         }
109 
110         /**
111          * Adds the stored procedure to the constructor (to get it autowired into the class) and creates the actual
112          * method to call the stored procedure.
113          */
114         public DtoClassGeneratorInstance addStoredProcedureMethods() throws JClassAlreadyExistsException {
115             for (StoredProcedureMethod storedProcedureMethod : dtoClass.getStoredProcedureMethods()) {
116                 String fieldName = storedProcedureMethod.getDtoFieldName();
117 
118                 if (!spFields.containsKey(fieldName)) {
119                     spFields.put(fieldName, addConstructorField(storedProcedureMethod));
120                 }
121 
122                 addDtoMethod(storedProcedureMethod, spFields.get(fieldName));
123             }
124             return this;
125         }
126 
127         /**
128          * Generates:
129          * <pre>
130          * implements *Dao
131          * extends *Dao
132          * </pre>
133          */
134         private void addSuperClassOrInterface() {
135             if (dtoClass.isAnInterface()) {
136                 dtoJClass._implements(model.directClass(dtoClass.getSuperQualifiedClassName()));
137             } else {
138                 dtoJClass._extends(model.directClass(dtoClass.getSuperQualifiedClassName()));
139             }
140         }
141 
142         /**
143          * Generates:
144          * Field variable:
145          * <pre>
146          * [ private final {SP_NAME_CLASS} {SP_NAME_VARIABLE} ]+;
147          * <pre>
148          * Constructor assignment:
149          * <pre>
150          * [ {SP_NAME_VARIABLE} = new {SP_NAME_CLASS}(dataSource) ]+
151          * </pre>
152          */
153         private JFieldVar addConstructorField(StoredProcedureMethod storedProcedureMethod) {
154             if (constructor == null) {
155                 throw new RuntimeException("Invalid Usage. createConstructor() must be called first.");
156             }
157 
158             JClass jClass = model.directClass(storedProcedureMethod.getQualifiedClassName());
159             JFieldVar field = dtoJClass.field(JMod.PRIVATE | JMod.FINAL, jClass, storedProcedureMethod.getDtoFieldName());
160             constructor.body().assign(field, JExpr._new(jClass).arg(dataSource));
161             return field;
162         }
163 
164         /**
165          * Generates:
166          * <pre>
167          * public {DTO_METHOD_RETURN_TYPE} {DTO_METHOD_NAME}({DTO_METHOD_PARAMETERS}) {
168          *      return (({DTO_METHOD_RETURN_TYPE}) {SP_NAME_VARIABLE}.execute({DTO_METHOD_PARAMETERS}).get("#result-set-0"));
169          * }
170          * </pre>
171          * If it's a ResultSet:
172          * <pre>
173          * public {DTO_METHOD_RETURN_TYPE} {DTO_METHOD_NAME}({DTO_METHOD_PARAMETERS}) {
174          *      Map<String, Object> map = {SP_NAME_VARIABLE}.execute({DTO_METHOD_PARAMETERS});
175          *      return new {DTO_METHOD_RETURN_TYPE}((*)map.get("#result-set-0"), (*)map.get("#result-set-*"), ...);
176          * }
177          * </pre>
178          */
179         private void addDtoMethod(StoredProcedureMethod storedProcedureMethod, JFieldVar field) throws JClassAlreadyExistsException {
180             JClass returnClass = getReturnClass(storedProcedureMethod);
181             JMethod method = dtoJClass.method(JMod.PUBLIC, returnClass, storedProcedureMethod.getMethodName());
182             addAnnotations(storedProcedureMethod, method);
183             JInvocation execute = getExecute(storedProcedureMethod, field, method);
184             JVar interceptorIdObject = null;
185 
186             if (config.containsKey("interceptor")) {
187                 JInvocation before = model.ref(config.getProperty("interceptor")).staticInvoke("before");
188                 before.arg(JExpr.lit(storedProcedureMethod.getStoredProcedureName()));
189 
190                 for (JExpression arg : execute.listArgs()) {
191                     before.arg(arg);
192                 }
193 
194                 interceptorIdObject = method.body().decl(model.directClass(Object.class.getCanonicalName()), "interceptorIdObject");
195                 method.body().assign(interceptorIdObject, before);
196             }
197 
198             if ("void".equals(storedProcedureMethod.getReturnTypeInfo().getType())) {
199                 method.body().add(execute);
200                 addInterceptorCallAfter(storedProcedureMethod, method, execute, interceptorIdObject);
201             } else if (resultSetMap.containsKey(storedProcedureMethod.getReturnTypeInfo().getType())) {
202                 multipleResultSets(storedProcedureMethod, returnClass, method, execute, interceptorIdObject);
203             } else {
204                 singleResultSet(storedProcedureMethod, returnClass, method, execute, interceptorIdObject);
205             }
206         }
207 
208         /**
209          * Generates:
210          * <pre>
211          * {FIELD}.execute( [ * ]* )
212          * </pre>
213          */
214         private JInvocation getExecute(StoredProcedureMethod storedProcedureMethod, JFieldVar field, JMethod method) {
215             JInvocation execute = JExpr.invoke(field, "execute");
216 
217             for (Variable variable : storedProcedureMethod.getArguments()) {
218                 JVar param = method.param(model.directClass(variable.getTypeInfo().asString()), variable.getName());
219                 execute.arg(param);
220             }
221 
222             return execute;
223         }
224 
225         /**
226          * Generates the class for the return type.
227          */
228         private JClass getReturnClass(StoredProcedureMethod storedProcedureMethod) {
229             Optional<String> genericType = storedProcedureMethod.getReturnTypeInfo().getGenericType();
230             JClass returnClass = model.ref(storedProcedureMethod.getReturnTypeInfo().getType());
231 
232             if (genericType.isPresent()) {
233                 returnClass = returnClass.narrow(model.ref(genericType.get()));
234             }
235 
236             return returnClass;
237         }
238 
239         /**
240          * Adds the annotations to the method.
241          */
242         private void addAnnotations(StoredProcedureMethod storedProcedureMethod, JMethod method) throws JClassAlreadyExistsException {
243             for (AnnotationInfo annotationInfo : storedProcedureMethod.getAnnotations()) {
244                 JAnnotationUse jAnnotationUse = method.annotate(model.ref(annotationInfo.getAnnotationType()));
245 
246                 for (AnnotationValueInfo annotationValueInfo : annotationInfo.getAnnotationValueInfos()) {
247                     addAnnotationParam(jAnnotationUse, annotationValueInfo);
248                 }
249             }
250         }
251 
252         /**
253          * Generates the body of the DTO method for methods with several result-sets.
254          * <p>
255          * Example:
256          * <pre>
257          * Object interceptorIdObject; // optional
258          * interceptorIdObject = *SpInterceptor.before("*"); // optional
259          * Map<String, Object> map;
260          * map = sp*.execute(id);
261          * *SpInterceptor.after(interceptorIdObject, "*"); // optional
262          * List<*> list0;
263          * list0 = ((*> ) map.get("#result-set-0"));
264          * * obj0;
265          * if (list0 .size() == 1) {
266          *     obj0 = list0.get(0);
267          * } else {
268          *     if (list0.size() == 0) {
269          *         throw new ObjectDoesNotExist();
270          *     } else {
271          *         throw new MultipleObjectsReturned();
272          *     }
273          * }
274          * List<*> list1;
275          * list1 = ((<*> ) map.get("#result-set-1"));
276          * return new *ResultSet(obj0, list1);
277          * </pre>
278          * <p>
279          * Example if the entity in the ResultSet is annotated with @ReturnNull:
280          * <pre>
281          * Object interceptorIdObject; // optional
282          * interceptorIdObject = *SpInterceptor.before("*"); // optional
283          * Map<String, Object> map;
284          * map = sp*.execute(id);
285          * *SpInterceptor.after(interceptorIdObject, "*"); // optional
286          * List<*> list0;
287          * list0 = ((List<*>) map.get("#result-set-0"));
288          * * obj0;
289          * if (list0.size() == 1) {
290          *     obj0 = list0.get(0);
291          * } else {
292          *     if (list0.size() == 0) {
293          *         obj0 = null;
294          *     } else {
295          *         throw new MultipleObjectsReturned();
296          *     }
297          * }
298          * List<*> list1;
299          * list1 = ((List<*>) map.get("#result-set-1"));
300          * return new *ResultSet(obj0, list1);
301          * </pre>
302          * <p>
303          * Example if the entity in the ResultSet is an Optional:
304          * <pre>
305          * Object interceptorIdObject; // optional
306          * interceptorIdObject = *SpInterceptor.before("*"); // optional
307          * Map<String, Object> map;
308          * map = sp*.execute(id);
309          * *SpInterceptor.after(interceptorIdObject, "*"); // optional
310          * List<*> list0;
311          * list0 = ((List<*>) map.get("#result-set-0"));
312          * Optional obj0;
313          * if (list0.size() == 1) {
314          *     obj0 = Optional.of(list0.get(0));
315          * } else {
316          *     if (list0.size() == 0) {
317          *         obj0 = Optional.empty();
318          *     } else {
319          *         throw new MultipleObjectsReturned();
320          *     }
321          * }
322          * List<*> list1;
323          * list1 = ((List<*>) map.get("#result-set-1"));
324          * return new *ResultSet(obj0, list1);
325          * </pre>
326          */
327         private void multipleResultSets(StoredProcedureMethod storedProcedureMethod, JClass returnClass, JMethod method, JInvocation execute, JVar interceptorIdObject) {
328             JVar map = method.body().decl(CodeModelUtil.getMapStringObject(model), "map");
329             method.body().assign(map, execute);
330             addInterceptorCallAfter(storedProcedureMethod, method, execute, interceptorIdObject);
331             JInvocation resultSetsInvoke = JExpr._new(returnClass);
332 
333             List<JVar> args = new ArrayList<>();
334             List<ResultSetVariable> variables = resultSetMap.get(storedProcedureMethod.getReturnTypeInfo().getType()).getResultSetVariables();
335 
336             for (int i = 0; i < variables.size(); i++) {
337                 ResultSetVariable variable = variables.get(i);
338                 Optional<String> genericType = variable.getTypeInfo().getGenericType();
339 
340                 if (genericType.isPresent()) {
341                     if (Optional.class.getCanonicalName().equals(variable.getTypeInfo().getType())) {
342                         JClass varType = CodeModelUtil.getGenericList(model, variable.getTypeInfo().getGenericType().get());
343                         JVar list = method.body().decl(varType, "list" + i);
344                         method.body().assign(list, JExpr.cast(varType, map.invoke("get").arg("#result-set-" + i)));
345 
346                         JVar obj = method.body().decl(model.directClass(variable.getTypeInfo().getType()), "obj" + i);
347                         JConditional condition = method.body()._if(list.invoke("size").eq(JExpr.lit(1)));
348                         condition._then().assign(obj, model.directClass(Optional.class.getCanonicalName()).staticInvoke("of").arg(list.invoke("get").arg(JExpr.lit(0))));
349 
350                         condition = condition._elseif(list.invoke("size").eq(JExpr.lit(0)));
351                         condition._then().assign(obj, model.directClass(Optional.class.getCanonicalName()).staticInvoke("empty"));
352                         condition._else()._throw(JExpr._new(model.directClass(MultipleObjectsReturned.class.getCanonicalName())));
353 
354                         args.add(obj);
355                     } else {
356                         JClass varType = model.directClass(variable.getTypeInfo().getType()).narrow(model.directClass(genericType.get()));
357                         JVar list = method.body().decl(varType, "list" + i);
358                         method.body().assign(list, JExpr.cast(varType, map.invoke("get").arg("#result-set-" + i)));
359                         args.add(list);
360                     }
361                 } else {
362                     JClass varType = CodeModelUtil.getGenericList(model, variable.getTypeInfo().getType());
363                     JVar list = method.body().decl(varType, "list" + i);
364                     method.body().assign(list, JExpr.cast(varType, map.invoke("get").arg("#result-set-" + i)));
365 
366                     JVar obj = method.body().decl(model.directClass(variable.getTypeInfo().getType()), "obj" + i);
367                     JConditional condition = method.body()._if(list.invoke("size").eq(JExpr.lit(1)));
368                     condition._then().assign(obj, list.invoke("get").arg(JExpr.lit(0)));
369 
370                     if (variable.useNullInsteadOfAnException()) {
371                         condition = condition._elseif(list.invoke("size").eq(JExpr.lit(0)));
372                         condition._then().assign(obj, JExpr._null());
373                         condition._else()._throw(JExpr._new(model.directClass(MultipleObjectsReturned.class.getCanonicalName())));
374                     } else {
375                         condition = condition._elseif(list.invoke("size").eq(JExpr.lit(0)));
376                         condition._then()._throw(JExpr._new(model.directClass(ObjectDoesNotExist.class.getCanonicalName())));
377                         condition._else()._throw(JExpr._new(model.directClass(MultipleObjectsReturned.class.getCanonicalName())));
378                     }
379 
380                     args.add(obj);
381                 }
382             }
383 
384             args.forEach(resultSetsInvoke::arg);
385 
386             method.body()._return(resultSetsInvoke);
387         }
388 
389         /**
390          * Generates the body of the DTO method for methods with exactly one result-set.
391          * <p>
392          * If the method's return value is a list:
393          * <pre>
394          * Map<String, Object> map;
395          * Object interceptorIdObject; // optional
396          * interceptorIdObject = *SpInterceptor.before("*"); // optional
397          * map = sp*.execute();
398          * *SpInterceptor.after(interceptorIdObject, "*"); // optional
399          * return ((List<*> ) map.get("#result-set-0"));
400          * </pre>
401          * <p>
402          * If the method's return value is an entity:
403          * <pre>
404          * Object interceptorIdObject; // optional
405          * interceptorIdObject = *SpInterceptor.before("*"); // optional
406          * List<*> list;
407          * list = ((List<*> ) sp*.execute( [ * ]* ).get("#result-set-0"));
408          * *SpInterceptor.after(interceptorIdObject, "*"); // optional
409          * if (list.size() == 1) {
410          *     return list.get(0);
411          * } else {
412          *     if (list.size() == 0) {
413          *         throw new ObjectDoesNotExist();
414          *     } else {
415          *         throw new MultipleObjectsReturned();
416          *     }
417          * }
418          * </pre>
419          * <p>
420          * If the method's return value is an entity and the method is annotated with @ReturnNull:
421          * <pre>
422          * Object interceptorIdObject; // optional
423          * interceptorIdObject = *SpInterceptor.before("*"); // optional
424          * List<*> list;
425          * list = ((List<*> ) sp*.execute( [ * ]* ).get("#result-set-0"));
426          * *SpInterceptor.after(interceptorIdObject, "*"); // optional
427          * if (list.size() == 1) {
428          *     return list.get(0);
429          * } else {
430          *     if (list.size() == 0) {
431          *         return null;
432          *     } else {
433          *         throw new MultipleObjectsReturned();
434          *     }
435          * }
436          * </pre>
437          * <p>
438          * If the method's return value is an Optional of an entity:
439          * <pre>
440          * Object interceptorIdObject; // optional
441          * interceptorIdObject = *SpInterceptor.before("*"); // optional
442          * List<*> list;
443          * list = ((List<*> ) sp*.execute( [ * ]* ).get("#result-set-0"));
444          * *SpInterceptor.after(interceptorIdObject, "*"); // optional
445          * if (list.size() == 1) {
446          *     return Optional.of(list.get(0));
447          * } else {
448          *     if (list.size() == 0) {
449          *         return Optional.empty();
450          *     } else {
451          *         throw new MultipleObjectsReturned();
452          *     }
453          * }
454          * </pre>
455          */
456         private void singleResultSet(StoredProcedureMethod storedProcedureMethod, JClass returnClass, JMethod method, JInvocation execute, JVar interceptorIdObject) {
457             if (storedProcedureMethod.getReturnTypeInfo().getGenericType().isPresent()) {
458                 if (Optional.class.getCanonicalName().equals(storedProcedureMethod.getReturnTypeInfo().getType())) {
459                     String genericClassType = storedProcedureMethod.getReturnTypeInfo().getGenericType().get();
460                     JVar list = method.body().decl(CodeModelUtil.getGenericList(model, genericClassType), "list");
461                     method.body().assign(list, JExpr.cast(model.ref(List.class).narrow(model.ref(genericClassType)), execute.invoke("get").arg("#result-set-0")));
462                     addInterceptorCallAfter(storedProcedureMethod, method, execute, interceptorIdObject);
463                     JConditional condition = method.body()._if(list.invoke("size").eq(JExpr.lit(1)));
464                     condition._then()._return(model.directClass(Optional.class.getCanonicalName()).staticInvoke("of").arg(list.invoke("get").arg(JExpr.lit(0))));
465                     condition = condition._elseif(list.invoke("size").eq(JExpr.lit(0)));
466                     condition._then()._return(model.directClass(Optional.class.getCanonicalName()).staticInvoke("empty"));
467                     condition._else()._throw(JExpr._new(model.directClass(MultipleObjectsReturned.class.getCanonicalName())));
468                 } else {
469                     JVar map = method.body().decl(CodeModelUtil.getMapStringObject(model), "map");
470                     method.body().assign(map, execute);
471                     addInterceptorCallAfter(storedProcedureMethod, method, execute, interceptorIdObject);
472                     method.body()._return(JExpr.cast(returnClass, map.invoke("get").arg("#result-set-0")));
473                 }
474             } else {
475                 JVar list = method.body().decl(CodeModelUtil.getGenericList(model, storedProcedureMethod.getReturnTypeInfo().getType()), "list");
476                 method.body().assign(list, JExpr.cast(model.ref(List.class).narrow(returnClass), execute.invoke("get").arg("#result-set-0")));
477                 addInterceptorCallAfter(storedProcedureMethod, method, execute, interceptorIdObject);
478                 JConditional condition = method.body()._if(list.invoke("size").eq(JExpr.lit(1)));
479                 condition._then()._return(list.invoke("get").arg(JExpr.lit(0)));
480 
481                 if (storedProcedureMethod.useNullInsteadOfAnException()) {
482                     condition = condition._elseif(list.invoke("size").eq(JExpr.lit(0)));
483                     condition._then()._return(JExpr._null());
484                     condition._else()._throw(JExpr._new(model.directClass(MultipleObjectsReturned.class.getCanonicalName())));
485                 } else {
486                     condition = condition._elseif(list.invoke("size").eq(JExpr.lit(0)));
487                     condition._then()._throw(JExpr._new(model.directClass(ObjectDoesNotExist.class.getCanonicalName())));
488                     condition._else()._throw(JExpr._new(model.directClass(MultipleObjectsReturned.class.getCanonicalName())));
489                 }
490             }
491         }
492 
493         /**
494          * Adds the interceptor call of the after method.
495          */
496         private void addInterceptorCallAfter(StoredProcedureMethod storedProcedureMethod, JMethod method, JInvocation execute, JVar interceptorIdObject) {
497             if(interceptorIdObject != null) {
498                 JInvocation after = model.ref(config.getProperty("interceptor")).staticInvoke("after");
499                 after.arg(interceptorIdObject);
500                 after.arg(JExpr.lit(storedProcedureMethod.getStoredProcedureName()));
501 
502                 for (JExpression arg : execute.listArgs()) {
503                     after.arg(arg);
504                 }
505 
506                 method.body().add(after);
507             }
508         }
509 
510         private void addAnnotationParam(JAnnotationUse jAnnotationUse, AnnotationValueInfo annotationValueInfo) throws JClassAlreadyExistsException {
511             Object value = annotationValueInfo.getValue();
512             String annotationName = annotationValueInfo.getName();
513 
514             switch (annotationValueInfo.getKind()) {
515                 case BASIC:
516                     if (value instanceof Boolean) {
517                         jAnnotationUse.param(annotationName, (Boolean) value);
518                     } else if (value instanceof Byte) {
519                         jAnnotationUse.param(annotationName, (Byte) value);
520                     } else if (value instanceof Character) {
521                         jAnnotationUse.param(annotationName, (Character) value);
522                     } else if (value instanceof Double) {
523                         jAnnotationUse.param(annotationName, (Double) value);
524                     } else if (value instanceof Float) {
525                         jAnnotationUse.param(annotationName, (Float) value);
526                     } else if (value instanceof Long) {
527                         jAnnotationUse.param(annotationName, (Long) value);
528                     } else if (value instanceof Short) {
529                         jAnnotationUse.param(annotationName, (Short) value);
530                     } else if (value instanceof Integer) {
531                         jAnnotationUse.param(annotationName, (Integer) value);
532                     } else if (value instanceof String) {
533                         jAnnotationUse.param(annotationName, (String) value);
534                     }
535                     break;
536                 case DECLARED_TYPE:
537                     jAnnotationUse.param(annotationName, model.ref(value.toString()));
538                     break;
539                 case ELEMENT:
540                     String qualifiedEnumName = StringUtil.getPackage(annotationValueInfo.getType());
541                     JPackage dtoJPackage = new JCodeModel()._package(StringUtil.getPackage(qualifiedEnumName));
542                     JDefinedClass definedClass = dtoJPackage._class(StringUtil.getSimpleClassName(qualifiedEnumName));
543                     jAnnotationUse.param(annotationName, definedClass.enumConstant(value.toString()));
544                     break;
545                 case LIST:
546                     JAnnotationArrayMember jAnnotationArrayMember = jAnnotationUse.paramArray(annotationName);
547                     List<AnnotationValueInfo> list = (List<AnnotationValueInfo>) value;
548 
549                     for (AnnotationValueInfo valueInfo : list) {
550                         addAnnotationArrayMemberParam(jAnnotationArrayMember, valueInfo);
551                     }
552                     break;
553                 default:
554                     throw new RuntimeException("Failed to addAnnotationParam, because the kind is unknown: " + annotationValueInfo.getKind());
555             }
556         }
557 
558         private void addAnnotationArrayMemberParam(JAnnotationArrayMember jAnnotationArrayMember, AnnotationValueInfo annotationValueInfo) {
559             Object value = annotationValueInfo.getValue();
560 
561             try {
562                 switch (annotationValueInfo.getKind()) {
563                     case BASIC:
564                         if (value instanceof Boolean) {
565                             jAnnotationArrayMember.param((Boolean) value);
566                         } else if (value instanceof Byte) {
567                             jAnnotationArrayMember.param((Byte) value);
568                         } else if (value instanceof Character) {
569                             jAnnotationArrayMember.param((Character) value);
570                         } else if (value instanceof Double) {
571                             jAnnotationArrayMember.param((Double) value);
572                         } else if (value instanceof Float) {
573                             jAnnotationArrayMember.param((Float) value);
574                         } else if (value instanceof Long) {
575                             jAnnotationArrayMember.param((Long) value);
576                         } else if (value instanceof Short) {
577                             jAnnotationArrayMember.param((Short) value);
578                         } else if (value instanceof Integer) {
579                             jAnnotationArrayMember.param((Integer) value);
580                         } else if (value instanceof String) {
581                             jAnnotationArrayMember.param((String) value);
582                         }
583                         break;
584                     case DECLARED_TYPE:
585                         jAnnotationArrayMember.param(model.ref(value.toString()));
586                         break;
587                     case ELEMENT:
588                         String qualifiedEnumName = StringUtil.getPackage(value.toString());
589                         JPackage dtoJPackage = model._package(StringUtil.getPackage(qualifiedEnumName));
590                         JDefinedClass definedClass = dtoJPackage._class(StringUtil.getSimpleClassName(qualifiedEnumName));
591                         jAnnotationArrayMember.param(definedClass.enumConstant(value.toString()));
592                         break;
593                     default:
594                         throw new RuntimeException("Failed to addAnnotationParam, because the kind is unknown: " + annotationValueInfo.getKind());
595                 }
596             } catch (JClassAlreadyExistsException e) {
597                 throw new RuntimeException("JClassAlreadyExistsException", e);
598             }
599         }
600 
601     }
602 }